diff options
author | Stef Walter <stef@thewalter.net> | 2013-07-17 11:57:02 +0200 |
---|---|---|
committer | Stef Walter <stef@thewalter.net> | 2013-07-18 08:45:57 +0200 |
commit | 936e4c229a4ed205e9981fc4f31acea063701b69 (patch) | |
tree | f6f9c7fcbee8a097e7b1abfad9c4bdd8552708cc /common | |
parent | 81a6e16539e5e4a27c55194ae095cc4a75d08ade (diff) |
Don't load configs from user directory when setuid
When running as setuid() or setgid() don't access the user's home
directory, or use $HOME environment variables.
https://bugzilla.redhat.com/show_bug.cgi?id=985014
Diffstat (limited to 'common')
-rw-r--r-- | common/compat.c | 48 | ||||
-rw-r--r-- | common/compat.h | 12 | ||||
-rw-r--r-- | common/path.c | 5 | ||||
-rw-r--r-- | common/test.c | 99 | ||||
-rw-r--r-- | common/test.h | 9 | ||||
-rw-r--r-- | common/tests/Makefile.am | 5 | ||||
-rw-r--r-- | common/tests/frob-getauxval.c | 63 | ||||
-rw-r--r-- | common/tests/test-compat.c | 30 |
8 files changed, 270 insertions, 1 deletions
diff --git a/common/compat.c b/common/compat.c index 5efc932..3b1361c 100644 --- a/common/compat.c +++ b/common/compat.c @@ -759,3 +759,51 @@ mkdtemp (char *template) } #endif /* HAVE_MKDTEMP */ + +#ifndef HAVE_GETAUXVAL + +unsigned long +getauxval (unsigned long type) +{ + static unsigned long secure = 0UL; + static bool check_secure_initialized = false; + + /* + * This is the only one our stand-in impl supports and is + * also the only type we define in compat.h header + */ + assert (type == AT_SECURE); + + if (!check_secure_initialized) { +#if defined(HAVE___LIBC_ENABLE_SECURE) + extern int __libc_enable_secure; + secure = __libc_enable_secure; + +#elif defined(HAVE_ISSETUGID) + secure = issetugid (); + +#elif defined(OS_UNIX) + uid_t ruid, euid, suid; /* Real, effective and saved user ID's */ + gid_t rgid, egid, sgid; /* Real, effective and saved group ID's */ + +#ifdef HAVE_GETRESUID + if (getresuid (&ruid, &euid, &suid) != 0 || + getresgid (&rgid, &egid, &sgid) != 0) +#endif /* HAVE_GETRESUID */ + { + suid = ruid = getuid (); + sgid = rgid = getgid (); + euid = geteuid (); + egid = getegid (); + } + + secure = (ruid != euid || ruid != suid || + rgid != egid || rgid != sgid); +#endif /* OS_UNIX */ + check_secure_initialized = true; + } + + return secure; +} + +#endif /* HAVE_GETAUXVAL */ diff --git a/common/compat.h b/common/compat.h index 20f9a81..1cedc35 100644 --- a/common/compat.h +++ b/common/compat.h @@ -298,4 +298,16 @@ time_t timegm (struct tm *tm); #endif /* HAVE_TIMEGM */ +#ifdef HAVE_GETAUXVAL + +#include <sys/auxv.h> + +#else /* !HAVE_GETAUXVAL */ + +unsigned long getauxval (unsigned long type); + +#define AT_SECURE 23 + +#endif /* !HAVE_GETAUXVAL */ + #endif /* __COMPAT_H__ */ diff --git a/common/path.c b/common/path.c index 0ff1431..d807301 100644 --- a/common/path.c +++ b/common/path.c @@ -99,6 +99,11 @@ expand_homedir (const char *remainder) if (remainder[0] == '\0') remainder = NULL; + if (getauxval (AT_SECURE)) { + errno = EPERM; + return NULL; + } + env = getenv ("HOME"); if (env && env[0]) { return p11_path_build (env, remainder, NULL); diff --git a/common/test.c b/common/test.c index 0f5c451..eb02645 100644 --- a/common/test.c +++ b/common/test.c @@ -48,6 +48,12 @@ #include <stdlib.h> #include <string.h> +#ifdef OS_UNIX +#include <sys/stat.h> +#include <sys/wait.h> +#include <unistd.h> +#endif + enum { FIXTURE, TEST, @@ -331,3 +337,96 @@ p11_test_directory (const char *prefix) free (templ); return directory; } + +#ifdef OS_UNIX + +static void +copy_file (const char *input, + int fd) +{ + p11_mmap *mmap; + const char *data; + ssize_t written; + size_t size; + + mmap = p11_mmap_open (input, (void **)&data, &size); + assert (mmap != NULL); + + while (size > 0) { + written = write (fd, data, size); + assert (written >= 0); + + data += written; + size -= written; + } + + p11_mmap_close (mmap); +} + +char * +p11_test_copy_setgid (const char *input) +{ + gid_t groups[128]; + char *path; + gid_t group = 0; + int ret; + int fd; + int i; + + ret = getgroups (128, groups); + for (i = 0; i < ret; ++i) { + if (groups[i] != getgid ()) { + group = groups[i]; + break; + } + } + if (i == ret) { + fprintf (stderr, "# no suitable group, skipping test"); + return NULL; + } + + path = strdup ("/tmp/test-setgid.XXXXXX"); + assert (path != NULL); + + fd = mkstemp (path); + assert (fd >= 0); + + copy_file (input, fd); + if (fchown (fd, getuid (), group) < 0) + assert_not_reached (); + if (fchmod (fd, 02750) < 0) + assert_not_reached (); + if (close (fd) < 0) + assert_not_reached (); + + return path; +} + +int +p11_test_run_child (const char **argv, + bool quiet_out) +{ + pid_t child; + int status; + + child = fork (); + assert (child >= 0); + + /* In the child process? */ + if (child == 0) { + if (quiet_out) + close (1); /* stdout */ + execve (argv[0], (char **)argv, NULL); + assert_not_reached (); + } + + if (waitpid (child, &status, 0) < 0) + assert_not_reached (); + + assert (!WIFSIGNALED (status)); + assert (WIFEXITED (status)); + + return WEXITSTATUS (status); +} + +#endif /* OS_UNIX */ diff --git a/common/test.h b/common/test.h index 7354595..c9f519a 100644 --- a/common/test.h +++ b/common/test.h @@ -130,4 +130,13 @@ int p11_test_run (int argc, char * p11_test_directory (const char *prefix); +#ifdef OS_UNIX + +char * p11_test_copy_setgid (const char *path); + +int p11_test_run_child (const char **argv, + bool quiet_out); + +#endif + #endif /* P11_TEST_H_ */ diff --git a/common/tests/Makefile.am b/common/tests/Makefile.am index 637399b..b1a42bd 100644 --- a/common/tests/Makefile.am +++ b/common/tests/Makefile.am @@ -7,7 +7,9 @@ AM_CPPFLAGS = \ -I$(top_srcdir) \ -I$(srcdir)/.. \ -I$(COMMON) \ - $(TEST_CFLAGS) + -DBUILDDIR=\"$(abs_builddir)\" \ + $(TEST_CFLAGS) \ + $(CUTEST_CFLAGS) LDADD = \ $(NULL) @@ -26,6 +28,7 @@ CHECK_PROGS = \ $(NULL) noinst_PROGRAMS = \ + frob-getauxval \ $(CHECK_PROGS) TESTS = $(CHECK_PROGS) diff --git a/common/tests/frob-getauxval.c b/common/tests/frob-getauxval.c new file mode 100644 index 0000000..54ebea0 --- /dev/null +++ b/common/tests/frob-getauxval.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2013 Red Hat Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the + * above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or + * other materials provided with the distribution. + * * The names of contributors to this software may not be + * used to endorse or promote products derived from this + * software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * Author: Stef Walter <stefw@gnome.org> + */ + +#include "config.h" +#include "compat.h" + +#include <libtasn1.h> + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +int +main (int argc, + char *argv[]) +{ + unsigned long type = 0; + unsigned long ret; + + if (argc == 2) + type = atoi (argv[1]); + + if (type == 0) { + fprintf (stderr, "usage: frob-getauxval 23"); + abort (); + } + + ret = getauxval (type); + printf ("getauxval(%lu) == %lu\n", type, ret); + return (int)ret; +} diff --git a/common/tests/test-compat.c b/common/tests/test-compat.c index f1960ce..a541235 100644 --- a/common/tests/test-compat.c +++ b/common/tests/test-compat.c @@ -35,6 +35,7 @@ #include "config.h" #include "test.h" +#include <errno.h> #include <stdlib.h> #include <stdio.h> #include <string.h> @@ -56,10 +57,39 @@ test_strndup (void) free (res); } +#ifdef OS_UNIX + +static void +test_getauxval (void) +{ + /* 23 is AT_SECURE */ + const char *args[] = { BUILDDIR "/frob-getauxval", "23", NULL }; + char *path; + int ret; + + ret = p11_test_run_child (args, true); + assert_num_eq (ret, 0); + + path = p11_test_copy_setgid (args[0]); + if (path == NULL) + return; + + args[0] = path; + ret = p11_test_run_child (args, true); + assert_num_cmp (ret, !=, 0); + + if (unlink (path) < 0) + assert_fail ("unlink failed", strerror (errno)); + free (path); +} + +#endif /* OS_UNIX */ + int main (int argc, char *argv[]) { p11_test (test_strndup, "/test/strndup"); + p11_test (test_getauxval, "/test/getauxval"); return p11_test_run (argc, argv); } |