--- //depot/projects/smpng/sys/compat/freebsd32/freebsd32_misc.c +++ //depot/user/jhb/proc/compat/freebsd32/freebsd32_misc.c @@ -56,6 +56,7 @@ #include #include #include +#include #include #include #include @@ -2999,3 +3001,23 @@ } return (0); } + +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 @@ -1056,3 +1056,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_NULL STD { int freebsd32_procctl(int idtype, int pad, \ + uint32_t id1, uint32_t id2, int com, \ + void *data); } +#else +544 AUE_NULL STD { int freebsd32_procctl(int idtype, \ + uint32_t id1, uint32_t id2, int com, \ + void *data); } +#endif --- //depot/projects/smpng/sys/kern/init_main.c +++ //depot/user/jhb/proc/kern/init_main.c @@ -474,6 +474,7 @@ p->p_sysent = &null_sysvec; p->p_flag = P_SYSTEM | P_INMEM; + p->p_flag2 = 0; p->p_state = PRS_NORMAL; knlist_init_mtx(&p->p_klist, &p->p_mtx); STAILQ_INIT(&p->p_ktr); --- //depot/projects/smpng/sys/kern/kern_fork.c +++ //depot/user/jhb/proc/kern/kern_fork.c @@ -489,6 +489,7 @@ * Increase reference counts on shared objects. */ p2->p_flag = P_INMEM; + p2->p_flag2 = 0; p2->p_swtick = ticks; if (p1->p_flag & P_PROFIL) startprofclock(p2); @@ -512,6 +513,11 @@ p2->p_fd = fd; p2->p_fdtol = fdtol; + if (p1->p_flag2 & P2_INHERIT_PROTECTED) { + p2->p_flag |= P_PROTECTED; + p2->p_flag2 |= P2_INHERIT_PROTECTED; + } + /* * p_limit is copy-on-write. Bump its refcount. */ --- //depot/projects/smpng/sys/kern/kern_proc.c +++ //depot/user/jhb/proc/kern/kern_proc.c @@ -802,6 +802,7 @@ kp->ki_fd = p->p_fd; kp->ki_vmspace = p->p_vmspace; kp->ki_flag = p->p_flag; + kp->ki_flag2 = p->p_flag2; cred = p->p_ucred; if (cred) { kp->ki_uid = cred->cr_uid; --- //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,196 @@ 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; + if (flags & PPROT_INHERIT) + p->p_flag2 |= P2_INHERIT_PROTECTED; + } else { + p->p_flag &= ~P_PROTECTED; + p->p_flag2 &= ~P2_INHERIT_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; + + switch (PPROT_OP(flags)) { + case PPROT_SET: + case PPROT_CLEAR: + break; + default: + return (EINVAL); + } + + if ((PPROT_FLAGS(flags) & ~(PPROT_DESCEND | PPROT_INHERIT)) != 0) + return (EINVAL); + + 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 --- //depot/projects/smpng/sys/sys/proc.h +++ //depot/user/jhb/proc/sys/proc.h @@ -492,11 +492,8 @@ struct callout p_limco; /* (c) Limit callout handle */ struct sigacts *p_sigacts; /* (x) Signal actions, state (CPU). */ - /* - * The following don't make too much sense. - * See the td_ or ke_ versions of the same flags. - */ int p_flag; /* (c) P_* flags. */ + int p_flag2; /* (c) P2_* flags. */ enum { PRS_NEW = 0, /* In creation */ PRS_NORMAL, /* threads can be run. */ @@ -641,6 +638,9 @@ #define P_SHOULDSTOP(p) ((p)->p_flag & P_STOPPED) #define P_KILLED(p) ((p)->p_flag & P_WKILLED) +/* These flags are kept in p_flag2. */ +#define P2_INHERIT_PROTECTED 0x00000001 /* New children get P_PROTECTED. */ + /* * These were process status values (p_stat), now they are only used in * legacy conversion code. --- /dev/null +++ //depot/user/jhb/proc/sys/procctl.h @@ -0,0 +1,55 @@ +/*- + * Copyright (c) 2013 Advanced Computing Technologies LLC + * Written by: John H. Baldwin + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _SYS_PROCCTL_H_ +#define _SYS_PROCCTL_H_ + +#define PROC_SPROTECT 1 /* set protected state */ + +/* Operations for PROC_SPROTECT (passed in integer arg). */ +#define PPROT_OP(x) ((x) & 0xf) +#define PPROT_SET 1 +#define PPROT_CLEAR 2 + +/* Flags for PROC_SPROTECT (ORed in with operation). */ +#define PPROT_FLAGS(x) ((x) & ~0xf) +#define PPROT_DESCEND 0x10 +#define PPROT_INHERIT 0x20 + +#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; @@ -167,6 +168,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/sys/user.h +++ //depot/user/jhb/proc/sys/user.h @@ -84,7 +84,7 @@ * it in two places: function fill_kinfo_proc in sys/kern/kern_proc.c and * function kvm_proclist in lib/libkvm/kvm_proc.c . */ -#define KI_NSPARE_INT 8 +#define KI_NSPARE_INT 7 #define KI_NSPARE_LONG 12 #define KI_NSPARE_PTR 6 @@ -187,6 +187,7 @@ */ char ki_sparestrings[50]; /* spare string space */ int ki_spareints[KI_NSPARE_INT]; /* spare room for growth */ + int ki_flag2; /* P2_* flags */ int ki_fibnum; /* Default FIB number */ u_int ki_cr_flags; /* Credential flags */ int ki_jid; /* Process jail ID */ --- //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 @@ -723,23 +725,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 */