It would be nice to have the ability to set a user's rtable upon login. This would be useful both for road warrior VPN setups (put both the VPN interface and user in an rdomain other than 0) and to differentiate users in firewall rules on the gateway or unbound views on a resolver. The below patch adds an rtable capability to login.conf which sets the user's default rtable on login.
Since setusercontext will now call setrtable, that syscall needs to be covered under some pledge promise. Since the wroute promise already allows programs to set a different rtable on a per socket basis, I don't think adding the setrtable syscall materially changes the scope or attack surface. This impacts dhcpleased, iked, rad, and slaacd which already use the wroute promise. The wroute promise is added to calendar, skeyaudit, su, cron, and inetd. chroot, login, ssh, nsd, and unbound are impacted, but don't show up in the diff because they don't use pledge. ssh continues to work as expected: the user's session has the login specified default rtable; however, the socket connecting the user to the session remains in the original rtable so the connection doesn't break. nsd and unbound open their listening sockets prior to privdrop, so those sockets are in the original rtable (which should be set via rcctl). Notifications and XFRs for nsd and lookups for unbound happen in the login specified rtable. While this is somewhat surprising, I think most people would set the rtable for a daemon via rcctl. doas is a bit of a special case: it explicitly lists the LOGIN_ flags rather than using LOGIN_SETALL and removing specific flags. I am inclined to say doas should also set the default rtable, but it's not a strong stance. I've left it out of this version of the patch pending feedback on how others feel. In addition xenodm would need to add wroute to the pledge in dm.c StartDisplay and to the first pledge in session.c StartClient. >From a Debian code search the ports which use LOGIN_SETALL appear to be mail/alpine, security/sudo, and x11/gnome/gdm. None of these ports have pledge markers in their Makefile. Finally it may be nicer to drop -a from calendar and skeyaudit. Each user that desires the service could then create their own cron job. While it would allow a fair bit of code to be deleted and a tighter pledge, it would break existing workflows and could be considered as in a separate thread if desired. - Matthew Martin diff --git include/login_cap.h include/login_cap.h index d9a4c2c349c..1e831b6471a 100644 --- include/login_cap.h +++ include/login_cap.h @@ -53,7 +53,8 @@ #define LOGIN_SETUMASK 0x0020 /* Set umask */ #define LOGIN_SETUSER 0x0040 /* Set user */ #define LOGIN_SETENV 0x0080 /* Set environment */ -#define LOGIN_SETALL 0x00ff /* Set all. */ +#define LOGIN_SETRTABLE 0x0100 /* Set rtable */ +#define LOGIN_SETALL 0x01ff /* Set all. */ #define BI_AUTH "authorize" /* Accepted authentication */ #define BI_REJECT "reject" /* Rejected authentication */ diff --git lib/libc/gen/login_cap.c lib/libc/gen/login_cap.c index 862f33b2065..65848f09ef6 100644 --- lib/libc/gen/login_cap.c +++ lib/libc/gen/login_cap.c @@ -52,6 +52,7 @@ #include <sys/stat.h> #include <sys/time.h> #include <sys/resource.h> +#include <sys/socket.h> #include <err.h> #include <errno.h> @@ -574,7 +575,7 @@ int setusercontext(login_cap_t *lc, struct passwd *pwd, uid_t uid, u_int flags) { login_cap_t *flc; - quad_t p; + quad_t p, rtable; int i; flc = NULL; @@ -625,6 +626,14 @@ setusercontext(login_cap_t *lc, struct passwd *pwd, uid_t uid, u_int flags) umask((mode_t)p); } + if (flags & LOGIN_SETRTABLE) { + rtable = login_getcapnum(lc, "rtable", 0, 0); + + if (setrtable((int)rtable) == -1) { + syslog(LOG_ERR, "%s: setrtable: %m", lc->lc_class); + } + } + if (flags & LOGIN_SETGROUP) { if (setresgid(pwd->pw_gid, pwd->pw_gid, pwd->pw_gid) == -1) { syslog(LOG_ERR, "setresgid(%u,%u,%u): %m", diff --git share/man/man5/login.conf.5 share/man/man5/login.conf.5 index da935fa223e..ffeafc3531c 100644 --- share/man/man5/login.conf.5 +++ share/man/man5/login.conf.5 @@ -276,6 +276,10 @@ Initial priority (nice) level. Require home directory to login. .\" .Pp +.It rtable Ta number Ta Dv 0 Ta +Rtable to be set for the class. +.\" +.Pp .It setenv Ta envlist Ta "" Ta A list of environment variables and associated values to be set for the class. .\" diff --git sys/kern/kern_pledge.c sys/kern/kern_pledge.c index 6687bf91f09..901d41cefb6 100644 --- sys/kern/kern_pledge.c +++ sys/kern/kern_pledge.c @@ -373,6 +373,8 @@ const uint64_t pledge_syscalls[SYS_MAXSYSCALL] = { [SYS_flock] = PLEDGE_FLOCK | PLEDGE_YPACTIVE, [SYS_swapctl] = PLEDGE_VMINFO, /* XXX should limit to "get" operations */ + + [SYS_setrtable] = PLEDGE_WROUTE, }; static const struct { diff --git usr.bin/calendar/calendar.c usr.bin/calendar/calendar.c index ad82a94707c..bda19f4c6a6 100644 --- usr.bin/calendar/calendar.c +++ usr.bin/calendar/calendar.c @@ -126,7 +126,7 @@ main(int argc, char *argv[]) usage(); if (doall) { - if (pledge("stdio rpath tmppath fattr getpw id proc exec", NULL) + if (pledge("stdio rpath tmppath fattr getpw id proc exec wroute", NULL) == -1) err(1, "pledge"); } else { diff --git usr.bin/skeyaudit/skeyaudit.c usr.bin/skeyaudit/skeyaudit.c index 3cad9b2eafa..1462d677650 100644 --- usr.bin/skeyaudit/skeyaudit.c +++ usr.bin/skeyaudit/skeyaudit.c @@ -71,7 +71,7 @@ main(int argc, char **argv) char *name; int ch, left, aflag, iflag, limit; - if (pledge("stdio rpath wpath flock getpw proc exec id", NULL) == -1) + if (pledge("stdio rpath wpath flock getpw proc exec id wroute", NULL) == -1) err(1, "pledge"); aflag = iflag = 0; diff --git usr.bin/su/su.c usr.bin/su/su.c index f9fb2c0ac88..1fc73fa36bd 100644 --- usr.bin/su/su.c +++ usr.bin/su/su.c @@ -73,7 +73,7 @@ main(int argc, char **argv) uid_t ruid; u_int flags; - if (pledge("stdio unveil rpath getpw proc exec id", NULL) == -1) + if (pledge("stdio unveil rpath getpw proc exec id wroute", NULL) == -1) err(1, "pledge"); while ((ch = getopt(argc, argv, "a:c:fKLlms:-")) != -1) @@ -232,7 +232,7 @@ main(int argc, char **argv) if (pwd == NULL) auth_errx(as, 1, "internal error"); - if (pledge("stdio unveil rpath getpw exec id", NULL) == -1) + if (pledge("stdio unveil rpath getpw exec id wroute", NULL) == -1) err(1, "pledge"); if (!altshell) { @@ -309,7 +309,7 @@ main(int argc, char **argv) if (setenv("SHELL", shell, 1) == -1) auth_err(as, 1, "unable to set environment"); } - if (pledge("stdio rpath getpw exec id", NULL) == -1) + if (pledge("stdio rpath getpw exec id wroute", NULL) == -1) err(1, "pledge"); np = *argv ? argv : argv - 1; diff --git usr.sbin/cron/cron.c usr.sbin/cron/cron.c index 831a70d5411..033864b1369 100644 --- usr.sbin/cron/cron.c +++ usr.sbin/cron/cron.c @@ -99,7 +99,7 @@ main(int argc, char *argv[]) openlog(__progname, LOG_PID, LOG_CRON); - if (pledge("stdio rpath wpath cpath fattr getpw unix id dns proc exec", + if (pledge("stdio rpath wpath cpath fattr getpw unix id dns proc exec wroute", NULL) == -1) { warn("pledge"); syslog(LOG_ERR, "(CRON) PLEDGE (%m)"); diff --git usr.sbin/inetd/inetd.c usr.sbin/inetd/inetd.c index 2c623ef66d1..6ad2aec838b 100644 --- usr.sbin/inetd/inetd.c +++ usr.sbin/inetd/inetd.c @@ -344,7 +344,7 @@ main(int argc, char *argv[]) (void) setlogin(""); } - if (pledge("stdio rpath cpath getpw dns inet unix proc exec id", NULL) == -1) + if (pledge("stdio rpath cpath getpw dns inet unix proc exec id wroute", NULL) == -1) err(1, "pledge"); if (uid == 0) {