diff options
author | Stefano Brivio <sbrivio@redhat.com> | 2022-10-13 18:21:27 +0200 |
---|---|---|
committer | Stefano Brivio <sbrivio@redhat.com> | 2022-10-15 02:10:36 +0200 |
commit | 3e2eb4337bc06e2331b200b5805ed09244f92bf7 (patch) | |
tree | f6fdf320de5853a28ec8b3fca3e1c4b9f3ed3533 /conf.c | |
parent | 40abd447c80a01fbbfa5de70ad3c33bdc1380c06 (diff) | |
download | passt-3e2eb4337bc06e2331b200b5805ed09244f92bf7.tar passt-3e2eb4337bc06e2331b200b5805ed09244f92bf7.tar.gz passt-3e2eb4337bc06e2331b200b5805ed09244f92bf7.tar.bz2 passt-3e2eb4337bc06e2331b200b5805ed09244f92bf7.tar.lz passt-3e2eb4337bc06e2331b200b5805ed09244f92bf7.tar.xz passt-3e2eb4337bc06e2331b200b5805ed09244f92bf7.tar.zst passt-3e2eb4337bc06e2331b200b5805ed09244f92bf7.zip |
conf: Bind inbound ports with CAP_NET_BIND_SERVICE before isolate_user()
Even if CAP_NET_BIND_SERVICE is granted, we'll lose the capability in
the target user namespace as we isolate the process, which means
we're unable to bind to low ports at that point.
Bind inbound ports, and only those, before isolate_user(). Keep the
handling of outbound ports (for pasta mode only) after the setup of
the namespace, because that's where we'll bind them.
To this end, initialise the netlink socket for the init namespace
before isolate_user() as well, as we actually need to know the
addresses of the upstream interface before binding ports, in case
they're not explicitly passed by the user.
As we now call nl_sock_init() twice, checking its return code from
conf() twice looks a bit heavy: make it exit(), instead, as we
can't do much if we don't have netlink sockets.
While at it:
- move the v4_only && v6_only options check just after the first
option processing loop, as this is more strictly related to
option parsing proper
- update the man page, explaining that CAP_NET_BIND_SERVICE is
*not* the preferred way to bind ports, because passt and pasta
can be abused to allow other processes to make effective usage
of it. Add a note about the recommended sysctl instead
- simplify nl_sock_init_do() now that it's called once for each
case
Reported-by: David Gibson <david@gibson.dropbear.id.au>
Signed-off-by: Stefano Brivio <sbrivio@redhat.com>
Diffstat (limited to 'conf.c')
-rw-r--r-- | conf.c | 71 |
1 files changed, 35 insertions, 36 deletions
@@ -1530,6 +1530,11 @@ void conf(struct ctx *c, int argc, char **argv) } } while (name != -1); + if (v4_only && v6_only) { + err("Options ipv4-only and ipv6-only are mutually exclusive"); + usage(argv[0]); + } + ret = conf_ugid(runas, &uid, &gid); if (ret) usage(argv[0]); @@ -1539,6 +1544,30 @@ void conf(struct ctx *c, int argc, char **argv) logfile, logsize); } + nl_sock_init(c, false); + if (!v6_only) + c->ifi4 = conf_ip4(ifi, &c->ip4, c->mac); + if (!v4_only) + c->ifi6 = conf_ip6(ifi, &c->ip6, c->mac); + if (!c->ifi4 && !c->ifi6) { + err("External interface not usable"); + exit(EXIT_FAILURE); + } + + /* Inbound port options can be parsed now (after IPv4/IPv6 settings) */ + optind = 1; + do { + struct port_fwd *fwd; + + name = getopt_long(argc, argv, optstring, options, NULL); + + if ((name == 't' && (fwd = &c->tcp.fwd_in)) || + (name == 'u' && (fwd = &c->udp.fwd_in.f))) { + if (!optarg || conf_ports(c, name, optarg, fwd)) + usage(argv[0]); + } + } while (name != -1); + if (c->mode == MODE_PASTA) { if (conf_pasta_ns(&netns_only, userns, netns, optind, argc, argv) < 0) @@ -1561,50 +1590,20 @@ void conf(struct ctx *c, int argc, char **argv) } } - if (nl_sock_init(c)) { - err("Failed to get netlink socket"); - exit(EXIT_FAILURE); - } - - if (v4_only && v6_only) { - err("Options ipv4-only and ipv6-only are mutually exclusive"); - usage(argv[0]); - } - if (!v6_only) - c->ifi4 = conf_ip4(ifi, &c->ip4, c->mac); - if (!v4_only) - c->ifi6 = conf_ip6(ifi, &c->ip6, c->mac); - if (!c->ifi4 && !c->ifi6) { - err("External interface not usable"); - exit(EXIT_FAILURE); - } + if (c->mode == MODE_PASTA) + nl_sock_init(c, true); - /* Now we can process port configuration options */ + /* ...and outbound port options now that namespaces are set up. */ optind = 1; do { - struct port_fwd *fwd = NULL; + struct port_fwd *fwd; name = getopt_long(argc, argv, optstring, options, NULL); - switch (name) { - case 't': - case 'u': - case 'T': - case 'U': - if (name == 't') - fwd = &c->tcp.fwd_in; - else if (name == 'T') - fwd = &c->tcp.fwd_out; - else if (name == 'u') - fwd = &c->udp.fwd_in.f; - else if (name == 'U') - fwd = &c->udp.fwd_out.f; + if ((name == 'T' && (fwd = &c->tcp.fwd_out)) || + (name == 'U' && (fwd = &c->udp.fwd_out.f))) { if (!optarg || conf_ports(c, name, optarg, fwd)) usage(argv[0]); - - break; - default: - break; } } while (name != -1); |