passt/passt.h
David Gibson eed17a47fe Handle userns isolation and dropping root at the same time
passt/pasta can interact with user namespaces in a number of ways:
   1) With --netns-only we'll remain in our original user namespace
   2) With --userns or a PID option to pasta we'll join either the given
      user namespace or that of the PID
   3) When pasta spawns a shell or command we'll start a new user namespace
      for the command and then join it
   4) With passt we'll create a new user namespace when we sandbox()
      ourself

However (3) and (4) turn out to have essentially the same effect.  In both
cases we create one new user namespace.  The spawned command starts there,
and passt/pasta itself will live there from sandbox() onwards.

Because of this, we can simplify user namespace handling by moving the
userns handling earlier, to the same point we drop root in the original
namespace.  Extend the drop_user() function to isolate_user() which does
both.

After switching UID and GID in the original userns, isolate_user() will
either join or create the userns we require.  When we spawn a command with
pasta_start_ns()/pasta_setup_ns() we no longer need to create a userns,
because we're already made one.  sandbox() likewise no longer needs to
create (or join) an userns because we're already in the one we need.

We no longer need c->pasta_userns_fd, since the fd is only used locally
in isolate_user().  Likewise we can replace c->netns_only with a local
in conf(), since it's not used outside there.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
2022-09-13 05:31:51 +02:00

249 lines
6.9 KiB
C

