> From: Theo de Raadt <[email protected]>
> Date: Sun, 22 Jan 2017 20:52:14 -0700
>
> Early during pledge development the "ioctl" promise was a kitchen
> sink of options until we could differentiate use cases, identify
> common patterns, and then create domain-specific promises.
>
> only 4 cases remain of "ioctl" remain:
>
> - pax/tar/cpio experience great difficulty finding tape drives quite
> late, so they need a few MTIO ioctls. this is not easily fixable
> in the program, let's create a "tape" promise.
> - tcpdump and pflogd need a single bpf ioctl to collect status information
> at termination
> - httpd wants SIOCGIFGROUP during the config file parser, but kernel code
> indicates this is a pretty safe piece of code, so let's serve it with
> the "inet" promise.
>
> So let's just split these cases out. "ioctl"'s number gets reused for
> tape, and a new "bpf" promise is added.. That paves the way for a
> more complex diff coming in a few hours.
ok kettenis@
> Index: sys/sys/pledge.h
> ===================================================================
> RCS file: /cvs/src/sys/sys/pledge.h,v
> retrieving revision 1.29
> diff -u -p -u -r1.29 pledge.h
> --- sys/sys/pledge.h 3 Jul 2016 04:36:08 -0000 1.29
> +++ sys/sys/pledge.h 23 Jan 2017 03:22:23 -0000
> @@ -36,7 +36,7 @@
> #define PLEDGE_FLOCK 0x0000000000000080ULL /* file locking */
> #define PLEDGE_UNIX 0x0000000000000100ULL /* AF_UNIX sockets */
> #define PLEDGE_ID 0x0000000000000200ULL /* allow setuid, setgid, etc */
> -#define PLEDGE_IOCTL 0x0000000000000400ULL /* Select ioctl */
> +#define PLEDGE_TAPE 0x0000000000000400ULL /* Tape ioctl */
> #define PLEDGE_GETPW 0x0000000000000800ULL /* YP enables if ypbind.lock */
> #define PLEDGE_PROC 0x0000000000001000ULL /* fork, waitpid, etc */
> #define PLEDGE_SETTIME 0x0000000000002000ULL /* able to set/adj
> time/freq */
> @@ -58,6 +58,7 @@
> #define PLEDGE_VMM 0x0000000040000000ULL /* vmm ioctls */
> #define PLEDGE_CHOWN 0x0000000080000000ULL /* chown(2) family */
> #define PLEDGE_CHOWNUID 0x0000000100000000ULL /* allow owner/group
> changes */
> +#define PLEDGE_BPF 0x0000000200000000ULL /* bpf ioctl */
>
> /*
> * Bits outside PLEDGE_USERSET are used by the kernel itself
> @@ -82,7 +83,7 @@ static struct {
> { PLEDGE_FLOCK, "flock" },
> { PLEDGE_UNIX, "unix" },
> { PLEDGE_ID, "id" },
> - { PLEDGE_IOCTL, "ioctl" },
> + { PLEDGE_TAPE, "tape" },
> { PLEDGE_GETPW, "getpw" },
> { PLEDGE_PROC, "proc" },
> { PLEDGE_SETTIME, "settime" },
> @@ -103,6 +104,7 @@ static struct {
> { PLEDGE_DRM, "drm" },
> { PLEDGE_VMM, "vmm" },
> { PLEDGE_CHOWNUID, "chown" },
> + { PLEDGE_BPF, "bpf" },
> { 0, NULL },
> };
> #endif
> Index: sys/kern/kern_pledge.c
> ===================================================================
> RCS file: /cvs/src/sys/kern/kern_pledge.c,v
> retrieving revision 1.190
> diff -u -p -u -r1.190 kern_pledge.c
> --- sys/kern/kern_pledge.c 23 Jan 2017 03:17:55 -0000 1.190
> +++ sys/kern/kern_pledge.c 23 Jan 2017 03:28:08 -0000
> @@ -235,8 +235,7 @@ const uint64_t pledge_syscalls[SYS_MAXSY
>
> /*
> * FIONREAD/FIONBIO for "stdio"
> - * A few non-tty ioctl available using "ioctl"
> - * tty-centric ioctl available using "tty"
> + * Other ioctl are selectively allowed based upon other pledges.
> */
> [SYS_ioctl] = PLEDGE_STDIO,
>
> @@ -360,6 +359,7 @@ static const struct {
> uint64_t flags;
> } pledgereq[] = {
> { "audio", PLEDGE_AUDIO },
> + { "bpf", PLEDGE_BPF },
> { "chown", PLEDGE_CHOWN | PLEDGE_CHOWNUID },
> { "cpath", PLEDGE_CPATH },
> { "disklabel", PLEDGE_DISKLABEL },
> @@ -372,7 +372,6 @@ static const struct {
> { "getpw", PLEDGE_GETPW },
> { "id", PLEDGE_ID },
> { "inet", PLEDGE_INET },
> - { "ioctl", PLEDGE_IOCTL },
> { "mcast", PLEDGE_MCAST },
> { "pf", PLEDGE_PF },
> { "proc", PLEDGE_PROC },
> @@ -384,6 +383,7 @@ static const struct {
> { "sendfd", PLEDGE_SENDFD },
> { "settime", PLEDGE_SETTIME },
> { "stdio", PLEDGE_STDIO },
> + { "tape", PLEDGE_TAPE },
> { "tmppath", PLEDGE_TMPPATH },
> { "tty", PLEDGE_TTY },
> { "unix", PLEDGE_UNIX },
> @@ -1127,23 +1127,27 @@ pledge_ioctl(struct proc *p, long com, s
> return (ENOTTY);
> }
>
> - /*
> - * Further sets of ioctl become available, but are checked a
> - * bit more carefully against the vnode.
> - */
> - if ((p->p_p->ps_pledge & PLEDGE_IOCTL)) {
> + if ((p->p_p->ps_pledge & PLEDGE_INET)) {
> switch (com) {
> - case TIOCGETA:
> - case TIOCGPGRP:
> - case TIOCGWINSZ: /* ENOTTY return for non-tty */
> - if (fp->f_type == DTYPE_VNODE && (vp->v_flag & VISTTY))
> + case SIOCGIFGROUP:
> + if (fp->f_type == DTYPE_SOCKET)
> return (0);
> - return (ENOTTY);
> + break;
> + }
> + }
> +
> + if ((p->p_p->ps_pledge & PLEDGE_BPF)) {
> + switch (com) {
> case BIOCGSTATS: /* bpf: tcpdump privsep on ^C */
> if (fp->f_type == DTYPE_VNODE &&
> fp->f_ops->fo_ioctl == vn_ioctl)
> return (0);
> break;
> + }
> + }
> +
> + if ((p->p_p->ps_pledge & PLEDGE_TAPE)) {
> + switch (com) {
> case MTIOCGET:
> case MTIOCTOP:
> /* for pax(1) and such, checking tapes... */
> @@ -1151,11 +1155,6 @@ pledge_ioctl(struct proc *p, long com, s
> (vp->v_type == VCHR || vp->v_type == VBLK))
> return (0);
> break;
> - case SIOCGIFGROUP:
> - if ((p->p_p->ps_pledge & PLEDGE_INET) &&
> - fp->f_type == DTYPE_SOCKET)
> - return (0);
> - break;
> }
> }
>
> @@ -1314,7 +1313,7 @@ pledge_ioctl(struct proc *p, long com, s
> #endif
> }
>
> - return pledge_fail(p, error, PLEDGE_IOCTL);
> + return pledge_fail(p, error, PLEDGE_TTY);
> }
>
> int
> Index: bin/pax/ar_io.c
> ===================================================================
> RCS file: /cvs/src/bin/pax/ar_io.c,v
> retrieving revision 1.59
> diff -u -p -u -r1.59 ar_io.c
> --- bin/pax/ar_io.c 26 Aug 2016 04:31:35 -0000 1.59
> +++ bin/pax/ar_io.c 23 Jan 2017 03:39:43 -0000
> @@ -1261,7 +1261,7 @@ ar_start_gzip(int fd, const char *path,
> close(fds[1]);
>
> if (pmode == 0 || (act != EXTRACT && act != COPY)) {
> - if (pledge("stdio rpath wpath cpath fattr dpath getpw ioctl
> proc",
> + if (pledge("stdio rpath wpath cpath fattr dpath getpw proc
> tape",
> NULL) == -1)
> err(1, "pledge");
> }
> Index: bin/pax/pax.c
> ===================================================================
> RCS file: /cvs/src/bin/pax/pax.c,v
> retrieving revision 1.47
> diff -u -p -u -r1.47 pax.c
> --- bin/pax/pax.c 26 Aug 2016 04:11:16 -0000 1.47
> +++ bin/pax/pax.c 23 Jan 2017 03:26:23 -0000
> @@ -261,13 +261,13 @@ main(int argc, char **argv)
> * so can't pledge at all then.
> */
> if (pmode == 0 || (act != EXTRACT && act != COPY)) {
> - if (pledge("stdio rpath wpath cpath fattr dpath getpw ioctl
> proc exec",
> + if (pledge("stdio rpath wpath cpath fattr dpath getpw proc exec
> tape",
> NULL) == -1)
> err(1, "pledge");
>
> /* Copy mode, or no gzip -- don't need to fork/exec. */
> if (gzip_program == NULL || act == COPY) {
> - if (pledge("stdio rpath wpath cpath fattr dpath getpw
> ioctl",
> + if (pledge("stdio rpath wpath cpath fattr dpath getpw
> tape",
> NULL) == -1)
> err(1, "pledge");
> }
> Index: usr.sbin/tcpdump/privsep.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/tcpdump/privsep.c,v
> retrieving revision 1.43
> diff -u -p -u -r1.43 privsep.c
> --- usr.sbin/tcpdump/privsep.c 25 Jul 2016 02:35:26 -0000 1.43
> +++ usr.sbin/tcpdump/privsep.c 23 Jan 2017 03:26:54 -0000
> @@ -272,7 +272,7 @@ priv_init(int argc, char **argv)
> test_state(cmd, STATE_RUN);
> impl_init_done(socks[0], &bpfd);
>
> - if (pledge("stdio rpath inet unix ioctl dns recvfd",
> NULL) == -1)
> + if (pledge("stdio rpath inet unix dns recvfd bpf",
> NULL) == -1)
> err(1, "pledge");
>
> break;
> Index: sbin/pflogd/privsep.c
> ===================================================================
> RCS file: /cvs/src/sbin/pflogd/privsep.c,v
> retrieving revision 1.22
> diff -u -p -u -r1.22 privsep.c
> --- sbin/pflogd/privsep.c 16 Jan 2016 03:17:48 -0000 1.22
> +++ sbin/pflogd/privsep.c 23 Jan 2017 03:27:22 -0000
> @@ -120,8 +120,7 @@ priv_init(void)
>
>
> #if notyet
> - /* This needs to do bpf ioctl */
> - if (pledge("stdio rpath wpath cpath ioctl sendfd", NULL) == -1)
> + if (pledge("stdio rpath wpath cpath sendfd bpf", NULL) == -1)
> err(1, "pledge");
> #endif
> while (!gotsig_chld) {
> Index: usr.sbin/httpd/httpd.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/httpd/httpd.c,v
> retrieving revision 1.63
> diff -u -p -u -r1.63 httpd.c
> --- usr.sbin/httpd/httpd.c 9 Jan 2017 14:49:22 -0000 1.63
> +++ usr.sbin/httpd/httpd.c 23 Jan 2017 03:27:57 -0000
> @@ -222,8 +222,7 @@ main(int argc, char *argv[])
> if (ps->ps_noaction == 0)
> log_info("startup");
>
> - if (pledge("stdio rpath wpath cpath inet dns ioctl sendfd",
> - NULL) == -1)
> + if (pledge("stdio rpath wpath cpath inet dns sendfd", NULL) == -1)
> fatal("pledge");
>
> event_init();
> Index: lib/libc/sys/pledge.2
> ===================================================================
> RCS file: /cvs/src/lib/libc/sys/pledge.2,v
> retrieving revision 1.37
> diff -u -p -u -r1.37 pledge.2
> --- lib/libc/sys/pledge.2 27 Oct 2016 10:48:25 -0000 1.37
> +++ lib/libc/sys/pledge.2 23 Jan 2017 03:50:13 -0000
> @@ -76,11 +76,25 @@ Read-only, for
> .Pp
> .It Xr ioctl 2
> Only the
> -.Dv FIONREAD
> +.Dv FIONREAD ,
> +.Dv FIONBIO ,
> +.Dv FIOCLEX ,
> and
> -.Dv FIONBIO
> +.Dv FIONCLEX
> operations are allowed by default.
> -Use of the "tty" and "ioctl" promises receive more ioctl requests.
> +Various ioctl requests are allowed against specific file descriptors
> +based upon the requests
> +.Va "audio" ,
> +.Va "bpf" ,
> +.Va "disklabel" ,
> +.Va "drm" ,
> +.Va "inet" ,
> +.Va "pf" ,
> +.Va "route" ,
> +.Va "tape" ,
> +.Va "tty" ,
> +and
> +.Va "vmm".
> .Pp
> .It Xr chmod 2
> .It Xr fchmod 2
> @@ -386,26 +400,12 @@ File descriptors referring to directorie
> Allows receiving of file descriptors using
> .Xr recvmsg 2 .
> File descriptors referring to directories may not be passed.
> -.It Va "ioctl"
> -Allows a subset of
> -.Xr ioctl 2
> -operations:
> -.Pp
> -.Dv FIOCLEX ,
> -.Dv FIONCLEX ,
> -.Dv FIOASYNC ,
> -.Dv FIOGETOWN ,
> -and
> -.Dv FIOSETOWN .
> -On a tty device
> -.Dv TIOCGETA will succeed otherwise fail with
> -.Er EPERM .
> -On a tty device,
> -.Dv TIOCGPGRP
> +.It Va "tape"
> +Allow
> +.Dv MTIOCGET
> and
> -.Dv TIOCGWINSZ
> -are allowed.
> -A few other operations are allowed, but not listed here.
> +.Dv MTIOCTOP
> +operations against tape drives.
> .It Va "tty"
> In addition to allowing read-write operations on
> .Pa /dev/tty ,
> @@ -528,6 +528,10 @@ devices:
> .Dv AUDIO_SETPAR ,
> .Dv AUDIO_START ,
> .Dv AUDIO_STOP .
> +.It Va "bpf"
> +Allow
> +.Dv BIOCGSTATS
> +operation for statistics collection from a bpf device.
> .Pp
> See
> .Xr sio_open 3
>
>