Skip to content
Commits on Source (51)
Overview of changes in GLib 2.67.6
==================================
* Fix a security issue when using `g_file_replace()` with
`G_FILE_CREATE_REPLACE_DESTINATION` (#2325)
* Disallow operations on the empty path with `g_file_new_from_path()` (#2328)
* Various fixes for GLib when building with clang-cl on Windows (work by
Aleksandr Mezin) (#2341, #2344)
* Bugs fixed:
- #2325 file-roller symlink attack
- #2327 Teach glib-mkenums about GLIB_AVAILABLE_ENUMERATOR_IN_2_68, and start using it
- #2328 g_file_new_for_path("") yields CWD, which seems wrong
- #2341 glib-genmarshal output is sometimes empty because output file is not closed
- #2344 c_std=c11: gbitlock.c: ‘asm’ undeclared
- !1962 Validate D-Bus machine ID after loading
- !1976 Use the right permissions for directory watching on Win32
- !1977 gio/tests/{meson.build,pollable.c}: Determine libutil SONAME at build time
- !1980 glib.supp: Add another system thread suppression
* Translation updates:
- Basque
- Catalan
- Czech
- French
- Galician
- German
- Hungarian
- Indonesian
- Korean
- Latvian
- Portuguese
- Portuguese (Brazil)
- Serbian
- Spanish
- Swedish
- Ukrainian
Overview of changes in GLib 2.67.5
==================================
......
......@@ -2470,31 +2470,63 @@ _g_dbus_get_machine_id (GError **error)
return res;
#else
gchar *ret;
GError *first_error;
/* TODO: use PACKAGE_LOCALSTATEDIR ? */
ret = NULL;
first_error = NULL;
if (!g_file_get_contents ("/var/lib/dbus/machine-id",
gchar *ret = NULL;
GError *first_error = NULL;
gsize i;
gboolean non_zero = FALSE;
/* Copy what dbus.git does: allow the /var/lib path to be configurable at
* build time, but hard-code the system-wide machine ID path in /etc. */
const gchar *var_lib_path = LOCALSTATEDIR "/lib/dbus/machine-id";
const gchar *etc_path = "/etc/machine-id";
if (!g_file_get_contents (var_lib_path,
&ret,
NULL,
&first_error) &&
!g_file_get_contents ("/etc/machine-id",
!g_file_get_contents (etc_path,
&ret,
NULL,
NULL))
{
g_propagate_prefixed_error (error, first_error,
_("Unable to load /var/lib/dbus/machine-id or /etc/machine-id: "));
g_propagate_prefixed_error (error, g_steal_pointer (&first_error),
/* Translators: Both placeholders are file paths */
_("Unable to load %s or %s: "),
var_lib_path, etc_path);
return NULL;
}
else
/* ignore the error from the first try, if any */
g_clear_error (&first_error);
/* Validate the machine ID. From `man 5 machine-id`:
* > The machine ID is a single newline-terminated, hexadecimal, 32-character,
* > lowercase ID. When decoded from hexadecimal, this corresponds to a
* > 16-byte/128-bit value. This ID may not be all zeros.
*/
for (i = 0; ret[i] != '\0' && ret[i] != '\n'; i++)
{
/* ignore the error from the first try, if any */
g_clear_error (&first_error);
/* TODO: validate value */
g_strstrip (ret);
/* Break early if it’s invalid. */
if (!g_ascii_isxdigit (ret[i]) || g_ascii_isupper (ret[i]))
break;
if (ret[i] != '0')
non_zero = TRUE;
}
return ret;
if (i != 32 || ret[i] != '\n' || ret[i + 1] != '\0' || !non_zero)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"Invalid machine ID in %s or %s",
var_lib_path, etc_path);
g_free (ret);
return NULL;
}
/* Strip trailing newline. */
ret[32] = '\0';
return g_steal_pointer (&ret);
#endif
}
......
......@@ -126,7 +126,7 @@ g_dummy_file_get_basename (GFile *file)
if (dummy->decoded_uri)
return g_path_get_basename (dummy->decoded_uri->path);
return g_strdup (dummy->text_uri);
return NULL;
}
static char *
......
......@@ -1220,7 +1220,7 @@ typedef enum {
G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS = (1<<2),
G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION = (1<<3),
G_DBUS_CONNECTION_FLAGS_DELAY_MESSAGE_PROCESSING = (1<<4),
G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_REQUIRE_SAME_USER = (1<<5)
G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_REQUIRE_SAME_USER GLIB_AVAILABLE_ENUMERATOR_IN_2_68 = (1<<5)
} GDBusConnectionFlags;
/**
......@@ -1383,7 +1383,7 @@ typedef enum
G_DBUS_SERVER_FLAGS_NONE = 0,
G_DBUS_SERVER_FLAGS_RUN_IN_THREAD = (1<<0),
G_DBUS_SERVER_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS = (1<<1),
G_DBUS_SERVER_FLAGS_AUTHENTICATION_REQUIRE_SAME_USER = (1<<2)
G_DBUS_SERVER_FLAGS_AUTHENTICATION_REQUIRE_SAME_USER GLIB_AVAILABLE_ENUMERATOR_IN_2_68 = (1<<2)
} GDBusServerFlags;
/**
......
......@@ -107,6 +107,12 @@ g_io_error_from_errno (gint err_no)
break;
#endif
#ifdef ENXIO
case ENXIO:
return G_IO_ERROR_NOT_REGULAR_FILE;
break;
#endif
#ifdef EROFS
case EROFS:
return G_IO_ERROR_READ_ONLY;
......
......@@ -63,6 +63,12 @@
#define O_BINARY 0
#endif
#ifndef O_CLOEXEC
#define O_CLOEXEC 0
#else
#define HAVE_O_CLOEXEC 1
#endif
struct _GLocalFileOutputStreamPrivate {
char *tmp_filename;
char *original_filename;
......@@ -850,11 +856,12 @@ handle_overwrite_open (const char *filename,
int res;
int mode;
int errsv;
gboolean replace_destination_set = (flags & G_FILE_CREATE_REPLACE_DESTINATION);
mode = mode_from_flags_or_info (flags, reference_info);
/* We only need read access to the original file if we are creating a backup.
* We also add O_CREATE to avoid a race if the file was just removed */
* We also add O_CREAT to avoid a race if the file was just removed */
if (create_backup || readable)
open_flags = O_RDWR | O_CREAT | O_BINARY;
else
......@@ -877,16 +884,22 @@ handle_overwrite_open (const char *filename,
/* Could be a symlink, or it could be a regular ELOOP error,
* but then the next open will fail too. */
is_symlink = TRUE;
fd = g_open (filename, open_flags, mode);
if (!replace_destination_set)
fd = g_open (filename, open_flags, mode);
}
#else
fd = g_open (filename, open_flags, mode);
errsv = errno;
#else /* if !O_NOFOLLOW */
/* This is racy, but we do it as soon as possible to minimize the race */
is_symlink = g_file_test (filename, G_FILE_TEST_IS_SYMLINK);
if (!is_symlink || !replace_destination_set)
{
fd = g_open (filename, open_flags, mode);
errsv = errno;
}
#endif
if (fd == -1)
if (fd == -1 &&
(!is_symlink || !replace_destination_set))
{
char *display_name = g_filename_display_name (filename);
g_set_error (error, G_IO_ERROR,
......@@ -897,15 +910,30 @@ handle_overwrite_open (const char *filename,
return -1;
}
res = g_local_file_fstat (fd,
G_LOCAL_FILE_STAT_FIELD_TYPE |
G_LOCAL_FILE_STAT_FIELD_MODE |
G_LOCAL_FILE_STAT_FIELD_UID |
G_LOCAL_FILE_STAT_FIELD_GID |
G_LOCAL_FILE_STAT_FIELD_MTIME |
G_LOCAL_FILE_STAT_FIELD_NLINK,
G_LOCAL_FILE_STAT_FIELD_ALL, &original_stat);
errsv = errno;
if (!is_symlink)
{
res = g_local_file_fstat (fd,
G_LOCAL_FILE_STAT_FIELD_TYPE |
G_LOCAL_FILE_STAT_FIELD_MODE |
G_LOCAL_FILE_STAT_FIELD_UID |
G_LOCAL_FILE_STAT_FIELD_GID |
G_LOCAL_FILE_STAT_FIELD_MTIME |
G_LOCAL_FILE_STAT_FIELD_NLINK,
G_LOCAL_FILE_STAT_FIELD_ALL, &original_stat);
errsv = errno;
}
else
{
res = g_local_file_lstat (filename,
G_LOCAL_FILE_STAT_FIELD_TYPE |
G_LOCAL_FILE_STAT_FIELD_MODE |
G_LOCAL_FILE_STAT_FIELD_UID |
G_LOCAL_FILE_STAT_FIELD_GID |
G_LOCAL_FILE_STAT_FIELD_MTIME |
G_LOCAL_FILE_STAT_FIELD_NLINK,
G_LOCAL_FILE_STAT_FIELD_ALL, &original_stat);
errsv = errno;
}
if (res != 0)
{
......@@ -922,16 +950,27 @@ handle_overwrite_open (const char *filename,
if (!S_ISREG (_g_stat_mode (&original_stat)))
{
if (S_ISDIR (_g_stat_mode (&original_stat)))
g_set_error_literal (error,
G_IO_ERROR,
G_IO_ERROR_IS_DIRECTORY,
_("Target file is a directory"));
else
g_set_error_literal (error,
{
g_set_error_literal (error,
G_IO_ERROR,
G_IO_ERROR_IS_DIRECTORY,
_("Target file is a directory"));
goto err_out;
}
else if (!is_symlink ||
#ifdef S_ISLNK
!S_ISLNK (_g_stat_mode (&original_stat))
#else
FALSE
#endif
)
{
g_set_error_literal (error,
G_IO_ERROR,
G_IO_ERROR_NOT_REGULAR_FILE,
_("Target file is not a regular file"));
goto err_out;
goto err_out;
}
}
if (etag != NULL)
......@@ -960,7 +999,7 @@ handle_overwrite_open (const char *filename,
* to a backup file and rewrite the contents of the file.
*/
if ((flags & G_FILE_CREATE_REPLACE_DESTINATION) ||
if (replace_destination_set ||
(!(_g_stat_nlink (&original_stat) > 1) && !is_symlink))
{
char *dirname, *tmp_filename;
......@@ -979,7 +1018,7 @@ handle_overwrite_open (const char *filename,
/* try to keep permissions (unless replacing) */
if ( ! (flags & G_FILE_CREATE_REPLACE_DESTINATION) &&
if (!replace_destination_set &&
(
#ifdef HAVE_FCHOWN
fchown (tmpfd, _g_stat_uid (&original_stat), _g_stat_gid (&original_stat)) == -1 ||
......@@ -1014,7 +1053,8 @@ handle_overwrite_open (const char *filename,
}
}
g_close (fd, NULL);
if (fd >= 0)
g_close (fd, NULL);
*temp_filename = tmp_filename;
return tmpfd;
}
......@@ -1120,7 +1160,7 @@ handle_overwrite_open (const char *filename,
}
}
if (flags & G_FILE_CREATE_REPLACE_DESTINATION)
if (replace_destination_set)
{
g_close (fd, NULL);
......@@ -1205,7 +1245,7 @@ _g_local_file_output_stream_replace (const char *filename,
sync_on_close = FALSE;
/* If the file doesn't exist, create it */
open_flags = O_CREAT | O_EXCL | O_BINARY;
open_flags = O_CREAT | O_EXCL | O_BINARY | O_CLOEXEC;
if (readable)
open_flags |= O_RDWR;
else
......@@ -1235,8 +1275,11 @@ _g_local_file_output_stream_replace (const char *filename,
set_error_from_open_errno (filename, error);
return NULL;
}
#if !defined(HAVE_O_CLOEXEC) && defined(F_SETFD)
else
fcntl (fd, F_SETFD, FD_CLOEXEC);
#endif
stream = g_object_new (G_TYPE_LOCAL_FILE_OUTPUT_STREAM, NULL);
stream->priv->fd = fd;
stream->priv->sync_on_close = sync_on_close;
......
......@@ -80,7 +80,10 @@ static GFile *
g_local_vfs_get_file_for_path (GVfs *vfs,
const char *path)
{
return _g_local_file_new (path);
if (*path == '\0')
return _g_dummy_file_new (path);
else
return _g_local_file_new (path);
}
static GFile *
......
......@@ -2,6 +2,7 @@ gio_c_args = [
'-DG_LOG_DOMAIN="GLib-GIO"',
'-DGIO_COMPILATION',
'-DGIO_MODULE_DIR="@0@"'.format(glib_giomodulesdir),
'-DLOCALSTATEDIR="@0@"'.format(glib_localstatedir),
]
gio_c_args += glib_hidden_visibility_args
......
This diff is collapsed.
......@@ -12,6 +12,21 @@ test_c_args = [
'-UG_DISABLE_ASSERT',
]
# workaround for https://github.com/mesonbuild/meson/issues/6880
if build_machine.system() == 'linux'
libutil_name = 'libutil'
libutil = run_command('sh', '-c',
'''ldconfig -p | grep -o "[[:space:]]@0@\.so\(\.[0-9]\+\)\?\b"'''
.format(libutil_name)).stdout().strip().split('\n')
if libutil.length() > 0
message('Found libutil as @0@'.format(libutil[0]))
test_c_args += '-DLIBUTIL_SONAME="@0@"'.format(libutil[0])
else
warning('libutil not found')
endif # libutil.length() > 0
endif # build_machine.system() == 'linux'
if host_machine.system() == 'windows'
common_gio_tests_deps += [iphlpapi_dep, winsock2, cc.find_library ('secur32')]
endif
......
......@@ -187,14 +187,15 @@ test_pollable_unix_pty (void)
{
int (*openpty_impl) (int *, int *, char *, void *, void *);
int a, b, status;
#ifdef __linux__
#ifdef LIBUTIL_SONAME
void *handle;
#endif
g_test_summary ("Test that PTYs are considered pollable");
#ifdef __linux__
handle = dlopen ("libutil.so", RTLD_GLOBAL | RTLD_LAZY);
#ifdef LIBUTIL_SONAME
handle = dlopen (LIBUTIL_SONAME, RTLD_GLOBAL | RTLD_LAZY);
g_assert_nonnull (handle);
#endif
openpty_impl = dlsym (RTLD_DEFAULT, "openpty");
......@@ -223,7 +224,7 @@ test_pollable_unix_pty (void)
close (b);
close_libutil:
#ifdef __linux__
#ifdef LIBUTIL_SONAME
dlclose (handle);
#else
return;
......
......@@ -345,7 +345,7 @@ g_win32_fs_monitor_init (GWin32FSMonitorPrivate *monitor,
monitor->file_attribs = INVALID_FILE_ATTRIBUTES;
monitor->pfni_prev = NULL;
monitor->hDirectory = CreateFileW (wdirname_with_long_prefix != NULL ? wdirname_with_long_prefix : monitor->wfullpath_with_long_prefix,
FILE_GENERIC_READ | FILE_GENERIC_WRITE,
FILE_LIST_DIRECTORY,
FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
......
......@@ -492,6 +492,15 @@
fun:g_system_thread_new
}
{
g-system-thread-init-malloc
Memcheck:Leak
match-leak-kinds:possible,reachable
fun:malloc
...
fun:g_system_thread_new
}
{
g-task-thread-pool-init
Memcheck:Leak
......
......@@ -322,10 +322,10 @@ g_bit_unlock (volatile gint *address,
gint lock_bit)
{
#ifdef USE_ASM_GOTO
asm volatile ("lock btr %1, (%0)"
: /* no output */
: "r" (address), "r" (lock_bit)
: "cc", "memory");
__asm__ volatile ("lock btr %1, (%0)"
: /* no output */
: "r" (address), "r" (lock_bit)
: "cc", "memory");
#else
guint mask = 1u << lock_bit;
......@@ -405,12 +405,12 @@ void
{
#ifdef USE_ASM_GOTO
retry:
asm volatile goto ("lock bts %1, (%0)\n"
"jc %l[contended]"
: /* no output */
: "r" (address), "r" ((gsize) lock_bit)
: "cc", "memory"
: contended);
__asm__ volatile goto ("lock bts %1, (%0)\n"
"jc %l[contended]"
: /* no output */
: "r" (address), "r" ((gsize) lock_bit)
: "cc", "memory"
: contended);
return;
contended:
......@@ -477,12 +477,12 @@ gboolean
#ifdef USE_ASM_GOTO
gboolean result;
asm volatile ("lock bts %2, (%1)\n"
"setnc %%al\n"
"movzx %%al, %0"
: "=r" (result)
: "r" (address), "r" ((gsize) lock_bit)
: "cc", "memory");
__asm__ volatile ("lock bts %2, (%1)\n"
"setnc %%al\n"
"movzx %%al, %0"
: "=r" (result)
: "r" (address), "r" ((gsize) lock_bit)
: "cc", "memory");
return result;
#else
......@@ -520,10 +520,10 @@ void
{
#ifdef USE_ASM_GOTO
asm volatile ("lock btr %1, (%0)"
: /* no output */
: "r" (address), "r" ((gsize) lock_bit)
: "cc", "memory");
__asm__ volatile ("lock btr %1, (%0)"
: /* no output */
: "r" (address), "r" ((gsize) lock_bit)
: "cc", "memory");
#else
volatile gsize *pointer_address = address;
gsize mask = 1u << lock_bit;
......
......@@ -87,7 +87,7 @@ typedef enum {
G_URI_FLAGS_ENCODED_QUERY = 1 << 5,
G_URI_FLAGS_ENCODED_PATH = 1 << 6,
G_URI_FLAGS_ENCODED_FRAGMENT = 1 << 7,
G_URI_FLAGS_SCHEME_NORMALIZE = 1 << 8,
G_URI_FLAGS_SCHEME_NORMALIZE GLIB_AVAILABLE_ENUMERATOR_IN_2_68 = 1 << 8,
} GUriFlags;
GLIB_AVAILABLE_IN_2_66
......
......@@ -864,7 +864,7 @@ def generate_marshallers_body(outfile, retval, params,
outfile.write('\n\n')
if __name__ == '__main__':
def parse_args():
arg_parser = argparse.ArgumentParser(description='Generate signal marshallers for GObject')
arg_parser.add_argument('--prefix', metavar='STRING',
default='g_cclosure_user_marshal',
......@@ -945,6 +945,10 @@ if __name__ == '__main__':
print(VERSION_STR)
sys.exit(0)
return args
def generate(args):
# Backward compatibility hack; some projects use both arguments to
# generate the marshallers prototype in the C source, even though
# it's not really a supported use case. We keep this behaviour by
......@@ -1067,3 +1071,10 @@ if __name__ == '__main__':
if args.header:
generate_header_postamble(args.output, prefix=args.prefix, use_pragma=args.pragma_once)
if __name__ == '__main__':
args = parse_args()
with args.output:
generate(args)
......@@ -219,6 +219,7 @@ def parse_entries(file, file_name):
m = re.match(r'''\s*
(\w+)\s* # name
(\s+[A-Z]+_(?:AVAILABLE|DEPRECATED)_ENUMERATOR_IN_[0-9_]+(?:_FOR\s*\(\s*\w+\s*\))?\s*)? # availability
(?:=( # value
\s*\w+\s*\(.*\)\s* # macro with multiple args
| # OR
......@@ -231,12 +232,15 @@ def parse_entries(file, file_name):
if m:
groups = m.groups()
name = groups[0]
availability = None
value = None
options = None
if len(groups) > 1:
value = groups[1]
availability = groups[1]
if len(groups) > 2:
options = groups[2]
value = groups[2]
if len(groups) > 3:
options = groups[3]
if flags is None and value is not None and '<<' in value:
seenbitshift = 1
......
......@@ -650,6 +650,84 @@ comment: {standard_bottom_comment}
"0",
)
def test_available_in(self):
"""Test GLIB_AVAILABLE_ENUMERATOR_IN_2_68 handling
https://gitlab.gnome.org/GNOME/glib/-/issues/2327"""
h_contents = """
typedef enum {
G_DBUS_SERVER_FLAGS_AUTHENTICATION_REQUIRE_SAME_USER GLIB_AVAILABLE_ENUMERATOR_IN_2_68 = (1<<2)
} GDBusServerFlags;
"""
result = self.runMkenumsWithHeader(h_contents)
self.assertEqual("", result.err)
self.assertSingleEnum(
result,
"GDBusServerFlags",
"g_dbus_server_flags",
"G_DBUS_SERVER_FLAGS",
"DBUS_SERVER_FLAGS",
"G",
"",
"flags",
"Flags",
"FLAGS",
"G_DBUS_SERVER_FLAGS_AUTHENTICATION_REQUIRE_SAME_USER",
"user",
"4",
)
def test_deprecated_in(self):
"""Test GLIB_DEPRECATED_ENUMERATOR_IN_2_68 handling
https://gitlab.gnome.org/GNOME/glib/-/issues/2327"""
h_contents = """
typedef enum {
G_DBUS_SERVER_FLAGS_AUTHENTICATION_REQUIRE_SAME_USER GLIB_DEPRECATED_ENUMERATOR_IN_2_68 = (1<<2)
} GDBusServerFlags;
"""
result = self.runMkenumsWithHeader(h_contents)
self.assertEqual("", result.err)
self.assertSingleEnum(
result,
"GDBusServerFlags",
"g_dbus_server_flags",
"G_DBUS_SERVER_FLAGS",
"DBUS_SERVER_FLAGS",
"G",
"",
"flags",
"Flags",
"FLAGS",
"G_DBUS_SERVER_FLAGS_AUTHENTICATION_REQUIRE_SAME_USER",
"user",
"4",
)
def test_deprecated_in_for(self):
"""Test GLIB_DEPRECATED_ENUMERATOR_IN_2_68_FOR() handling
https://gitlab.gnome.org/GNOME/glib/-/issues/2327"""
h_contents = """
typedef enum {
G_DBUS_SERVER_FLAGS_AUTHENTICATION_REQUIRE_SAME_USER GLIB_DEPRECATED_ENUMERATOR_IN_2_68_FOR(G_DBUS_SERVER_FLAGS_AUTHENTICATION_REQUIRE_SAME_USER2) = (1<<2)
} GDBusServerFlags;
"""
result = self.runMkenumsWithHeader(h_contents)
self.assertEqual("", result.err)
self.assertSingleEnum(
result,
"GDBusServerFlags",
"g_dbus_server_flags",
"G_DBUS_SERVER_FLAGS",
"DBUS_SERVER_FLAGS",
"G",
"",
"flags",
"Flags",
"FLAGS",
"G_DBUS_SERVER_FLAGS_AUTHENTICATION_REQUIRE_SAME_USER",
"user",
"4",
)
class TestRspMkenums(TestMkenums):
"""Run all tests again in @rspfile mode"""
......
project('glib', 'c', 'cpp',
version : '2.67.5',
version : '2.67.6',
# NOTE: We keep this pinned at 0.49 because that's what Debian 10 ships
meson_version : '>= 0.49.2',
default_options : [
......@@ -87,6 +87,12 @@ else
glib_charsetaliasdir = glib_libdir
endif
glib_localstatedir = get_option('localstatedir')
if not glib_localstatedir.startswith('/')
# See https://mesonbuild.com/Builtin-options.html#directories
glib_localstatedir = join_paths(glib_prefix, glib_localstatedir)
endif
installed_tests_metadir = join_paths(glib_datadir, 'installed-tests', meson.project_name())
installed_tests_execdir = join_paths(glib_libexecdir, 'installed-tests', meson.project_name())
installed_tests_enabled = get_option('installed_tests')
......
This diff is collapsed.