mirror of
git://sourceware.org/git/glibc.git
synced 2024-11-27 03:41:23 +08:00
Allow $ORIGIN to reference trusted directoreis in SUID binaries.
This commit is contained in:
parent
d08055417d
commit
47c3cd7a74
10
ChangeLog
10
ChangeLog
@ -1,3 +1,13 @@
|
|||||||
|
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-05-06 Paul Pluzhnikov <ppluzhnikov@google.com>
|
2011-05-06 Paul Pluzhnikov <ppluzhnikov@google.com>
|
||||||
|
|
||||||
* sysdeps/unix/sysv/linux/sys/sysmacros.h: Add missing
|
* sysdeps/unix/sysv/linux/sys/sysmacros.h: Add missing
|
||||||
|
5
NEWS
5
NEWS
@ -22,8 +22,9 @@ Version 2.14
|
|||||||
|
|
||||||
* The following bugs are resolved with this release:
|
* The following bugs are resolved with this release:
|
||||||
|
|
||||||
11724, 12420, 12445, 12454, 12460, 12469, 12489, 12509, 12510, 12518, 12583,
|
11724, 12393, 12420, 12445, 12454, 12460, 12469, 12489, 12509, 12510,
|
||||||
12587, 12597, 12631, 12650, 12653, 12655, 12685, 12714, 12717, 12723
|
12518, 12583, 12587, 12597, 12631, 12650, 12653, 12655, 12685, 12714,
|
||||||
|
12717, 12723
|
||||||
|
|
||||||
Version 2.13
|
Version 2.13
|
||||||
|
|
||||||
|
120
elf/dl-load.c
120
elf/dl-load.c
@ -1,5 +1,5 @@
|
|||||||
/* Map in a shared object's segments from the file.
|
/* Map in a shared object's segments from the file.
|
||||||
Copyright (C) 1995-2005, 2006, 2007, 2009, 2010, 2011 Free Software Foundation, Inc.
|
Copyright (C) 1995-2007, 2009, 2010, 2011 Free Software Foundation, Inc.
|
||||||
This file is part of the GNU C Library.
|
This file is part of the GNU C Library.
|
||||||
|
|
||||||
The GNU C Library is free software; you can redistribute it and/or
|
The GNU C Library is free software; you can redistribute it and/or
|
||||||
@ -168,6 +168,71 @@ local_strdup (const char *s)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool
|
||||||
|
is_trusted_path (const char *path, size_t len)
|
||||||
|
{
|
||||||
|
/* All trusted directories must be complete names. */
|
||||||
|
if (path[0] != '/')
|
||||||
|
return false;
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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++ = '/';
|
||||||
|
*wnp = '\0';
|
||||||
|
|
||||||
|
return is_trusted_path (npath, wnp - npath);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static size_t
|
static size_t
|
||||||
is_dst (const char *start, const char *name, const char *str,
|
is_dst (const char *start, const char *name, const char *str,
|
||||||
int is_path, int secure)
|
int is_path, int secure)
|
||||||
@ -240,13 +305,14 @@ _dl_dst_substitute (struct link_map *l, const char *name, char *result,
|
|||||||
int is_path)
|
int is_path)
|
||||||
{
|
{
|
||||||
const char *const start = name;
|
const char *const start = name;
|
||||||
char *last_elem, *wp;
|
|
||||||
|
|
||||||
/* Now fill the result path. While copying over the string we keep
|
/* 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
|
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)
|
a DST we copy over the value or (if the value is not available)
|
||||||
leave the entire path element out. */
|
leave the entire path element out. */
|
||||||
last_elem = wp = result;
|
char *wp = result;
|
||||||
|
char *last_elem = result;
|
||||||
|
bool check_for_trusted = false;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
@ -265,6 +331,9 @@ _dl_dst_substitute (struct link_map *l, const char *name, char *result,
|
|||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
repl = l->l_origin;
|
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)
|
else if ((len = is_dst (start, name, "PLATFORM", is_path, 0)) != 0)
|
||||||
repl = GLRO(dl_platform);
|
repl = GLRO(dl_platform);
|
||||||
@ -297,11 +366,29 @@ _dl_dst_substitute (struct link_map *l, const char *name, char *result,
|
|||||||
{
|
{
|
||||||
*wp++ = *name++;
|
*wp++ = *name++;
|
||||||
if (is_path && *name == ':')
|
if (is_path && *name == ':')
|
||||||
|
{
|
||||||
|
/* 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;
|
||||||
|
check_for_trusted = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
last_elem = wp;
|
last_elem = wp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
while (*name != '\0');
|
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';
|
*wp = '\0';
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -411,33 +498,8 @@ fillin_rpath (char *rpath, struct r_search_path_elem **result, const char *sep,
|
|||||||
cp[len++] = '/';
|
cp[len++] = '/';
|
||||||
|
|
||||||
/* Make sure we don't use untrusted directories if we run SUID. */
|
/* Make sure we don't use untrusted directories if we run SUID. */
|
||||||
if (__builtin_expect (check_trusted, 0))
|
if (__builtin_expect (check_trusted, 0) && !is_trusted_path (cp, len))
|
||||||
{
|
|
||||||
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;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
/* See if this directory is already known. */
|
/* See if this directory is already known. */
|
||||||
for (dirp = GL(dl_all_dirs); dirp != NULL; dirp = dirp->next)
|
for (dirp = GL(dl_all_dirs); dirp != NULL; dirp = dirp->next)
|
||||||
|
Loading…
Reference in New Issue
Block a user