Skip to content

Commit

Permalink
Merge pull request #2596 from brauner/2018-09-05/attach_id
Browse files Browse the repository at this point in the history
utils: allow lxc-attach to set uid / gid
  • Loading branch information
Blub committed Sep 11, 2018
2 parents 1ea1496 + 464c461 commit 88fbc01
Show file tree
Hide file tree
Showing 11 changed files with 207 additions and 77 deletions.
26 changes: 26 additions & 0 deletions doc/lxc-attach.sgml.in
Expand Up @@ -60,6 +60,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
<arg choice="opt">--clear-env</arg>
<arg choice="opt">-v, --set-var <replaceable>variable</replaceable></arg>
<arg choice="opt">--keep-var <replaceable>variable</replaceable></arg>
<arg choice="opt">-u, --uid <replaceable>uid</replaceable></arg>
<arg choice="opt">-g, --gid <replaceable>gid</replaceable></arg>
<arg choice="opt">-- <replaceable>command</replaceable></arg>
</cmdsynopsis>
</refsynopsisdiv>
Expand Down Expand Up @@ -282,6 +284,30 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
</listitem>
</varlistentry>

<varlistentry>
<term>
<option>--u, --uid <replaceable>uid</replaceable></option>
</term>
<listitem>
<para>
Executes the <replaceable>command</replaceable> with user ID
<replaceable>uid</replaceable> inside the container.
</para>
</listitem>
</varlistentry>

<varlistentry>
<term>
<option>--g, --gid <replaceable>gid</replaceable></option>
</term>
<listitem>
<para>
Executes the <replaceable>command</replaceable> with group ID
<replaceable>gid</replaceable> inside the container.
</para>
</listitem>
</varlistentry>

</variablelist>

</refsect1>
Expand Down
26 changes: 26 additions & 0 deletions doc/lxc-execute.sgml.in
Expand Up @@ -53,6 +53,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
<arg choice="opt">-d</arg>
<arg choice="opt">-f <replaceable>config_file</replaceable></arg>
<arg choice="opt">-s KEY=VAL</arg>
<arg choice="opt">-u, --uid <replaceable>uid</replaceable></arg>
<arg choice="opt">-g, --gid <replaceable>gid</replaceable></arg>
<arg choice="opt">-- <replaceable>command</replaceable></arg>
</cmdsynopsis>
</refsynopsisdiv>
Expand Down Expand Up @@ -139,6 +141,30 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
</listitem>
</varlistentry>

<varlistentry>
<term>
<option>--u, --uid <replaceable>uid</replaceable></option>
</term>
<listitem>
<para>
Executes the <replaceable>command</replaceable> with user ID
<replaceable>uid</replaceable> inside the container.
</para>
</listitem>
</varlistentry>

<varlistentry>
<term>
<option>--g, --gid <replaceable>gid</replaceable></option>
</term>
<listitem>
<para>
Executes the <replaceable>command</replaceable> with group ID
<replaceable>gid</replaceable> inside the container.
</para>
</listitem>
</varlistentry>

<varlistentry>
<term><option>--</option></term>
<listitem>
Expand Down
55 changes: 37 additions & 18 deletions src/lxc/attach.c
Expand Up @@ -749,6 +749,8 @@ static int attach_child_main(struct attach_clone_payload *payload)
int fd, lsm_fd, ret;
uid_t new_uid;
gid_t new_gid;
uid_t ns_root_uid = 0;
gid_t ns_root_gid = 0;
lxc_attach_options_t* options = payload->options;
struct lxc_proc_context_info* init_ctx = payload->init_ctx;
bool needs_lsm = (options->namespaces & CLONE_NEWNS) &&
Expand Down Expand Up @@ -836,33 +838,40 @@ static int attach_child_main(struct attach_clone_payload *payload)
goto on_error;
}

