diff --git a/jail/jail.c b/jail/jail.c index 49aabe3..3ee6a18 100644 --- a/jail/jail.c +++ b/jail/jail.c @@ -102,7 +102,7 @@ #define PR_MDWE_NO_INHERIT (1UL << 1) #endif -#define OPT_ARGS "a:A:b:cC:d:De:EfFG:h:iI:j:J:k:lm:M:n:NoO:pP:r:R:sS:uU:V:w:x:t:T:yY:Z" +#define OPT_ARGS "a:A:b:cC:d:De:EfFG:h:iI:j:J:k:lm:M:n:NoO:pP:r:R:sS:uU:V:w:W:x:t:T:yY:Z" #define JAIL_MAX_CREDENTIALS 16 static const char *cred_targets[JAIL_MAX_CREDENTIALS]; @@ -2464,6 +2464,7 @@ static void usage(void) fprintf(stderr, " -n \tthe name of the jail\n"); fprintf(stderr, " -e \timport environment variable\n"); fprintf(stderr, " -x \tappend KEY=VALUE lines from to the container env\n"); + fprintf(stderr, " -W \tworking directory for the jailed process\n"); fprintf(stderr, "namespace jail options:\n"); fprintf(stderr, " -h \tchange the hostname of the jail\n"); fprintf(stderr, " -N\t\tjail has network namespace\n"); @@ -4084,8 +4085,10 @@ static int parseOCIprocess(struct blob_attr *msg) if (tb[OCI_PROCESS_NONEWPRIVILEGES]) opts.no_new_privs = blobmsg_get_bool(tb[OCI_PROCESS_NONEWPRIVILEGES]); - if (tb[OCI_PROCESS_CWD]) + if (tb[OCI_PROCESS_CWD]) { + free(opts.cwd); opts.cwd = strdup(blobmsg_get_string(tb[OCI_PROCESS_CWD])); + } if (tb[OCI_PROCESS_ENV]) { res = parseOCIenvarray(tb[OCI_PROCESS_ENV], &opts.envp); @@ -6841,6 +6844,12 @@ int main(int argc, char **argv) case 'G': opts.group = optarg; break; + case 'W': + free(opts.cwd); + opts.cwd = strdup(optarg); + if (!opts.cwd) + free_and_exit(EXIT_FAILURE); + break; case 'O': opts.overlaydir = realpath(optarg, NULL); break; diff --git a/service/instance.c b/service/instance.c index 7c91fae..289f09d 100644 --- a/service/instance.c +++ b/service/instance.c @@ -46,6 +46,7 @@ enum { INSTANCE_ATTR_COMMAND, + INSTANCE_ATTR_WORKDIR, INSTANCE_ATTR_ENV, INSTANCE_ATTR_DATA, INSTANCE_ATTR_NETDEV, @@ -81,6 +82,7 @@ enum { static const struct blobmsg_policy instance_attr[__INSTANCE_ATTR_MAX] = { [INSTANCE_ATTR_COMMAND] = { "command", BLOBMSG_TYPE_ARRAY }, + [INSTANCE_ATTR_WORKDIR] = { "workdir", BLOBMSG_TYPE_STRING }, [INSTANCE_ATTR_ENV] = { "env", BLOBMSG_TYPE_TABLE }, [INSTANCE_ATTR_DATA] = { "data", BLOBMSG_TYPE_TABLE }, [INSTANCE_ATTR_NETDEV] = { "netdev", BLOBMSG_TYPE_ARRAY }, @@ -359,6 +361,11 @@ jail_run(struct service_instance *in, char **argv) argv[argc++] = in->group; } + if (in->workdir) { + argv[argc++] = "-W"; + argv[argc++] = in->workdir; + } + if (in->capabilities) { argv[argc++] = "-C"; argv[argc++] = in->capabilities; @@ -632,6 +639,12 @@ instance_run(struct service_instance *in, int _stdout, int _stderr) exit(127); } + if (!in->has_jail && in->workdir && chdir(in->workdir)) { + ERROR("failed to change directory to %s for %s::%s: %m\n", + in->workdir, in->srv->name, in->name); + exit(127); + } + execvp(argv[0], argv); exit(127); } @@ -1279,6 +1292,9 @@ instance_config_changed(struct service_instance *in, struct service_instance *in if (!blob_attr_equal(in->command, in_new->command)) return true; + if (string_changed(in->workdir, in_new->workdir)) + return true; + if (string_changed(in->bundle, in_new->bundle)) return true; @@ -1622,6 +1638,9 @@ instance_jail_parse(struct service_instance *in, struct blob_attr *attr) if (in->group) jail->argc += 2; + if (in->workdir) + jail->argc += 2; + if (in->extroot) jail->argc += 2; @@ -1736,6 +1755,12 @@ instance_config_parse(struct service_instance *in) } } + if (tb[INSTANCE_ATTR_WORKDIR]) { + in->workdir = strdup(blobmsg_get_string(tb[INSTANCE_ATTR_WORKDIR])); + if (!in->workdir) + return false; + } + if (tb[INSTANCE_ATTR_TRACE]) in->trace = blobmsg_get_bool(tb[INSTANCE_ATTR_TRACE]); @@ -1934,6 +1959,7 @@ instance_config_move(struct service_instance *in, struct service_instance *in_sr instance_config_move_strdup(&in->tmpoverlaysize, in_src->tmpoverlaysize); instance_config_move_strdup(&in->user, in_src->user); instance_config_move_strdup(&in->group, in_src->group); + instance_config_move_strdup(&in->workdir, in_src->workdir); instance_config_move_strdup(&in->jail.name, in_src->jail.name); instance_config_move_strdup(&in->jail.hostname, in_src->jail.hostname); instance_config_move_strdup(&in->jail.pidfile, in_src->jail.pidfile); @@ -2041,6 +2067,7 @@ instance_free(struct service_instance *in) free(in->data_blob); free(in->user); free(in->group); + free(in->workdir); free(in->extroot); free(in->overlaydir); free(in->tmpoverlaysize); @@ -2126,6 +2153,8 @@ void instance_dump(struct blob_buf *b, struct service_instance *in, int verbose) blobmsg_add_u64(b, "incarnation", in->incarnation); if (in->command) blobmsg_add_blob(b, in->command); + if (in->workdir) + blobmsg_add_string(b, "workdir", in->workdir); if (in->bundle) blobmsg_add_string(b, "bundle", in->bundle); blobmsg_add_u32(b, "term_timeout", in->term_timeout); diff --git a/service/instance.h b/service/instance.h index d5df8bd..8a25aaf 100644 --- a/service/instance.h +++ b/service/instance.h @@ -99,6 +99,7 @@ struct service_instance { char *seccomp_log; char *capabilities; char *pidfile; + char *workdir; char *extroot; char *overlaydir; char *tmpoverlaysize;