FreeBSD Bugzilla – Attachment 157661 Details for
Bug 48471
[jail] Private IPC for every jail
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
IPC key_t space separation between jails (fix)
jailed-sysvipc-for-stable10-again.patch (text/plain), 24.40 KB, created by
kikuchan98
on 2015-06-12 02:56:05 UTC
(
hide
)
Description:
IPC key_t space separation between jails (fix)
Filename:
MIME Type:
Creator:
kikuchan98
Created:
2015-06-12 02:56:05 UTC
Size:
24.40 KB
patch
obsolete
>diff --git a/sys/kern/kern_jail.c b/sys/kern/kern_jail.c >index e9c71ca..cf63196 100644 >--- a/sys/kern/kern_jail.c >+++ b/sys/kern/kern_jail.c >@@ -60,6 +60,7 @@ __FBSDID("$FreeBSD$"); > #include <sys/syscallsubr.h> > #include <sys/sysctl.h> > #include <sys/vnode.h> >+#include <sys/ipc.h> > > #include <net/if.h> > #include <net/vnet.h> >@@ -2330,6 +2331,9 @@ prison_remove_one(struct prison *pr) > pr->pr_flags &= ~PR_PERSIST; > } > >+ /* SysV IPC cleanup for the prison */ >+ ipc_cleanup_for_prison(pr); >+ > /* > * jail_remove added a reference. If that's the only one, remove > * the prison now. >diff --git a/sys/kern/sysv_ipc.c b/sys/kern/sysv_ipc.c >index e402cb5..9985b87 100644 >--- a/sys/kern/sysv_ipc.c >+++ b/sys/kern/sysv_ipc.c >@@ -47,9 +47,13 @@ __FBSDID("$FreeBSD$"); > #include <sys/priv.h> > #include <sys/proc.h> > #include <sys/ucred.h> >+#include <sys/jail.h> > > void (*shmfork_hook)(struct proc *, struct proc *) = NULL; > void (*shmexit_hook)(struct vmspace *) = NULL; >+void (*sysvshm_cleanup_for_prison_hook)(struct prison *) = NULL; >+void (*sysvmsg_cleanup_for_prison_hook)(struct prison *) = NULL; >+void (*sysvsem_cleanup_for_prison_hook)(struct prison *) = NULL; > > /* called from kern_fork.c */ > void >@@ -72,6 +76,19 @@ shmexit(struct vmspace *vm) > return; > } > >+/* called from kern_jail.c */ >+void >+ipc_cleanup_for_prison(struct prison *pr) >+{ >+ >+ if (sysvshm_cleanup_for_prison_hook != NULL) >+ sysvshm_cleanup_for_prison_hook(pr); >+ if (sysvmsg_cleanup_for_prison_hook != NULL) >+ sysvmsg_cleanup_for_prison_hook(pr); >+ if (sysvsem_cleanup_for_prison_hook != NULL) >+ sysvsem_cleanup_for_prison_hook(pr); >+} >+ > /* > * Check for IPC permission. > * >diff --git a/sys/kern/sysv_msg.c b/sys/kern/sysv_msg.c >index d58cb7e..99edabe 100644 >--- a/sys/kern/sysv_msg.c >+++ b/sys/kern/sysv_msg.c >@@ -68,6 +68,7 @@ __FBSDID("$FreeBSD$"); > #include <sys/syscallsubr.h> > #include <sys/sysent.h> > #include <sys/sysctl.h> >+#include <sys/sbuf.h> > #include <sys/malloc.h> > #include <sys/jail.h> > >@@ -80,6 +81,9 @@ static MALLOC_DEFINE(M_MSG, "msg", "SVID compatible message queues"); > static int msginit(void); > static int msgunload(void); > static int sysvmsg_modload(struct module *, int, void *); >+static int cr_cansee_msq(struct ucred *, struct msqid_kernel *); >+static void msq_remove(struct msqid_kernel *); >+static void sysvmsg_cleanup_for_prison_myhook(struct prison *); > > > #ifdef MSG_DEBUG >@@ -257,6 +261,7 @@ msginit() > #endif > } > mtx_init(&msq_mtx, "msq", NULL, MTX_DEF); >+ sysvmsg_cleanup_for_prison_hook = &sysvmsg_cleanup_for_prison_myhook; > > error = syscall_helper_register(msg_syscalls); > if (error != 0) >@@ -282,6 +287,7 @@ msgunload() > #ifdef COMPAT_FREEBSD32 > syscall32_helper_unregister(msg32_syscalls); > #endif >+ sysvmsg_cleanup_for_prison_hook = NULL; > > for (msqid = 0; msqid < msginfo.msgmni; msqid++) { > /* >@@ -372,6 +378,69 @@ msg_freehdr(msghdr) > #endif > } > >+static int >+cr_cansee_msq(struct ucred *cred, struct msqid_kernel *msqkptr) >+{ >+ >+ if (msqkptr->cred == NULL || prison_check(cred, msqkptr->cred)) >+ return (EINVAL); >+ return (0); >+} >+ >+static void >+msq_remove(struct msqid_kernel *msqkptr) >+{ >+ struct msg *msghdr; >+ >+ racct_sub_cred(msqkptr->cred, RACCT_NMSGQ, 1); >+ racct_sub_cred(msqkptr->cred, RACCT_MSGQQUEUED, msqkptr->u.msg_qnum); >+ racct_sub_cred(msqkptr->cred, RACCT_MSGQSIZE, msqkptr->u.msg_cbytes); >+ crfree(msqkptr->cred); >+ msqkptr->cred = NULL; >+ >+ /* Free the message headers */ >+ msghdr = msqkptr->u.msg_first; >+ while (msghdr != NULL) { >+ struct msg *msghdr_tmp; >+ >+ /* Free the segments of each message */ >+ msqkptr->u.msg_cbytes -= msghdr->msg_ts; >+ msqkptr->u.msg_qnum--; >+ msghdr_tmp = msghdr; >+ msghdr = msghdr->msg_next; >+ msg_freehdr(msghdr_tmp); >+ } >+ >+ if (msqkptr->u.msg_cbytes != 0) >+ panic("msg_cbytes is screwed up"); >+ if (msqkptr->u.msg_qnum != 0) >+ panic("msg_qnum is screwed up"); >+ >+ msqkptr->u.msg_qbytes = 0; /* Mark it as free */ >+ >+#ifdef MAC >+ mac_sysvmsq_cleanup(msqkptr); >+#endif >+ >+ wakeup(msqkptr); >+} >+ >+static void >+sysvmsg_cleanup_for_prison_myhook(struct prison *pr) >+{ >+ int i; >+ struct msqid_kernel *msqkptr; >+ >+ mtx_lock(&msq_mtx); >+ for (i = 0; i < msginfo.msgmni; i++) { >+ msqkptr = &msqids[i]; >+ if (msqkptr->u.msg_qbytes != 0 && >+ msqkptr->cred && msqkptr->cred->cr_prison == pr) >+ msq_remove(msqkptr); >+ } >+ mtx_unlock(&msq_mtx); >+} >+ > #ifndef _SYS_SYSPROTO_H_ > struct msgctl_args { > int msqid; >@@ -433,6 +502,9 @@ kern_msgctl(td, msqid, cmd, msqbuf) > error = EINVAL; > goto done2; > } >+ error = cr_cansee_msq(td->td_ucred, msqkptr); >+ if (error != 0) >+ goto done2; > #ifdef MAC > error = mac_sysvmsq_check_msqctl(td->td_ucred, msqkptr, cmd); > if (error != 0) >@@ -446,7 +518,9 @@ kern_msgctl(td, msqid, cmd, msqbuf) > > case IPC_RMID: > { >+#ifdef MAC > struct msg *msghdr; >+#endif > if ((error = ipcperm(td, &msqkptr->u.msg_perm, IPC_M))) > goto done2; > >@@ -468,37 +542,7 @@ kern_msgctl(td, msqid, cmd, msqbuf) > } > #endif > >- racct_sub_cred(msqkptr->cred, RACCT_NMSGQ, 1); >- racct_sub_cred(msqkptr->cred, RACCT_MSGQQUEUED, msqkptr->u.msg_qnum); >- racct_sub_cred(msqkptr->cred, RACCT_MSGQSIZE, msqkptr->u.msg_cbytes); >- crfree(msqkptr->cred); >- msqkptr->cred = NULL; >- >- /* Free the message headers */ >- msghdr = msqkptr->u.msg_first; >- while (msghdr != NULL) { >- struct msg *msghdr_tmp; >- >- /* Free the segments of each message */ >- msqkptr->u.msg_cbytes -= msghdr->msg_ts; >- msqkptr->u.msg_qnum--; >- msghdr_tmp = msghdr; >- msghdr = msghdr->msg_next; >- msg_freehdr(msghdr_tmp); >- } >- >- if (msqkptr->u.msg_cbytes != 0) >- panic("msg_cbytes is screwed up"); >- if (msqkptr->u.msg_qnum != 0) >- panic("msg_qnum is screwed up"); >- >- msqkptr->u.msg_qbytes = 0; /* Mark it as free */ >- >-#ifdef MAC >- mac_sysvmsq_cleanup(msqkptr); >-#endif >- >- wakeup(msqkptr); >+ msq_remove(msqkptr); > } > > break; >@@ -578,6 +622,7 @@ sys_msgget(td, uap) > for (msqid = 0; msqid < msginfo.msgmni; msqid++) { > msqkptr = &msqids[msqid]; > if (msqkptr->u.msg_qbytes != 0 && >+ msqkptr->cred && msqkptr->cred->cr_prison == cred->cr_prison && > msqkptr->u.msg_perm.key == key) > break; > } >@@ -718,6 +763,8 @@ kern_msgsnd(td, msqid, msgp, msgsz, msgflg, mtype) > goto done2; > } > >+ if ((error = cr_cansee_msq(td->td_ucred, msqkptr))) >+ goto done2; > if ((error = ipcperm(td, &msqkptr->u.msg_perm, IPC_W))) { > DPRINTF(("requester doesn't have write access\n")); > goto done2; >@@ -1081,6 +1128,8 @@ kern_msgrcv(td, msqid, msgp, msgsz, msgtyp, msgflg, mtype) > goto done2; > } > >+ if ((error = cr_cansee_msq(td->td_ucred, msqkptr))) >+ goto done2; > if ((error = ipcperm(td, &msqkptr->u.msg_perm, IPC_R))) { > DPRINTF(("requester doesn't have read access\n")); > goto done2; >@@ -1320,9 +1369,37 @@ sys_msgrcv(td, uap) > static int > sysctl_msqids(SYSCTL_HANDLER_ARGS) > { >+ int error; >+ struct sbuf sb; >+ struct msqid_kernel tmp, empty; >+ int i; >+ >+ error = sysctl_wire_old_buffer(req, 0); >+ if (error != 0) >+ goto done; >+ sbuf_new_for_sysctl(&sb, NULL, sizeof(struct msqid_kernel) * msginfo.msgmni, req); >+ >+ bzero(&empty, sizeof(empty)); >+ for (i = 0; i < msginfo.msgmni; i++) { >+ struct msqid_kernel *msqkptr; >+ >+ msqkptr = &msqids[i]; >+ if (msqkptr->u.msg_qbytes == 0 || >+ cr_cansee_msq(req->td->td_ucred, msqkptr)) { >+ msqkptr = ∅ >+ } else if (req->td->td_ucred->cr_prison != msqkptr->cred->cr_prison) { >+ bcopy(msqkptr, &tmp, sizeof(tmp)); >+ msqkptr = &tmp; >+ msqkptr->u.msg_perm.key = IPC_PRIVATE; >+ } > >- return (SYSCTL_OUT(req, msqids, >- sizeof(struct msqid_kernel) * msginfo.msgmni)); >+ sbuf_bcat(&sb, msqkptr, sizeof(*msqkptr)); >+ } >+ error = sbuf_finish(&sb); >+ sbuf_delete(&sb); >+ >+done: >+ return (error); > } > > SYSCTL_INT(_kern_ipc, OID_AUTO, msgmax, CTLFLAG_RD, &msginfo.msgmax, 0, >diff --git a/sys/kern/sysv_sem.c b/sys/kern/sysv_sem.c >index f9ff217..5b9e1ca 100644 >--- a/sys/kern/sysv_sem.c >+++ b/sys/kern/sysv_sem.c >@@ -57,6 +57,7 @@ __FBSDID("$FreeBSD$"); > #include <sys/syscallsubr.h> > #include <sys/sysent.h> > #include <sys/sysctl.h> >+#include <sys/sbuf.h> > #include <sys/uio.h> > #include <sys/malloc.h> > #include <sys/jail.h> >@@ -79,6 +80,9 @@ static int semunload(void); > static void semexit_myhook(void *arg, struct proc *p); > static int sysctl_sema(SYSCTL_HANDLER_ARGS); > static int semvalid(int semid, struct semid_kernel *semakptr); >+static int cr_cansee_sem(struct ucred *cred, struct semid_kernel *semakptr); >+static void sem_remove(int semidx, struct ucred *cred); >+static void sysvsem_cleanup_for_prison_myhook(struct prison *pr); > > #ifndef _SYS_SYSPROTO_H_ > struct __semctl_args; >@@ -287,6 +291,7 @@ seminit(void) > mtx_init(&sem_undo_mtx, "semu", NULL, MTX_DEF); > semexit_tag = EVENTHANDLER_REGISTER(process_exit, semexit_myhook, NULL, > EVENTHANDLER_PRI_ANY); >+ sysvsem_cleanup_for_prison_hook = &sysvsem_cleanup_for_prison_myhook; > > error = syscall_helper_register(sem_syscalls); > if (error != 0) >@@ -313,6 +318,7 @@ semunload(void) > #endif > syscall_helper_unregister(sem_syscalls); > EVENTHANDLER_DEREGISTER(process_exit, semexit_tag); >+ sysvsem_cleanup_for_prison_hook = NULL; > #ifdef MAC > for (i = 0; i < seminfo.semmni; i++) > mac_sysvsem_destroy(&sema[i]); >@@ -506,6 +512,70 @@ semvalid(int semid, struct semid_kernel *semakptr) > semakptr->u.sem_perm.seq != IPCID_TO_SEQ(semid) ? EINVAL : 0); > } > >+static int >+cr_cansee_sem(struct ucred *cred, struct semid_kernel *semakptr) >+{ >+ >+ if (semakptr->cred == NULL || prison_check(cred, semakptr->cred)) >+ return (EINVAL); >+ return (0); >+} >+ >+static void >+sem_remove(int semidx, struct ucred *cred) >+{ >+ int i; >+ struct semid_kernel *semakptr; >+ >+ KASSERT(semidx >= 0 && semidx < seminfo.semmni, ("semidx out of bounds")); >+ semakptr = &sema[semidx]; >+ semakptr->u.sem_perm.cuid = cred ? cred->cr_uid : 0; >+ semakptr->u.sem_perm.uid = cred ? cred->cr_uid : 0; >+ semakptr->u.sem_perm.mode = 0; >+ racct_sub_cred(semakptr->cred, RACCT_NSEM, semakptr->u.sem_nsems); >+ crfree(semakptr->cred); >+ semakptr->cred = NULL; >+ SEMUNDO_LOCK(); >+ semundo_clear(semidx, -1); >+ SEMUNDO_UNLOCK(); >+#ifdef MAC >+ mac_sysvsem_cleanup(semakptr); >+#endif >+ wakeup(semakptr); >+ for (i = 0; i < seminfo.semmni; i++) { >+ if ((sema[i].u.sem_perm.mode & SEM_ALLOC) && >+ sema[i].u.sem_base > semakptr->u.sem_base) >+ mtx_lock_flags(&sema_mtx[i], LOP_DUPOK); >+ } >+ for (i = semakptr->u.sem_base - sem; i < semtot; i++) >+ sem[i] = sem[i + semakptr->u.sem_nsems]; >+ for (i = 0; i < seminfo.semmni; i++) { >+ if ((sema[i].u.sem_perm.mode & SEM_ALLOC) && >+ sema[i].u.sem_base > semakptr->u.sem_base) { >+ sema[i].u.sem_base -= semakptr->u.sem_nsems; >+ mtx_unlock(&sema_mtx[i]); >+ } >+ } >+ semtot -= semakptr->u.sem_nsems; >+} >+ >+static void >+sysvsem_cleanup_for_prison_myhook(struct prison *pr) >+{ >+ int i; >+ >+ mtx_lock(&sem_mtx); >+ for (i = 0; i < seminfo.semmni; i++) { >+ if ((sema[i].u.sem_perm.mode & SEM_ALLOC) && >+ sema[i].cred && sema[i].cred->cr_prison == pr) { >+ mtx_lock(&sema_mtx[i]); >+ sem_remove(i, NULL); >+ mtx_unlock(&sema_mtx[i]); >+ } >+ } >+ mtx_unlock(&sem_mtx); >+} >+ > /* > * Note that the user-mode half of this passes a union, not a pointer. > */ >@@ -610,6 +680,8 @@ kern_semctl(struct thread *td, int semid, int semnum, int cmd, > error = EINVAL; > goto done2; > } >+ if ((error = cr_cansee_sem(td->td_ucred, semakptr)) != 0) >+ goto done2; > if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) > goto done2; > #ifdef MAC >@@ -632,6 +704,7 @@ kern_semctl(struct thread *td, int semid, int semnum, int cmd, > if (cmd == IPC_RMID) > mtx_lock(&sem_mtx); > mtx_lock(sema_mtxp); >+ > #ifdef MAC > error = mac_sysvsem_check_semctl(cred, semakptr, cmd); > if (error != 0) >@@ -645,41 +718,18 @@ kern_semctl(struct thread *td, int semid, int semnum, int cmd, > case IPC_RMID: > if ((error = semvalid(semid, semakptr)) != 0) > goto done2; >+ if ((error = cr_cansee_sem(td->td_ucred, semakptr)) != 0) >+ goto done2; > if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_M))) > goto done2; >- semakptr->u.sem_perm.cuid = cred->cr_uid; >- semakptr->u.sem_perm.uid = cred->cr_uid; >- semakptr->u.sem_perm.mode = 0; >- racct_sub_cred(semakptr->cred, RACCT_NSEM, semakptr->u.sem_nsems); >- crfree(semakptr->cred); >- semakptr->cred = NULL; >- SEMUNDO_LOCK(); >- semundo_clear(semidx, -1); >- SEMUNDO_UNLOCK(); >-#ifdef MAC >- mac_sysvsem_cleanup(semakptr); >-#endif >- wakeup(semakptr); >- for (i = 0; i < seminfo.semmni; i++) { >- if ((sema[i].u.sem_perm.mode & SEM_ALLOC) && >- sema[i].u.sem_base > semakptr->u.sem_base) >- mtx_lock_flags(&sema_mtx[i], LOP_DUPOK); >- } >- for (i = semakptr->u.sem_base - sem; i < semtot; i++) >- sem[i] = sem[i + semakptr->u.sem_nsems]; >- for (i = 0; i < seminfo.semmni; i++) { >- if ((sema[i].u.sem_perm.mode & SEM_ALLOC) && >- sema[i].u.sem_base > semakptr->u.sem_base) { >- sema[i].u.sem_base -= semakptr->u.sem_nsems; >- mtx_unlock(&sema_mtx[i]); >- } >- } >- semtot -= semakptr->u.sem_nsems; >+ sem_remove(semidx, cred); > break; > > case IPC_SET: > if ((error = semvalid(semid, semakptr)) != 0) > goto done2; >+ if ((error = cr_cansee_sem(td->td_ucred, semakptr)) != 0) >+ goto done2; > if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_M))) > goto done2; > sbuf = arg->buf; >@@ -693,6 +743,8 @@ kern_semctl(struct thread *td, int semid, int semnum, int cmd, > case IPC_STAT: > if ((error = semvalid(semid, semakptr)) != 0) > goto done2; >+ if ((error = cr_cansee_sem(td->td_ucred, semakptr)) != 0) >+ goto done2; > if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) > goto done2; > bcopy(&semakptr->u, arg->buf, sizeof(struct semid_ds)); >@@ -701,6 +753,8 @@ kern_semctl(struct thread *td, int semid, int semnum, int cmd, > case GETNCNT: > if ((error = semvalid(semid, semakptr)) != 0) > goto done2; >+ if ((error = cr_cansee_sem(td->td_ucred, semakptr)) != 0) >+ goto done2; > if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) > goto done2; > if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { >@@ -713,6 +767,8 @@ kern_semctl(struct thread *td, int semid, int semnum, int cmd, > case GETPID: > if ((error = semvalid(semid, semakptr)) != 0) > goto done2; >+ if ((error = cr_cansee_sem(td->td_ucred, semakptr)) != 0) >+ goto done2; > if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) > goto done2; > if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { >@@ -725,6 +781,8 @@ kern_semctl(struct thread *td, int semid, int semnum, int cmd, > case GETVAL: > if ((error = semvalid(semid, semakptr)) != 0) > goto done2; >+ if ((error = cr_cansee_sem(td->td_ucred, semakptr)) != 0) >+ goto done2; > if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) > goto done2; > if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { >@@ -762,6 +820,8 @@ kern_semctl(struct thread *td, int semid, int semnum, int cmd, > if ((error = semvalid(semid, semakptr)) != 0) > goto done2; > KASSERT(count == semakptr->u.sem_nsems, ("nsems changed")); >+ if ((error = cr_cansee_sem(td->td_ucred, semakptr)) != 0) >+ goto done2; > if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) > goto done2; > for (i = 0; i < semakptr->u.sem_nsems; i++) >@@ -774,6 +834,8 @@ kern_semctl(struct thread *td, int semid, int semnum, int cmd, > case GETZCNT: > if ((error = semvalid(semid, semakptr)) != 0) > goto done2; >+ if ((error = cr_cansee_sem(td->td_ucred, semakptr)) != 0) >+ goto done2; > if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R))) > goto done2; > if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { >@@ -786,6 +848,8 @@ kern_semctl(struct thread *td, int semid, int semnum, int cmd, > case SETVAL: > if ((error = semvalid(semid, semakptr)) != 0) > goto done2; >+ if ((error = cr_cansee_sem(td->td_ucred, semakptr)) != 0) >+ goto done2; > if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_W))) > goto done2; > if (semnum < 0 || semnum >= semakptr->u.sem_nsems) { >@@ -818,6 +882,8 @@ kern_semctl(struct thread *td, int semid, int semnum, int cmd, > if ((error = semvalid(semid, semakptr)) != 0) > goto done2; > KASSERT(count == semakptr->u.sem_nsems, ("nsems changed")); >+ if ((error = cr_cansee_sem(td->td_ucred, semakptr)) != 0) >+ goto done2; > if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_W))) > goto done2; > for (i = 0; i < semakptr->u.sem_nsems; i++) { >@@ -872,6 +938,7 @@ sys_semget(struct thread *td, struct semget_args *uap) > if (key != IPC_PRIVATE) { > for (semid = 0; semid < seminfo.semmni; semid++) { > if ((sema[semid].u.sem_perm.mode & SEM_ALLOC) && >+ sema[semid].cred && sema[semid].cred->cr_prison == cred->cr_prison && > sema[semid].u.sem_perm.key == key) > break; > } >@@ -1049,6 +1116,8 @@ sys_semop(struct thread *td, struct semop_args *uap) > error = EINVAL; > goto done2; > } >+ if ((error = cr_cansee_sem(td->td_ucred, semakptr)) != 0) >+ goto done2; > /* > * Initial pass thru sops to see what permissions are needed. > * Also perform any checks that don't need repeating on each >@@ -1372,9 +1441,37 @@ semexit_myhook(void *arg, struct proc *p) > static int > sysctl_sema(SYSCTL_HANDLER_ARGS) > { >+ int error; >+ struct sbuf sb; >+ struct semid_kernel tmp, empty; >+ int i; >+ >+ error = sysctl_wire_old_buffer(req, 0); >+ if (error != 0) >+ goto done; >+ sbuf_new_for_sysctl(&sb, NULL, sizeof(struct semid_kernel) * seminfo.semmni, req); > >- return (SYSCTL_OUT(req, sema, >- sizeof(struct semid_kernel) * seminfo.semmni)); >+ bzero(&empty, sizeof(empty)); >+ for (i = 0; i < seminfo.semmni; i++) { >+ struct semid_kernel *semakptr; >+ >+ semakptr = &sema[i]; >+ if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0 || >+ cr_cansee_sem(req->td->td_ucred, semakptr)) { >+ semakptr = ∅ >+ } else if (req->td->td_ucred->cr_prison != semakptr->cred->cr_prison) { >+ bcopy(semakptr, &tmp, sizeof(tmp)); >+ semakptr = &tmp; >+ semakptr->u.sem_perm.key = IPC_PRIVATE; >+ } >+ >+ sbuf_bcat(&sb, semakptr, sizeof(*semakptr)); >+ } >+ error = sbuf_finish(&sb); >+ sbuf_delete(&sb); >+ >+done: >+ return (error); > } > > #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ >diff --git a/sys/kern/sysv_shm.c b/sys/kern/sysv_shm.c >index 66a2a43..52760cf 100644 >--- a/sys/kern/sysv_shm.c >+++ b/sys/kern/sysv_shm.c >@@ -86,6 +86,7 @@ __FBSDID("$FreeBSD$"); > #include <sys/sysent.h> > #include <sys/sysproto.h> > #include <sys/jail.h> >+#include <sys/sbuf.h> > > #include <security/mac/mac_framework.h> > >@@ -120,7 +121,7 @@ struct shmmap_state { > }; > > static void shm_deallocate_segment(struct shmid_kernel *); >-static int shm_find_segment_by_key(key_t); >+static int shm_find_segment_by_key(struct prison *, key_t); > static struct shmid_kernel *shm_find_segment(int, bool); > static int shm_delete_mapping(struct vmspace *vm, struct shmmap_state *); > static void shmrealloc(void); >@@ -130,6 +131,9 @@ static int shmunload(void); > static void shmexit_myhook(struct vmspace *vm); > static void shmfork_myhook(struct proc *p1, struct proc *p2); > static int sysctl_shmsegs(SYSCTL_HANDLER_ARGS); >+static int cr_cansee_shm(struct ucred *, struct shmid_kernel *); >+static void shm_remove(struct shmid_kernel *, int); >+static void sysvshm_cleanup_for_prison_myhook(struct prison *); > > /* > * Tuneable values. >@@ -189,12 +193,13 @@ static struct sx sysvshmsx; > #define SYSVSHM_ASSERT_LOCKED() sx_assert(&sysvshmsx, SA_XLOCKED) > > static int >-shm_find_segment_by_key(key_t key) >+shm_find_segment_by_key(struct prison *pr, key_t key) > { > int i; > > for (i = 0; i < shmalloced; i++) > if ((shmsegs[i].u.shm_perm.mode & SHMSEG_ALLOCATED) && >+ shmsegs[i].cred && shmsegs[i].cred->cr_prison == pr && > shmsegs[i].u.shm_perm.key == key) > return (i); > return (-1); >@@ -272,6 +277,45 @@ shm_delete_mapping(struct vmspace *vm, struct shmmap_state *shmmap_s) > } > > static int >+cr_cansee_shm(struct ucred *cred, struct shmid_kernel *shmseg) >+{ >+ >+ if (shmseg->cred == NULL || prison_check(cred, shmseg->cred)) >+ return (EINVAL); >+ return (0); >+} >+ >+static void >+shm_remove(struct shmid_kernel *shmseg, int segnum) >+{ >+ >+ shmseg->u.shm_perm.key = IPC_PRIVATE; >+ shmseg->u.shm_perm.mode |= SHMSEG_REMOVED; >+ if (shmseg->u.shm_nattch <= 0) { >+ shm_deallocate_segment(shmseg); >+ shm_last_free = segnum; >+ } >+} >+ >+static void >+sysvshm_cleanup_for_prison_myhook(struct prison *pr) >+{ >+ int i; >+ >+ SYSVSHM_LOCK(); >+ for (i = 0; i < shmalloced; i++) { >+ struct shmid_kernel *shmseg; >+ >+ shmseg = &shmsegs[i]; >+ if ((shmseg->u.shm_perm.mode & SHMSEG_ALLOCATED) && >+ shmseg->cred->cr_prison == pr) { >+ shm_remove(shmseg, i); >+ } >+ } >+ SYSVSHM_UNLOCK(); >+} >+ >+static int > kern_shmdt_locked(struct thread *td, const void *shmaddr) > { > struct proc *p = td->td_proc; >@@ -348,6 +392,9 @@ kern_shmat_locked(struct thread *td, int shmid, const void *shmaddr, > shmseg = shm_find_segment(shmid, true); > if (shmseg == NULL) > return (EINVAL); >+ error = cr_cansee_shm(td->td_ucred, shmseg); >+ if (error != 0) >+ return (error); > error = ipcperm(td, &shmseg->u.shm_perm, > (shmflg & SHM_RDONLY) ? IPC_R : IPC_R|IPC_W); > if (error != 0) >@@ -477,6 +524,9 @@ kern_shmctl_locked(struct thread *td, int shmid, int cmd, void *buf, > shmseg = shm_find_segment(shmid, cmd != SHM_STAT); > if (shmseg == NULL) > return (EINVAL); >+ error = cr_cansee_shm(td->td_ucred, shmseg); >+ if (error != 0) >+ return (error); > #ifdef MAC > error = mac_sysvshm_check_shmctl(td->td_ucred, shmseg, cmd); > if (error != 0) >@@ -512,12 +562,8 @@ kern_shmctl_locked(struct thread *td, int shmid, int cmd, void *buf, > error = ipcperm(td, &shmseg->u.shm_perm, IPC_M); > if (error != 0) > return (error); >- shmseg->u.shm_perm.key = IPC_PRIVATE; >- shmseg->u.shm_perm.mode |= SHMSEG_REMOVED; >- if (shmseg->u.shm_nattch <= 0) { >- shm_deallocate_segment(shmseg); >- shm_last_free = IPCID_TO_IX(shmid); >- } >+ >+ shm_remove(shmseg, IPCID_TO_IX(shmid)); > break; > #if 0 > case SHM_LOCK: >@@ -727,7 +773,7 @@ sys_shmget(struct thread *td, struct shmget_args *uap) > if (uap->key == IPC_PRIVATE) { > error = shmget_allocate_segment(td, uap, mode); > } else { >- segnum = shm_find_segment_by_key(uap->key); >+ segnum = shm_find_segment_by_key(td->td_ucred->cr_prison, uap->key); > if (segnum >= 0) > error = shmget_existing(td, uap, mode, segnum); > else if ((uap->shmflg & IPC_CREAT) == 0) >@@ -883,6 +929,7 @@ shminit(void) > sx_init(&sysvshmsx, "sysvshmsx"); > shmexit_hook = &shmexit_myhook; > shmfork_hook = &shmfork_myhook; >+ sysvshm_cleanup_for_prison_hook = &sysvshm_cleanup_for_prison_myhook; > > error = syscall_helper_register(shm_syscalls); > if (error != 0) >@@ -923,6 +970,7 @@ shmunload(void) > free(shmsegs, M_SHM); > shmexit_hook = NULL; > shmfork_hook = NULL; >+ sysvshm_cleanup_for_prison_hook = NULL; > sx_destroy(&sysvshmsx); > return (0); > } >@@ -931,9 +979,38 @@ static int > sysctl_shmsegs(SYSCTL_HANDLER_ARGS) > { > int error; >+ struct sbuf sb; >+ struct shmid_kernel tmp, empty; >+ int i; > > SYSVSHM_LOCK(); >- error = SYSCTL_OUT(req, shmsegs, shmalloced * sizeof(shmsegs[0])); >+ >+ error = sysctl_wire_old_buffer(req, 0); >+ if (error != 0) >+ goto done; >+ sbuf_new_for_sysctl(&sb, NULL, shmalloced * sizeof(shmsegs[0]), req); >+ >+ bzero(&empty, sizeof(empty)); >+ empty.u.shm_perm.mode = SHMSEG_FREE; >+ for (i = 0; i < shmalloced; i++) { >+ struct shmid_kernel *shmseg; >+ >+ shmseg = &shmsegs[i]; >+ if ((shmseg->u.shm_perm.mode & SHMSEG_ALLOCATED) == 0 || >+ cr_cansee_shm(req->td->td_ucred, &shmsegs[i])) { >+ shmseg = ∅ >+ } else if (req->td->td_ucred->cr_prison != shmseg->cred->cr_prison) { >+ bcopy(shmseg, &tmp, sizeof(tmp)); >+ shmseg = &tmp; >+ shmseg->u.shm_perm.key = IPC_PRIVATE; >+ } >+ >+ sbuf_bcat(&sb, shmseg, sizeof(*shmseg)); >+ } >+ error = sbuf_finish(&sb); >+ sbuf_delete(&sb); >+ >+done: > SYSVSHM_UNLOCK(); > return (error); > } >@@ -977,6 +1054,11 @@ oshmctl(struct thread *td, struct oshmctl_args *uap) > SYSVSHM_UNLOCK(); > return (EINVAL); > } >+ error = cr_cansee_shm(td->td_ucred, shmseg); >+ if (error != 0) { >+ SYSVSHM_UNLOCK(); >+ return (error); >+ } > error = ipcperm(td, &shmseg->u.shm_perm, IPC_R); > if (error != 0) { > SYSVSHM_UNLOCK(); >diff --git a/sys/sys/ipc.h b/sys/sys/ipc.h >index e643d48..88b5f14 100644 >--- a/sys/sys/ipc.h >+++ b/sys/sys/ipc.h >@@ -126,6 +126,7 @@ struct ipc_perm { > struct thread; > struct proc; > struct vmspace; >+struct prison; > > #if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \ > defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7) >@@ -133,9 +134,13 @@ void ipcperm_old2new(struct ipc_perm_old *, struct ipc_perm *); > void ipcperm_new2old(struct ipc_perm *, struct ipc_perm_old *); > #endif > >+void ipc_cleanup_for_prison(struct prison *); > int ipcperm(struct thread *, struct ipc_perm *, int); > extern void (*shmfork_hook)(struct proc *, struct proc *); > extern void (*shmexit_hook)(struct vmspace *); >+extern void (*sysvshm_cleanup_for_prison_hook)(struct prison *); >+extern void (*sysvmsg_cleanup_for_prison_hook)(struct prison *); >+extern void (*sysvsem_cleanup_for_prison_hook)(struct prison *); > > #else /* ! _KERNEL */ >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 48471
:
28925
|
28926
|
157658
| 157661 |
169450
|
169452
|
169480