/* Set {u,g}id. */
new_uid = 0;
new_gid = 0;
if (options->namespaces & CLONE_NEWUSER) {
/* Check whether nsuid 0 has a mapping. */
ns_root_uid = get_ns_uid(0);

/* Ignore errors, we will fall back to root in that case (/proc was not
* mounted etc.).
*/
if (options->namespaces & CLONE_NEWUSER)
lxc_attach_get_init_uidgid(&new_uid, &new_gid);
/* Check whether nsgid 0 has a mapping. */
ns_root_gid = get_ns_gid(0);

if (options->uid != (uid_t)-1)
new_uid = options->uid;
/* If there's no mapping for nsuid 0 try to retrieve the nsuid
* init was started with.
*/
if (ns_root_uid == LXC_INVALID_UID)
lxc_attach_get_init_uidgid(&ns_root_uid, &ns_root_gid);

if (options->gid != (gid_t)-1)
new_gid = options->gid;
if (ns_root_uid == LXC_INVALID_UID)
goto on_error;

/* Try to set the {u,g}id combination. */
if (new_uid != 0 || new_gid != 0 || options->namespaces & CLONE_NEWUSER) {
ret = lxc_switch_uid_gid(new_uid, new_gid);
if (ret < 0)
if (!lxc_switch_uid_gid(ns_root_uid, ns_root_gid))
goto on_error;
}

ret = lxc_setgroups(0, NULL);
if (ret < 0 && errno != EPERM)
if (!lxc_setgroups(0, NULL) && errno != EPERM)
goto on_error;

/* Set {u,g}id. */
if (options->uid != LXC_INVALID_UID)
new_uid = options->uid;
else
new_uid = ns_root_uid;

if (options->gid != LXC_INVALID_GID)
new_gid = options->gid;
else
new_gid = ns_root_gid;

if ((init_ctx->container && init_ctx->container->lxc_conf &&
init_ctx->container->lxc_conf->no_new_privs) ||
(options->attach_flags & LXC_ATTACH_NO_NEW_PRIVS)) {
Expand Down Expand Up @@ -952,6 +961,16 @@ static int attach_child_main(struct attach_clone_payload *payload)
TRACE("Prepared terminal file descriptor %d", payload->terminal_slave_fd);
}

/* Avoid unnecessary syscalls. */
if (new_uid == ns_root_uid)
new_uid = LXC_INVALID_UID;

if (new_gid == ns_root_gid)
new_gid = LXC_INVALID_GID;

if (!lxc_switch_uid_gid(new_uid, new_gid))
goto on_error;

/* We're done, so we can now do whatever the user intended us to do. */
_exit(payload->exec_function(payload->exec_payload));

Expand Down
2 changes: 2 additions & 0 deletions src/lxc/cgroups/cgfsng.c
Expand Up @@ -1388,6 +1388,8 @@ static int chown_cgroup_wrapper(void *data)
}

destuid = get_ns_uid(arg->origuid);
if (destuid == LXC_INVALID_UID)
destuid = 0;

