Hi,

two notes about vmd with this diff:

1. "vmm" pledge can be !fdpledged as well as it already pre-opens the
/dev/vmm fd for ioctls.  I added the following chunk on top of your
diff and it works as expected:

---snip---
        if ((p->p_p->ps_pledge & PLEDGE_VMM)) {
 #if NVMM > 0
-               if ((fp->f_type == DTYPE_VNODE) &&
+               if (!fdpledged &&
+                   (fp->f_type == DTYPE_VNODE) &&
                    (vp->v_type == VCHR) &&
                    (cdevsw[major(vp->v_rdev)].d_open == vmmopen)) {
                        error = pledge_ioctl_vmm(p, com);
                        if (error == 0)
                                return 0;
                }
-#endif
+#endif /* NVMM > 0 */
        }
---snap---

2. vmd calls openpty() in the pledged parent whenever a new VM is
started - effectively doing ioctls on post-pledge fds.  I will
probably solve this by opening the pty in the non-pledged "priv"
process, and do some additional passing, but then I'll also have to
give up its chroot to access /dev/.

vmd: ioctl 40287401 post-pledge fd 12
vmd(51681): syscall 54 "tty"

Reyk

On Tue, Jan 24, 2017 at 07:36:47PM -0700, Theo de Raadt wrote:
> Here is the proposed ioctl lock-down policy for file descriptors
> allocated in a process before pledge(2).
> 
> The manual page diff is first, that explains the direction this is
> going.
> 
> The other supporting code has been commited already, so feel free
> to take this for a ride and let's see what programs need further
> modification to cope with it.
> 
> Index: lib/libc/sys/pledge.2
> ===================================================================
> RCS file: /cvs/src/lib/libc/sys/pledge.2,v
> retrieving revision 1.39
> diff -u -p -u -r1.39 pledge.2
> --- lib/libc/sys/pledge.2     23 Jan 2017 07:19:39 -0000      1.39
> +++ lib/libc/sys/pledge.2     24 Jan 2017 10:04:31 -0000
> @@ -43,6 +43,16 @@ Subsequent calls to
>  .Fn pledge
>  can reduce the abilities further, but abilities can never be regained.
>  .Pp
> +New file descriptors created by a pledged process are annotated internally
> +to permit a greater set of
> +.Xr ioctl 2
> +operations.
> +File descriptors obtained via
> +.Xr dup 2
> +or
> +.Xr recvmsg 2
> +retain the annotation from the process who originally opened them.
> +.Pp
>  A process which attempts a restricted operation is killed with an uncatchable
>  .Dv SIGABRT ,
>  delivering a core file if possible.
> Index: sys/sys/pledge.h
> ===================================================================
> RCS file: /cvs/src/sys/sys/pledge.h,v
> retrieving revision 1.30
> diff -u -p -u -r1.30 pledge.h
> --- sys/sys/pledge.h  23 Jan 2017 04:25:05 -0000      1.30
> +++ sys/sys/pledge.h  23 Jan 2017 11:40:58 -0000
> @@ -126,7 +126,7 @@ int       pledge_adjtime(struct proc *p, const
>  int  pledge_sendit(struct proc *p, const void *to);
>  int  pledge_sockopt(struct proc *p, int set, int level, int optname);
>  int  pledge_socket(struct proc *p, int domain, int state);
> -int  pledge_ioctl(struct proc *p, long com, struct file *);
> +int  pledge_ioctl(struct proc *p, long com, struct file *, int, int);
>  int  pledge_ioctl_drm(struct proc *p, long com, dev_t device);
>  int  pledge_ioctl_vmm(struct proc *p, long com);
>  int  pledge_flock(struct proc *p);
> Index: sys/kern/kern_pledge.c
> ===================================================================
> RCS file: /cvs/src/sys/kern/kern_pledge.c,v
> retrieving revision 1.192
> diff -u -p -u -r1.192 kern_pledge.c
> --- sys/kern/kern_pledge.c    23 Jan 2017 05:49:24 -0000      1.192
> +++ sys/kern/kern_pledge.c    24 Jan 2017 08:19:03 -0000
> @@ -66,6 +66,7 @@
>  
>  #include "audio.h"
>  #include "pf.h"
> +#include "bpfilter.h"
>  #include "pty.h"
>  
>  #if defined(__amd64__) || defined(__i386__)
> @@ -538,6 +539,22 @@ sys_pledge(struct proc *p, void *v, regi
>       }
>  
>       if (SCARG(uap, request)) {
> +#ifdef DIAGNOSTIC
> +             if (!ISSET(pr->ps_flags, PS_PLEDGE)) {
> +                     struct filedesc *fdp = p->p_fd;
> +                     int fd;
> +
> +                     fdplock(fdp);
> +                     for (fd = 0; fd <= fdp->fd_lastfile; fd++) {
> +                             if (fdp->fd_ofiles[fd] &&
> +                                 (fdp->fd_ofileflags[fd] & UF_PLEDGED))
> +                                     printf("%s: fd %d was set!\n",
> +                                         pr->ps_comm, fd);
> +                             fdp->fd_ofileflags[fd] &= ~UF_PLEDGED;
> +                     }
> +                     fdpunlock(fdp);
> +             }
> +#endif
>               pr->ps_pledge = flags;
>               pr->ps_flags |= PS_PLEDGE;
>       }
> @@ -1102,7 +1119,7 @@ pledge_sendit(struct proc *p, const void
>  }
>  
>  int
> -pledge_ioctl(struct proc *p, long com, struct file *fp)
> +pledge_ioctl(struct proc *p, long com, struct file *fp, int fd, int 
> fdpledged)
>  {
>       struct vnode *vp = NULL;
>       int error = EPERM;
> @@ -1137,30 +1154,32 @@ pledge_ioctl(struct proc *p, long com, s
>               }
>       }
>  
> +#if NBPFILTER > 0
>       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)
> +             case BIOCGSTATS:        /* tcpdump, pflogd */
> +                     if (!fdpledged &&
> +                         fp->f_type == DTYPE_VNODE &&
> +                         vp->v_type == VCHR &&
> +                         cdevsw[major(vp->v_rdev)].d_open == bpfopen)
>                               return (0);
>                       break;
>               }
>       }
> +#endif /* NBPFILTER > 0 */
>  
>       if ((p->p_p->ps_pledge & PLEDGE_TAPE)) {
>               switch (com) {
> -             case MTIOCGET:
> +             case MTIOCGET:          /* pax */
>               case MTIOCTOP:
> -                     /* for pax(1) and such, checking tapes... */
>                       if (fp->f_type == DTYPE_VNODE &&
>                           (vp->v_type == VCHR || vp->v_type == VBLK))
>                               return (0);
> -                     break;
>               }
>       }
>  
> -     if ((p->p_p->ps_pledge & PLEDGE_DRM)) {
>  #if NDRM > 0
> +     if ((p->p_p->ps_pledge & PLEDGE_DRM)) {
>               if ((fp->f_type == DTYPE_VNODE) &&
>                   (vp->v_type == VCHR) &&
>                   (cdevsw[major(vp->v_rdev)].d_open == drmopen)) {
> @@ -1168,11 +1187,11 @@ pledge_ioctl(struct proc *p, long com, s
>                       if (error == 0)
>                               return 0;
>               }
> -#endif /* NDRM > 0 */
>       }
> +#endif /* NDRM > 0 */
>  
> -     if ((p->p_p->ps_pledge & PLEDGE_AUDIO)) {
>  #if NAUDIO > 0
> +     if ((p->p_p->ps_pledge & PLEDGE_AUDIO)) {
>               switch (com) {
>               case AUDIO_GETPOS:
>               case AUDIO_GETPAR:
> @@ -1184,19 +1203,22 @@ pledge_ioctl(struct proc *p, long com, s
>                           cdevsw[major(vp->v_rdev)].d_open == audioopen)
>                               return (0);
>               }
> -#endif /* NAUDIO > 0 */
>       }
> +#endif /* NAUDIO > 0 */
>  
>       if ((p->p_p->ps_pledge & PLEDGE_DISKLABEL)) {
>               switch (com) {
> -             case DIOCGDINFO:
> -             case DIOCGPDINFO:
> -             case DIOCRLDINFO:
> +             case DIOCRLDINFO:       /* change operations, etc. */
>               case DIOCWDINFO:
>               case BIOCDISK:
>               case BIOCINQ:
>               case BIOCINSTALLBOOT:
>               case BIOCVOL:
> +                     if (fdpledged)
> +                             break;
> +                     /* FALLTHROUGH */
> +             case DIOCGDINFO:        /* read operations, etc. */
> +             case DIOCGPDINFO:
>                       if (fp->f_type == DTYPE_VNODE &&
>                           ((vp->v_type == VCHR &&
>                           cdevsw[major(vp->v_rdev)].d_type == D_DISK) ||
> @@ -1213,10 +1235,10 @@ pledge_ioctl(struct proc *p, long com, s
>               }
>       }
>  
> -     if ((p->p_p->ps_pledge & PLEDGE_PF)) {
>  #if NPF > 0
> +     if ((p->p_p->ps_pledge & PLEDGE_PF)) {
>               switch (com) {
> -             case DIOCADDRULE:
> +             case DIOCADDRULE:       /* relayd */
>               case DIOCGETSTATUS:
>               case DIOCNATLOOK:
>               case DIOCRADDTABLES:
> @@ -1225,41 +1247,46 @@ pledge_ioctl(struct proc *p, long com, s
>               case DIOCRCLRTSTATS:
>               case DIOCRGETTSTATS:
>               case DIOCRSETADDRS:
> -             case DIOCXBEGIN:
> +             case DIOCXBEGIN:        /* relayd, proxies */
>               case DIOCXCOMMIT:
>               case DIOCKILLSRCNODES:
> -                     if ((fp->f_type == DTYPE_VNODE) &&
> +             case DIOCRGETASTATS:    /* bgpd */
> +             case DIOCRDELADDRS:
> +             case DIOCRADDADDRS:
> +                     if (!fdpledged &&
> +                         (fp->f_type == DTYPE_VNODE) &&
>                           (vp->v_type == VCHR) &&
>                           (cdevsw[major(vp->v_rdev)].d_open == pfopen))
>                               return (0);
>                       break;
>               }
> -#endif
>       }
> +#endif /* NPF > 0 */
>  
>       if ((p->p_p->ps_pledge & PLEDGE_TTY)) {
>               switch (com) {
>  #if NPTY > 0
> -             case PTMGET:
> -                     if ((p->p_p->ps_pledge & PLEDGE_RPATH) == 0)
> -                             break;
> -                     if ((p->p_p->ps_pledge & PLEDGE_WPATH) == 0)
> -                             break;
> -                     if (fp->f_type != DTYPE_VNODE || vp->v_type != VCHR)
> -                             break;
> -                     if (cdevsw[major(vp->v_rdev)].d_open != ptmopen)
> -                             break;
> -                     return (0);
> +             case PTMGET:            /* tmux */
> +                     if (!fdpledged &&
> +                         (p->p_p->ps_pledge & PLEDGE_RPATH) &&
> +                         (p->p_p->ps_pledge & PLEDGE_WPATH) &&
> +                         fp->f_type == DTYPE_VNODE && vp->v_type == VCHR &&
> +                         cdevsw[major(vp->v_rdev)].d_open == ptmopen)
> +                             return (0);
> +                     break;
>  #endif /* NPTY > 0 */
> -             case TIOCSTI:           /* ksh? csh? */
> -                     if ((p->p_p->ps_pledge & PLEDGE_PROC) &&
> +             case TIOCSTI:           /* csh */
> +                     if (!fdpledged &&
> +                         (p->p_p->ps_pledge & PLEDGE_PROC) &&
>                           fp->f_type == DTYPE_VNODE && (vp->v_flag & VISTTY))
>                               return (0);
>                       break;
>               case TIOCSPGRP:
> -                     if ((p->p_p->ps_pledge & PLEDGE_PROC) == 0)
> -                             break;
> -                     /* FALLTHROUGH */
> +                     /* cannot do !fdpledged test */
> +                     if ((p->p_p->ps_pledge & PLEDGE_PROC) &&
> +                         fp->f_type == DTYPE_VNODE && (vp->v_flag & VISTTY))
> +                             return (0);
> +                     break;
>               case TIOCFLUSH:         /* getty, telnet */
>               case TIOCGPGRP:
>               case TIOCGETA:
> @@ -1267,7 +1294,7 @@ pledge_ioctl(struct proc *p, long com, s
>                       if (fp->f_type == DTYPE_VNODE && (vp->v_flag & VISTTY))
>                               return (0);
>                       return (ENOTTY);
> -             case TIOCSWINSZ:
> +             case TIOCSWINSZ:        /* tmux, script */
>               case TIOCEXT:           /* mail, libedit .. */
>               case TIOCCBRK:          /* cu */
>               case TIOCSBRK:          /* cu */
> @@ -1275,7 +1302,7 @@ pledge_ioctl(struct proc *p, long com, s
>               case TIOCSDTR:          /* cu */
>               case TIOCEXCL:          /* cu */
>               case TIOCSETA:          /* cu, ... */
> -             case TIOCSETAW:         /* cu, ... */
> +             case TIOCSETAW:         /* tmux, cu, ksh ... */
>               case TIOCSETAF:         /* tcsetattr TCSAFLUSH, script */
>               case TIOCSCTTY:         /* forkpty(3), login_tty(3), ... */
>                       if (fp->f_type == DTYPE_VNODE && (vp->v_flag & VISTTY))
> @@ -1296,7 +1323,7 @@ pledge_ioctl(struct proc *p, long com, s
>               case SIOCGNBRINFO_IN6:
>               case SIOCGIFINFO_IN6:
>               case SIOCGIFMEDIA:
> -                     if (fp->f_type == DTYPE_SOCKET)
> +                     if (!fdpledged && fp->f_type == DTYPE_SOCKET)
>                               return (0);
>                       break;
>               }
> @@ -1311,9 +1338,11 @@ pledge_ioctl(struct proc *p, long com, s
>                       if (error == 0)
>                               return 0;
>               }
> -#endif
> +#endif /* NVMM > 0 */
>       }
>  
> +     if (fdpledged)
> +             printf("%s: ioctl %08lx post-pledge fd %d\n", p->p_p->ps_comm, 
> com, fd);
>       return pledge_fail(p, error, PLEDGE_TTY);
>  }
>  
> Index: sys/kern/sys_generic.c
> ===================================================================
> RCS file: /cvs/src/sys/kern/sys_generic.c,v
> retrieving revision 1.114
> diff -u -p -u -r1.114 sys_generic.c
> --- sys/kern/sys_generic.c    24 Jan 2017 00:58:55 -0000      1.114
> +++ sys/kern/sys_generic.c    24 Jan 2017 11:23:11 -0000
> @@ -390,17 +390,20 @@ sys_ioctl(struct proc *p, void *v, regis
>               syscallarg(void *) data;
>       } */ *uap = v;
>       struct file *fp;
> -     struct filedesc *fdp;
> +     struct filedesc *fdp = p->p_fd;
>       u_long com = SCARG(uap, com);
>       int error;
>       u_int size;
>       caddr_t data, memp;
> -     int tmp;
> +     int tmp, pl;
>  #define STK_PARAMS   128
>       long long stkbuf[STK_PARAMS / sizeof(long long)];
>  
> -     fdp = p->p_fd;
> +     fdplock(fdp);
>       fp = fd_getfile_mode(fdp, SCARG(uap, fd), FREAD|FWRITE);
> +     if (fp)
> +             pl = fdp->fd_ofileflags[SCARG(uap, fd)] & UF_PLEDGED;
> +     fdpunlock(fdp);
>  
>       if (fp == NULL)
>               return (EBADF);
> @@ -412,7 +415,7 @@ sys_ioctl(struct proc *p, void *v, regis
>                       return (EINVAL);
>       }
>  
> -     error = pledge_ioctl(p, com, fp);
> +     error = pledge_ioctl(p, com, fp, SCARG(uap, fd), pl);
>       if (error)
>               return (error);
>  
> 

-- 

Reply via email to