mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-10 07:10:06 +00:00
ld.so: Reject overly long LD_PRELOAD path elements
This commit is contained in:
parent
bf15120dd7
commit
6d0ba62289
@ -1,3 +1,10 @@
|
||||
2017-06-19 Florian Weimer <fweimer@redhat.com>
|
||||
|
||||
* elf/rtld.c (SECURE_NAME_LIMIT, SECURE_PATH_LIMIT): Define.
|
||||
(dso_name_valid_for_suid): New function.
|
||||
(handle_ld_preload): Likewise.
|
||||
(dl_main): Call it. Remove alloca.
|
||||
|
||||
2017-06-19 Joseph Myers <joseph@codesourcery.com>
|
||||
|
||||
[BZ #21625]
|
||||
|
82
elf/rtld.c
82
elf/rtld.c
@ -99,6 +99,35 @@ uintptr_t __pointer_chk_guard_local
|
||||
strong_alias (__pointer_chk_guard_local, __pointer_chk_guard)
|
||||
#endif
|
||||
|
||||
/* Length limits for names and paths, to protect the dynamic linker,
|
||||
particularly when __libc_enable_secure is active. */
|
||||
#ifdef NAME_MAX
|
||||
# define SECURE_NAME_LIMIT NAME_MAX
|
||||
#else
|
||||
# define SECURE_NAME_LIMIT 255
|
||||
#endif
|
||||
#ifdef PATH_MAX
|
||||
# define SECURE_PATH_LIMIT PATH_MAX
|
||||
#else
|
||||
# define SECURE_PATH_LIMIT 1024
|
||||
#endif
|
||||
|
||||
/* Check that AT_SECURE=0, or that the passed name does not contain
|
||||
directories and is not overly long. Reject empty names
|
||||
unconditionally. */
|
||||
static bool
|
||||
dso_name_valid_for_suid (const char *p)
|
||||
{
|
||||
if (__glibc_unlikely (__libc_enable_secure))
|
||||
{
|
||||
/* Ignore pathnames with directories for AT_SECURE=1
|
||||
programs, and also skip overlong names. */
|
||||
size_t len = strlen (p);
|
||||
if (len >= SECURE_NAME_LIMIT || memchr (p, '/', len) != NULL)
|
||||
return false;
|
||||
}
|
||||
return *p != '\0';
|
||||
}
|
||||
|
||||
/* List of auditing DSOs. */
|
||||
static struct audit_list
|
||||
@ -718,6 +747,42 @@ static const char *preloadlist attribute_relro;
|
||||
/* Nonzero if information about versions has to be printed. */
|
||||
static int version_info attribute_relro;
|
||||
|
||||
/* The LD_PRELOAD environment variable gives list of libraries
|
||||
separated by white space or colons that are loaded before the
|
||||
executable's dependencies and prepended to the global scope list.
|
||||
(If the binary is running setuid all elements containing a '/' are
|
||||
ignored since it is insecure.) Return the number of preloads
|
||||
performed. */
|
||||
unsigned int
|
||||
handle_ld_preload (const char *preloadlist, struct link_map *main_map)
|
||||
{
|
||||
unsigned int npreloads = 0;
|
||||
const char *p = preloadlist;
|
||||
char fname[SECURE_PATH_LIMIT];
|
||||
|
||||
while (*p != '\0')
|
||||
{
|
||||
/* Split preload list at space/colon. */
|
||||
size_t len = strcspn (p, " :");
|
||||
if (len > 0 && len < sizeof (fname))
|
||||
{
|
||||
memcpy (fname, p, len);
|
||||
fname[len] = '\0';
|
||||
}
|
||||
else
|
||||
fname[0] = '\0';
|
||||
|
||||
/* Skip over the substring and the following delimiter. */
|
||||
p += len;
|
||||
if (*p != '\0')
|
||||
++p;
|
||||
|
||||
if (dso_name_valid_for_suid (fname))
|
||||
npreloads += do_preload (fname, main_map, "LD_PRELOAD");
|
||||
}
|
||||
return npreloads;
|
||||
}
|
||||
|
||||
static void
|
||||
dl_main (const ElfW(Phdr) *phdr,
|
||||
ElfW(Word) phnum,
|
||||
@ -1464,23 +1529,8 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n",
|
||||
|
||||
if (__glibc_unlikely (preloadlist != NULL))
|
||||
{
|
||||
/* The LD_PRELOAD environment variable gives list of libraries
|
||||
separated by white space or colons that are loaded before the
|
||||
executable's dependencies and prepended to the global scope
|
||||
list. If the binary is running setuid all elements
|
||||
containing a '/' are ignored since it is insecure. */
|
||||
char *list = strdupa (preloadlist);
|
||||
char *p;
|
||||
|
||||
HP_TIMING_NOW (start);
|
||||
|
||||
/* Prevent optimizing strsep. Speed is not important here. */
|
||||
while ((p = (strsep) (&list, " :")) != NULL)
|
||||
if (p[0] != '\0'
|
||||
&& (__builtin_expect (! __libc_enable_secure, 1)
|
||||
|| strchr (p, '/') == NULL))
|
||||
npreloads += do_preload (p, main_map, "LD_PRELOAD");
|
||||
|
||||
npreloads += handle_ld_preload (preloadlist, main_map);
|
||||
HP_TIMING_NOW (stop);
|
||||
HP_TIMING_DIFF (diff, start, stop);
|
||||
HP_TIMING_ACCUM_NT (load_time, diff);
|
||||
|
Loading…
Reference in New Issue
Block a user