--- //depot/projects/smpng/sys/compat/freebsd32/freebsd32_misc.c +++ //depot/user/jhb/proc/compat/freebsd32/freebsd32_misc.c @@ -55,6 +55,7 @@ #include #include #include +#include #include #include #include @@ -2898,3 +2900,23 @@ return (kern_posix_fadvise(td, uap->fd, PAIR32TO64(off_t, uap->offset), PAIR32TO64(off_t, uap->len), uap->advice)); } + +int +freebsd32_procctl(struct thread *td, struct freebsd32_procctl_args *uap) +{ + void *data; + int error, flags; + + switch (uap->com) { + case PROC_SPROTECT: + error = copyin(PTRIN(uap->data), &flags, sizeof(flags)); + if (error) + return (error); + data = &flags; + break; + default: + return (EINVAL); + } + return (kern_procctl(td, uap->idtype, PAIR32TO64(id_t, uap->id), + uap->com, data)); +} --- //depot/projects/smpng/sys/compat/freebsd32/syscalls.master +++ //depot/user/jhb/proc/compat/freebsd32/syscalls.master @@ -1046,3 +1046,12 @@ 542 AUE_PIPE NOPROTO { int pipe2(int *fildes, int flags); } 543 AUE_NULL NOSTD { int freebsd32_aio_mlock( \ struct aiocb32 *aiocbp); } +#ifdef PAD64_REQUIRED +544 AUE_WAIT6 STD { int freebsd32_procctl(int idtype, int pad, \ + uint32_t id1, uint32_t id2, int com, \ + void *data); } +#else +544 AUE_WAIT6 STD { int freebsd32_procctl(int idtype, \ + uint32_t id1, uint32_t id2, int com, \ + void *data); } +#endif --- //depot/projects/smpng/sys/kern/makesyscalls.sh +++ //depot/user/jhb/proc/kern/makesyscalls.sh @@ -156,7 +156,8 @@ printf "#include \n" > sysarg printf "#include \n" > sysarg printf "#include \n" > sysarg - printf "#include \n\n" > sysarg + printf "#include \n" > sysarg + printf "#include \n\n" > sysarg printf "#include \n\n" > sysarg printf "struct proc;\n\n" > sysarg printf "struct thread;\n\n" > sysarg --- //depot/projects/smpng/sys/kern/sys_process.c +++ //depot/user/jhb/proc/kern/sys_process.c @@ -41,7 +41,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -1240,3 +1248,187 @@ msleep(&p->p_step, &p->p_mtx, PWAIT, "stopevent", 0); } while (p->p_step); } + +static int +protect_setchild(struct thread *td, struct proc *p, int flags) +{ + + PROC_LOCK_ASSERT(p, MA_OWNED); + if (p->p_flag & P_SYSTEM || p_cansee(td, p) != 0) + return (0); + if (flags & PPROT_SET) + p->p_flag |= P_PROTECTED; + else + p->p_flag &= ~P_PROTECTED; + return (1); +} + +static int +protect_setchildren(struct thread *td, struct proc *top, int flags) +{ + struct proc *p; + int ret; + + p = top; + ret = 0; + sx_assert(&proctree_lock, SX_LOCKED); + for (;;) { + ret |= protect_setchild(td, p, flags); + PROC_UNLOCK(p); + /* + * If this process has children, descend to them next, + * otherwise do any siblings, and if done with this level, + * follow back up the tree (but not past top). + */ + if (!LIST_EMPTY(&p->p_children)) + p = LIST_FIRST(&p->p_children); + else for (;;) { + if (p == top) { + PROC_LOCK(p); + return (ret); + } + if (LIST_NEXT(p, p_sibling)) { + p = LIST_NEXT(p, p_sibling); + break; + } + p = p->p_pptr; + } + PROC_LOCK(p); + } +} + +static int +protect_set(struct thread *td, struct proc *p, int flags) +{ + int error, ret; + + if ((flags & ~(PPROT_SET | PPROT_CLEAR | PPROT_DESCEND | + PPROT_INHERIT)) != 0) + return (EINVAL); + if (flags & PPROT_INHERIT) + return (EOPNOTSUPP); + + error = priv_check(td, PRIV_VM_MADV_PROTECT); + if (error) + return (error); + + if (flags & PPROT_DESCEND) + ret = protect_setchildren(td, p, flags); + else + ret = protect_setchild(td, p, flags); + if (ret == 0) + return (EPERM); + return (0); +} + +#ifndef _SYS_SYSPROTO_H_ +struct procctl_args { + idtype_t idtype; + id_t id; + int com; + void *data; +}; +#endif +/* ARGSUSED */ +int +sys_procctl(struct thread *td, struct procctl_args *uap) +{ + int error, flags; + void *data; + + switch (uap->com) { + case PROC_SPROTECT: + error = copyin(uap->data, &flags, sizeof(flags)); + if (error) + return (error); + data = &flags; + break; + default: + return (EINVAL); + } + + return (kern_procctl(td, uap->idtype, uap->id, uap->com, data)); +} + +static int +kern_procctl_single(struct thread *td, struct proc *p, int com, void *data) +{ + + PROC_LOCK_ASSERT(p, MA_OWNED); + switch (com) { + case PROC_SPROTECT: + return (protect_set(td, p, *(int *)data)); + default: + return (EINVAL); + } +} + +int +kern_procctl(struct thread *td, idtype_t idtype, id_t id, int com, void *data) +{ + struct pgrp *pg; + struct proc *p; + int error, first_error, ok; + + sx_slock(&proctree_lock); + switch (idtype) { + case P_PID: + p = pfind(id); + if (p == NULL) { + error = ESRCH; + break; + } + if (p->p_state == PRS_NEW) + error = ESRCH; + else + error = p_cansee(td, p); + if (error == 0) + error = kern_procctl_single(td, p, com, data); + PROC_UNLOCK(p); + break; + case P_PGID: + /* + * Attempt to apply the operation to all members of the + * group. Ignore processes in the group that can't be + * seen. Ignore errors so long as at least one process is + * able to complete the request successfully. + */ + pg = pgfind(id); + if (pg == NULL) { + error = ESRCH; + break; + } + PGRP_UNLOCK(pg); + ok = 0; + first_error = 0; + LIST_FOREACH(p, &pg->pg_members, p_pglist) { + PROC_LOCK(p); + if (p->p_state == PRS_NEW || p_cansee(td, p) != 0) { + PROC_UNLOCK(p); + continue; + } + error = kern_procctl_single(td, p, com, data); + PROC_UNLOCK(p); + if (error == 0) + ok = 1; + else if (first_error == 0) + first_error = error; + } + if (ok) + error = 0; + else if (first_error != 0) + error = first_error; + else + /* + * Was not able to see any processes in the + * process group. + */ + error = ESRCH; + break; + default: + error = EINVAL; + break; + } + sx_sunlock(&proctree_lock); + return (error); +} --- //depot/projects/smpng/sys/kern/syscalls.master +++ //depot/user/jhb/proc/kern/syscalls.master @@ -952,7 +952,7 @@ off_t offset, off_t len); } 531 AUE_NULL STD { int posix_fadvise(int fd, off_t offset, \ off_t len, int advice); } -532 AUE_WAIT6 STD { int wait6(int idtype, id_t id, \ +532 AUE_WAIT6 STD { int wait6(idtype_t idtype, id_t id, \ int *status, int options, \ struct __wrusage *wrusage, \ siginfo_t *info); } @@ -978,5 +978,7 @@ int flags); } 542 AUE_PIPE STD { int pipe2(int *fildes, int flags); } 543 AUE_NULL NOSTD { int aio_mlock(struct aiocb *aiocbp); } +544 AUE_NULL STD { int procctl(idtype_t idtype, id_t id, \ + int com, void *data); } ; Please copy any additions and changes to the following compatability tables: ; sys/compat/freebsd32/syscalls.master --- /dev/null +++ //depot/user/jhb/proc/sys/procctl.h @@ -0,0 +1,28 @@ +/*- + * XXX: License + * + * $FreeBSD$ + */ + +#ifndef _SYS_PROCCTL_H_ +#define _SYS_PROCCTL_H_ + +#define PROC_SPROTECT 1 /* set protected state */ + +/* Flags for PROC_SPROTECT (passed in integer arg). */ +#define PPROT_SET 0x1 +#define PPROT_CLEAR 0x0 +#define PPROT_DESCEND 0x2 +#define PPROT_INHERIT 0x4 + +#ifndef _KERNEL +#include +#include + +__BEGIN_DECLS +int procctl(idtype_t, id_t, int, void *); +__END_DECLS + +#endif + +#endif /* !_SYS_PROCCTL_H_ */ --- //depot/projects/smpng/sys/sys/syscallsubr.h +++ //depot/user/jhb/proc/sys/syscallsubr.h @@ -33,6 +33,7 @@ #include #include #include +#include struct file; enum idtype; @@ -163,6 +164,8 @@ int advice); int kern_posix_fallocate(struct thread *td, int fd, off_t offset, off_t len); +int kern_procctl(struct thread *td, idtype_t idtype, id_t id, int com, + void *data); int kern_preadv(struct thread *td, int fd, struct uio *auio, off_t offset); int kern_pselect(struct thread *td, int nd, fd_set *in, fd_set *ou, fd_set *ex, struct timeval *tvp, sigset_t *uset, int abi_nfdbits); --- //depot/projects/smpng/sys/vm/vm_mmap.c +++ //depot/user/jhb/proc/vm/vm_mmap.c @@ -56,6 +56,7 @@ #include #include #include +#include #include #include #include @@ -68,6 +69,7 @@ #include #include #include +#include #include #include @@ -716,23 +718,18 @@ { vm_offset_t start, end; vm_map_t map; - struct proc *p; - int error; + int flags; /* * Check for our special case, advising the swap pager we are * "immortal." */ if (uap->behav == MADV_PROTECT) { - error = priv_check(td, PRIV_VM_MADV_PROTECT); - if (error == 0) { - p = td->td_proc; - PROC_LOCK(p); - p->p_flag |= P_PROTECTED; - PROC_UNLOCK(p); - } - return (error); + flags = PPROT_SET; + return (kern_procctl(td, P_PID, td->td_proc->p_pid, + PROC_SPROTECT, &flags)); } + /* * Check for illegal behavior */