aboutsummaryrefslogtreecommitdiff
path: root/libminijail.c
diff options
context:
space:
mode:
Diffstat (limited to 'libminijail.c')
-rw-r--r--libminijail.c85
1 files changed, 26 insertions, 59 deletions
diff --git a/libminijail.c b/libminijail.c
index 0eca595..9915afe 100644
--- a/libminijail.c
+++ b/libminijail.c
@@ -13,7 +13,6 @@
#include <fcntl.h>
#include <grp.h>
#include <linux/capability.h>
-#include <pwd.h>
#include <sched.h>
#include <signal.h>
#include <stdbool.h>
@@ -294,66 +293,26 @@ void API minijail_keep_supplementary_gids(struct minijail *j) {
int API minijail_change_user(struct minijail *j, const char *user)
{
- char *buf = NULL;
- struct passwd pw;
- struct passwd *ppw = NULL;
- ssize_t sz = sysconf(_SC_GETPW_R_SIZE_MAX);
- if (sz == -1)
- sz = 65536; /* your guess is as good as mine... */
-
- /*
- * sysconf(_SC_GETPW_R_SIZE_MAX), under glibc, is documented to return
- * the maximum needed size of the buffer, so we don't have to search.
- */
- buf = malloc(sz);
- if (!buf)
- return -ENOMEM;
- getpwnam_r(user, &pw, buf, sz, &ppw);
- /*
- * We're safe to free the buffer here. The strings inside |pw| point
- * inside |buf|, but we don't use any of them; this leaves the pointers
- * dangling but it's safe. |ppw| points at |pw| if getpwnam_r(3)
- * succeeded.
- */
- free(buf);
- /* getpwnam_r(3) does *not* set errno when |ppw| is NULL. */
- if (!ppw)
- return -1;
- minijail_change_uid(j, ppw->pw_uid);
+ uid_t uid;
+ gid_t gid;
+ int rc = lookup_user(user, &uid, &gid);
+ if (rc)
+ return rc;
+ minijail_change_uid(j, uid);
j->user = strdup(user);
if (!j->user)
return -ENOMEM;
- j->usergid = ppw->pw_gid;
+ j->usergid = gid;
return 0;
}
int API minijail_change_group(struct minijail *j, const char *group)
{
- char *buf = NULL;
- struct group gr;
- struct group *pgr = NULL;
- ssize_t sz = sysconf(_SC_GETGR_R_SIZE_MAX);
- if (sz == -1)
- sz = 65536; /* and mine is as good as yours, really */
-
- /*
- * sysconf(_SC_GETGR_R_SIZE_MAX), under glibc, is documented to return
- * the maximum needed size of the buffer, so we don't have to search.
- */
- buf = malloc(sz);
- if (!buf)
- return -ENOMEM;
- getgrnam_r(group, &gr, buf, sz, &pgr);
- /*
- * We're safe to free the buffer here. The strings inside gr point
- * inside buf, but we don't use any of them; this leaves the pointers
- * dangling but it's safe. pgr points at gr if getgrnam_r succeeded.
- */
- free(buf);
- /* getgrnam_r(3) does *not* set errno when |pgr| is NULL. */
- if (!pgr)
- return -1;
- minijail_change_gid(j, pgr->gr_gid);
+ gid_t gid;
+ int rc = lookup_group(group, &gid);
+ if (rc)
+ return rc;
+ minijail_change_gid(j, gid);
return 0;
}
@@ -1458,10 +1417,16 @@ static void write_ugid_maps_or_die(const struct minijail *j)
static void enter_user_namespace(const struct minijail *j)
{
- if (j->uidmap && setresuid(0, 0, 0))
- pdie("user_namespaces: setresuid(0, 0, 0) failed");
- if (j->gidmap && setresgid(0, 0, 0))
- pdie("user_namespaces: setresgid(0, 0, 0) failed");
+ int uid = j->flags.uid ? j->uid : 0;
+ int gid = j->flags.gid ? j->gid : 0;
+ if (j->gidmap && setresgid(gid, gid, gid)) {
+ pdie("user_namespaces: setresgid(%d, %d, %d) failed", gid, gid,
+ gid);
+ }
+ if (j->uidmap && setresuid(uid, uid, uid)) {
+ pdie("user_namespaces: setresuid(%d, %d, %d) failed", uid, uid,
+ uid);
+ }
}
static void parent_setup_complete(int *pipe_fds)
@@ -1500,10 +1465,12 @@ static void drop_ugid(const struct minijail *j)
} else if (j->flags.set_suppl_gids) {
if (setgroups(j->suppl_gid_count, j->suppl_gid_list))
pdie("setgroups(suppl_gids) failed");
- } else if (!j->flags.keep_suppl_gids) {
+ } else if (!j->flags.keep_suppl_gids && !j->flags.disable_setgroups) {
/*
* Only attempt to clear supplementary groups if we are changing
- * users or groups.
+ * users or groups, and if the caller did not request to disable
+ * setgroups (used when entering a user namespace as a
+ * non-privileged user).
*/
if ((j->flags.uid || j->flags.gid) && setgroups(0, NULL))
pdie("setgroups(0, NULL) failed");