Skip to content

Instantly share code, notes, and snippets.

@kikuchan
Created June 3, 2015 18:37
Show Gist options
  • Save kikuchan/c7b645e1c0c7f7b7c1b0 to your computer and use it in GitHub Desktop.
Save kikuchan/c7b645e1c0c7f7b7c1b0 to your computer and use it in GitHub Desktop.
A patch to run multiple (version of, if you want, ) PostgreSQL (with same uid) simultaneously on FreeBSD jail. (Change sysv_sem/shm policy to per jail basis)
diff --git a/kern/sysv_sem.c b/kern/sysv_sem.c
index 53b63e0..25fe343 100644
--- a/kern/sysv_sem.c
+++ b/kern/sysv_sem.c
@@ -506,6 +506,17 @@ semvalid(int semid, struct semid_kernel *semakptr)
semakptr->u.sem_perm.seq != IPCID_TO_SEQ(semid) ? EINVAL : 0);
}
+static int
+jail_check_semperm(td, semakptr)
+ struct thread *td;
+ struct semid_kernel *semakptr;
+{
+ if (semakptr->cred->cr_prison != td->td_ucred->cr_prison)
+ return EACCES;
+ return 0;
+}
+
+
/*
* Note that the user-mode half of this passes a union, not a pointer.
*/
@@ -612,6 +623,8 @@ kern_semctl(struct thread *td, int semid, int semnum, int cmd,
}
if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R)))
goto done2;
+ if ((error = jail_check_semperm(td, semakptr)))
+ goto done2;
#ifdef MAC
error = mac_sysvsem_check_semctl(cred, semakptr, cmd);
if (error != 0)
@@ -647,6 +660,8 @@ kern_semctl(struct thread *td, int semid, int semnum, int cmd,
goto done2;
if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_M)))
goto done2;
+ if ((error = jail_check_semperm(td, semakptr)))
+ goto done2;
semakptr->u.sem_perm.cuid = cred->cr_uid;
semakptr->u.sem_perm.uid = cred->cr_uid;
semakptr->u.sem_perm.mode = 0;
@@ -682,6 +697,8 @@ kern_semctl(struct thread *td, int semid, int semnum, int cmd,
goto done2;
if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_M)))
goto done2;
+ if ((error = jail_check_semperm(td, semakptr)))
+ goto done2;
sbuf = arg->buf;
semakptr->u.sem_perm.uid = sbuf->sem_perm.uid;
semakptr->u.sem_perm.gid = sbuf->sem_perm.gid;
@@ -695,6 +712,8 @@ kern_semctl(struct thread *td, int semid, int semnum, int cmd,
goto done2;
if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R)))
goto done2;
+ if ((error = jail_check_semperm(td, semakptr)))
+ goto done2;
bcopy(&semakptr->u, arg->buf, sizeof(struct semid_ds));
break;
@@ -703,6 +722,8 @@ kern_semctl(struct thread *td, int semid, int semnum, int cmd,
goto done2;
if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R)))
goto done2;
+ if ((error = jail_check_semperm(td, semakptr)))
+ goto done2;
if (semnum < 0 || semnum >= semakptr->u.sem_nsems) {
error = EINVAL;
goto done2;
@@ -715,6 +736,8 @@ kern_semctl(struct thread *td, int semid, int semnum, int cmd,
goto done2;
if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R)))
goto done2;
+ if ((error = jail_check_semperm(td, semakptr)))
+ goto done2;
if (semnum < 0 || semnum >= semakptr->u.sem_nsems) {
error = EINVAL;
goto done2;
@@ -727,6 +750,8 @@ kern_semctl(struct thread *td, int semid, int semnum, int cmd,
goto done2;
if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R)))
goto done2;
+ if ((error = jail_check_semperm(td, semakptr)))
+ goto done2;
if (semnum < 0 || semnum >= semakptr->u.sem_nsems) {
error = EINVAL;
goto done2;
@@ -764,6 +789,8 @@ kern_semctl(struct thread *td, int semid, int semnum, int cmd,
KASSERT(count == semakptr->u.sem_nsems, ("nsems changed"));
if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R)))
goto done2;
+ if ((error = jail_check_semperm(td, semakptr)))
+ goto done2;
for (i = 0; i < semakptr->u.sem_nsems; i++)
array[i] = semakptr->u.sem_base[i].semval;
mtx_unlock(sema_mtxp);
@@ -776,6 +803,8 @@ kern_semctl(struct thread *td, int semid, int semnum, int cmd,
goto done2;
if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R)))
goto done2;
+ if ((error = jail_check_semperm(td, semakptr)))
+ goto done2;
if (semnum < 0 || semnum >= semakptr->u.sem_nsems) {
error = EINVAL;
goto done2;
@@ -788,6 +817,8 @@ kern_semctl(struct thread *td, int semid, int semnum, int cmd,
goto done2;
if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_W)))
goto done2;
+ if ((error = jail_check_semperm(td, semakptr)))
+ goto done2;
if (semnum < 0 || semnum >= semakptr->u.sem_nsems) {
error = EINVAL;
goto done2;
@@ -820,6 +851,8 @@ kern_semctl(struct thread *td, int semid, int semnum, int cmd,
KASSERT(count == semakptr->u.sem_nsems, ("nsems changed"));
if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_W)))
goto done2;
+ if ((error = jail_check_semperm(td, semakptr)))
+ goto done2;
for (i = 0; i < semakptr->u.sem_nsems; i++) {
usval = array[i];
if (usval > seminfo.semvmx) {
@@ -872,7 +905,8 @@ 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].u.sem_perm.key == key)
+ sema[semid].u.sem_perm.key == key &&
+ sema[semid].cred->cr_prison == cred->cr_prison)
break;
}
if (semid < seminfo.semmni) {
@@ -1049,6 +1083,8 @@ sys_semop(struct thread *td, struct semop_args *uap)
error = EINVAL;
goto done2;
}
+ if ((error = jail_check_semperm(td, semakptr)))
+ goto done2;
/*
* Initial pass thru sops to see what permissions are needed.
* Also perform any checks that don't need repeating on each
diff --git a/kern/sysv_shm.c b/kern/sysv_shm.c
index 9a111d7..e663462 100644
--- a/kern/sysv_shm.c
+++ b/kern/sysv_shm.c
@@ -121,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(key_t, struct ucred *);
static struct shmid_kernel *shm_find_segment_by_shmid(int);
static struct shmid_kernel *shm_find_segment_by_shmidx(int);
static int shm_delete_mapping(struct vmspace *vm, struct shmmap_state *);
@@ -186,14 +186,26 @@ SYSCTL_PROC(_kern_ipc, OID_AUTO, shmsegs, CTLTYPE_OPAQUE | CTLFLAG_RD,
"Current number of shared memory segments allocated");
static int
-shm_find_segment_by_key(key)
+jail_check_shmctl(td, shmseg)
+ struct thread *td;
+ struct shmid_kernel *shmseg;
+{
+ if (shmseg->cred->cr_prison != td->td_ucred->cr_prison)
+ return EACCES;
+ return 0;
+}
+
+static int
+shm_find_segment_by_key(key, cred)
key_t key;
+ struct ucred *cred;
{
int i;
for (i = 0; i < shmalloced; i++)
if ((shmsegs[i].u.shm_perm.mode & SHMSEG_ALLOCATED) &&
- shmsegs[i].u.shm_perm.key == key)
+ shmsegs[i].u.shm_perm.key == key &&
+ shmsegs[i].cred->cr_prison == cred->cr_prison)
return (i);
return (-1);
}
@@ -369,6 +381,7 @@ kern_shmat(td, shmid, shmaddr, shmflg)
}
error = ipcperm(td, &shmseg->u.shm_perm,
(shmflg & SHM_RDONLY) ? IPC_R : IPC_R|IPC_W);
+ if (!error) error = jail_check_shmctl(td, shmseg);
if (error)
goto done2;
#ifdef MAC
@@ -503,6 +516,7 @@ kern_shmctl(td, shmid, cmd, buf, bufsz)
case SHM_STAT:
case IPC_STAT:
error = ipcperm(td, &shmseg->u.shm_perm, IPC_R);
+ if (!error) error = jail_check_shmctl(td, shmseg);
if (error)
goto done2;
memcpy(buf, &shmseg->u, sizeof(struct shmid_ds));
@@ -516,6 +530,7 @@ kern_shmctl(td, shmid, cmd, buf, bufsz)
shmid = (struct shmid_ds *)buf;
error = ipcperm(td, &shmseg->u.shm_perm, IPC_M);
+ if (!error) error = jail_check_shmctl(td, shmseg);
if (error)
goto done2;
shmseg->u.shm_perm.uid = shmid->shm_perm.uid;
@@ -528,6 +543,7 @@ kern_shmctl(td, shmid, cmd, buf, bufsz)
}
case IPC_RMID:
error = ipcperm(td, &shmseg->u.shm_perm, IPC_M);
+ if (!error) error = jail_check_shmctl(td, shmseg);
if (error)
goto done2;
shmseg->u.shm_perm.key = IPC_PRIVATE;
@@ -762,7 +778,7 @@ sys_shmget(td, uap)
mode = uap->shmflg & ACCESSPERMS;
if (uap->key != IPC_PRIVATE) {
again:
- segnum = shm_find_segment_by_key(uap->key);
+ segnum = shm_find_segment_by_key(uap->key, td->td_ucred);
if (segnum >= 0) {
error = shmget_existing(td, uap, mode, segnum);
if (error == EAGAIN)
@@ -1005,6 +1021,7 @@ oshmctl(struct thread *td, struct oshmctl_args *uap)
switch (uap->cmd) {
case IPC_STAT:
error = ipcperm(td, &shmseg->u.shm_perm, IPC_R);
+ if (!error) error = jail_check_shmctl(td, shmseg);
if (error)
goto done2;
#ifdef MAC
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment