From 8049535ffefc177ca645e049dd29d7d4164c42e7 Mon Sep 17 00:00:00 2001 From: Sergio Gelato Date: Wed, 8 Jul 2020 12:43:55 +0100 Subject: [PATCH 1/3] glocalfileinfo: Handle arbitrary binary data in extended attribute values It's safe to assume an escaped string doesn't contain embedded null bytes, but raw memory buffers (as returned by getxattr()) require more care. If the length of the data to be escaped is known, use that knowledge instead of invoking strlen(). (Turned into a git-format patch by Philip Withnall. One minor formatting tweak. Original patch submitted on the Debian bug tracker, bug#962912.) Fixes: #422 --- gio/glocalfileinfo.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/gio/glocalfileinfo.c b/gio/glocalfileinfo.c index db10f342d..6cac187fd 100644 --- a/gio/glocalfileinfo.c +++ b/gio/glocalfileinfo.c @@ -305,17 +305,15 @@ name_is_valid (const char *str) } static char * -hex_escape_string (const char *str, +hex_escape_buffer (const char *str, + size_t len, gboolean *free_return) { - int num_invalid, i; + size_t num_invalid, i; char *escaped_str, *p; unsigned char c; static char *hex_digits = "0123456789abcdef"; - int len; - len = strlen (str); - num_invalid = 0; for (i = 0; i < len; i++) { @@ -351,6 +349,13 @@ hex_escape_string (const char *str, return escaped_str; } +static char * +hex_escape_string (const char *str, + gboolean *free_return) +{ + return hex_escape_buffer (str, strlen (str), free_return); +} + static char * hex_unescape_string (const char *str, int *out_len, @@ -406,7 +411,7 @@ escape_xattr (GFileInfo *info, char *escaped_val; gboolean free_escaped_val; - escaped_val = hex_escape_string (value, &free_escaped_val); + escaped_val = hex_escape_buffer (value, len, &free_escaped_val); g_file_info_set_attribute_string (info, gio_attr, escaped_val); From 63b329fb818358eaf6688f4f78779ef3ee6cfb99 Mon Sep 17 00:00:00 2001 From: Sergio Gelato Date: Wed, 8 Jul 2020 12:45:43 +0100 Subject: [PATCH 2/3] glocalfileinfo: Correct an off-by-one error when unescaping hex Correct an off-by-one error in hex_unescape_string()'s computation of the output string length. (Turned into a git-format patch by Philip Withnall. Original patch submitted on the Debian bug tracker, bug#962912.) --- gio/glocalfileinfo.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gio/glocalfileinfo.c b/gio/glocalfileinfo.c index 6cac187fd..4ca1ce658 100644 --- a/gio/glocalfileinfo.c +++ b/gio/glocalfileinfo.c @@ -394,10 +394,10 @@ hex_unescape_string (const char *str, else *p++ = str[i]; } - *p++ = 0; - if (out_len) *out_len = p - unescaped_str; + *p++ = 0; + *free_return = TRUE; return unescaped_str; } From b80b864fe350d310a00de36f1ac8d5065d14d45c Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Wed, 8 Jul 2020 13:31:44 +0100 Subject: [PATCH 3/3] tests: Add a test for getting/setting xattrs on a local file Signed-off-by: Philip Withnall Helps: #422 --- gio/tests/g-file-info.c | 61 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/gio/tests/g-file-info.c b/gio/tests/g-file-info.c index c4cfd3702..809b0ec79 100644 --- a/gio/tests/g-file-info.c +++ b/gio/tests/g-file-info.c @@ -677,6 +677,66 @@ test_internal_enhanced_stdio (void) } #endif +static void +test_xattrs (void) +{ + GFile *file = NULL; + GFileIOStream *stream = NULL; + GFileInfo *file_info0 = NULL, *file_info1 = NULL; + GError *local_error = NULL; + + g_test_summary ("Test setting and getting escaped xattrs"); + + /* Create a temporary file; no need to write anything to it. */ + file = g_file_new_tmp ("g-file-info-test-xattrs-XXXXXX", &stream, &local_error); + g_assert_no_error (local_error); + g_assert_nonnull (file); + + g_io_stream_close (G_IO_STREAM (stream), NULL, NULL); + g_object_unref (stream); + + /* Check the existing xattrs. */ + file_info0 = g_file_query_info (file, "xattr::*", G_FILE_QUERY_INFO_NONE, NULL, &local_error); + g_assert_no_error (local_error); + g_assert_nonnull (file_info0); + + /* Set some new xattrs, with escaping and some embedded nuls. */ + g_file_info_set_attribute_string (file_info0, "xattr::escaped", "hello\\x82\\x80\\xbd"); + g_file_info_set_attribute_string (file_info0, "xattr::string", "hi there"); + g_file_info_set_attribute_string (file_info0, "xattr::embedded-nul", "hi\\x00there"); + + g_file_set_attributes_from_info (file, file_info0, G_FILE_QUERY_INFO_NONE, NULL, &local_error); + + g_object_unref (file_info0); + + if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED)) + { + g_test_skip ("xattrs not supported on this file system"); + g_clear_error (&local_error); + } + else + { + g_assert_no_error (local_error); + + /* Check they were set properly. */ + file_info1 = g_file_query_info (file, "xattr::*", G_FILE_QUERY_INFO_NONE, NULL, &local_error); + g_assert_no_error (local_error); + g_assert_nonnull (file_info1); + + g_assert_true (g_file_info_has_namespace (file_info1, "xattr")); + + g_assert_cmpstr (g_file_info_get_attribute_string (file_info1, "xattr::escaped"), ==, "hello\\x82\\x80\\xbd"); + g_assert_cmpstr (g_file_info_get_attribute_string (file_info1, "xattr::string"), ==, "hi there"); + g_assert_cmpstr (g_file_info_get_attribute_string (file_info1, "xattr::embedded-nul"), ==, "hi\\x00there"); + + g_object_unref (file_info1); + } + + /* Tidy up. */ + g_file_delete (file, NULL, NULL); + + g_object_unref (file); +} int main (int argc, @@ -689,6 +749,7 @@ main (int argc, #ifdef G_OS_WIN32 g_test_add_func ("/g-file-info/internal-enhanced-stdio", test_internal_enhanced_stdio); #endif + g_test_add_func ("/g-file-info/xattrs", test_xattrs); return g_test_run(); }