Convert all the call sites which use `g_memdup()`’s length argument
trivially (for example, by passing a `sizeof()`), so that they use
`g_memdup2()` instead.
In almost all of these cases the use of `g_memdup()` would not have
caused problems, but it will soon be deprecated, so best port away from
it.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Helps: #2319
This will replace the existing `g_memdup()` function for use within
GLib. It has an unavoidable security flaw of taking its `byte_size`
argument as a `guint` rather than as a `gsize`. Most callers will
expect it to be a `gsize`, and may pass in large values which could
silently be truncated, resulting in an undersize allocation compared
to what the caller expects.
This could lead to a classic buffer overflow vulnerability for many
callers of `g_memdup()`.
`g_memdup2()`, in comparison, takes its `byte_size` as a `gsize`.
Spotted by Kevin Backhouse of GHSL.
In GLib 2.68, `g_memdup2()` will be a new public API. In this version
for backport to older stable releases, it’s a new `static inline` API
in a private header, so that use of `g_memdup()` within GLib can be
fixed without adding a new API in a stable release series.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Helps: GHSL-2021-045
Helps: #2319
We're using "setuid" here as shorthand for any elevated privileges
that should make us distrust the caller: setuid, setgid, filesystem
capabilities, more obscure Linux things that set the AT_SECURE flag
(such as certain AppArmor transitions), and their equivalents on
other operating systems. This is fine if we do it consistently, but
I'm about to add a check for whether we are *literally* setuid,
which would be particularly confusing without a rename.
Signed-off-by: Simon McVittie <smcv@collabora.com>
We preallocate buffers that are used after forked. That is because
malloc()/free() are not async-signal-safe and must not be used between
fork() and exec().
However, for the child process that exits without fork, valgrind wrongly
reports these buffers as leaked.
That can be suppressed with "--child-silent-after-fork=yes", but it is
cumbersome.
Work around by trying to allocate the buffers on the stack. At
least in the common cases where the pointers are small enough
so that we can reasonably do that.
If the buffers happen to be large, we still allocate them on the heap
and the problem still happens. Maybe we could have also allocated them
as thread_local, but currently glib doesn't use that.
[smcv: Cosmetic adjustments to address review comments from pwithnall]
For manual test coverage that would reproduce the bug fixed in !1902,
copy /bin/true (or any other harmless executable) to
/usr/bin/spawn-test-helper.
Signed-off-by: Simon McVittie <smcv@collabora.com>
do_exec() and g_execute() rely on being passed a NULL search path
if we intend to avoid searching the PATH, but since the refactoring
in commit 62ce66d4, this was never done. This resulted in some spawn
calls searching the PATH when it was not intended.
Spawn calls that go through the posix_spawn fast-path were unaffected.
The deprecated gtester utility, as used in GTK 3, relies on the
ability to run an executable from the current working directory by
omitting the G_SPAWN_SEARCH_PATH flag. This *mostly* worked, because
our fallback PATH ends with ".". However, if an executable of the
same name existed in /usr/bin or /bin, it would run that instead of the
intended test: in particular, GTK 3's build-time tests failed if
ImageMagick happens to be installed, because gtester would accidentally
run display(1) instead of testsuite/gdk/display.
Fixes: 62ce66d4 "gspawn: Don’t use getenv() in async-signal-safe context"
Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=977961
Split out XDG_CURRENT_DESKTOP handling to a separate function and make
sure that it drops all the invalid entries properly. Earlier a bad
entry could slip through the checks by sitting just after another bad
entry, like in env being set to `invalid1!:invalid2!`, where
`invalid2!` could slip the checks.
As with previous commits, this could have been used to load private data
for an unprivileged caller.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Helps: #2168
It could have been used to load private data which would not normally be
accessible to an unprivileged caller.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Helps: #2168
Its components are used to build filenames, so if the value of
`XDG_CURRENT_DESKTOP` comes from an untrusted caller (as can happen in
setuid programs), using it unvalidated may be unsafe.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Helps: #2168
As with the previous commit, it’s unsafe to trust the environment when
running as setuid, as it comes from an untrusted caller. In particular,
with D-Bus, the caller could set up a fake ‘system’ bus which fed
incorrect data to this process.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Helps: #2168
Even if the modules in the given directory never get chosen to be used,
loading arbitrary code from a user-provided directory is not safe when
running as setuid, as the process’ environment comes from an untrusted
source.
Also ignore `GIO_EXTRA_MODULES`.
Spotted by Simon McVittie.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Fixes: #2168
Contrary to what the WSARecvFrom seem to imply, a UDP socket is perfectly recoverable and usable after a WSAECONNRESET error (and, I assume, WSAENETRESET).
However GSocket condition has the FD_READ bit set after a UDP socket fails with WSAECONNRESET, even if no data is available on the socket anymore; this causes select calls to report the socket as readable when, in fact, it's not.
The change resets FD_READ flag on a socket upon the above error conditions; there's no 'if' to filter between datagram and stream sockets as the change should be harmless in the case of stream sockets which are, however, very unlikely to be usable after a WSAECONNRESET.
Realistically any date over 200 bytes long is not going to be valid, so
limit the input length so we can’t spend too long doing UTF-8 validation
or normalisation.
oss-fuzz#28718
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
If the old value is destroyed before updating the TLS value in pthreads
(or the Windows equivalent) then there’s a risk of infinite recursion if
`g_private_replace()` is called from within the `GDestroyNotify`.
Avoid that by destroying the old value after doing the TLS update.
Thanks to Matthias Clasen for diagnosing the issue.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Fixes: #2210
Both are provided by libm, but `isnan()` is provided as a macro, whereas
`isfinite()` is an actual function, and hence libm has to be available
at runtime. That didn’t trivially work on FreeBSD, resulting in this
refactor.
`isfinite(x)` is equivalent to `!isnan(x) && !isinfinite(x)`. The case
of `x` being (negative or positive) infinity is already handled by the
range checks on the next line, so it’s safe to switch to `isnan()` here.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Rather than parsing the seconds in an ISO 8601 date/time using a pair of
floating point numbers (numerator and denominator), use two integers
instead. This avoids issues around floating point precision, and also
makes it easier to check for potential overflow from overlong inputs.
This last point means that the `isfinite()` check can be removed, as it
was covering the case where a NAN was generated, which isn’t now
possible using integer arithmetic.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
NULL is valid return value for the g_unix_mount_get_options function
because mount options are currently provided only by libmount implementation.
However, the gio tool passes the returned value to the g_strescape function
without checking, which produces the following critical warning:
GLib-CRITICAL **: 13:47:15.294: g_strescape: assertion 'source != NULL' failed
Let's add the missing check to prevent the critical warnings.
The fiendish thing about NAN is that it never compares TRUE against
anything, so the limit checks `seconds < 0.0 || seconds >= 60.0` were
never triggering.
oss-fuzz#28473
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
As hidden file caches currently work, every look up on a directory caches
its .hidden file contents, and sets a 5s timeout to prune the directory
from the cache.
This creates a problem for usecases like Tracker Miners, which is in the
business of inspecting as many files as possible from as many directories
as possible in the shortest time possible. One timeout is created for each
directory, which possibly means gobbling thousands of entries in the hidden
file cache. This adds as many GSources to the glib worker thread, with the
involved CPU overhead in iterating those in its main context.
To fix this, use a unique timeout that will keep running until the cache
is empty. This will keep the overhead constant with many files/folders
being queried.
This incidentally also exercises the intended pattern for sending fds in
a D-Bus message: the fd list is meant to contain exactly those fds that
are referenced by a handle (type 'h') in the body of the message, with
numeric handle value n corresponding to g_unix_fd_list_peek_fds(...)[n].
Being able to send and receive file descriptors that are not referenced by
a handle (as in OpenFile here) is a quirk of the GDBus API, and while it's
entirely possible in the wire protocol, other D-Bus implementations like
libdbus and sd-bus typically don't provide APIs that make this possible.
Reproduces: https://gitlab.gnome.org/GNOME/glib/-/issues/2074
Signed-off-by: Simon McVittie <smcv@collabora.com>