Change the semantics of sysv shm emulation to take a additional
argument to the functions shm{at,ctl}1 and shm_find_segment_by_shmid{x}. The BSD semantics didn't allow the usage of shared segment after being marked for removal through IPC_RMID. The patch involves the following functions: - shmat - shmctl - shm_find_segment_by_shmid - shm_find_segment_by_shmidx - linux_shmat - linux_shmctl Submitted by: Orlando Bassotto <orlando.bassotto@ieo-research.it> Reviewed by: marcel
This commit is contained in:
parent
824eb9dc1b
commit
f130dcf22a
@ -30,6 +30,7 @@
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/syscallsubr.h>
|
||||
#include <sys/sysproto.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/limits.h>
|
||||
@ -703,81 +704,93 @@ linux_shmctl(struct thread *td, struct linux_shmctl_args *args)
|
||||
struct l_shmid_ds linux_shmid;
|
||||
struct l_shminfo linux_shminfo;
|
||||
struct l_shm_info linux_shm_info;
|
||||
struct shmctl_args /* {
|
||||
int shmid;
|
||||
int cmd;
|
||||
struct shmid_ds *buf;
|
||||
} */ bsd_args;
|
||||
struct shmid_ds bsd_shmid;
|
||||
size_t bufsz;
|
||||
int error;
|
||||
caddr_t sg = stackgap_init();
|
||||
|
||||
switch (args->cmd & ~LINUX_IPC_64) {
|
||||
|
||||
case LINUX_IPC_INFO:
|
||||
bsd_args.shmid = args->shmid;
|
||||
bsd_args.cmd = IPC_INFO;
|
||||
bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shminfo));
|
||||
if ((error = shmctl(td, &bsd_args)))
|
||||
case LINUX_IPC_INFO: {
|
||||
struct shminfo bsd_shminfo;
|
||||
|
||||
/* Perform shmctl wanting removed segments lookup */
|
||||
error = kern_shmctl(td, args->shmid, IPC_INFO,
|
||||
(void *)&bsd_shminfo, &bufsz, 1);
|
||||
if (error)
|
||||
return error;
|
||||
bsd_to_linux_shminfo( (struct shminfo *)bsd_args.buf, &linux_shminfo );
|
||||
return (linux_shminfo_pushdown(args->cmd & LINUX_IPC_64,
|
||||
&linux_shminfo, (caddr_t)args->buf));
|
||||
|
||||
bsd_to_linux_shminfo(&bsd_shminfo, &linux_shminfo);
|
||||
|
||||
case LINUX_SHM_INFO:
|
||||
bsd_args.shmid = args->shmid;
|
||||
bsd_args.cmd = SHM_INFO;
|
||||
bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shm_info));
|
||||
if ((error = shmctl(td, &bsd_args)))
|
||||
return error;
|
||||
bsd_to_linux_shm_info( (struct shm_info *)bsd_args.buf, &linux_shm_info );
|
||||
return copyout(&linux_shm_info, (caddr_t)args->buf, sizeof(struct shm_info));
|
||||
|
||||
case LINUX_IPC_STAT:
|
||||
bsd_args.shmid = args->shmid;
|
||||
bsd_args.cmd = IPC_STAT;
|
||||
bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds));
|
||||
if ((error = shmctl(td, &bsd_args)))
|
||||
return error;
|
||||
bsd_to_linux_shmid_ds(bsd_args.buf, &linux_shmid);
|
||||
return (linux_shmid_pushdown(args->cmd & LINUX_IPC_64,
|
||||
&linux_shmid, (caddr_t)args->buf));
|
||||
|
||||
case LINUX_SHM_STAT:
|
||||
bsd_args.shmid = args->shmid;
|
||||
bsd_args.cmd = SHM_STAT;
|
||||
bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds));
|
||||
if ((error = shmctl(td, &bsd_args))) {
|
||||
return error;
|
||||
return (linux_shminfo_pushdown(args->cmd & LINUX_IPC_64,
|
||||
&linux_shminfo, (caddr_t)args->buf));
|
||||
}
|
||||
bsd_to_linux_shmid_ds(bsd_args.buf, &linux_shmid);
|
||||
return (linux_shmid_pushdown(args->cmd & LINUX_IPC_64,
|
||||
|
||||
case LINUX_SHM_INFO: {
|
||||
struct shm_info bsd_shm_info;
|
||||
|
||||
/* Perform shmctl wanting removed segments lookup */
|
||||
error = kern_shmctl(td, args->shmid, SHM_INFO,
|
||||
(void *)&bsd_shm_info, &bufsz, 1);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
bsd_to_linux_shm_info(&bsd_shm_info, &linux_shm_info);
|
||||
|
||||
return copyout(&linux_shm_info, (caddr_t)args->buf,
|
||||
sizeof(struct l_shm_info));
|
||||
}
|
||||
|
||||
case LINUX_IPC_STAT:
|
||||
/* Perform shmctl wanting removed segments lookup */
|
||||
error = kern_shmctl(td, args->shmid, IPC_STAT,
|
||||
(void *)&bsd_shmid, &bufsz, 1);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
bsd_to_linux_shmid_ds(&bsd_shmid, &linux_shmid);
|
||||
|
||||
return (linux_shmid_pushdown(args->cmd & LINUX_IPC_64,
|
||||
&linux_shmid, (caddr_t)args->buf));
|
||||
|
||||
case LINUX_SHM_STAT:
|
||||
/* Perform shmctl wanting removed segments lookup */
|
||||
error = kern_shmctl(td, args->shmid, IPC_STAT,
|
||||
(void *)&bsd_shmid, &bufsz, 1);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
bsd_to_linux_shmid_ds(&bsd_shmid, &linux_shmid);
|
||||
|
||||
return (linux_shmid_pushdown(args->cmd & LINUX_IPC_64,
|
||||
&linux_shmid, (caddr_t)args->buf));
|
||||
|
||||
case LINUX_IPC_SET:
|
||||
error = linux_shmid_pullup(args->cmd & LINUX_IPC_64,
|
||||
&linux_shmid, (caddr_t)args->buf);
|
||||
if (error != 0)
|
||||
return error;
|
||||
bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds));
|
||||
linux_to_bsd_shmid_ds(&linux_shmid, bsd_args.buf);
|
||||
bsd_args.shmid = args->shmid;
|
||||
bsd_args.cmd = IPC_SET;
|
||||
return shmctl(td, &bsd_args);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
case LINUX_IPC_RMID:
|
||||
bsd_args.shmid = args->shmid;
|
||||
bsd_args.cmd = IPC_RMID;
|
||||
linux_to_bsd_shmid_ds(&linux_shmid, &bsd_shmid);
|
||||
|
||||
/* Perform shmctl wanting removed segments lookup */
|
||||
return kern_shmctl(td, args->shmid, IPC_SET,
|
||||
(void *)&bsd_shmid, &bufsz, 1);
|
||||
|
||||
case LINUX_IPC_RMID: {
|
||||
void *buf;
|
||||
|
||||
if (args->buf == NULL)
|
||||
bsd_args.buf = NULL;
|
||||
buf = NULL;
|
||||
else {
|
||||
error = linux_shmid_pullup(args->cmd & LINUX_IPC_64,
|
||||
&linux_shmid, (caddr_t)args->buf);
|
||||
if (error != 0)
|
||||
return error;
|
||||
bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds));
|
||||
linux_to_bsd_shmid_ds(&linux_shmid, bsd_args.buf);
|
||||
error = linux_shmid_pullup(args->cmd & LINUX_IPC_64,
|
||||
&linux_shmid, (caddr_t)args->buf);
|
||||
if (error)
|
||||
return error;
|
||||
linux_to_bsd_shmid_ds(&linux_shmid, &bsd_shmid);
|
||||
buf = (void *)&bsd_shmid;
|
||||
}
|
||||
return shmctl(td, &bsd_args);
|
||||
return kern_shmctl(td, args->shmid, IPC_RMID, buf, &bufsz, 1);
|
||||
}
|
||||
|
||||
case LINUX_SHM_LOCK:
|
||||
case LINUX_SHM_UNLOCK:
|
||||
|
@ -46,6 +46,7 @@
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/syscallsubr.h>
|
||||
#include <sys/sysent.h>
|
||||
#include <sys/sysproto.h>
|
||||
#include <sys/jail.h>
|
||||
@ -95,8 +96,8 @@ struct shmmap_state {
|
||||
|
||||
static void shm_deallocate_segment(struct shmid_ds *);
|
||||
static int shm_find_segment_by_key(key_t);
|
||||
static struct shmid_ds *shm_find_segment_by_shmid(int);
|
||||
static struct shmid_ds *shm_find_segment_by_shmidx(int);
|
||||
static struct shmid_ds *shm_find_segment_by_shmid(int, int);
|
||||
static struct shmid_ds *shm_find_segment_by_shmidx(int, int);
|
||||
static int shm_delete_mapping(struct vmspace *vm, struct shmmap_state *);
|
||||
static void shmrealloc(void);
|
||||
static void shminit(void);
|
||||
@ -163,8 +164,7 @@ shm_find_segment_by_key(key)
|
||||
}
|
||||
|
||||
static struct shmid_ds *
|
||||
shm_find_segment_by_shmid(shmid)
|
||||
int shmid;
|
||||
shm_find_segment_by_shmid(int shmid, int wantrem)
|
||||
{
|
||||
int segnum;
|
||||
struct shmid_ds *shmseg;
|
||||
@ -173,23 +173,23 @@ shm_find_segment_by_shmid(shmid)
|
||||
if (segnum < 0 || segnum >= shmalloced)
|
||||
return (NULL);
|
||||
shmseg = &shmsegs[segnum];
|
||||
if ((shmseg->shm_perm.mode & (SHMSEG_ALLOCATED | SHMSEG_REMOVED))
|
||||
!= SHMSEG_ALLOCATED ||
|
||||
if (!((shmseg->shm_perm.mode & SHMSEG_ALLOCATED) ||
|
||||
(wantrem && !(shmseg->shm_perm.mode & SHMSEG_REMOVED))) ||
|
||||
shmseg->shm_perm.seq != IPCID_TO_SEQ(shmid))
|
||||
return (NULL);
|
||||
return (shmseg);
|
||||
}
|
||||
|
||||
static struct shmid_ds *
|
||||
shm_find_segment_by_shmidx(int segnum)
|
||||
shm_find_segment_by_shmidx(int segnum, int wantrem)
|
||||
{
|
||||
struct shmid_ds *shmseg;
|
||||
|
||||
if (segnum < 0 || segnum >= shmalloced)
|
||||
return (NULL);
|
||||
shmseg = &shmsegs[segnum];
|
||||
if ((shmseg->shm_perm.mode & (SHMSEG_ALLOCATED | SHMSEG_REMOVED))
|
||||
!= SHMSEG_ALLOCATED )
|
||||
if (!((shmseg->shm_perm.mode & SHMSEG_ALLOCATED) ||
|
||||
(wantrem && !(shmseg->shm_perm.mode & SHMSEG_REMOVED))))
|
||||
return (NULL);
|
||||
return (shmseg);
|
||||
}
|
||||
@ -293,9 +293,12 @@ struct shmat_args {
|
||||
* MPSAFE
|
||||
*/
|
||||
int
|
||||
shmat(td, uap)
|
||||
kern_shmat(td, shmid, shmaddr, shmflg, wantrem)
|
||||
struct thread *td;
|
||||
struct shmat_args *uap;
|
||||
int shmid;
|
||||
const void *shmaddr;
|
||||
int shmflg;
|
||||
int wantrem;
|
||||
{
|
||||
struct proc *p = td->td_proc;
|
||||
int i, flags;
|
||||
@ -319,13 +322,13 @@ shmat(td, uap)
|
||||
shmmap_s[i].shmid = -1;
|
||||
p->p_vmspace->vm_shm = shmmap_s;
|
||||
}
|
||||
shmseg = shm_find_segment_by_shmid(uap->shmid);
|
||||
shmseg = shm_find_segment_by_shmid(shmid, wantrem);
|
||||
if (shmseg == NULL) {
|
||||
error = EINVAL;
|
||||
goto done2;
|
||||
}
|
||||
error = ipcperm(td, &shmseg->shm_perm,
|
||||
(uap->shmflg & SHM_RDONLY) ? IPC_R : IPC_R|IPC_W);
|
||||
(shmflg & SHM_RDONLY) ? IPC_R : IPC_R|IPC_W);
|
||||
if (error)
|
||||
goto done2;
|
||||
for (i = 0; i < shminfo.shmseg; i++) {
|
||||
@ -343,15 +346,15 @@ shmat(td, uap)
|
||||
#else
|
||||
prot = VM_PROT_READ;
|
||||
#endif
|
||||
if ((uap->shmflg & SHM_RDONLY) == 0)
|
||||
if ((shmflg & SHM_RDONLY) == 0)
|
||||
prot |= VM_PROT_WRITE;
|
||||
flags = MAP_ANON | MAP_SHARED;
|
||||
if (uap->shmaddr) {
|
||||
if (shmaddr) {
|
||||
flags |= MAP_FIXED;
|
||||
if (uap->shmflg & SHM_RND) {
|
||||
attach_va = (vm_offset_t)uap->shmaddr & ~(SHMLBA-1);
|
||||
} else if (((vm_offset_t)uap->shmaddr & (SHMLBA-1)) == 0) {
|
||||
attach_va = (vm_offset_t)uap->shmaddr;
|
||||
if (shmflg & SHM_RND) {
|
||||
attach_va = (vm_offset_t)shmaddr & ~(SHMLBA-1);
|
||||
} else if (((vm_offset_t)shmaddr & (SHMLBA-1)) == 0) {
|
||||
attach_va = (vm_offset_t)shmaddr;
|
||||
} else {
|
||||
error = EINVAL;
|
||||
goto done2;
|
||||
@ -377,7 +380,7 @@ shmat(td, uap)
|
||||
attach_va, attach_va + size, VM_INHERIT_SHARE);
|
||||
|
||||
shmmap_s->va = attach_va;
|
||||
shmmap_s->shmid = uap->shmid;
|
||||
shmmap_s->shmid = shmid;
|
||||
shmseg->shm_lpid = p->p_pid;
|
||||
shmseg->shm_atime = time_second;
|
||||
shmseg->shm_nattch++;
|
||||
@ -387,6 +390,14 @@ done2:
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
shmat(td, uap)
|
||||
struct thread *td;
|
||||
struct shmat_args *uap;
|
||||
{
|
||||
return kern_shmat(td, uap->shmid, uap->shmaddr, uap->shmflg, 0);
|
||||
}
|
||||
|
||||
struct oshmid_ds {
|
||||
struct ipc_perm shm_perm; /* operation perms */
|
||||
int shm_segsz; /* size of segment (bytes) */
|
||||
@ -421,7 +432,7 @@ oshmctl(td, uap)
|
||||
if (!jail_sysvipc_allowed && jailed(td->td_ucred))
|
||||
return (ENOSYS);
|
||||
mtx_lock(&Giant);
|
||||
shmseg = shm_find_segment_by_shmid(uap->shmid);
|
||||
shmseg = shm_find_segment_by_shmid(uap->shmid, 0);
|
||||
if (shmseg == NULL) {
|
||||
error = EINVAL;
|
||||
goto done2;
|
||||
@ -469,22 +480,26 @@ struct shmctl_args {
|
||||
* MPSAFE
|
||||
*/
|
||||
int
|
||||
shmctl(td, uap)
|
||||
kern_shmctl(td, shmid, cmd, buf, bufsz, wantrem)
|
||||
struct thread *td;
|
||||
struct shmctl_args *uap;
|
||||
int shmid;
|
||||
int cmd;
|
||||
void *buf;
|
||||
size_t *bufsz;
|
||||
int wantrem;
|
||||
{
|
||||
int error = 0;
|
||||
struct shmid_ds inbuf;
|
||||
struct shmid_ds *shmseg;
|
||||
|
||||
if (!jail_sysvipc_allowed && jailed(td->td_ucred))
|
||||
return (ENOSYS);
|
||||
|
||||
mtx_lock(&Giant);
|
||||
switch (uap->cmd) {
|
||||
switch (cmd) {
|
||||
case IPC_INFO:
|
||||
error = copyout(&shminfo, uap->buf, sizeof(shminfo));
|
||||
if (error)
|
||||
goto done2;
|
||||
memcpy(buf, &shminfo, sizeof(shminfo));
|
||||
if (bufsz)
|
||||
*bufsz = sizeof(shminfo);
|
||||
td->td_retval[0] = shmalloced;
|
||||
goto done2;
|
||||
case SHM_INFO: {
|
||||
@ -495,47 +510,48 @@ shmctl(td, uap)
|
||||
shm_info.shm_swp = 0; /*XXX where to get from ? */
|
||||
shm_info.swap_attempts = 0; /*XXX where to get from ? */
|
||||
shm_info.swap_successes = 0; /*XXX where to get from ? */
|
||||
error = copyout(&shm_info, uap->buf, sizeof(shm_info));
|
||||
if (error)
|
||||
goto done2;
|
||||
memcpy(buf, &shm_info, sizeof(shm_info));
|
||||
if (bufsz)
|
||||
*bufsz = sizeof(shm_info);
|
||||
td->td_retval[0] = shmalloced;
|
||||
goto done2;
|
||||
}
|
||||
}
|
||||
if( (uap->cmd) == SHM_STAT )
|
||||
shmseg = shm_find_segment_by_shmidx(uap->shmid);
|
||||
if (cmd == SHM_STAT)
|
||||
shmseg = shm_find_segment_by_shmidx(shmid, wantrem);
|
||||
else
|
||||
shmseg = shm_find_segment_by_shmid(uap->shmid);
|
||||
shmseg = shm_find_segment_by_shmid(shmid, wantrem);
|
||||
if (shmseg == NULL) {
|
||||
error = EINVAL;
|
||||
goto done2;
|
||||
}
|
||||
switch (uap->cmd) {
|
||||
switch (cmd) {
|
||||
case SHM_STAT:
|
||||
case IPC_STAT:
|
||||
error = ipcperm(td, &shmseg->shm_perm, IPC_R);
|
||||
if (error)
|
||||
goto done2;
|
||||
error = copyout(shmseg, uap->buf, sizeof(inbuf));
|
||||
if (error)
|
||||
goto done2;
|
||||
else if( (uap->cmd) == SHM_STAT )
|
||||
td->td_retval[0] = IXSEQ_TO_IPCID( uap->shmid, shmseg->shm_perm );
|
||||
memcpy(buf, shmseg, sizeof(struct shmid_ds));
|
||||
if (bufsz)
|
||||
*bufsz = sizeof(struct shmid_ds);
|
||||
if (cmd == SHM_STAT)
|
||||
td->td_retval[0] = IXSEQ_TO_IPCID(shmid, shmseg->shm_perm);
|
||||
break;
|
||||
case IPC_SET:
|
||||
case IPC_SET: {
|
||||
struct shmid_ds *shmid;
|
||||
|
||||
shmid = (struct shmid_ds *)buf;
|
||||
error = ipcperm(td, &shmseg->shm_perm, IPC_M);
|
||||
if (error)
|
||||
goto done2;
|
||||
error = copyin(uap->buf, &inbuf, sizeof(inbuf));
|
||||
if (error)
|
||||
goto done2;
|
||||
shmseg->shm_perm.uid = inbuf.shm_perm.uid;
|
||||
shmseg->shm_perm.gid = inbuf.shm_perm.gid;
|
||||
shmseg->shm_perm.uid = shmid->shm_perm.uid;
|
||||
shmseg->shm_perm.gid = shmid->shm_perm.gid;
|
||||
shmseg->shm_perm.mode =
|
||||
(shmseg->shm_perm.mode & ~ACCESSPERMS) |
|
||||
(inbuf.shm_perm.mode & ACCESSPERMS);
|
||||
(shmid->shm_perm.mode & ACCESSPERMS);
|
||||
shmseg->shm_ctime = time_second;
|
||||
break;
|
||||
}
|
||||
case IPC_RMID:
|
||||
error = ipcperm(td, &shmseg->shm_perm, IPC_M);
|
||||
if (error)
|
||||
@ -544,7 +560,7 @@ shmctl(td, uap)
|
||||
shmseg->shm_perm.mode |= SHMSEG_REMOVED;
|
||||
if (shmseg->shm_nattch <= 0) {
|
||||
shm_deallocate_segment(shmseg);
|
||||
shm_last_free = IPCID_TO_IX(uap->shmid);
|
||||
shm_last_free = IPCID_TO_IX(shmid);
|
||||
}
|
||||
break;
|
||||
#if 0
|
||||
@ -560,6 +576,44 @@ done2:
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
shmctl(td, uap)
|
||||
struct thread *td;
|
||||
struct shmctl_args *uap;
|
||||
{
|
||||
int error = 0;
|
||||
struct shmid_ds buf;
|
||||
size_t bufsz;
|
||||
|
||||
/* IPC_SET needs to copyin the buffer before calling kern_shmctl */
|
||||
if (uap->cmd == IPC_SET) {
|
||||
if ((error = copyin(uap->buf, &buf, sizeof(struct shmid_ds))))
|
||||
goto done;
|
||||
}
|
||||
|
||||
error = kern_shmctl(td, uap->shmid, uap->cmd, (void *)&buf, &bufsz, 0);
|
||||
if (error)
|
||||
goto done;
|
||||
|
||||
/* Cases in which we need to copyout */
|
||||
switch (uap->cmd) {
|
||||
case IPC_INFO:
|
||||
case SHM_INFO:
|
||||
case SHM_STAT:
|
||||
case IPC_STAT:
|
||||
error = copyout(&buf, uap->buf, bufsz);
|
||||
break;
|
||||
}
|
||||
|
||||
done:
|
||||
if (error) {
|
||||
/* Invalidate the return value */
|
||||
td->td_retval[0] = -1;
|
||||
}
|
||||
return (error);
|
||||
}
|
||||
|
||||
|
||||
#ifndef _SYS_SYSPROTO_H_
|
||||
struct shmget_args {
|
||||
key_t key;
|
||||
|
@ -70,6 +70,10 @@ int kern_rename(struct thread *td, char *from, char *to,
|
||||
int kern_rmdir(struct thread *td, char *path, enum uio_seg pathseg);
|
||||
int kern_select(struct thread *td, int nd, fd_set *fd_in, fd_set *fd_ou,
|
||||
fd_set *fd_ex, struct timeval *tvp);
|
||||
int kern_shmat(struct thread *td, int shmid, const void *shmaddr,
|
||||
int shmflg, int wantrem);
|
||||
int kern_shmctl(struct thread *td, int shmid, int cmd, void *buf,
|
||||
size_t *bufsz, int wantrem);
|
||||
int kern_sigaction(struct thread *td, int sig, struct sigaction *act,
|
||||
struct sigaction *oact, int flags);
|
||||
int kern_sigaltstack(struct thread *td, stack_t *ss, stack_t *oss);
|
||||
|
Loading…
x
Reference in New Issue
Block a user