If different elements of a variable sized array can overlap with each
other then we can cause a `GVariant` to normalise to a much larger type.
This commit changes the behaviour of `GVariant` with non-normal form data. If
an invalid frame offset is found all subsequent elements are given their
default value.
When retrieving an element at index `n` we scan the frame offsets up to index
`n` and if they are not in order we return an element with the default value
for that type. This guarantees that elements don't overlap with each
other. We remember the offset we've scanned up to so we don't need to
repeat this work on subsequent accesses. We skip these checks for trusted
data.
Unfortunately this makes random access of untrusted data O(n) — at least
on first access. It doesn't affect the algorithmic complexity of accessing
elements in order, such as when using the `GVariantIter` interface. Also:
the cost of validation will be amortised as the `GVariant` instance is
continued to be used.
I've implemented this with 4 different functions, 1 for each element size,
rather than looping calling `gvs_read_unaligned_le` in the hope that the
compiler will find it easy to optimise and should produce fairly tight
code.
Fixes: #2121
The following few commits will add a couple of new fields to
`GVariantSerialised`, and they should be zero-filled by default.
Try and pre-empt that a bit by zero-filling `GVariantSerialised` by
default in a few places.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Helps: #2121
If a seccomp policy is set up incorrectly so that it returns `EPERM` for
`close_range()` rather than `ENOSYS` due to it not being recognised, no
error would previously be reported from GLib, but some file descriptors
wouldn’t be closed, and that would cause a hung zombie process. The
zombie process would be waiting for one half of a socket to be closed.
Fix that by correctly propagating errors from `close_range()` back to the
parent process so they can be reported correctly.
Distributions which aren’t yet carrying the Docker fix to correctly
return `ENOSYS` from unrecognised syscalls may want to temporarily carry
an additional patch to fall back to `safe_fdwalk()` if `close_range()`
fails with `EPERM`. This change will not be accepted upstream as `EPERM`
is not the right error for `close_range()` to be returning.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Fixes: #2580
g_get_user_database_entry() uses variable pwd to store the contents of
the call to getpwnam_r(), then capitalises the first letter of pw_name
with g_ascii_toupper (pw->pw_name[0]).
However, as per the getpwnam manpage, the result of that call "may point
to a static area". When this happens, GLib is trying to edit static
memory which belongs to a shared library, so segfaults.
Instead, copy pw_name off to a temporary variable, set uppercase on
that variable, and use the variable to join into the desired string.
Free the new variable after it is no longer needed.
Signed-off-by: Jamie Bainbridge <jamie.bainbridge@gmail.com>
This tests for #2503. It's fragile, but there is no non-fragile way to
test this. If the test breaks in the future, it will pass without
successfully testing the bug, not fail spuriously, so I think this is
OK.
Although unlikely, these functions can fail, e.g. if we run out of file
descriptors. Check for errors to improve robustness. This is especially
important now that I changed our use of dupfd_cloexec() to avoid
returning fds smaller than the largest fd in target_fds. An application
that attempts to remap to the highest-allowed fd value deserves at least
some sort of attempt at error reporting, not silent failure.
We should run test_pass_fd twice, once using gspawn's fork/exec codepath
and once attempting to use its posix_spawn() codepath. There's no
guarantee we'll actually get the posix_spawn() codepath, but it works
for now on Linux.
For good measure, run it a third time with no flags at all.
This causes the test to fail if I separately break the fd remapping
implementation. Without this, we fail to test fd remapping on the
posix_spawn() codepath.
We currently dup all source fds to avoid possible conflation with the
target fds, but fail to consider that the result of a dup might itself
conflict with one of the target fds. Solve this the easy way by duping
all source_fds to values that are greater than the largest fd in
target_fds.
Fixes#2503
In case child_err_report_fd conflicts with one of the target_fds, the
code here is careful to dup child_err_report_fd in order to avoid
conflating the two. It was a good idea, but evidently was not tested,
because the newly-created fd is not created with CLOEXEC set. This means
it stays open in the child process, causing the parent to hang forever
waiting to read from the other end of the pipe. Oops!
The fix is simple: just set CLOEXEC. This removes our only usage of the
safe_dup() function, so it can be dropped.
Fixes#2506
systemd allows setting a SourcePath= which shows the file that the unit
has been generated from. KDE is starting to set this and it seems like a
good idea, so do the same here.
See https://invent.kde.org/frameworks/kio/-/merge_requests/124
This allows delaying the return of the task until all dbus calls (in
particular the ones to setup the scope) have finished.
This fixes the behaviour of the previous commit which would not
correctly move the process into the scope if the application exited
right after the task returned.
Try to move the spawned executable into its own systemd scope. To avoid
possible race conditions and ensure proper accounting, we delay the
execution of the real command until after the DBus call to systemd has
finished.
From the two approaches we can take here, this is better in the sense
that we have a child that the API consumer can watch. API consumers
should not be doing this, however, gnome-session needs to watch children
during session startup. Until gnome-session is fixed, we will not be
able to change this.
The alternative approach is to delegate launching itself to systemd by
creating a transient .service unit instead. This is cleaner and has e.g.
the advantage that systemd will take care of log redirection and similar
issues.
Note that this patch is incomplete. The DBus call is done in a "fire and
forget" manner, which is fine in most cases, but means that "gio open"
will fail to move the child into the new scope as gio quits before the
DBus call finishes.
When launching an application, we wait for the DBus response from
systemd before executing the binary. Because of this the main loop needs
to be iterated for spawning to completed and the file to be created.
Without this the test will time out if GLib was able to connect to the
session bus.
g_win32_package_parser_enum_packages() reads beyond the end of a buffer
when doing a memcpy. With app verifier enabled on Windows, it causes
the application to crash on startup.
This change limits the memcpy to the size of the source string.
Fixes: #2454
The value should be initialized to NULL before calling
g_win32_registry_key_get_value_w(), to ensure that cleanup
can be done unconditionally afterward.
To ensure that the watch is properly re-set every time, call
watch_keys() from the watch callback. Previously the watch was only
renewed after a data update was done in a worker thread, which made
no sense, since the update function was implemented in such a way
that it can (and should) be re-triggered on each key change, until
the changes stop coming, and that can only happen if we renew
the registry watcher right away.
If a key watch is renewed from the key watch callback, it results
in the callback being NULL, since we clear it after we call it.
Rearrange the function to make sure that the changes done by the
callback function are preserved properly.
This function can, in fact, return STATUS_SUCCESS. We shouldn't
assert that it doesn't.
For now interpret it just like STATUS_PENDING (i.e. APC will be called),
see how it goes (it isn't documented how the function behaves in this
case, we have to play it by ear).
Note that while we *can* use a better-documented RegNotifyChangeKeyValue() here,
it communicates back to us via event objects, which means that the registry
watcher would have to interact with the main loop directly and insert its
events (plural; one event per key) there. That would make the API more complicated.
Whereas the internal NT function communicates by calling an APC - we're good
as long as something somewhere puts the thread in alertable state.
Previously, these would have done 2**32 replacements, and the first one
would have consumed 6GB of memory in the process. They now match what
Python `str.replace()` does.
Reproduces: https://gitlab.gnome.org/GNOME/glib/-/issues/2452
Signed-off-by: Simon McVittie <smcv@collabora.com>
This matches the behaviour of Python `str.replace()`, and avoids carrying
out 2**32 replacements before n wraps around, which is almost certainly
not what we want.
Resolves: https://gitlab.gnome.org/GNOME/glib/-/issues/2452
Signed-off-by: Simon McVittie <smcv@collabora.com>
These are taken from another project (steam-runtime-tools) where I
implemented a similar replace method before realising that more recent
GLib versions had g_string_replace().
Signed-off-by: Simon McVittie <smcv@collabora.com>