summaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
authorStef Walter <stef@thewalter.net>2013-07-17 11:57:02 +0200
committerStef Walter <stef@thewalter.net>2013-07-18 08:45:57 +0200
commit936e4c229a4ed205e9981fc4f31acea063701b69 (patch)
treef6f9c7fcbee8a097e7b1abfad9c4bdd8552708cc /common
parent81a6e16539e5e4a27c55194ae095cc4a75d08ade (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.c48
-rw-r--r--common/compat.h12
-rw-r--r--common/path.c5
-rw-r--r--common/test.c99
-rw-r--r--common/test.h9
-rw-r--r--common/tests/Makefile.am5
-rw-r--r--common/tests/frob-getauxval.c63
-rw-r--r--common/tests/test-compat.c30
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);
}