/* SPDX-License-Identifier: AGPL-3.0-or-later
* Copyright (c) 2021 Red Hat GmbH
* Author: Stefano Brivio <sbrivio@redhat.com>
*/
#ifndef PASST_H
#define PASST_H
#define UNIX_SOCK_MAX 100
#define UNIX_SOCK_PATH "/tmp/passt_%i.socket"
/**
* struct tap_msg - Generic message descriptor for arrays of messages
* @pkt_buf_offset: Offset from @pkt_buf
* @len: Message length, with L2 headers
*/
struct tap_msg {
uint32_t pkt_buf_offset;
uint16_t len;
};
/**
* struct tap_l4_msg - Layer-4 message descriptor for protocol handlers
* @pkt_buf_offset: Offset of message from @pkt_buf
* @l4_len: Length of Layer-4 payload, host order
*/
struct tap_l4_msg {
uint32_t pkt_buf_offset;
uint16_t l4_len;
};
union epoll_ref;
#include "packet.h"
#include "icmp.h"
#include "tcp.h"
#include "udp.h"
/**
* union epoll_ref - Breakdown of reference for epoll socket bookkeeping
* @proto: IP protocol number
* @s: Socket number (implies 2^24 limit on number of descriptors)
* @tcp: TCP-specific reference part
* @udp: UDP-specific reference part
* @icmp: ICMP-specific reference part
* @data: Data handled by protocol handlers
* @u64: Opaque reference for epoll_ctl() and epoll_wait()
*/
union epoll_ref {
struct {
int32_t proto:8,
#define SOCKET_REF_BITS 24
#define SOCKET_MAX (1 << SOCKET_REF_BITS)
s:SOCKET_REF_BITS;
union {
union tcp_epoll_ref tcp;
union udp_epoll_ref udp;
union icmp_epoll_ref icmp;
uint32_t data;
} p;
} r;
uint64_t u64;
};
#define TAP_BUF_BYTES \
ROUND_DOWN(((ETH_MAX_MTU + sizeof(uint32_t)) * 128), PAGE_SIZE)
#define TAP_BUF_FILL (TAP_BUF_BYTES - ETH_MAX_MTU - sizeof(uint32_t))
#define TAP_MSGS \
DIV_ROUND_UP(TAP_BUF_BYTES, ETH_ZLEN - 2 * ETH_ALEN + sizeof(uint32_t))
#define PKT_BUF_BYTES MAX(TAP_BUF_BYTES, 0)
extern char pkt_buf [PKT_BUF_BYTES];
extern char *ip_proto_str[];
#define IP_PROTO_STR(n) \
(((uint8_t)(n) <= IPPROTO_SCTP && ip_proto_str[(n)]) ? \
ip_proto_str[(n)] : "?")
#include <resolv.h> /* For MAXNS below */
/**
* struct fqdn - Representation of fully-qualified domain name
* @n: Domain name string
*/
struct fqdn {
char n[NS_MAXDNAME];
};
#include <net/if.h>
#include <linux/un.h>
enum passt_modes {
MODE_PASST,
MODE_PASTA,
};
/**
* struct ip4_ctx - IPv4 execution context
* @addr: IPv4 address for external, routable interface
* @addr_seen: Latest IPv4 address seen as source from tap
* @mask: IPv4 netmask, network order
* @gw: Default IPv4 gateway, network order
* @dns: IPv4 DNS addresses, zero-terminated, network order
* @dns_fwd: Address forwarded (UDP) to first IPv4 DNS, network order
*/
struct ip4_ctx {
uint32_t addr;
uint32_t addr_seen;
uint32_t mask;
uint32_t gw;
uint32_t dns[MAXNS + 1];
uint32_t dns_fwd;
};
/**
* struct ip6_ctx - IPv6 execution context
* @addr: IPv6 address for external, routable interface
* @addr_ll: Link-local IPv6 address on external, routable interface
* @addr_seen: Latest IPv6 global/site address seen as source from tap
* @addr_ll_seen: Latest IPv6 link-local address seen as source from tap
* @gw: Default IPv6 gateway
* @dns: IPv6 DNS addresses, zero-terminated
* @dns_fwd: Address forwarded (UDP) to first IPv6 DNS, network order
*/
struct ip6_ctx {
struct in6_addr addr;
struct in6_addr addr_ll;
struct in6_addr addr_seen;
struct in6_addr addr_ll_seen;
struct in6_addr gw;
struct in6_addr dns[MAXNS + 1];
struct in6_addr dns_fwd;
};
/**
* struct ctx - Execution context
* @mode: Operation mode, qemu/UNIX domain socket or namespace/tap
* @debug: Enable debug mode
* @trace: Enable tracing (extra debug) mode
* @quiet: Don't print informational messages
* @foreground: Run in foreground, don't log to stderr by default
* @stderr: Force logging to stderr
* @nofile: Maximum number of open files (ulimit -n)
* @sock_path: Path for UNIX domain socket
* @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
* @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
* @proc_net_tcp: Stored handles for /proc/net/tcp{,6} in init and ns
* @proc_net_udp: Stored handles for /proc/net/udp{,6} in init and ns
* @epollfd: File descriptor for epoll instance
* @fd_tap_listen: File descriptor for listening AF_UNIX socket, if any
* @fd_tap: File descriptor for AF_UNIX socket or tuntap device
* @mac: Host MAC address
* @mac_guest: MAC address of guest or namespace, seen or configured
* @ifi4: Index of routable interface for IPv4, 0 if IPv4 disabled
* @ip: IPv4 configuration
* @dns_search: DNS search list
* @ifi6: Index of routable interface for IPv6, 0 if IPv6 disabled
* @ip6: IPv6 configuration
* @pasta_ifn: Name of namespace interface for pasta
* @pasta_ifn: Index of namespace interface for pasta
* @pasta_conf_ns: Configure namespace interface after creating it
* @no_tcp: Disable TCP operation
* @tcp: Context for TCP protocol handler
* @no_tcp: Disable UDP operation
* @udp: Context for UDP protocol handler
* @no_icmp: Disable ICMP operation
* @icmp: Context for ICMP protocol handler
* @mtu: MTU passed via DHCP/NDP
* @no_dns: Do not source/use DNS servers for any purpose
* @no_dns_search: Do not source/use domain search lists for any purpose
* @no_dhcp_dns: Do not assign any DNS server via DHCP/DHCPv6/NDP
* @no_dhcp_dns_search: Do not assign any DNS domain search via DHCP/DHCPv6/NDP
* @no_dhcp: Disable DHCP server
* @no_dhcpv6: Disable DHCPv6 server
* @no_ndp: Disable NDP handler altogether
* @no_ra: Disable router advertisements
* @no_map_gw: Don't map connections, untracked UDP to gateway to host
* @low_wmem: Low probed net.core.wmem_max
* @low_rmem: Low probed net.core.rmem_max
*/
struct ctx {
enum passt_modes mode;
int debug;
int trace;
int quiet;
int foreground;
int stderr;
int nofile;
char sock_path[UNIX_PATH_MAX];
char pcap[PATH_MAX];
char pid_file[PATH_MAX];
int pasta_netns_fd;
int no_netns_quit;
char netns_base[PATH_MAX];
char netns_dir[PATH_MAX];
int proc_net_tcp[IP_VERSIONS][2];
int proc_net_udp[IP_VERSIONS][2];
int epollfd;
int fd_tap_listen;
int fd_tap;
unsigned char mac[ETH_ALEN];
unsigned char mac_guest[ETH_ALEN];
unsigned int ifi4;
struct ip4_ctx ip4;
struct fqdn dns_search[MAXDNSRCH];
unsigned int ifi6;
struct ip6_ctx ip6;
char pasta_ifn[IF_NAMESIZE];
unsigned int pasta_ifi;
int pasta_conf_ns;
int no_tcp;
struct tcp_ctx tcp;
int no_udp;
struct udp_ctx udp;
int no_icmp;
struct icmp_ctx icmp;
int mtu;
int no_dns;
int no_dns_search;
int no_dhcp_dns;
int no_dhcp_dns_search;
int no_dhcp;
int no_dhcpv6;
int no_ndp;
int no_ra;
int no_map_gw;
int low_wmem;
int low_rmem;
};
void proto_update_l2_buf(const unsigned char *eth_d, const unsigned char *eth_s,
const uint32_t *ip_da);
#endif /* PASST_H */