r5277 - in glibc-package/trunk/debian: . patches patches/any
Author: aurel32
Date: 2012-06-03 18:11:47 +0000 (Sun, 03 Jun 2012)
New Revision: 5277
Added:
glibc-package/trunk/debian/patches/any/cvs-ld.so-rpath-origin.diff
Modified:
glibc-package/trunk/debian/changelog
glibc-package/trunk/debian/patches/series
Log:
* Add patches/any/cvs-ld.so-rpath-origin.diff to fix an insecure handling
of privileged programs' RPATHs with $ORIGIN (CVE-2011-1658). Closes:
#672119.
Modified: glibc-package/trunk/debian/changelog
===================================================================
--- glibc-package/trunk/debian/changelog 2012-06-03 17:57:45 UTC (rev 5276)
+++ glibc-package/trunk/debian/changelog 2012-06-03 18:11:47 UTC (rev 5277)
@@ -59,6 +59,9 @@
* Set libc*-dev "Multi-Arch: same". Add conflicts betwwen libc*-dev
packages. Move a.out.h and ieee754.h to the arch qualified path.
Thanks to Thibaut Girka for the help. Closes: #666760.
+ * Add patches/any/cvs-ld.so-rpath-origin.diff to fix an insecure handling
+ of privileged programs' RPATHs with $ORIGIN (CVE-2011-1658). Closes:
+ #672119.
-- Clint Adams <clint@debian.org> Fri, 04 May 2012 23:39:00 -0400
Added: glibc-package/trunk/debian/patches/any/cvs-ld.so-rpath-origin.diff
===================================================================
--- glibc-package/trunk/debian/patches/any/cvs-ld.so-rpath-origin.diff (rev 0)
+++ glibc-package/trunk/debian/patches/any/cvs-ld.so-rpath-origin.diff 2012-06-03 18:11:47 UTC (rev 5277)
@@ -0,0 +1,296 @@
+2011-05-11 Ulrich Drepper <drepper@gmail.com>
+
+ [BZ #12393]
+ * elf/dl-load.c (is_trusted_path): Remove unnecessary test.
+ (is_trusted_path_normalize): Skip initial colon. Append slash
+ to empty buffer. Duplicate is_trusted_path code but allow
+ constructed patch to be prefix.
+ (is_dst): Allow $ORIGIN followed by /.
+ (_dl_dst_substitute): Correct clearing of check_for_trusted.
+ Correct testing of result of is_trusted_path_normalize
+ (decompose_rpath): Fix warning.
+
+2011-05-07 Petr Baudis <pasky@suse.cz>
+ Ulrich Drepper <drepper@gmail.com>
+
+ [BZ #12393]
+ * elf/dl-load.c (fillin_rpath): Move trusted path check...
+ (is_trusted_path): ...to here.
+ (is_norm_trusted_path): Add wrapper for /../ and /./ normalization.
+ (_dl_dst_substitute): Verify expanded $ORIGIN path elements
+ using is_norm_trusted_path() in setuid scripts.
+
+2011-03-14 Andreas Schwab <schwab@redhat.com>
+
+ * elf/dl-load.c (_dl_dst_substitute): When skipping the first
+ rpath element also skip the following colon.
+ (expand_dynamic_string_token): Add is_path parameter and pass
+ down to DL_DST_REQUIRED and _dl_dst_substitute.
+ (decompose_rpath): Call expand_dynamic_string_token with
+ non-zero is_path. Ignore empty rpaths.
+ (_dl_map_object_from_fd): Call expand_dynamic_string_token
+ with zero is_path.
+
+--- a/elf/dl-load.c
++++ b/elf/dl-load.c
+@@ -168,6 +168,87 @@
+ }
+
+
++static bool
++is_trusted_path (const char *path, size_t len)
++{
++ const char *trun = system_dirs;
++
++ for (size_t idx = 0; idx < nsystem_dirs_len; ++idx)
++ {
++ if (len == system_dirs_len[idx] && memcmp (trun, path, len) == 0)
++ /* Found it. */
++ return true;
++
++ trun += system_dirs_len[idx] + 1;
++ }
++
++ return false;
++}
++
++
++static bool
++is_trusted_path_normalize (const char *path, size_t len)
++{
++ if (len == 0)
++ return false;
++
++ if (*path == ':')
++ {
++ ++path;
++ --len;
++ }
++
++ char *npath = (char *) alloca (len + 2);
++ char *wnp = npath;
++ while (*path != '\0')
++ {
++ if (path[0] == '/')
++ {
++ if (path[1] == '.')
++ {
++ if (path[2] == '.' && (path[3] == '/' || path[3] == '\0'))
++ {
++ while (wnp > npath && *--wnp != '/')
++ ;
++ path += 3;
++ continue;
++ }
++ else if (path[2] == '/' || path[2] == '\0')
++ {
++ path += 2;
++ continue;
++ }
++ }
++
++ if (wnp > npath && wnp[-1] == '/')
++ {
++ ++path;
++ continue;
++ }
++ }
++
++ *wnp++ = *path++;
++ }
++
++ if (wnp == npath || wnp[-1] != '/')
++ *wnp++ = '/';
++
++ const char *trun = system_dirs;
++
++ for (size_t idx = 0; idx < nsystem_dirs_len; ++idx)
++ {
++ if (wnp - npath >= system_dirs_len[idx]
++ && memcmp (trun, npath, system_dirs_len[idx]) == 0)
++ /* Found it. */
++ return true;
++
++ trun += system_dirs_len[idx] + 1;
++ }
++
++ return false;
++}
++
++
+ static size_t
+ is_dst (const char *start, const char *name, const char *str,
+ int is_path, int secure)
+@@ -200,7 +281,8 @@
+ return 0;
+
+ if (__builtin_expect (secure, 0)
+- && ((name[len] != '\0' && (!is_path || name[len] != ':'))
++ && ((name[len] != '\0' && name[len] != '/'
++ && (!is_path || name[len] != ':'))
+ || (name != start + 1 && (!is_path || name[-2] != ':'))))
+ return 0;
+
+@@ -240,13 +322,14 @@
+ int is_path)
+ {
+ const char *const start = name;
+- char *last_elem, *wp;
+
+ /* Now fill the result path. While copying over the string we keep
+ track of the start of the last path element. When we come accross
+ a DST we copy over the value or (if the value is not available)
+ leave the entire path element out. */
+- last_elem = wp = result;
++ char *wp = result;
++ char *last_elem = result;
++ bool check_for_trusted = false;
+
+ do
+ {
+@@ -265,6 +348,9 @@
+ else
+ #endif
+ repl = l->l_origin;
++
++ check_for_trusted = (INTUSE(__libc_enable_secure)
++ && l->l_type == lt_executable);
+ }
+ else if ((len = is_dst (start, name, "PLATFORM", is_path, 0)) != 0)
+ repl = GLRO(dl_platform);
+@@ -284,6 +370,10 @@
+ name += len;
+ while (*name != '\0' && (!is_path || *name != ':'))
+ ++name;
++ /* Also skip following colon if this is the first rpath
++ element, but keep an empty element at the end. */
++ if (wp == result && is_path && *name == ':' && name[1] != '\0')
++ ++name;
+ }
+ else
+ /* No DST we recognize. */
+@@ -293,11 +383,28 @@
+ {
+ *wp++ = *name++;
+ if (is_path && *name == ':')
+- last_elem = wp;
++ {
++ /* In SUID/SGID programs, after $ORIGIN expansion the
++ normalized path must be rooted in one of the trusted
++ directories. */
++ if (__builtin_expect (check_for_trusted, false)
++ && !is_trusted_path_normalize (last_elem, wp - last_elem))
++ wp = last_elem;
++ else
++ last_elem = wp;
++
++ check_for_trusted = false;
++ }
+ }
+ }
+ while (*name != '\0');
+
++ /* In SUID/SGID programs, after $ORIGIN expansion the normalized
++ path must be rooted in one of the trusted directories. */
++ if (__builtin_expect (check_for_trusted, false)
++ && !is_trusted_path_normalize (last_elem, wp - last_elem))
++ wp = last_elem;
++
+ *wp = '\0';
+
+ return result;
+@@ -310,7 +417,7 @@
+ belonging to the map is loaded. In this case the path element
+ containing $ORIGIN is left out. */
+ static char *
+-expand_dynamic_string_token (struct link_map *l, const char *s)
++expand_dynamic_string_token (struct link_map *l, const char *s, int is_path)
+ {
+ /* We make two runs over the string. First we determine how large the
+ resulting string is and then we copy it over. Since this is no
+@@ -321,7 +428,7 @@
+ char *result;
+
+ /* Determine the number of DST elements. */
+- cnt = DL_DST_COUNT (s, 1);
++ cnt = DL_DST_COUNT (s, is_path);
+
+ /* If we do not have to replace anything simply copy the string. */
+ if (__builtin_expect (cnt, 0) == 0)
+@@ -335,7 +442,7 @@
+ if (result == NULL)
+ return NULL;
+
+- return _dl_dst_substitute (l, s, result, 1);
++ return _dl_dst_substitute (l, s, result, is_path);
+ }
+
+
+@@ -407,33 +514,8 @@
+ cp[len++] = '/';
+
+ /* Make sure we don't use untrusted directories if we run SUID. */
+- if (__builtin_expect (check_trusted, 0))
+- {
+- const char *trun = system_dirs;
+- size_t idx;
+- int unsecure = 1;
+-
+- /* All trusted directories must be complete names. */
+- if (cp[0] == '/')
+- {
+- for (idx = 0; idx < nsystem_dirs_len; ++idx)
+- {
+- if (len == system_dirs_len[idx]
+- && memcmp (trun, cp, len) == 0)
+- {
+- /* Found it. */
+- unsecure = 0;
+- break;
+- }
+-
+- trun += system_dirs_len[idx] + 1;
+- }
+- }
+-
+- if (unsecure)
+- /* Simply drop this directory. */
+- continue;
+- }
++ if (__builtin_expect (check_trusted, 0) && !is_trusted_path (cp, len))
++ continue;
+
+ /* See if this directory is already known. */
+ for (dirp = GL(dl_all_dirs); dirp != NULL; dirp = dirp->next)
+@@ -551,13 +633,21 @@
+
+ /* Make a writable copy. At the same time expand possible dynamic
+ string tokens. */
+- copy = expand_dynamic_string_token (l, rpath);
++ copy = expand_dynamic_string_token (l, rpath, 1);
+ if (copy == NULL)
+ {
+ errstring = N_("cannot create RUNPATH/RPATH copy");
+ goto signal_error;
+ }
+
++ /* Ignore empty rpaths. */
++ if (*copy == 0)
++ {
++ free (copy);
++ sps->dirs = (struct r_search_path_elem **) -1;
++ return false;
++ }
++
+ /* Count the number of necessary elements in the result array. */
+ nelems = 0;
+ for (cp = copy; *cp != '\0'; ++cp)
+@@ -2400,7 +2490,7 @@
+ {
+ /* The path may contain dynamic string tokens. */
+ realname = (loader
+- ? expand_dynamic_string_token (loader, name)
++ ? expand_dynamic_string_token (loader, name, 0)
+ : local_strdup (name));
+ if (realname == NULL)
+ fd = -1;
Modified: glibc-package/trunk/debian/patches/series
===================================================================
--- glibc-package/trunk/debian/patches/series 2012-06-03 17:57:45 UTC (rev 5276)
+++ glibc-package/trunk/debian/patches/series 2012-06-03 18:11:47 UTC (rev 5277)
@@ -359,3 +359,4 @@
any/cvs-regex.diff
any/cvs-getpwuid-nsswitch.diff
any/local-sunrpc-dos.diff
+any/cvs-ld.so-rpath-origin.diff
Reply to: