From db33f7d4aef7422140d5e19c440bb5e084fbe186 Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Thu, 25 May 2000 05:02:35 +0000 Subject: Update. * csu/Makefile (routines): Add check_fds. * elf/rtld.c (dl_main): Call __libc_check_standard_fds for SUID binaries. Add various __builtin_expect. * sysdeps/generic/libc-start.c: Move check_fds and helper functions... * sysdeps/generic/check_fds.c: ...here. New file. * malloc/malloc.c (ptmalloc_init): Only enable debugging for SUID binaries if file /etc/suid-debug is available. --- ChangeLog | 9 +++++++ csu/Makefile | 2 +- elf/rtld.c | 20 ++++++++++---- malloc/malloc.c | 2 +- sysdeps/generic/check_fds.c | 62 ++++++++++++++++++++++++++++++++++++++++++++ sysdeps/generic/libc-start.c | 43 +++++------------------------- 6 files changed, 95 insertions(+), 43 deletions(-) create mode 100644 sysdeps/generic/check_fds.c diff --git a/ChangeLog b/ChangeLog index 5ce40be..ec1f958 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,14 @@ 2000-05-24 Ulrich Drepper + * csu/Makefile (routines): Add check_fds. + * elf/rtld.c (dl_main): Call __libc_check_standard_fds for SUID + binaries. Add various __builtin_expect. + * sysdeps/generic/libc-start.c: Move check_fds and helper functions... + * sysdeps/generic/check_fds.c: ...here. New file. + + * malloc/malloc.c (ptmalloc_init): Only enable debugging for SUID + binaries if file /etc/suid-debug is available. + * locale/programs/ld-collate.c (struct element_t): Add mbseqorder and wcseqorder members. (struct locale_collate_t): Likewise. diff --git a/csu/Makefile b/csu/Makefile index 9937a91..01a44cf 100644 --- a/csu/Makefile +++ b/csu/Makefile @@ -27,7 +27,7 @@ subdir := csu -routines = init-first libc-start $(libc-init) sysdep version +routines = init-first libc-start $(libc-init) sysdep version check_fds csu-dummies = $(filter-out $(start-installed-name),crt1.o Mcrt1.o) extra-objs = start.o gmon-start.o \ $(start-installed-name) g$(start-installed-name) \ diff --git a/elf/rtld.c b/elf/rtld.c index 5c3dd43..b41a90f 100644 --- a/elf/rtld.c +++ b/elf/rtld.c @@ -52,6 +52,9 @@ extern void *_dl_sysdep_read_whole_file (const char *filename, size_t *filesize_ptr, int mmap_prot); +/* Protec SUID program against misuse of file descriptors. */ +extern void __libc_check_standard_fds (void); + /* Helper function to handle errors while resolving symbols. */ static void print_unresolved (int errcode, const char *objname, const char *errsting); @@ -396,6 +399,12 @@ dl_main (const ElfW(Phdr) *phdr, hp_timing_t diff; #endif + /* First thing, if this is a SUID program we make sure that FDs 0, + 1, and 2 are allocated. If necessary we are doing it ourself. + If it is not possible we stop the program. */ + if (__builtin_expect (__libc_enable_secure, 0)) + __libc_check_standard_fds (); + /* Process the environment variable which control the behaviour. */ process_envvars (&mode, &_dl_lazy); @@ -673,7 +682,7 @@ of this helper program; chances are you did not intend to run this program.\n\ preloads = NULL; npreloads = 0; - if (preloadlist) + if (__builtin_expect (preloadlist != NULL, 0)) { /* The LD_PRELOAD environment variable gives list of libraries separated by white space or colons that are loaded before the @@ -687,7 +696,8 @@ of this helper program; chances are you did not intend to run this program.\n\ while ((p = strsep (&list, " :")) != NULL) if (p[0] != '\0' - && (! __libc_enable_secure || strchr (p, '/') == NULL)) + && (__builtin_expect (! __libc_enable_secure, 1) + || strchr (p, '/') == NULL)) { struct link_map *new_map = _dl_map_object (_dl_loaded, p, 1, lt_library, 0); @@ -704,7 +714,7 @@ of this helper program; chances are you did not intend to run this program.\n\ /* Read the contents of the file. */ file = _dl_sysdep_read_whole_file ("/etc/ld.so.preload", &file_size, PROT_READ | PROT_WRITE); - if (file) + if (__builtin_expect (file != NULL, 0)) { /* Parse the file. It contains names of libraries to be loaded, separated by white spaces or `:'. It may also contain @@ -783,7 +793,7 @@ of this helper program; chances are you did not intend to run this program.\n\ __munmap (file, file_size); } - if (npreloads != 0) + if (__builtin_expect (npreloads, 0) != 0) { /* Set up PRELOADS with a vector of the preloaded libraries. */ struct link_map *l; @@ -1072,7 +1082,7 @@ of this helper program; chances are you did not intend to run this program.\n\ this has to go here because the calls it makes should use the rtld versions of the functions (particularly calloc()), but it needs to have _dl_profile_map set up by the relocator. */ - if (_dl_profile_map != NULL) + if (__builtin_expect (_dl_profile_map != NULL, 0)) /* We must prepare the profiling. */ _dl_start_profile (_dl_profile_map, _dl_profile_output); diff --git a/malloc/malloc.c b/malloc/malloc.c index 7f33ebf..21cb9d9 100644 --- a/malloc/malloc.c +++ b/malloc/malloc.c @@ -1722,7 +1722,7 @@ ptmalloc_init __MALLOC_P((void)) __malloc_hook = save_malloc_hook; __free_hook = save_free_hook; #endif - if(s) { + if(s && (! __libc_enable_secure || access ("/etc/suid-debug", F_OK) == 0)) { if(s[0]) mALLOPt(M_CHECK_ACTION, (int)(s[0] - '0')); __malloc_check_init(); } diff --git a/sysdeps/generic/check_fds.c b/sysdeps/generic/check_fds.c new file mode 100644 index 0000000..4eea168 --- /dev/null +++ b/sysdeps/generic/check_fds.c @@ -0,0 +1,62 @@ +/* Copyright (C) 2000 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include +#include +#include +#include + +/* Try to get a machine dependent instruction which will make the + program crash. This is used in case everything else fails. */ +#include +#ifndef ABORT_INSTRUCTION +/* No such instruction is available. */ +# define ABORT_INSTRUCTION +#endif + + +/* Should other OSes (e.g., Hurd) have different versions which can + be written in a better way? */ +static void +check_one_fd (int fd, int mode) +{ + if (__builtin_expect (__libc_fcntl (fd, F_GETFD), 0) == -1 + && errno == EBADF) + { + /* Something is wrong with this descriptor, it's probably not + opened. Open /dev/null so that the SUID program we are + about to start does not accidently use this descriptor. */ + int nullfd = __libc_open (_PATH_DEVNULL, mode); + if (__builtin_expect (nullfd, 0) == -1) + /* We cannot even give an error message here since it would + run into the same problems. */ + while (1) + /* Try for ever and ever. */ + ABORT_INSTRUCTION; + } +} + + +void +__libc_check_standard_fds (void) +{ +/* Check all three standard file descriptors. */ + check_one_fd (STDIN_FILENO, O_RDONLY); + check_one_fd (STDOUT_FILENO, O_RDWR); + check_one_fd (STDERR_FILENO, O_RDWR); +} diff --git a/sysdeps/generic/libc-start.c b/sysdeps/generic/libc-start.c index fe4966c..f5486f9 100644 --- a/sysdeps/generic/libc-start.c +++ b/sysdeps/generic/libc-start.c @@ -16,12 +16,8 @@ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include -#include -#include #include #include -#include #include extern void __libc_init_first (int argc, char **argv, char **envp); @@ -32,7 +28,7 @@ extern int __libc_multiple_libcs; extern void *__libc_stack_end; /* Prototype for local function. */ -static void check_standard_fds (void); +extern void __libc_check_standard_fds (void); int __libc_start_main (int (*main) (int, char **, char **), int argc, @@ -54,10 +50,14 @@ __libc_start_main (int (*main) (int, char **, char **), int argc, /* Set the global _environ variable correctly. */ __environ = &argv[argc + 1]; +#ifndef SHARED /* Some security at this point. Prevent starting a SUID binary where - the standard file descriptors are not opened. */ + the standard file descriptors are not opened. We have to do this + only for statically linked applications since otherwise the dynamic + loader did the work already. */ if (__builtin_expect (__libc_enable_secure, 0)) - check_standard_fds (); + __libc_check_standard_fds (); +#endif /* Register the destructor of the dynamic linker if there is any. */ if (__builtin_expect (rtld_fini != NULL, 1)) @@ -89,32 +89,3 @@ __libc_start_main (int (*main) (int, char **, char **), int argc, exit ((*main) (argc, argv, __environ)); } - - -/* Should other OSes (e.g., Hurd) have different versions which can - be written in a better way? */ -static void -check_one_fd (int fd, int mode) -{ - if (__libc_fcntl (fd, F_GETFD) == -1 && errno == EBADF) - { - /* Something is wrong with this descriptor, it's probably not - opened. Open /dev/null so that the SUID program we are - about to start does not accidently use this descriptor. */ - int nullfd = __libc_open (_PATH_DEVNULL, mode); - if (nullfd == -1) - /* We cannot even give an error message here since it would - run into the same problems. */ - abort (); - } -} - - -static void -check_standard_fds (void) -{ -/* Check all three standard file descriptors. */ - check_one_fd (STDIN_FILENO, O_RDONLY); - check_one_fd (STDOUT_FILENO, O_RDWR); - check_one_fd (STDERR_FILENO, O_RDWR); -} -- cgit v1.1