summaryrefslogtreecommitdiff
path: root/libc/stdlib
diff options
context:
space:
mode:
authorjoseph <joseph@7b3dc134-2b1b-0410-93df-9e9f96275f8d>2012-07-31 15:30:38 +0000
committerjoseph <joseph@7b3dc134-2b1b-0410-93df-9e9f96275f8d>2012-07-31 15:30:38 +0000
commitdd3105b347f432016fcdc1abd472c3717f557c9e (patch)
treecbaaecdaa1d3ad240177c9040f7f46c1387716ce /libc/stdlib
parent20f73aac36c2b2c240dcc379d5117488fe44960c (diff)
Merge changes between r19464 and r19920 from /fsf/trunk.
git-svn-id: svn://svn.eglibc.org/trunk@19921 7b3dc134-2b1b-0410-93df-9e9f96275f8d
Diffstat (limited to 'libc/stdlib')
-rw-r--r--libc/stdlib/Makefile4
-rw-r--r--libc/stdlib/Versions7
-rw-r--r--libc/stdlib/bug-getcontext.c25
-rw-r--r--libc/stdlib/secure-getenv.c13
-rw-r--r--libc/stdlib/stdlib.h4
-rw-r--r--libc/stdlib/tst-makecontext.c4
-rw-r--r--libc/stdlib/tst-secure-getenv.c250
7 files changed, 295 insertions, 12 deletions
diff --git a/libc/stdlib/Makefile b/libc/stdlib/Makefile
index 0ae7047c1..f7e97e9c4 100644
--- a/libc/stdlib/Makefile
+++ b/libc/stdlib/Makefile
@@ -77,7 +77,9 @@ tests := tst-strtol tst-strtod testrand testsort testdiv \
test-a64l tst-qsort tst-system bug-strtod2 \
tst-atof1 tst-atof2 tst-strtod2 tst-rand48-2 \
tst-makecontext tst-qsort2 tst-makecontext2 tst-strtod6 \
- tst-unsetenv1 tst-makecontext3 bug-getcontext bug-fmtmsg1
+ tst-unsetenv1 tst-makecontext3 bug-getcontext bug-fmtmsg1 \
+ tst-secure-getenv
+tests-static := tst-secure-getenv
tests-$(OPTION_EGLIBC_LOCALE_CODE) \
+= tst-strtod3 tst-strtod4 tst-strtod5 testmb2
tests-$(OPTION_POSIX_C_LANG_WIDE_CHAR) \
diff --git a/libc/stdlib/Versions b/libc/stdlib/Versions
index 2aa396ecb..250bd5fad 100644
--- a/libc/stdlib/Versions
+++ b/libc/stdlib/Versions
@@ -6,7 +6,7 @@ libc {
# functions used in inline functions or macros
__strto*_internal;
- # functions used in other libraries
+ # compatibility symbol
__secure_getenv;
# a*
@@ -103,11 +103,16 @@ libc {
GLIBC_2.13 {
__fentry__;
}
+ GLIBC_2.17 {
+ secure_getenv;
+ }
GLIBC_PRIVATE {
# functions which have an additional interface since they are
# are cancelable.
__libc_system;
# Variable which needs a dynamic symbol table entry.
__abort_msg;
+ # Used from other libraries
+ __libc_secure_getenv;
}
}
diff --git a/libc/stdlib/bug-getcontext.c b/libc/stdlib/bug-getcontext.c
index 7db49c849..133ee91ef 100644
--- a/libc/stdlib/bug-getcontext.c
+++ b/libc/stdlib/bug-getcontext.c
@@ -9,10 +9,25 @@
static int
do_test (void)
{
-#if FE_ALL_EXCEPT == 0
- printf("Skipping test; no support for FP exceptions.\n");
-#else
- int except_mask = FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW;
+ if (FE_ALL_EXCEPT == 0)
+ {
+ printf("Skipping test; no support for FP exceptions.\n");
+ return 0;
+ }
+
+ int except_mask = 0;
+#ifdef FE_DIVBYZERO
+ except_mask |= FE_DIVBYZERO;
+#endif
+#ifdef FE_INVALID
+ except_mask |= FE_INVALID;
+#endif
+#ifdef FE_OVERFLOW
+ except_mask |= FE_OVERFLOW;
+#endif
+#ifdef FE_UNDERFLOW
+ except_mask |= FE_UNDERFLOW;
+#endif
int status = feenableexcept (except_mask);
except_mask = fegetexcept ();
@@ -44,7 +59,7 @@ do_test (void)
printf("\nAt end fegetexcept() returned %d, expected: %d.\n",
mask, except_mask);
-#endif
+
return 0;
}
diff --git a/libc/stdlib/secure-getenv.c b/libc/stdlib/secure-getenv.c
index f64759f09..2e696e90f 100644
--- a/libc/stdlib/secure-getenv.c
+++ b/libc/stdlib/secure-getenv.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991, 1992, 1994, 1996, 2002 Free Software Foundation, Inc.
+/* Copyright (C) 1991-2012 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
@@ -18,13 +18,20 @@
#include <stdlib.h>
#include <unistd.h>
+#include <shlib-compat.h>
+
/* Some programs and especially the libc itself have to be careful
what values to accept from the environment. This special version
checks for SUID or SGID first before doing any work. */
char *
-__secure_getenv (name)
+__libc_secure_getenv (name)
const char *name;
{
return __libc_enable_secure ? NULL : getenv (name);
}
-libc_hidden_def (__secure_getenv)
+weak_alias (__libc_secure_getenv, secure_getenv)
+libc_hidden_weak (__libc_secure_getenv)
+
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_16)
+compat_symbol (libc, __libc_secure_getenv, __secure_getenv, GLIBC_2_0);
+#endif
diff --git a/libc/stdlib/stdlib.h b/libc/stdlib/stdlib.h
index f652eda3f..cf3f39ca8 100644
--- a/libc/stdlib/stdlib.h
+++ b/libc/stdlib/stdlib.h
@@ -568,10 +568,12 @@ __BEGIN_NAMESPACE_STD
extern char *getenv (const char *__name) __THROW __nonnull ((1)) __wur;
__END_NAMESPACE_STD
+#ifdef __USE_GNU
/* This function is similar to the above but returns NULL if the
programs is running with SUID or SGID enabled. */
-extern char *__secure_getenv (const char *__name)
+extern char *secure_getenv (const char *__name)
__THROW __nonnull ((1)) __wur;
+#endif
#if defined __USE_SVID || defined __USE_XOPEN
/* The SVID says this is in <stdio.h>, but this seems a better place. */
diff --git a/libc/stdlib/tst-makecontext.c b/libc/stdlib/tst-makecontext.c
index 31859007d..eb6e89bda 100644
--- a/libc/stdlib/tst-makecontext.c
+++ b/libc/stdlib/tst-makecontext.c
@@ -35,7 +35,9 @@ cf (int i)
printf ("i %d thr %d\n", i, thr);
exit (1);
}
- exit (0);
+
+ /* Since uc_link below has been set to NULL, setcontext is supposed to
+ terminate the process normally after this function returns. */
}
int
diff --git a/libc/stdlib/tst-secure-getenv.c b/libc/stdlib/tst-secure-getenv.c
new file mode 100644
index 000000000..76d8de6ed
--- /dev/null
+++ b/libc/stdlib/tst-secure-getenv.c
@@ -0,0 +1,250 @@
+/* Copyright (C) 2012 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 Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* Test that secure_getenv works by invoking the test as a SGID
+ program with a group ID from the supplementary group list. This
+ test can fail spuriously if the user is not a member of a suitable
+ supplementary group. */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+static char MAGIC_ARGUMENT[] = "run-actual-test";
+#define MAGIC_STATUS 19
+
+static const char *test_dir;
+
+/* Return a GID which is not our current GID, but is present in the
+ supplementary group list. */
+static gid_t
+choose_gid (void)
+{
+ const int count = 64;
+ gid_t groups[count];
+ int ret = getgroups (count, groups);
+ if (ret < 0)
+ {
+ perror ("getgroups");
+ exit (1);
+ }
+ gid_t current = getgid ();
+ for (int i = 0; i < ret; ++i)
+ {
+ if (groups[i] != current)
+ return groups[i];
+ }
+ return 0;
+}
+
+
+/* Copies the executable into a restricted directory, so that we can
+ safely make it SGID with the TARGET group ID. Then runs the
+ executable. */
+static int
+run_executable_sgid (gid_t target)
+{
+ char *dirname = 0;
+ char *execname = 0;
+ int infd = -1;
+ int outfd = -1;
+ int ret = -1;
+ if (asprintf (&dirname, "%s/secure-getenv.%jd",
+ test_dir, (intmax_t) getpid ()) < 0)
+ {
+ perror ("asprintf");
+ goto err;
+ }
+ if (mkdir (dirname, 0700) < 0)
+ {
+ perror ("mkdir");
+ goto err;
+ }
+ if (asprintf (&execname, "%s/bin", dirname) < 0)
+ {
+ perror ("asprintf");
+ goto err;
+ }
+ infd = open ("/proc/self/exe", O_RDONLY);
+ if (infd < 0)
+ {
+ perror ("open");
+ goto err;
+ }
+ outfd = open (execname, O_WRONLY | O_CREAT | O_EXCL, 0700);
+ if (outfd < 0)
+ {
+ perror ("open");
+ goto err;
+ }
+ char buf[4096];
+ for (;;)
+ {
+ ssize_t rdcount = read (infd, buf, sizeof (buf));
+ if (rdcount < 0)
+ {
+ perror ("read");
+ goto err;
+ }
+ if (rdcount == 0)
+ break;
+ char *p = buf;
+ char *end = buf + rdcount;
+ while (p != end)
+ {
+ ssize_t wrcount = write (outfd, buf, end - p);
+ if (wrcount == 0)
+ errno = ENOSPC;
+ if (wrcount <= 0)
+ {
+ perror ("write");
+ goto err;
+ }
+ p += wrcount;
+ }
+ }
+ if (fchown (outfd, getuid (), target) < 0)
+ {
+ perror ("fchown");
+ goto err;
+ }
+ if (fchmod (outfd, 02750) < 0)
+ {
+ perror ("fchmod");
+ goto err;
+ }
+ if (close (outfd) < 0)
+ {
+ perror ("close");
+ goto err;
+ }
+ if (close (infd) < 0)
+ {
+ perror ("close");
+ goto err;
+ }
+
+ int kid = fork ();
+ if (kid < 0)
+ {
+ perror ("fork");
+ goto err;
+ }
+ if (kid == 0)
+ {
+ /* Child process. */
+ char *args[] = { execname, MAGIC_ARGUMENT, NULL };
+ execve (execname, args, environ);
+ perror ("execve");
+ _exit (1);
+ }
+ int status;
+ if (waitpid (kid, &status, 0) < 0)
+ {
+ perror ("waitpid");
+ goto err;
+ }
+ if (!WIFEXITED (status) || WEXITSTATUS (status) != MAGIC_STATUS)
+ {
+ fprintf (stderr, "Unexpected exit status %d from child process\n",
+ status);
+ goto err;
+ }
+ ret = 0;
+
+err:
+ if (outfd >= 0)
+ close (outfd);
+ if (infd >= 0)
+ close (infd);
+ if (execname)
+ {
+ unlink (execname);
+ free (execname);
+ }
+ if (dirname)
+ {
+ rmdir (dirname);
+ free (dirname);
+ }
+ return ret;
+}
+
+static int
+do_test (void)
+{
+ if (getenv ("PATH") == NULL)
+ {
+ fprintf (stderr, "PATH not set\n");
+ exit (1);
+ }
+ if (secure_getenv ("PATH") == NULL)
+ {
+ fprintf (stderr, "PATH not set according to secure_getenv\n");
+ exit (1);
+ }
+ if (strcmp (getenv ("PATH"), secure_getenv ("PATH")) != 0)
+ {
+ fprintf (stderr, "PATH mismatch (%s, %s)\n",
+ getenv ("PATH"), secure_getenv ("PATH"));
+ exit (1);
+ }
+
+ gid_t target = choose_gid ();
+ if (target == 0)
+ {
+ fprintf (stderr, "Could not find a suitable GID user %jd\n",
+ (intmax_t) getuid ());
+ exit (1);
+ }
+ return run_executable_sgid (target);
+}
+
+static void
+alternative_main (int argc, char **argv)
+{
+ if (argc == 2 && strcmp (argv[1], MAGIC_ARGUMENT) == 0)
+ {
+ if (getgid () == getegid ())
+ {
+ fprintf (stderr, "SGID failed: GID and EGID match (%jd)\n",
+ (intmax_t) getgid ());
+ exit (2);
+ }
+ if (getenv ("PATH") == NULL)
+ {
+ fprintf (stderr, "PATH variable not present\n");
+ exit (3);
+ }
+ if (secure_getenv ("PATH") != NULL)
+ {
+ fprintf (stderr, "PATH variable not filtered out\n");
+ exit (4);
+ }
+ exit (MAGIC_STATUS);
+ }
+}
+
+#define PREPARE(argc, argv) alternative_main(argc, argv)
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"