Patch for bug 286102 from upstream git. It includes the following 5 commits: commit 3826963e65d8c4c68bcd3e4066505f63ef734b95 Author: Benjamin Otte Date: Tue Sep 1 21:53:35 2009 +0200 commit 48e0af0157f52ac12b904bd92540432a18b139c7 Author: Benjamin Otte Date: Tue Sep 1 21:26:08 2009 +0200 commit bb7852e34b1845e516290e1b45a960a345ee8a43 Author: Benjamin Otte Date: Tue Sep 1 20:36:31 2009 +0200 commit fc44bf40a4eff8e122b223e97ee5efcbc548be03 Author: Benjamin Otte Date: Tue Sep 1 12:48:55 2009 +0200 commit e695c0932f5d02f3b222f0b7a3de1f8c00ba7b81 Author: Benjamin Otte Date: Tue Sep 1 11:54:48 2009 +0200 Patch generated by a3li@gentoo.org, CVE available for 2.20.5 only (see timeline). diff --git a/configure.in b/configure.in index 7bda924..e2a33b5 100644 --- a/configure.in +++ b/configure.in @@ -952,7 +952,7 @@ AC_MSG_RESULT(unsigned $glib_size_type) # Check for some functions AC_CHECK_FUNCS(lstat strerror strsignal memmove vsnprintf stpcpy strcasecmp strncasecmp poll getcwd vasprintf setenv unsetenv getc_unlocked readlink symlink fdwalk) -AC_CHECK_FUNCS(chown lchown fchmod fchown link statvfs statfs utimes getgrgid getpwuid) +AC_CHECK_FUNCS(chown lchmod lchown fchmod fchown link statvfs statfs utimes getgrgid getpwuid) AC_CHECK_FUNCS(getmntent_r setmntent endmntent hasmntopt getmntinfo) # Check for high-resolution sleep functions AC_CHECK_FUNCS(nanosleep nsleep) diff --git a/gio/glocalfileinfo.c b/gio/glocalfileinfo.c index 72a59b5..a61cc55 100644 --- a/gio/glocalfileinfo.c +++ b/gio/glocalfileinfo.c @@ -1869,15 +1869,40 @@ get_string (const GFileAttributeValue *value, static gboolean set_unix_mode (char *filename, + GFileQueryInfoFlags flags, const GFileAttributeValue *value, GError **error) { guint32 val; + int res = 0; if (!get_uint32 (value, &val, error)) return FALSE; - - if (g_chmod (filename, val) == -1) + +#ifdef HAVE_SYMLINK + if (flags & G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS) { +#ifdef HAVE_LCHMOD + res = lchmod (filename, val); +#else + struct stat statbuf; + /* Calling chmod on a symlink changes permissions on the symlink. + * We don't want to do this, so we need to check for a symlink */ + res = g_lstat (filename, &statbuf); + if (res == 0 && S_ISLNK (statbuf.st_mode)) + { + g_set_error_literal (error, G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + _("Cannot set permissions on symlinks")); + return FALSE; + } + else if (res == 0) + res = g_chmod (filename, val); +#endif + } else +#endif + res = g_chmod (filename, val); + + if (res == -1) { int errsv = errno; @@ -2172,7 +2197,7 @@ _g_local_file_info_set_attribute (char *filename, _g_file_attribute_value_set_from_pointer (&value, type, value_p, FALSE); if (strcmp (attribute, G_FILE_ATTRIBUTE_UNIX_MODE) == 0) - return set_unix_mode (filename, &value, error); + return set_unix_mode (filename, flags, &value, error); #ifdef HAVE_CHOWN else if (strcmp (attribute, G_FILE_ATTRIBUTE_UNIX_UID) == 0) @@ -2316,7 +2341,7 @@ _g_local_file_info_set_attributes (char *filename, value = _g_file_info_get_attribute_value (info, G_FILE_ATTRIBUTE_UNIX_MODE); if (value) { - if (!set_unix_mode (filename, value, error)) + if (!set_unix_mode (filename, flags, value, error)) { value->status = G_FILE_ATTRIBUTE_STATUS_ERROR_SETTING; res = FALSE;