aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGilad Arnold <garnold@google.com>2015-09-01 08:19:02 -0700
committerGilad Arnold <garnold@google.com>2015-09-01 09:38:24 -0700
commitaab9382297008c1d1b7cef361159a44885d52af0 (patch)
tree0a5a172e84b8845a863d74058b6f3f64abef8734
parent98fc05cbb94eed6925d76de5a75e993296252e7c (diff)
downloadtlsdate-aab9382297008c1d1b7cef361159a44885d52af0.tar.gz
Support for dropping privileges with supplementary groups.
On Android, we need support for supplementary groups when dropping privileges in order to retain permissions for accessing system resources such as the DBus socket. This CL: 1) Adds a flag -G to tlsdated for listing supplementary groups used when dropping privileges. 2) Adds '-G dbus' to tlsdated Android init script. Bug: 22373707 Bug: 23651876 Change-Id: I0769d5ef496d073c20016c3252c5edbfead2aaa5
-rw-r--r--init/tlsdated.rc2
-rw-r--r--src/tlsdate-helper-plan9.c4
-rw-r--r--src/tlsdate-helper.c4
-rw-r--r--src/tlsdate.h1
-rw-r--r--src/tlsdated.c31
-rw-r--r--src/util-plan9.c6
-rw-r--r--src/util-plan9.h3
-rw-r--r--src/util.c38
-rw-r--r--src/util.h3
9 files changed, 72 insertions, 20 deletions
diff --git a/init/tlsdated.rc b/init/tlsdated.rc
index c36b920..2418255 100644
--- a/init/tlsdated.rc
+++ b/init/tlsdated.rc
@@ -1,5 +1,5 @@
# Init file for starting tlsdated on Android.
-service tlsdated /system/bin/tlsdated -v -l -s -U -- /system/bin/tlsdate -v -C /system/etc/security/cacerts -l
+service tlsdated /system/bin/tlsdated -v -l -s -G dbus -- /system/bin/tlsdate -v -C /system/etc/security/cacerts -l
class main
# This daemon needs to start as root and drops privileges early on.
user root
diff --git a/src/tlsdate-helper-plan9.c b/src/tlsdate-helper-plan9.c
index 3c532aa..c245a6b 100644
--- a/src/tlsdate-helper-plan9.c
+++ b/src/tlsdate-helper-plan9.c
@@ -1109,7 +1109,7 @@ main(int argc, char **argv)
/* We are not going to set the clock, thus no need to stay root */
if (0 == setclock && 0 == timewarp)
{
- drop_privs_to (UNPRIV_USER, UNPRIV_GROUP);
+ drop_privs_to (UNPRIV_USER, UNPRIV_GROUP, NULL);
}
/*
XXX: KILL ME
@@ -1171,7 +1171,7 @@ main(int argc, char **argv)
die ("fork failed: %s\n", strerror (errno));
if (0 == ssl_child)
{
- drop_privs_to (UNPRIV_USER, UNPRIV_GROUP);
+ drop_privs_to (UNPRIV_USER, UNPRIV_GROUP, NULL);
run_ssl (time_map, leap);
/*
XXX: should be a pipe close
diff --git a/src/tlsdate-helper.c b/src/tlsdate-helper.c
index 9322517..d923efd 100644
--- a/src/tlsdate-helper.c
+++ b/src/tlsdate-helper.c
@@ -1276,7 +1276,7 @@ main(int argc, char **argv)
if (0 == setclock && 0 == timewarp)
{
verb ("V: attemping to drop administrator privileges");
- drop_privs_to (UNPRIV_USER, UNPRIV_GROUP);
+ drop_privs_to (UNPRIV_USER, UNPRIV_GROUP, NULL);
}
// We cast the mmap value to remove this error when compiling with g++:
@@ -1337,7 +1337,7 @@ main(int argc, char **argv)
die ("fork failed: %s", strerror (errno));
if (0 == ssl_child)
{
- drop_privs_to (UNPRIV_USER, UNPRIV_GROUP);
+ drop_privs_to (UNPRIV_USER, UNPRIV_GROUP, NULL);
run_ssl (time_map, leap, http);
(void) munmap (time_map, sizeof (uint32_t));
_exit (0);
diff --git a/src/tlsdate.h b/src/tlsdate.h
index 52305eb..97d4fec 100644
--- a/src/tlsdate.h
+++ b/src/tlsdate.h
@@ -111,6 +111,7 @@ struct opts
{
const char *user;
const char *group;
+ char *supp_groups;
int max_tries;
int min_steady_state_interval;
int wait_between_tries;
diff --git a/src/tlsdated.c b/src/tlsdated.c
index a4af628..aa852ac 100644
--- a/src/tlsdated.c
+++ b/src/tlsdated.c
@@ -42,6 +42,8 @@
#include "src/dbus.h"
#include "src/platform.h"
+
+static const char kTlsdatedOpts[] = "hwrpt:d:T:D:c:a:lsvbm:j:f:x:Uu:g:G:";
const char *kCacheDir = DEFAULT_DAEMON_CACHEDIR;
int
@@ -102,6 +104,7 @@ usage (const char *progn)
printf (" -U don't use DBus if supported\n");
printf (" -u <user> user to change to\n");
printf (" -g <grp> group to change to\n");
+ printf (" -G <grps> comma-separated list of supplementary groups\n");
printf (" -v be verbose\n");
printf (" -b use verbose debugging\n");
printf (" -x <h> set proxy for subprocs to h\n");
@@ -117,6 +120,7 @@ set_conf_defaults (struct opts *opts)
};
opts->user = UNPRIV_USER;
opts->group = UNPRIV_GROUP;
+ opts->supp_groups = NULL;
opts->max_tries = MAX_TRIES;
opts->min_steady_state_interval = STEADY_STATE_INTERVAL;
opts->wait_between_tries = WAIT_BETWEEN_TRIES;
@@ -145,7 +149,7 @@ void
parse_argv (struct opts *opts, int argc, char *argv[])
{
int opt;
- while ((opt = getopt (argc, argv, "hwrpt:d:T:D:c:a:lsvbm:j:f:x:Uu:g:")) != -1)
+ while ((opt = getopt (argc, argv, kTlsdatedOpts)) != -1)
{
switch (opt)
{
@@ -209,6 +213,9 @@ parse_argv (struct opts *opts, int argc, char *argv[])
case 'g':
opts->group = optarg;
break;
+ case 'G':
+ opts->supp_groups = optarg;
+ break;
case 'h':
default:
usage (argv[0]);
@@ -220,6 +227,21 @@ parse_argv (struct opts *opts, int argc, char *argv[])
/* Validate arguments */
}
+static const char **
+parse_supp_groups (char *arg)
+{
+ size_t i;
+ char *scan;
+ const char **supp_groups;
+
+ for (i = 1, scan = arg; (scan = strchr (scan, ',')); i++, scan++) ;
+ supp_groups = (const char **) calloc (i + 1, sizeof (const char *));
+ if (!supp_groups)
+ die ("Failed to allocate memory for supplementary group names\n");
+ for (i = 0; (supp_groups[i] = strsep (&arg, ",")); i++) ;
+ return supp_groups;
+}
+
static
void add_source_to_conf (struct opts *opts, char *host, char *port, char *proxy)
{
@@ -446,6 +468,8 @@ cleanup_main (struct state *state)
int API
main (int argc, char *argv[], char *envp[])
{
+ const char **supp_groups = NULL;
+
initalize_syslog ();
struct state state;
/* TODO(wad) EVENT_BASE_FLAG_PRECISE_TIMER | EVENT_BASE_FLAG_PRECISE_TIMER */
@@ -498,7 +522,9 @@ main (int argc, char *argv[], char *envp[])
platform->rtc_close (&state.hwclock);
}
/* drop privileges before touching any untrusted data */
- drop_privs_to (state.opts.user, state.opts.group);
+ if (state.opts.supp_groups)
+ supp_groups = parse_supp_groups (state.opts.supp_groups);
+ drop_privs_to (state.opts.user, state.opts.group, supp_groups);
/* register a signal handler to save time at shutdown */
if (state.opts.should_save_disk)
{
@@ -598,6 +624,7 @@ main (int argc, char *argv[], char *envp[])
event_base_dispatch (base);
verb ("tlsdated event dispatch terminating gracefully");
out:
+ free (supp_groups);
return cleanup_main (&state);
}
#endif /* !TLSDATED_MAIN */
diff --git a/src/util-plan9.c b/src/util-plan9.c
index 77d2077..84b68fc 100644
--- a/src/util-plan9.c
+++ b/src/util-plan9.c
@@ -61,7 +61,7 @@ void API logat(int isverbose, const char *fmt, ...)
void
-drop_privs_to (const char *user, const char *group)
+drop_privs_to (const char *user, const char *group, const char **supp_groups)
{
#if !_PLAN9_SOURCE
@@ -70,6 +70,10 @@ drop_privs_to (const char *user, const char *group)
struct passwd *pw;
struct group *gr;
+ /* TODO(garnold) Implement supplementary group support. */
+ if (supp_groups)
+ die ("Supplementary groups not supported\n");
+
if (0 != getuid ())
return; /* not running as root to begin with; should (!) be harmless to continue
without dropping to 'nobody' (setting time will fail in the end) */
diff --git a/src/util-plan9.h b/src/util-plan9.h
index 7453235..62f2329 100644
--- a/src/util-plan9.h
+++ b/src/util-plan9.h
@@ -36,6 +36,7 @@ extern void logat(int isverbose, const char *fmt, ...);
static inline int min(int x, int y) { return x < y ? x : y; }
-void drop_privs_to (const char *user, const char *group);
+void drop_privs_to (const char *user, const char *group,
+ const char **supp_groups);
#endif /* !UTIL_H */
diff --git a/src/util.c b/src/util.c
index 9833ee3..5a0acb9 100644
--- a/src/util.c
+++ b/src/util.c
@@ -148,33 +148,39 @@ void enable_seccomp(void)
#endif
}
+static gid_t
+get_unpriv_gid (const char *group)
+{
+ struct group *gr = getgrnam (group);
+ if (NULL == gr)
+ die ("Failed to obtain GID for `%s'\n", group);
+ if (0 == gr->gr_gid)
+ die ("GID for `%s' is 0, refusing to run SSL\n", group);
+ return gr->gr_gid;
+}
+
void
-drop_privs_to (const char *user, const char *group)
+drop_privs_to (const char *user, const char *group, const char **supp_groups)
{
uid_t uid;
gid_t gid;
struct passwd *pw;
- struct group *gr;
+ size_t num_supp, i;
if (0 != getuid ())
return; /* not running as root to begin with; should (!) be harmless to continue
without dropping to 'nobody' (setting time will fail in the end) */
pw = getpwnam (user);
- gr = getgrnam (group);
if (NULL == pw)
die ("Failed to obtain UID for `%s'\n", user);
- if (NULL == gr)
- die ("Failed to obtain GID for `%s'\n", group);
uid = pw->pw_uid;
if (0 == uid)
die ("UID for `%s' is 0, refusing to run SSL\n", user);
- gid = pw->pw_gid;
- if (0 == gid || 0 == gr->gr_gid)
- die ("GID for `%s' is 0, refusing to run SSL\n", user);
- if (pw->pw_gid != gr->gr_gid)
+ gid = get_unpriv_gid (group);
+ if (pw->pw_gid != gid)
die ("GID for `%s' is not `%s' as expected, refusing to run SSL\n",
user, group);
- if (0 != initgroups ( (const char *) user, gr->gr_gid))
+ if (0 != initgroups ( (const char *) user, gid))
die ("Unable to initgroups for `%s' in group `%s' as expected\n",
user, group);
#ifdef HAVE_SETRESGID
@@ -184,6 +190,18 @@ drop_privs_to (const char *user, const char *group)
if (0 != (setgid (gid) | setegid (gid)))
die ("Failed to setgid: %s\n", strerror (errno));
#endif
+ if (supp_groups)
+ {
+ for (num_supp = 0; supp_groups[num_supp]; num_supp++) ;
+ gid_t *supp_gids = (gid_t *) calloc (num_supp, sizeof (gid_t));
+ if (!supp_gids)
+ die ("Failed to allocate memory for supplementary GIDs\n");
+ for (i = 0; i < num_supp; i++)
+ supp_gids[i] = get_unpriv_gid (supp_groups[i]);
+ if (0 != setgroups (num_supp, supp_gids))
+ die ("Failed to setgroups: %s\n", strerror (errno));
+ free (supp_gids);
+ }
#ifdef HAVE_SETRESUID
if (0 != setresuid (uid, uid, uid))
die ("Failed to setresuid: %s\n", strerror (errno));
diff --git a/src/util.h b/src/util.h
index eaceeeb..7166aa9 100644
--- a/src/util.h
+++ b/src/util.h
@@ -63,7 +63,8 @@ static inline int min (int x, int y)
return x < y ? x : y;
}
-void drop_privs_to (const char *user, const char *group);
+void drop_privs_to (const char *user, const char *group,
+ const char **supp_groups);
void no_new_privs (void);
const char *sync_type_str (int sync_type);