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, which 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.
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>
gio/ghttpproxy.c: In function ‘g_http_proxy_connect’:
gio/ghttpproxy.c:245:17: error: comparison of integer expressions of different signedness: ‘gsize’ {aka ‘long unsigned int’} and ‘int’
245 | if (nread == -1)
| ^~
gio/ghttpproxy.c:253:22: error: comparison of integer expressions of different signedness: ‘gssize’ {aka ‘long int’} and ‘gsize’ {aka ‘long unsigned int’}
253 | if (bytes_read == buffer_length)
| ^~
Various tests have leaks where it isn't clear whether the data is
intentionally not freed, or leaked due to a bug. If we mark these
tests as TODO, we can skip them under AddressSanitizer and get the
rest to pass, giving us a baseline from which to avoid regressions.
Signed-off-by: Simon McVittie <smcv@collabora.com>
AddressSanitizer detects memory leaks, NULL parameters where only a
non-NULL parameter is expected, and other suspicious behaviour, so if
we try to test that sort of thing we can expect it to fail.
Signed-off-by: Simon McVittie <smcv@collabora.com>
AddressSanitizer, UndefinedBehaviourSanitizer and probably others
involve adding instrumentation into the code under test, which doesn't
go well with LD_PRELOAD modules that absolutely need to be
self-contained.
Signed-off-by: Simon McVittie <smcv@collabora.com>
gio/gapplication.c: In function ‘g_application_parse_command_line’:
gio/gapplication.c:545:11: error: missing initializer for field ‘arg_description’ of ‘GOptionEntry’ {aka ‘struct _GOptionEntry’}
545 | N_("Enter GApplication service mode (use from D-Bus service files)") },
| ^~
gio/gapplication.c:557:11: error: missing initializer for field ‘arg_description’ of ‘GOptionEntry’ {aka ‘struct _GOptionEntry’}
557 | N_("Override the application’s ID") },
| ^~
gio/gapplication.c:569:11: error: missing initializer for field ‘arg_description’ of ‘GOptionEntry’ {aka ‘struct _GOptionEntry’}
569 | N_("Replace the running instance") },
| ^~
gio/gdbusconnection.c: In function ‘g_dbus_connection_register_object_with_closures’:
gio/gdbusconnection.c:5527:5: error: missing initializer for field ‘padding’ of ‘GDBusInterfaceVTable’ {aka ‘struct _GDBusInterfaceVTable’}
5527 | };
| ^
gio/gdelayedsettingsbackend.c: In function ‘delayed_backend_path_writable_changed’:
gio/gdelayedsettingsbackend.c:406:7: error: missing initializer for field ‘index’ of ‘CheckPrefixState’
406 | CheckPrefixState state = { path, g_new (const gchar *, n_keys) };
| ^~~~~~~~~~~~~~~~
We have a "good" implementation of g_clear_signal_handler() in
form of a macro. Use it, and don't duplicate the code.
Also add a comment to the documentation that "instance" in fact must
not point to a valid GObject instance -- if the handler ID is unset.
Also reword the documentation about the reasoning for why a macro
version exists. The reason is not to use the function "without
pointer cast". I don't think the non-macro version requires any
pointer cast, since "instance" is a void pointer. Was this referring
to the handler_id_ptr? That doesn't seem right either, because the
caller should always provide a "gulong *" pointer and nothing else.
Preferably macros behave function-like to minimize surprises. That
means for example that they evaluate all arguments exactly once.
Rework g_clear_signal_handler() to assign the macro parameters
to auto variables so they are accessed exactly once.
Also, drop the static assert for the size of (*handler_id_ptr).
As we now assign to a "gulong *" pointer, the compiler already
checks the types. In fact, the check is now stricter than before.
Previously it would have allowed a pointer to a "signed long".
This is a change in behavior of the macro and the stricter compile
check could cause a build failure with broken code.
Also, clear the handler id first, before calling
g_signal_handler_disconnect(). Disconnecting a signal invokes the
destroy notify, which can have side effects. It just feels cleaner
to first reset the *_handler_id_ptr, before those side effects
can happen. Of course, in practice it makes little difference.
g_signal_new_valist() is called by g_signal_new(), which is probably
the most common way to create a signal.
Also, in almost all cases is the number of signal parameters small.
Let's optimize for that by using a stack allocated buffer if we have
few parameters.
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]