From d6a734a44ccf8a3a56cc2ddb39956c1f4c117eb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A0=D1=83=D1=81=D0=BB=D0=B0=D0=BD=20=D0=98=D0=B6=D0=B1?= =?UTF-8?q?=D1=83=D0=BB=D0=B0=D1=82=D0=BE=D0=B2?= Date: Sat, 31 Jul 2021 10:50:12 +0000 Subject: [PATCH 1/5] GWin32RegistryKey: Change STATUS_SUCCESS handling 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. --- gio/gwin32registrykey.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/gio/gwin32registrykey.c b/gio/gwin32registrykey.c index 398d8f45b..d1ac09041 100644 --- a/gio/gwin32registrykey.c +++ b/gio/gwin32registrykey.c @@ -2550,9 +2550,7 @@ g_win32_registry_key_watch (GWin32RegistryKey *key, 0, TRUE); - g_assert (status != STATUS_SUCCESS); - - if (status == STATUS_PENDING) + if (status == STATUS_PENDING || status == STATUS_SUCCESS) return TRUE; g_atomic_int_set (&key->priv->change_indicator, G_WIN32_KEY_UNKNOWN); From 22e5e428de9cd8a760f1a6f9ab7362fa4ecce851 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A0=D1=83=D1=81=D0=BB=D0=B0=D0=BD=20=D0=98=D0=B6=D0=B1?= =?UTF-8?q?=D1=83=D0=BB=D0=B0=D1=82=D0=BE=D0=B2?= Date: Sat, 31 Jul 2021 10:57:44 +0000 Subject: [PATCH 2/5] GWin32RegistryKey: ensure reqeueing works correctly 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. --- gio/gwin32registrykey.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/gio/gwin32registrykey.c b/gio/gwin32registrykey.c index d1ac09041..5e2b006dd 100644 --- a/gio/gwin32registrykey.c +++ b/gio/gwin32registrykey.c @@ -2425,17 +2425,20 @@ key_changed (PVOID closure, ULONG reserved) { GWin32RegistryKey *key = G_WIN32_REGISTRY_KEY (closure); + gpointer user_data; + GWin32RegistryKeyWatchCallbackFunc callback; + + callback = g_steal_pointer (&key->priv->callback); + user_data = g_steal_pointer (&key->priv->user_data); g_free (status_block); g_atomic_int_set (&key->priv->change_indicator, G_WIN32_KEY_CHANGED); g_atomic_int_set (&key->priv->watch_indicator, G_WIN32_KEY_UNWATCHED); key->priv->update_flags = G_WIN32_REGISTRY_UPDATED_NOTHING; - if (key->priv->callback) - key->priv->callback (key, key->priv->user_data); + if (callback) + callback (key, user_data); - key->priv->callback = NULL; - key->priv->user_data = NULL; g_object_unref (key); } From d0ef6399d4c8f19621d6cfd1c6f3ef04b207a10a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A0=D1=83=D1=81=D0=BB=D0=B0=D0=BD=20=D0=98=D0=B6=D0=B1?= =?UTF-8?q?=D1=83=D0=BB=D0=B0=D1=82=D0=BE=D0=B2?= Date: Sat, 31 Jul 2021 11:01:06 +0000 Subject: [PATCH 3/5] GWin32AppInfo: re-trigger registry watcher from the callback 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. --- gio/gwin32appinfo.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/gio/gwin32appinfo.c b/gio/gwin32appinfo.c index 5403225e2..4074f402c 100644 --- a/gio/gwin32appinfo.c +++ b/gio/gwin32appinfo.c @@ -3828,6 +3828,9 @@ update_registry_data (void) return; } +static void +watch_keys (void); + /* This function is called when any of our registry watchers detect * changes in the registry. */ @@ -3835,6 +3838,7 @@ static void keys_updated (GWin32RegistryKey *key, gpointer user_data) { + watch_keys (); /* Indicate the tree as not up-to-date, push a new job for the AppInfo thread */ g_atomic_int_inc (&gio_win32_appinfo_update_counter); /* We don't use the data pointer, but it must be non-NULL */ @@ -4029,7 +4033,6 @@ gio_win32_appinfo_init (gboolean do_wait) g_mutex_lock (&gio_win32_appinfo_mutex); while (g_atomic_int_get (&gio_win32_appinfo_update_counter) > 0) g_cond_wait (&gio_win32_appinfo_cond, &gio_win32_appinfo_mutex); - watch_keys (); g_mutex_unlock (&gio_win32_appinfo_mutex); } } From 771a6e557a9a52953aa6f4c4c907ab1049d71009 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A0=D1=83=D1=81=D0=BB=D0=B0=D0=BD=20=D0=98=D0=B6=D0=B1?= =?UTF-8?q?=D1=83=D0=BB=D0=B0=D1=82=D0=BE=D0=B2?= Date: Mon, 2 Aug 2021 14:19:35 +0000 Subject: [PATCH 4/5] GWin32AppInfo: Fix missing initialization 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. --- gio/gwin32appinfo.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gio/gwin32appinfo.c b/gio/gwin32appinfo.c index 4074f402c..3468dfee0 100644 --- a/gio/gwin32appinfo.c +++ b/gio/gwin32appinfo.c @@ -1629,6 +1629,7 @@ process_uwp_verbs (GList *verbs, continue; } + acid = NULL; got_value = g_win32_registry_key_get_value_w (key, g_win32_registry_get_os_dirs_w (), TRUE, @@ -3634,6 +3635,7 @@ grab_registry_string (GWin32RegistryKey *handler_appkey, if (*destination != NULL) return; + value = NULL; if (g_win32_registry_key_get_value_w (handler_appkey, NULL, TRUE, From ee9443463260cbdefbce142c6e05bacf88b487b8 Mon Sep 17 00:00:00 2001 From: Jonathan Boeing Date: Wed, 4 Aug 2021 08:55:13 -0700 Subject: [PATCH 5/5] gwin32packageparser: Fix read past end of buffer 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 --- gio/gwin32packageparser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gio/gwin32packageparser.c b/gio/gwin32packageparser.c index ad5302270..ee05bb1dd 100755 --- a/gio/gwin32packageparser.c +++ b/gio/gwin32packageparser.c @@ -390,7 +390,7 @@ g_win32_package_parser_enum_packages (GWin32PackageParserCallback callback, wcs_path = LoadedWindowsGetStringRawBuffer (path, NULL); manifest_filename_size = wcslen (wcs_path) + wcslen (bslash_appmanifest); manifest_filename = g_new (wchar_t, manifest_filename_size + 1); - memcpy (manifest_filename, wcs_path, manifest_filename_size * sizeof (wchar_t)); + memcpy (manifest_filename, wcs_path, wcslen (wcs_path) * sizeof (wchar_t)); memcpy (&manifest_filename[wcslen (wcs_path)], bslash_appmanifest, (wcslen (bslash_appmanifest) + 1) * sizeof (wchar_t)); memset (sax, 0, sizeof (*sax));