aboutgitcodebugslistschat
diff options
context:
space:
mode:
-rw-r--r--conf.c11
-rw-r--r--isolation.c77
-rw-r--r--isolation.h2
-rw-r--r--passt.c3
-rw-r--r--passt.h4
-rw-r--r--pasta.c56
-rw-r--r--pasta.h2
-rw-r--r--util.c5
8 files changed, 77 insertions, 83 deletions
diff --git a/conf.c b/conf.c
index 8477a6e..7f32859 100644
--- a/conf.c
+++ b/conf.c
@@ -1043,6 +1043,7 @@ static int conf_ugid(const char *runas, uid_t *uid, gid_t *gid)
*/
void conf(struct ctx *c, int argc, char **argv)
{
+ int netns_only = 0;
struct option options[] = {
{"debug", no_argument, NULL, 'd' },
{"quiet", no_argument, NULL, 'q' },
@@ -1077,7 +1078,7 @@ void conf(struct ctx *c, int argc, char **argv)
{"udp-ns", required_argument, NULL, 'U' },
{"userns", required_argument, NULL, 2 },
{"netns", required_argument, NULL, 3 },
- {"netns-only", no_argument, &c->netns_only, 1 },
+ {"netns-only", no_argument, &netns_only, 1 },
{"config-net", no_argument, &c->pasta_conf_ns, 1 },
{"ns-mac-addr", required_argument, NULL, 4 },
{"dhcp-dns", no_argument, NULL, 5 },
@@ -1515,22 +1516,22 @@ void conf(struct ctx *c, int argc, char **argv)
if (ret)
usage(argv[0]);
- drop_root(uid, gid);
-
if (c->mode == MODE_PASTA) {
- if (conf_pasta_ns(&c->netns_only, userns, netns,
+ if (conf_pasta_ns(&netns_only, userns, netns,
optind, argc, argv) < 0)
usage(argv[0]);
} else if (optind != argc) {
usage(argv[0]);
}
+ isolate_user(uid, gid, !netns_only, userns);
+
if (c->pasta_conf_ns)
c->no_ra = 1;
if (c->mode == MODE_PASTA) {
if (*netns) {
- pasta_open_ns(c, userns, netns);
+ pasta_open_ns(c, netns);
} else {
pasta_start_ns(c, argc - optind, argv + optind);
}
diff --git a/isolation.c b/isolation.c
index 41ca888..124dea4 100644
--- a/isolation.c
+++ b/isolation.c
@@ -20,6 +20,7 @@
#include <limits.h>
#include <pwd.h>
#include <sched.h>
+#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
@@ -59,14 +60,19 @@ void drop_caps(void)
}
/**
- * drop_root() - Switch to given UID and GID
- * @uid: User ID to switch to
- * @gid: Group ID to switch to
+ * isolate_user() - Switch to final UID/GID and move into userns
+ * @uid: User ID to run as (in original userns)
+ * @gid: Group ID to run as (in original userns)
+ * @use_userns: Whether to join or create a userns
+ * @userns: userns path to enter, may be empty
*/
-void drop_root(uid_t uid, gid_t gid)
+void isolate_user(uid_t uid, gid_t gid, bool use_userns, const char *userns)
{
+ char nsmap[BUFSIZ];
+
+ /* First set our UID & GID in the original namespace */
if (setgroups(0, NULL)) {
- /* If we don't start with CAP_SETGID, this will EPERM */
+ /* If we don't have CAP_SETGID, this will EPERM */
if (errno != EPERM) {
err("Can't drop supplementary groups: %s",
strerror(errno));
@@ -74,11 +80,57 @@ void drop_root(uid_t uid, gid_t gid)
}
}
- if (!setgid(gid) && !setuid(uid))
+ if (setgid(gid) != 0) {
+ err("Can't set GID to %u: %s", gid, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ if (setuid(uid) != 0) {
+ err("Can't set UID to %u: %s", uid, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ /* If we're told not to use a userns, nothing more to do */
+ if (!use_userns)
+ return;
+
+ /* Otherwise, if given a userns, join it */
+ if (*userns) {
+ int ufd;
+
+ ufd = open(userns, O_RDONLY | O_CLOEXEC);
+ if (ufd < 0) {
+ err("Couldn't open user namespace %s: %s",
+ userns, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ if (setns(ufd, CLONE_NEWUSER) != 0) {
+ err("Couldn't enter user namespace %s: %s",
+ userns, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ close(ufd);
+
return;
+ }
- err("Can't change user/group, exiting");
- exit(EXIT_FAILURE);
+ /* Otherwise, create our own userns */
+ if (unshare(CLONE_NEWUSER) != 0) {
+ err("Couldn't create user namespace: %s", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ /* Configure user and group mappings */
+ snprintf(nsmap, BUFSIZ, "0 %u 1", uid);
+ FWRITE("/proc/self/uid_map", nsmap, "Cannot set uid_map in namespace");
+
+ FWRITE("/proc/self/setgroups", "deny",
+ "Cannot write to setgroups in namespace");
+
+ snprintf(nsmap, BUFSIZ, "0 %u 1", gid);
+ FWRITE("/proc/self/gid_map", nsmap, "Cannot set gid_map in namespace");
}
/**
@@ -90,15 +142,6 @@ int sandbox(struct ctx *c)
{
int flags = CLONE_NEWIPC | CLONE_NEWNS | CLONE_NEWUTS;
- if (!c->netns_only) {
- if (c->pasta_userns_fd == -1)
- flags |= CLONE_NEWUSER;
- else
- setns(c->pasta_userns_fd, CLONE_NEWUSER);
- }
-
- c->pasta_userns_fd = -1;
-
/* If we run in foreground, we have no chance to actually move to a new
* PID namespace. For passt, use CLONE_NEWPID anyway, in case somebody
* ever gets around seccomp profiles -- there's no harm in passing it.
diff --git a/isolation.h b/isolation.h
index 2540a35..2c73df7 100644
--- a/isolation.h
+++ b/isolation.h
@@ -8,7 +8,7 @@
#define ISOLATION_H
void drop_caps(void);
-void drop_root(uid_t uid, gid_t gid);
+void isolate_user(uid_t uid, gid_t gid, bool use_userns, const char *userns);
int sandbox(struct ctx *c);
void seccomp(const struct ctx *c);
diff --git a/passt.c b/passt.c
index 2a8314c..f0ed897 100644
--- a/passt.c
+++ b/passt.c
@@ -23,6 +23,7 @@
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/resource.h>
+#include <stdbool.h>
#include <stdlib.h>
#include <unistd.h>
#include <netdb.h>
@@ -185,7 +186,7 @@ int main(int argc, char **argv)
drop_caps();
- c.pasta_userns_fd = c.pasta_netns_fd = c.fd_tap = c.fd_tap_listen = -1;
+ c.pasta_netns_fd = c.fd_tap = c.fd_tap_listen = -1;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
diff --git a/passt.h b/passt.h
index 3035430..8c8d710 100644
--- a/passt.h
+++ b/passt.h
@@ -145,8 +145,6 @@ struct ip6_ctx {
* @pcap: Path for packet capture file
* @pid_file: Path to PID file, empty string if not configured
* @pasta_netns_fd: File descriptor for network namespace in pasta mode
- * @pasta_userns_fd: Descriptor for user namespace to join, -1 once joined
- * @netns_only: In pasta mode, don't join or create a user namespace
* @no_netns_quit: In pasta mode, don't exit if fs-bound namespace is gone
* @netns_base: Base name for fs-bound namespace, if any, in pasta mode
* @netns_dir: Directory of fs-bound namespace, if any, in pasta mode
@@ -197,8 +195,6 @@ struct ctx {
char pid_file[PATH_MAX];
int pasta_netns_fd;
- int pasta_userns_fd;
- int netns_only;
int no_netns_quit;
char netns_base[PATH_MAX];
diff --git a/pasta.c b/pasta.c
index 7eac8e9..e233762 100644
--- a/pasta.c
+++ b/pasta.c
@@ -23,6 +23,7 @@
#include <libgen.h>
#include <limits.h>
#include <stdlib.h>
+#include <stdbool.h>
#include <stdint.h>
#include <unistd.h>
#include <syslog.h>
@@ -83,16 +84,6 @@ static int pasta_wait_for_ns(void *arg)
int flags = O_RDONLY | O_CLOEXEC;
char ns[PATH_MAX];
- if (c->netns_only)
- goto netns;
-
- snprintf(ns, PATH_MAX, "/proc/%i/ns/user", pasta_child_pid);
- do
- while ((c->pasta_userns_fd = open(ns, flags)) < 0);
- while (setns(c->pasta_userns_fd, CLONE_NEWUSER) &&
- !close(c->pasta_userns_fd));
-
-netns:
snprintf(ns, PATH_MAX, "/proc/%i/ns/net", pasta_child_pid);
do
while ((c->pasta_netns_fd = open(ns, flags)) < 0);
@@ -112,25 +103,23 @@ static int ns_check(void *arg)
{
struct ctx *c = (struct ctx *)arg;
- if ((!c->netns_only && setns(c->pasta_userns_fd, CLONE_NEWUSER)) ||
- setns(c->pasta_netns_fd, CLONE_NEWNET))
- c->pasta_userns_fd = c->pasta_netns_fd = -1;
+ if (setns(c->pasta_netns_fd, CLONE_NEWNET))
+ c->pasta_netns_fd = -1;
return 0;
}
/**
- * pasta_open_ns() - Open network, user namespaces descriptors
+ * pasta_open_ns() - Open network namespace descriptors
* @c: Execution context
- * @userns: --userns argument, can be an empty string
* @netns: network namespace path
*
* Return: 0 on success, negative error code otherwise
*/
-void pasta_open_ns(struct ctx *c, const char *userns, const char *netns)
+void pasta_open_ns(struct ctx *c, const char *netns)
{
- int ufd = -1, nfd = -1;
+ int nfd = -1;
nfd = open(netns, O_RDONLY | O_CLOEXEC);
if (nfd < 0) {
@@ -138,17 +127,7 @@ void pasta_open_ns(struct ctx *c, const char *userns, const char *netns)
exit(EXIT_FAILURE);
}
- if (!c->netns_only && *userns) {
- ufd = open(userns, O_RDONLY | O_CLOEXEC);
- if (ufd < 0) {
- close(nfd);
- err("Couldn't open user namespace %s", userns);
- exit(EXIT_FAILURE);
- }
- }
-
c->pasta_netns_fd = nfd;
- c->pasta_userns_fd = ufd;
NS_CALL(ns_check, c);
@@ -169,12 +148,9 @@ void pasta_open_ns(struct ctx *c, const char *userns, const char *netns)
/**
* struct pasta_setup_ns_arg - Argument for pasta_setup_ns()
- * @c: Execution context
- * @euid: Effective UID of caller
+ * @argv: Command and arguments to run
*/
struct pasta_setup_ns_arg {
- struct ctx *c;
- int euid;
char **argv;
};
@@ -188,21 +164,6 @@ static int pasta_setup_ns(void *arg)
{
struct pasta_setup_ns_arg *a = (struct pasta_setup_ns_arg *)arg;
- if (!a->c->netns_only) {
- char buf[BUFSIZ];
-
- snprintf(buf, BUFSIZ, "%i %i %i", 0, a->euid, 1);
-
- FWRITE("/proc/self/uid_map", buf,
- "Cannot set uid_map in namespace");
-
- FWRITE("/proc/self/setgroups", "deny",
- "Cannot write to setgroups in namespace");
-
- FWRITE("/proc/self/gid_map", buf,
- "Cannot set gid_map in namespace");
- }
-
FWRITE("/proc/sys/net/ipv4/ping_group_range", "0 0",
"Cannot set ping_group_range, ICMP requests might fail");
@@ -221,8 +182,6 @@ static int pasta_setup_ns(void *arg)
void pasta_start_ns(struct ctx *c, int argc, char *argv[])
{
struct pasta_setup_ns_arg arg = {
- .c = c,
- .euid = geteuid(),
.argv = argv,
};
char *shell = getenv("SHELL") ? getenv("SHELL") : "/bin/sh";
@@ -244,7 +203,6 @@ void pasta_start_ns(struct ctx *c, int argc, char *argv[])
pasta_child_pid = clone(pasta_setup_ns,
ns_fn_stack + sizeof(ns_fn_stack) / 2,
- (c->netns_only ? 0 : CLONE_NEWUSER) |
CLONE_NEWIPC | CLONE_NEWPID | CLONE_NEWNET |
CLONE_NEWUTS,
(void *)&arg);
diff --git a/pasta.h b/pasta.h
index a1937b2..02df1f6 100644
--- a/pasta.h
+++ b/pasta.h
@@ -6,7 +6,7 @@
#ifndef PASTA_H
#define PASTA_H
-void pasta_open_ns(struct ctx *c, const char *userns, const char *netns);
+void pasta_open_ns(struct ctx *c, const char *netns);
void pasta_start_ns(struct ctx *c, int argc, char *argv[]);
void pasta_ns_conf(struct ctx *c);
void pasta_child_handler(int signal);
diff --git a/util.c b/util.c
index f709838..8d26561 100644
--- a/util.c
+++ b/util.c
@@ -464,11 +464,6 @@ void procfs_scan_listen(struct ctx *c, uint8_t proto, int ip_version, int ns,
*/
int ns_enter(const struct ctx *c)
{
- if (!c->netns_only &&
- c->pasta_userns_fd != -1 &&
- setns(c->pasta_userns_fd, CLONE_NEWUSER))
- exit(EXIT_FAILURE);
-
if (setns(c->pasta_netns_fd, CLONE_NEWNET))
exit(EXIT_FAILURE);