From 762c7c65103615d976beeb4c8e2d1d9a79c87d86 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Wed, 6 Apr 2005 14:44:16 -0400 Subject: [PATCH] Add paranoia checks into the blkid, ext2fs, and ss libraries to ignore environment variables if the libraries are called from setuid or setguid programs, or if kernel believes that the process is not eligible to create a core dump. In addition, if the libc has __secure_getenv(), use it so that the libc can also do any additional limitations regarding when libraries can trust environment variables (i.e., to integrate with systems like SELinux and Posix capabilities). --- ChangeLog | 5 +++++ configure | 7 +++++-- configure.in | 4 ++-- lib/blkid/ChangeLog | 9 +++++++++ lib/blkid/cache.c | 40 ++++++++++++++++++++++++++++++++++++++-- lib/ext2fs/ChangeLog | 6 ++++++ lib/ext2fs/test_io.c | 39 ++++++++++++++++++++++++++++++++++----- lib/ss/ChangeLog | 7 +++++++ lib/ss/get_readline.c | 2 +- lib/ss/pager.c | 31 ++++++++++++++++++++++++++++++- lib/ss/ss_internal.h | 1 + 11 files changed, 138 insertions(+), 13 deletions(-) diff --git a/ChangeLog b/ChangeLog index 89dd394ce..ef71f121e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2005-03-31 Theodore Ts'o + + * configure.in: Add tests for __secure_getenv(), prctl(), + and sys/prctl.h + 2005-03-21 Theodore Ts'o * Release of E2fsprogs 1.37 diff --git a/configure b/configure index d38fb2519..9b267e228 100644 --- a/configure +++ b/configure @@ -10713,7 +10713,8 @@ fi -for ac_header in stdlib.h unistd.h stdarg.h stdint.h errno.h malloc.h mntent.h paths.h dirent.h getopt.h setjmp.h signal.h termios.h linux/fd.h linux/major.h sys/disklabel.h sys/ioctl.h sys/mkdev.h sys/queue.h sys/sockio.h sys/socket.h sys/sysmacros.h sys/time.h sys/stat.h sys/types.h sys/wait.h sys/resource.h net/if_dl.h netinet/in.h + +for ac_header in stdlib.h unistd.h stdarg.h stdint.h errno.h malloc.h mntent.h paths.h dirent.h getopt.h setjmp.h signal.h termios.h linux/fd.h linux/major.h sys/disklabel.h sys/ioctl.h sys/mkdev.h sys/prctl.h sys/queue.h sys/sockio.h sys/socket.h sys/sysmacros.h sys/time.h sys/stat.h sys/types.h sys/wait.h sys/resource.h net/if_dl.h netinet/in.h do as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` if eval "test \"\${$as_ac_Header+set}\" = set"; then @@ -13816,7 +13817,9 @@ fi -for ac_func in chflags getrusage llseek lseek64 open64 getmntinfo strtoull strcasecmp srandom fchown mallinfo fdatasync strnlen strptime sysconf pathconf posix_memalign memalign valloc + + +for ac_func in chflags getrusage llseek lseek64 open64 getmntinfo strtoull strcasecmp srandom fchown mallinfo fdatasync strnlen strptime sysconf pathconf posix_memalign memalign valloc __secure_getenv prctl do as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` echo "$as_me:$LINENO: checking for $ac_func" >&5 diff --git a/configure.in b/configure.in index 1110d0387..c9600f0a2 100644 --- a/configure.in +++ b/configure.in @@ -525,7 +525,7 @@ if test $cross_compiling = no; then else AC_CHECK_PROGS(BUILD_CC, gcc cc) fi -AC_CHECK_HEADERS(stdlib.h unistd.h stdarg.h stdint.h errno.h malloc.h mntent.h paths.h dirent.h getopt.h setjmp.h signal.h termios.h linux/fd.h linux/major.h sys/disklabel.h sys/ioctl.h sys/mkdev.h sys/queue.h sys/sockio.h sys/socket.h sys/sysmacros.h sys/time.h sys/stat.h sys/types.h sys/wait.h sys/resource.h net/if_dl.h netinet/in.h) +AC_CHECK_HEADERS(stdlib.h unistd.h stdarg.h stdint.h errno.h malloc.h mntent.h paths.h dirent.h getopt.h setjmp.h signal.h termios.h linux/fd.h linux/major.h sys/disklabel.h sys/ioctl.h sys/mkdev.h sys/prctl.h sys/queue.h sys/sockio.h sys/socket.h sys/sysmacros.h sys/time.h sys/stat.h sys/types.h sys/wait.h sys/resource.h net/if_dl.h netinet/in.h) AC_CHECK_HEADERS(sys/disk.h sys/mount.h,,, [[ #if HAVE_SYS_QUEUE_H @@ -628,7 +628,7 @@ AC_CHECK_MEMBER(struct sockaddr.sa_len, [#include #include ]) dnl -AC_CHECK_FUNCS(chflags getrusage llseek lseek64 open64 getmntinfo strtoull strcasecmp srandom fchown mallinfo fdatasync strnlen strptime sysconf pathconf posix_memalign memalign valloc) +AC_CHECK_FUNCS(chflags getrusage llseek lseek64 open64 getmntinfo strtoull strcasecmp srandom fchown mallinfo fdatasync strnlen strptime sysconf pathconf posix_memalign memalign valloc __secure_getenv prctl) dnl dnl Check to see if -lsocket is required (solaris) to make something dnl that uses socket() to compile; this is needed for the UUID library diff --git a/lib/blkid/ChangeLog b/lib/blkid/ChangeLog index bfa6070b6..5d9ef2e8b 100644 --- a/lib/blkid/ChangeLog +++ b/lib/blkid/ChangeLog @@ -1,3 +1,12 @@ +2005-03-31 Theodore Ts'o + + * cache.c (blkid_get_cache): Use a much more paranoid + safe_getenv() function which will ignore the BLKID_FILE + environment varaible if the application program is setgid + or on a Linux system, if kernel doesn't think the process + is eligible to create a core dump. Also if glibc has + __secure_getenv(), then use it. + 2005-03-21 Theodore Ts'o * Release of E2fsprogs 1.37 diff --git a/lib/blkid/cache.c b/lib/blkid/cache.c index 12cae0c11..5813bbc5f 100644 --- a/lib/blkid/cache.c +++ b/lib/blkid/cache.c @@ -10,12 +10,48 @@ * %End-Header% */ +#if HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif #include #include +#ifdef HAVE_SYS_PRCTL_H +#include +#else +#define PR_GET_DUMPABLE 3 +#endif +#if (!defined(HAVE_PRCTL) && defined(linux)) +#include +#endif #include "blkidP.h" int blkid_debug_mask = 0; + +static char *safe_getenv(const char *arg) +{ + if ((getuid() != geteuid()) || (getgid() != getgid())) + return NULL; +#if HAVE_PRCTL + if (prctl(PR_GET_DUMPABLE) == 0) + return NULL; +#else +#if (defined(linux) && defined(SYS_prctl)) + if (syscall(SYS_prctl, PR_GET_DUMPABLE) == 0) + return NULL; +#endif +#endif + +#ifdef HAVE___SECURE_GETENV + return __secure_getenv("BLKID_FILE"); +#else + return getenv("BLKID_FILE"); +#endif +} + int blkid_get_cache(blkid_cache *ret_cache, const char *filename) { blkid_cache cache; @@ -41,8 +77,8 @@ int blkid_get_cache(blkid_cache *ret_cache, const char *filename) if (filename && !strlen(filename)) filename = 0; - if (!filename && (getuid() == geteuid())) - filename = getenv("BLKID_FILE"); + if (!filename) + filename = safe_getenv("BLKID_FILE"); if (!filename) filename = BLKID_CACHE_FILE; cache->bic_filename = blkid_strdup(filename); diff --git a/lib/ext2fs/ChangeLog b/lib/ext2fs/ChangeLog index b2a829ab6..a90dcbaf4 100644 --- a/lib/ext2fs/ChangeLog +++ b/lib/ext2fs/ChangeLog @@ -1,3 +1,9 @@ +2005-03-31 Theodore Ts'o + + * test_io.c (test_open): If called by a setuid/setgid or an + otherwise privileged program, be paranoid and ignore the + TEST_IO_* environment variables. + 2005-03-21 Theodore Ts'o * Release of E2fsprogs 1.37 diff --git a/lib/ext2fs/test_io.c b/lib/ext2fs/test_io.c index 6a3b248e9..f4d9b995e 100644 --- a/lib/ext2fs/test_io.c +++ b/lib/ext2fs/test_io.c @@ -22,6 +22,14 @@ #if HAVE_SYS_TYPES_H #include #endif +#ifdef HAVE_SYS_PRCTL_H +#include +#else +#define PR_GET_DUMPABLE 3 +#endif +#if (!defined(HAVE_PRCTL) && defined(linux)) +#include +#endif #include "ext2_fs.h" #include "ext2fs.h" @@ -132,6 +140,27 @@ static void test_abort(io_channel channel, unsigned long block) abort(); } +static char *safe_getenv(const char *arg) +{ + if ((getuid() != geteuid()) || (getgid() != getgid())) + return NULL; +#if HAVE_PRCTL + if (prctl(PR_GET_DUMPABLE) == 0) + return NULL; +#else +#if (defined(linux) && defined(SYS_prctl)) + if (syscall(SYS_prctl, PR_GET_DUMPABLE) == 0) + return NULL; +#endif +#endif + +#ifdef HAVE___SECURE_GETENV + return __secure_getenv("BLKID_FILE"); +#else + return getenv("BLKID_FILE"); +#endif +} + static errcode_t test_open(const char *name, int flags, io_channel *channel) { io_channel io = NULL; @@ -178,25 +207,25 @@ static errcode_t test_open(const char *name, int flags, io_channel *channel) data->write_byte = test_io_cb_write_byte; data->outfile = NULL; - if ((value = getenv("TEST_IO_LOGFILE")) != NULL) + if ((value = safe_getenv("TEST_IO_LOGFILE")) != NULL) data->outfile = fopen(value, "w"); if (!data->outfile) data->outfile = stderr; data->flags = 0; - if ((value = getenv("TEST_IO_FLAGS")) != NULL) + if ((value = safe_getenv("TEST_IO_FLAGS")) != NULL) data->flags = strtoul(value, NULL, 0); data->block = 0; - if ((value = getenv("TEST_IO_BLOCK")) != NULL) + if ((value = safe_getenv("TEST_IO_BLOCK")) != NULL) data->block = strtoul(value, NULL, 0); data->read_abort_count = 0; - if ((value = getenv("TEST_IO_READ_ABORT")) != NULL) + if ((value = safe_getenv("TEST_IO_READ_ABORT")) != NULL) data->read_abort_count = strtoul(value, NULL, 0); data->write_abort_count = 0; - if ((value = getenv("TEST_IO_WRITE_ABORT")) != NULL) + if ((value = safe_getenv("TEST_IO_WRITE_ABORT")) != NULL) data->write_abort_count = strtoul(value, NULL, 0); *channel = io; diff --git a/lib/ss/ChangeLog b/lib/ss/ChangeLog index 2dcc071f2..40be15f62 100644 --- a/lib/ss/ChangeLog +++ b/lib/ss/ChangeLog @@ -1,3 +1,10 @@ +2005-03-31 Theodore Ts'o + + * get_readline.c (ss_get_readline), pager.c (ss_page_stdin): If + called by a setuid/setgid or an otherwise privileged + program, be paranoid and ignore the PAGER and + SS_READLINE_PATH environment variables. + 2005-03-21 Theodore Ts'o * Release of E2fsprogs 1.37 diff --git a/lib/ss/get_readline.c b/lib/ss/get_readline.c index d9499e6d3..b9754d89d 100644 --- a/lib/ss/get_readline.c +++ b/lib/ss/get_readline.c @@ -50,7 +50,7 @@ void ss_get_readline(int sci_idx) if (info->readline_handle) return; - libpath = getenv("SS_READLINE_PATH"); + libpath = ss_safe_getenv("SS_READLINE_PATH"); if (!libpath) libpath = DEFAULT_LIBPATH; if (*libpath == 0 || !strcmp(libpath, "none")) diff --git a/lib/ss/pager.c b/lib/ss/pager.c index ba28f97a7..4030c7f76 100644 --- a/lib/ss/pager.c +++ b/lib/ss/pager.c @@ -28,11 +28,40 @@ extern int errno; #include #include #include +#ifdef HAVE_SYS_PRCTL_H +#include +#else +#define PR_GET_DUMPABLE 3 +#endif +#if (!defined(HAVE_PRCTL) && defined(linux)) +#include +#endif static char MORE[] = "more"; extern char *_ss_pager_name; extern char *getenv PROTOTYPE((const char *)); +char *ss_safe_getenv(const char *arg) +{ + if ((getuid() != geteuid()) || (getgid() != getgid())) + return NULL; +#if HAVE_PRCTL + if (prctl(PR_GET_DUMPABLE) == 0) + return NULL; +#else +#if (defined(linux) && defined(SYS_prctl)) + if (syscall(SYS_prctl, PR_GET_DUMPABLE) == 0) + return NULL; +#endif +#endif + +#ifdef HAVE___SECURE_GETENV + return __secure_getenv("BLKID_FILE"); +#else + return getenv("BLKID_FILE"); +#endif +} + /* * this needs a *lot* of work.... * @@ -89,7 +118,7 @@ void ss_page_stdin() sigdelset(&mask, SIGINT); sigprocmask(SIG_SETMASK, &mask, 0); if (_ss_pager_name == (char *)NULL) { - if ((_ss_pager_name = getenv("PAGER")) == (char *)NULL) + if ((_ss_pager_name = ss_safe_getenv("PAGER")) == (char *)NULL) _ss_pager_name = MORE; } (void) execlp(_ss_pager_name, _ss_pager_name, (char *) NULL); diff --git a/lib/ss/ss_internal.h b/lib/ss/ss_internal.h index 48afdbd06..15d618ee5 100644 --- a/lib/ss/ss_internal.h +++ b/lib/ss/ss_internal.h @@ -89,6 +89,7 @@ void ss_page_stdin(void); void ss_list_requests(int, char const * const *, int, pointer); int ss_execute_command(int sci_idx, char *argv[]); int ss_pager_create(void); +char *ss_safe_getenv(const char *arg); char **ss_rl_completion(const char *text, int start, int end); extern ss_data **_ss_table; -- 2.47.3