for (i = 0; arg->hierarchies[i]; i++) {
char *fullpath;
Expand Down
6 changes: 2 additions & 4 deletions src/lxc/cmd/lxc_usernsexec.c
Expand Up @@ -104,12 +104,10 @@ static int do_child(void *vargv)
char **argv = (char **)vargv;

/* Assume we want to become root */
ret = lxc_switch_uid_gid(0, 0);
if (ret < 0)
if (!lxc_switch_uid_gid(0, 0))
return -1;

ret = lxc_setgroups(0, NULL);
if (ret < 0)
if (!lxc_setgroups(0, NULL))
return -1;

ret = unshare(CLONE_NEWNS);
Expand Down
3 changes: 3 additions & 0 deletions src/lxc/macro.h
Expand Up @@ -340,4 +340,7 @@ extern int __build_bug_on_failed;
#define PTR_TO_INTMAX(p) ((intmax_t)((intptr_t)(p)))
#define INTMAX_TO_PTR(u) ((void *)((intptr_t)(u)))

#define LXC_INVALID_UID ((uid_t)-1)
#define LXC_INVALID_GID ((gid_t)-1)

#endif /* __LXC_MACRO_H */
57 changes: 29 additions & 28 deletions src/lxc/start.c
Expand Up @@ -1046,10 +1046,11 @@ static int do_start(void *data)
{
int ret;
char path[PATH_MAX];
bool have_cap_setgid;
uid_t new_uid;
gid_t new_gid;
struct lxc_list *iterator;
uid_t nsuid = 0;
gid_t nsgid = 0;
int devnull_fd = -1;
struct lxc_handler *handler = data;

Expand Down Expand Up @@ -1117,22 +1118,20 @@ static int do_start(void *data)
* privilege over our namespace.
*/
if (!lxc_list_empty(&handler->conf->id_map)) {
uid_t nsuid = (handler->conf->root_nsuid_map != NULL)
? 0
: handler->conf->init_uid;
gid_t nsgid = (handler->conf->root_nsgid_map != NULL)
? 0
: handler->conf->init_gid;

ret = lxc_switch_uid_gid(nsuid, nsgid);
if (ret < 0)
if (!handler->conf->root_nsuid_map)
nsuid = handler->conf->init_uid;

if (!handler->conf->root_nsgid_map)
nsgid = handler->conf->init_gid;

if (!lxc_switch_uid_gid(nsuid, nsgid))
goto out_warn_father;

/* Drop groups only after we switched to a valid gid in the new
* user namespace.
*/
ret = lxc_setgroups(0, NULL);
if (ret < 0 && (handler->am_root || errno != EPERM))
if (!lxc_setgroups(0, NULL) &&
(handler->am_root || errno != EPERM))
goto out_warn_father;

ret = prctl(PR_SET_DUMPABLE, prctl_arg(1), prctl_arg(0),
Expand Down Expand Up @@ -1355,25 +1354,27 @@ static int do_start(void *data)
new_uid = handler->conf->init_uid;
new_gid = handler->conf->init_gid;

/* If we are in a new user namespace we already dropped all groups when
* we switched to root in the new user namespace further above. Only
* drop groups if we can, so ensure that we have necessary privilege.
*/
#if HAVE_LIBCAP
have_cap_setgid = lxc_proc_cap_is_set(CAP_SETGID, CAP_EFFECTIVE);
#else
have_cap_setgid = false;
#endif
if (lxc_list_empty(&handler->conf->id_map) && have_cap_setgid) {
ret = lxc_setgroups(0, NULL);
if (ret < 0)
goto out_warn_father;
}
/* Avoid unnecessary syscalls. */
if (new_uid == nsuid)
new_uid = LXC_INVALID_UID;

ret = lxc_switch_uid_gid(new_uid, new_gid);
if (ret < 0)
if (new_gid == nsgid)
new_gid = LXC_INVALID_GID;

if (!lxc_switch_uid_gid(new_uid, new_gid))
goto out_warn_father;

/* If we are in a new user namespace we already dropped all groups when
* we switched to root in the new user namespace further above. Only
* drop groups if we can, so ensure that we have necessary privilege.
*/
if (lxc_list_empty(&handler->conf->id_map))
#if HAVE_LIBCAP
if (lxc_proc_cap_is_set(CAP_SETGID, CAP_EFFECTIVE))
#endif
if (!lxc_setgroups(0, NULL))
goto out_warn_father;

ret = lxc_ambient_caps_down();
if (ret < 0) {
ERROR("Failed to clear ambient capabilities");
Expand Down
12 changes: 4 additions & 8 deletions src/lxc/storage/rsync.c
Expand Up @@ -50,12 +50,10 @@ int lxc_rsync_exec_wrapper(void *data)
int ret;
struct rsync_data_char *args = data;

ret = lxc_switch_uid_gid(0, 0);
if (ret < 0)
if (!lxc_switch_uid_gid(0, 0))
return -1;

ret = lxc_setgroups(0, NULL);
if (ret < 0)
if (!lxc_setgroups(0, NULL))
return -1;

return lxc_rsync_exec(args->src, args->dest);
Expand Down Expand Up @@ -117,12 +115,10 @@ int lxc_rsync(struct rsync_data *data)
return -1;
}

ret = lxc_switch_uid_gid(0, 0);
if (ret < 0)
if (!lxc_switch_uid_gid(0, 0))
return -1;

ret = lxc_setgroups(0, NULL);
if (ret < 0)
if (!lxc_setgroups(0, NULL))
return -1;

src = lxc_storage_get_path(orig->dest, orig->type);
Expand Down
18 changes: 18 additions & 0 deletions src/lxc/tools/lxc_attach.c
Expand Up @@ -72,6 +72,8 @@ static const struct option my_longopts[] = {
{"set-var", required_argument, 0, 'v'},
{"pty-log", required_argument, 0, 'L'},
{"rcfile", required_argument, 0, 'f'},
{"uid", required_argument, 0, 'u'},
{"gid", required_argument, 0, 'g'},
LXC_COMMON_OPTIONS
};

Expand Down Expand Up @@ -122,6 +124,8 @@ Options :\n\
multiple times.\n\
-f, --rcfile=FILE\n\
Load configuration file FILE\n\
-u, --uid=UID Execute COMMAND with UID inside the container\n\
-g, --gid=GID Execute COMMAND with GID inside the container\n\
",
.options = my_longopts,
.parser = my_parser,
Expand Down Expand Up @@ -187,6 +191,14 @@ static int my_parser(struct lxc_arguments *args, int c, char *arg)
case 'f':
args->rcfile = arg;
break;
case 'u':
if (lxc_safe_uint(arg, &args->uid) < 0)
return -1;
break;
case 'g':
if (lxc_safe_uint(arg, &args->gid) < 0)
return -1;
break;
}

return 0;
Expand Down Expand Up @@ -333,6 +345,12 @@ int main(int argc, char *argv[])
goto out;
}

if (my_args.uid)
attach_options.uid = my_args.uid;

if (my_args.gid)
attach_options.gid = my_args.gid;

if (command.program)
ret = c->attach(c, lxc_attach_run_command, &command, &attach_options, &pid);
else
Expand Down

0 comments on commit 88fbc01

Please sign in to comment.