I believe it would be better to add setrtable to id pledge.
On 2022-01-29, Matthew Martin wrote:
> 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) {
>
>