Consolidate validation of pasta namespace options

There are a number of different ways to specify namespaces for pasta to
use.  Some combinations are valid and some are not.  Currently validation
for these is spread across several places: conf_ns_pid() validates PID
options specifically.  Near its callsite in conf() several other checks
are made. Some additional checks are made in conf_ns_open() and finally
theres a check just before the call to pasta_start_ns().

This is quite hard to follow.  Make it easier by putting all the validation
logic together in a new conf_pasta_ns() function, which subsumes
conf_ns_pid().  This reveals that some of the checks were redundant with
each other, so remove those.

For good measure, rename conf_netns() to conf_netns_opt() to make it
clearer its handling just the --netns option specifically, not overall
configuration of the netns.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
This commit is contained in:
David Gibson 2022-09-12 22:24:04 +10:00 committed by Stefano Brivio
parent d72a1e7bb9
commit e8b19a4bd2

73
conf.c
View file

@ -491,13 +491,13 @@ out:
} }
/** /**
* conf_netns() - Parse --netns option * conf_netns_opt() - Parse --netns option
* @netns: buffer of size PATH_MAX, updated with netns path * @netns: buffer of size PATH_MAX, updated with netns path
* @arg: --netns argument * @arg: --netns argument
* *
* Return: 0 on success, negative error code otherwise * Return: 0 on success, negative error code otherwise
*/ */
static int conf_netns(char *netns, const char *arg) static int conf_netns_opt(char *netns, const char *arg)
{ {
int ret; int ret;
@ -518,40 +518,59 @@ static int conf_netns(char *netns, const char *arg)
} }
/** /**
* conf_ns_pid() - Parse non-option argument as a PID * conf_pasta_ns() - Validate all pasta namespace options
* @netns_only: Don't use userns, may be updated
* @userns: buffer of size PATH_MAX, initially contains --userns * @userns: buffer of size PATH_MAX, initially contains --userns
* argument (may be empty), updated with userns path * argument (may be empty), updated with userns path
* @netns: buffer of size PATH_MAX, initial contains --netns * @netns: buffer of size PATH_MAX, initial contains --netns
* argument (may be empty), updated with netns path * argument (may be empty), updated with netns path
* @arg: PID of network namespace * @optind: Index of first non-option argument
* @argc: Number of arguments
* @argv: Command line arguments
* *
* Return: 0 on success, negative error code otherwise * Return: 0 on success, negative error code otherwise
*/ */
static int conf_ns_pid(char *userns, char *netns, const char *arg) static int conf_pasta_ns(int *netns_only, char *userns, char *netns,
int optind, int argc, char *argv[])
{ {
char *endptr; if (*netns_only && *userns) {
long pidval; err("Both --userns and --netns-only given");
if (*netns) {
err("Both --netns and PID given");
return -EINVAL; return -EINVAL;
} }
pidval = strtol(arg, &endptr, 10); if (*netns && optind != argc) {
err("Both --netns and PID or command given");
return -EINVAL;
}
if (optind + 1 == argc) {
char *endptr;
long pidval;
pidval = strtol(argv[optind], &endptr, 10);
if (!*endptr) { if (!*endptr) {
/* Looks like a pid */ /* Looks like a pid */
if (pidval < 0 || pidval > INT_MAX) { if (pidval < 0 || pidval > INT_MAX) {
err("Invalid PID %s", arg); err("Invalid PID %s", argv[optind]);
return -EINVAL; return -EINVAL;
} }
snprintf(netns, PATH_MAX, "/proc/%ld/ns/net", pidval); snprintf(netns, PATH_MAX, "/proc/%ld/ns/net", pidval);
if (!*userns) if (!*userns)
snprintf(userns, PATH_MAX, "/proc/%ld/ns/user", pidval); snprintf(userns, PATH_MAX, "/proc/%ld/ns/user",
return 0; pidval);
}
} }
/* Not a PID, later code will treat as a command */ if (*userns && !*netns) {
err("--userns requires --netns or PID");
return -EINVAL;
}
/* Attaching to a netns/PID, with no userns given */
if (*netns && !*userns)
*netns_only = 1;
return 0; return 0;
} }
@ -585,11 +604,6 @@ static int conf_ns_open(struct ctx *c, const char *userns, const char *netns)
{ {
int ufd = -1, nfd = -1; int ufd = -1, nfd = -1;
if (c->netns_only && *userns) {
err("Both --userns and --netns-only given");
return -EINVAL;
}
nfd = open(netns, O_RDONLY | O_CLOEXEC); nfd = open(netns, O_RDONLY | O_CLOEXEC);
if (nfd < 0) { if (nfd < 0) {
err("Couldn't open network namespace %s", netns); err("Couldn't open network namespace %s", netns);
@ -607,7 +621,6 @@ static int conf_ns_open(struct ctx *c, const char *userns, const char *netns)
c->pasta_netns_fd = nfd; c->pasta_netns_fd = nfd;
c->pasta_userns_fd = ufd; c->pasta_userns_fd = ufd;
c->netns_only = !*userns;
NS_CALL(conf_ns_check, c); NS_CALL(conf_ns_check, c);
@ -1194,7 +1207,7 @@ void conf(struct ctx *c, int argc, char **argv)
usage(argv[0]); usage(argv[0]);
} }
ret = conf_netns(netns, optarg); ret = conf_netns_opt(netns, optarg);
if (ret < 0) if (ret < 0)
usage(argv[0]); usage(argv[0]);
break; break;
@ -1573,17 +1586,9 @@ void conf(struct ctx *c, int argc, char **argv)
drop_root(uid, gid); drop_root(uid, gid);
if (c->mode == MODE_PASTA) { if (c->mode == MODE_PASTA) {
if (*netns && optind != argc) { if (conf_pasta_ns(&c->netns_only, userns, netns,
err("Both --netns and PID or command given"); optind, argc, argv) < 0)
usage(argv[0]); usage(argv[0]);
} else if (optind + 1 == argc) {
ret = conf_ns_pid(userns, netns, argv[optind]);
if (ret < 0)
usage(argv[0]);
} else if (*userns && !*netns && optind == argc) {
err("--userns requires --netns or PID");
usage(argv[0]);
}
} else if (optind != argc) { } else if (optind != argc) {
usage(argv[0]); usage(argv[0]);
} }
@ -1597,10 +1602,6 @@ void conf(struct ctx *c, int argc, char **argv)
if (ret < 0) if (ret < 0)
usage(argv[0]); usage(argv[0]);
} else { } else {
if (*userns) {
err("Both --userns and command given");
usage(argv[0]);
}
pasta_start_ns(c, argc - optind, argv + optind); pasta_start_ns(c, argc - optind, argv + optind);
} }
} }