I disagree strongly with the direction. Processes should follow the promises previous code made.
Developers should be "mindful" of their program's rules & model, if they can't design properly and keep the situation in their head in a 'static fashion', they don't stand a chance in hell of doing this work in a 'dynamic fashion' Noone should writing code which programatically 'studies the situation' and makes dynamic decisions. Furthermore, the pledge made by one program is an internal secret, noone needs to inspect it. This proposal is not going anywhere. Andy Seniuk <[email protected]> wrote: > Hello once again, > > I have CC'd the original developers of tame/pledge; hope that is > not in violation of etiquette? This is my last post on this > subject (or to any devs emails) if interest remains cool, but > it deserves a fair shot, and after all, 500 hours is nothing > to sneeze at! > > These non-invasive additions apply cleanly to the latest code of the > three affected source files. I admit I am still running -current > from mid-April, so I can't test it with these latest files, but the > only change since my mid-April versions was to syscalls.master, and > merged easily. > > https://fremissant.net/pledge > > This doesn't include patches to insert into <unistd.h>, but it's > sufficient for the present, so that pledge(1) can run at full > capabilities for anyone who has the patched kernel. Also, the > pledge.2 mdoc patch is not included; but is available at that URL. > > I don't think the patch is too long to include on tech@? > Copied below. > > The future of pledge(1) depends on your decision. > > Thanks for your consideration, > Andy. > > Index: sys/kern/kern_pledge.c > =================================================================== > RCS file: /cvs/src/sys/kern/kern_pledge.c,v > retrieving revision 1.251 > diff -u -p -r1.251 kern_pledge.c > --- sys/kern/kern_pledge.c 14 Feb 2019 15:41:47 -0000 1.251 > +++ sys/kern/kern_pledge.c 11 May 2019 23:50:24 -0000 > @@ -233,6 +233,11 @@ const uint64_t pledge_syscalls[SYS_MAXSY > > [SYS_wait4] = PLEDGE_STDIO, > > + [SYS_pledgepid] = PLEDGE_ALWAYS, > +#if 0 > + [SYS_pledgepid] = PLEDGE_PROC, /* if choose this, move it down */ > +#endif > + > /* > * Can kill self with "stdio". Killing another pid > * requires "proc" > @@ -500,6 +512,219 @@ sys_pledge(struct proc *p, void *v, regi > pr->ps_execpledge = execpromises; > pr->ps_flags |= PS_EXECPLEDGE; > } > + return (0); > +} > + > +/* > + * To query, PLEDGEPID_QUERY opts bit must be set, and results are > + * returned through copyout() to the pbits/epbits pointers. > + * To set/drop [exec]promises, set opts PLEDGEPID_SET/DROP_[E]PROMS; > + * the promise data are read from [e]pbits. > + * It is permissible to combine query and set/drop. > + * Query only affects the components (pbits/epbits) which were > + * passed non-NULL. Passing NULL with set/drop causes current > + * pledge state in that component to remain unchanged. > + * Caveat: query destructively overwrites userland data pointed to > + * by pbits/epbits (when not NULL). > + * ----- > + * [ based on sys_pledge(), sys/kern/kern_sig.c:cansignal(),sys_kill() ] > + */ > +int > +sys_pledgepid(struct proc *caller_p, void *v, register_t *retval) > +{ > + struct sys_pledgepid_args /* { > + syscallarg(pid_t)pid; > + syscallarg(uint32_t)opts; > + syscallarg(uint64_t *)pbits; > + syscallarg(uint64_t *)epbits; > + syscallarg(const void *)aux; > + } */ *uap = v; > + uint32_t opts = SCARG(uap, opts); > + uint64_t u64tmp, *pbits = NULL, *epbits = NULL; > + struct process *caller_pr = caller_p->p_p; > + struct process *target_pr; /* will be proc. corresp. to pid arg. */ > + pid_t pid_caller = caller_pr->ps_pid; > + pid_t pid_target = SCARG(uap, pid); > + /* see kern_sig.c:cansignal() */ > + struct ucred *caller_p_uc = caller_p->p_ucred; > + /* ...and not caller_pr->ps_ucred... */ > + struct ucred *target_pr_uc; /* will use (*process)->ps_ucred */ > + int empowered = 0; > + int error; > + > + /* > + * If caller is under pledge, and pid argument is not that of > + * the caller (or 0), fail immediately unless hold "proc" promise. > + */ > + if ((error = pledge_kill(caller_p, pid_target)) != 0) > + return (error); > + > + if (pid_target < 0) > + return (EINVAL); > + > + if (pid_target == 0) { > + pid_target = pid_caller; > + target_pr = caller_pr; > + } else if((target_pr = prfind(pid_target)) == NULL) { > + if ((target_pr = zombiefind(pid_target)) == NULL) > + return (ESRCH); > + else { > + /* > + * Let it go ahead and try to act on the zombie; if > + * it's possible to pledge it down as requested, so > + * much the better, zombie or not. :) > + */ > +#if 0 > +/* (This happens quite often when pledge(1) tries to set post-init promises > + * on a command which finishes sooner than the default 400 ms delay.) > + */ > + zombie = 1; > + uprintf("pledgepid: warn: [%d] zombie\n", pid_target); > +#endif > + } > + } > + > + target_pr_uc = target_pr->ps_ucred; > + > + if (opts & (PLEDGEPID_SET_PROMS | PLEDGEPID_SET_EPROMS | > + PLEDGEPID_DROP_PROMS | PLEDGEPID_DROP_EPROMS)) { > + /* Copy them now, or query will stomp. */ > + if (SCARG(uap, pbits) != NULL) { > + pbits = malloc(sizeof(*pbits), M_TEMP, M_WAITOK); > + if (copyin(SCARG(uap, pbits), pbits, sizeof(*pbits))) > + return (EFAULT); > + *pbits &= PLEDGE_USERSET; > + } > + if (SCARG(uap, epbits) != NULL) { > + epbits = malloc(sizeof(*epbits), M_TEMP, M_WAITOK); > + if (copyin(SCARG(uap, epbits), epbits, sizeof(*epbits))) > + return (EFAULT); > + *epbits &= PLEDGE_USERSET; > + } > + } > + > + /* > + * At present, any process can query any other process that it > + * can signal. Another possibility would be to only allow querying > + * when the caller has uid 0. The highest nibble is reserved for > + * kernel use, so it is safe to repurpose a high bit to additionally > + * convey the pr->flags PS_PLEDGE/PS_EXECPLEDGE status to userland. > + */ > + if (opts & PLEDGEPID_QUERY) { > + if (SCARG(uap, pbits) != NULL) { > + u64tmp = target_pr->ps_pledge & PLEDGE_USERSET; > + if (!ISSET(target_pr->ps_flags, PS_PLEDGE)) > + u64tmp |= PLEDGEPID_UNPLEDGED; > + if (copyout(&u64tmp, SCARG(uap, pbits), 8)) > + return (EFAULT); > + } > + if (SCARG(uap, epbits) != NULL) { > + u64tmp = target_pr->ps_execpledge & PLEDGE_USERSET; > + if (!ISSET(target_pr->ps_flags, PS_EXECPLEDGE)) > + u64tmp |= PLEDGEPID_UNPLEDGED; > + if (copyout(&u64tmp, SCARG(uap, epbits), 8)) > + return (EFAULT); > + } > + } > + > + if (!(opts & PLEDGEPID_MODSET)) > + return (0); > + > + /* > + * Note that the additional checks that promises are not augmented > + * are performed below; not even root is allowed to add promises! > + */ > + > + if (caller_p_uc->cr_uid == 0) > + empowered = 1; /* root can always pledge any pid */ > + > + if (caller_pr == target_pr) > + empowered = 1; /* process can always pledge itself */ > + > + /* see sys/kern/kern_sig.c:cansignal() */ > + if (!empowered && > + !(caller_p_uc->cr_ruid == target_pr_uc->cr_ruid || > + caller_p_uc->cr_ruid == target_pr_uc->cr_svuid || > + caller_p_uc->cr_uid == target_pr_uc->cr_ruid || > + caller_p_uc->cr_uid == target_pr_uc->cr_svuid)) > + return (EPERM); > + > + if (pbits == NULL) > + goto pledgepid_skip_1; > + > + if (opts & PLEDGEPID_DROP_PROMS) { > + /* Never augments promises */ > + u64tmp = target_pr->ps_pledge; > + u64tmp &= ~*pbits; /* already masked by PLEDGE_USERSET */ > + target_pr->ps_pledge = u64tmp; > +#if 1 > + target_pr->ps_flags |= PS_PLEDGE; > +#else > + atomic_setbits_int(&target_pr->ps_flags, PS_PLEDGE); > +#endif > + } else if (opts & PLEDGEPID_SET_PROMS) { > + /* In "error" mode, ignore promise increase requests, > + * but accept promise decrease requests */ > + if (ISSET(target_pr->ps_flags, PS_PLEDGE) && > + (target_pr->ps_pledge & PLEDGE_ERROR)) > + *pbits &= target_pr->ps_pledge; > + > + /* Only permit reductions */ > + if (ISSET(target_pr->ps_flags, PS_PLEDGE) && > + (((*pbits | target_pr->ps_pledge) != > + target_pr->ps_pledge))) > + return (EPERM); > + > + target_pr->ps_pledge = *pbits; > + target_pr->ps_flags |= PS_PLEDGE; > + } > + > +pledgepid_skip_1: > + > + if (epbits == NULL) > + goto pledgepid_skip_2; > + > + if (opts & PLEDGEPID_DROP_EPROMS) { > + /* Never augments execpromises */ > + u64tmp = target_pr->ps_execpledge; > + u64tmp &= ~*epbits; /* already masked by PLEDGE_USERSET */ > + target_pr->ps_execpledge = u64tmp; > +#if 1 > + target_pr->ps_flags |= PS_EXECPLEDGE; > +#else > + atomic_setbits_int(&target_pr->ps_flags, PS_EXECPLEDGE); > +#endif > + } else if (opts & PLEDGEPID_SET_EPROMS) { > + /* XXX should not such a case also be in pledge(2)? */ > + if (ISSET(target_pr->ps_flags, PS_PLEDGE) && > + (target_pr->ps_pledge & PLEDGE_ERROR)) > + *epbits &= target_pr->ps_execpledge; > + > + /* Only permit reductions */ > + if (ISSET(target_pr->ps_flags, PS_EXECPLEDGE) && > + (((*epbits | target_pr->ps_execpledge) != > + target_pr->ps_execpledge))) > + return (EPERM); > + > + target_pr->ps_execpledge = *epbits; > + target_pr->ps_flags |= PS_EXECPLEDGE; > + } > + > +pledgepid_skip_2: > + if (pbits != NULL) > + free(pbits, M_TEMP, sizeof(*pbits)); > + if (epbits != NULL) > + free(epbits, M_TEMP, sizeof(*epbits)); > + > + /* > + * Kill off unveil and drop unveil vnode refs if target process > + * no longer holds any path-accessing pledge. > + */ > + if ((target_pr->ps_pledge & (PLEDGE_RPATH | PLEDGE_WPATH | > + PLEDGE_CPATH | PLEDGE_DPATH | PLEDGE_TMPPATH | PLEDGE_EXEC | > + PLEDGE_UNIX | PLEDGE_UNVEIL)) == 0) > + unveil_destroy(target_pr); > + > return (0); > } > > Index: sys/kern/syscalls.master > =================================================================== > RCS file: /cvs/src/sys/kern/syscalls.master,v > retrieving revision 1.190 > diff -u -p -r1.190 syscalls.master > --- sys/kern/syscalls.master 9 May 2019 20:30:22 -0000 1.190 > +++ sys/kern/syscalls.master 11 May 2019 23:50:25 -0000 > @@ -226,7 +226,7 @@ > 106 STD { int sys_listen(int s, int backlog); } > 107 STD { int sys_chflagsat(int fd, const char *path, \ > u_int flags, int atflags); } > -108 STD { int sys_pledge(const char *promises, \ > +108 STD { int sys_pledge(const char *promises, \ > const char *execpromises); } > 109 STD { int sys_ppoll(struct pollfd *fds, \ > u_int nfds, const struct timespec *ts, \ > @@ -238,7 +238,7 @@ > 112 STD { int sys_sendsyslog(const char *buf, size_t nbyte, \ > int flags); } > 113 UNIMPL fktrace > -114 STD { int sys_unveil(const char *path, \ > +114 STD { int sys_unveil(const char *path, \ > const char *permissions); } > 115 OBSOL vtrace > 116 OBSOL t32_gettimeofday > @@ -565,3 +565,6 @@ > 328 OBSOL __tfork51 > 329 STD NOLOCK { void sys___set_tcb(void *tcb); } > 330 STD NOLOCK { void *sys___get_tcb(void); } > +331 STD { int sys_pledgepid(pid_t pid, uint32_t opts, \ > + uint64_t *pbits, uint64_t *epbits, \ > + const void *aux); } > Index: sys/sys/pledge.h > =================================================================== > RCS file: /cvs/src/sys/sys/pledge.h,v > retrieving revision 1.39 > diff -u -p -r1.39 pledge.h > --- sys/sys/pledge.h 21 Jan 2019 20:09:37 -0000 1.39 > +++ sys/sys/pledge.h 11 May 2019 23:50:25 -0000 > @@ -23,6 +23,35 @@ > #include <sys/cdefs.h> > > /* > + * pledgepid(2) opts flags > + */ > +/* Permissions allowing, the promises data is returned through pbits/epbits: > */ > +#define PLEDGEPID_QUERY 0x00000001U > +#if 0 > +#define PLEDGEPID__unused_1 0x00000002U > +#endif > +/* > + * pledge(2)-style operation: sets initial promises if unpledged in that > + * component; otherwise, sets the given promises if they are a subset > + * (inclusive) of the target's currently held set; otherwise returns EPERM. > + */ > +#define PLEDGEPID_SET_PROMS 0x00000004U > +#define PLEDGEPID_SET_EPROMS 0x00000008U > +/* Subtractive operation: remove specified promises from an existing pledge: > */ > +#define PLEDGEPID_DROP_PROMS 0x00000010U > +#define PLEDGEPID_DROP_EPROMS 0x00000020U > +/* > + * The 4 high bits of uint64_t promises/execpromises are available for > + * dual (independent) use kernel/userland; these are for userland. > + */ > +#if 0 > +#define PLEDGEPID__unused_2 0x1000000000000000ULL > +#define PLEDGEPID__unused_3 0x2000000000000000ULL > +#endif > +#define PLEDGEPID_SUBTRACTIVE 0x4000000000000000ULL > +#define PLEDGEPID_UNPLEDGED 0x8000000000000000ULL > + > +/* > * pledge(2) requests > */ > #define PLEDGE_ALWAYS 0xffffffffffffffffULL > @@ -50,6 +79,7 @@ > #define PLEDGE_MCAST 0x0000000000200000ULL /* multicast joins */ > #define PLEDGE_VMINFO 0x0000000000400000ULL /* vminfo listings */ > #define PLEDGE_PS 0x0000000000800000ULL /* ps listings */ > +#define PLEDGE_seniuk 0x0000000001000000ULL /* XXX reserved ;) */ > #define PLEDGE_DISKLABEL 0x0000000002000000ULL /* disklabels */ > #define PLEDGE_PF 0x0000000004000000ULL /* pf ioctls */ > #define PLEDGE_AUDIO 0x0000000008000000ULL /* audio ioctls */
