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:
Martin Blapp 2003-05-05 09:22:58 +00:00
parent 824eb9dc1b
commit f130dcf22a
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=114724
3 changed files with 178 additions and 107 deletions

View File

@ -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:

View File

@ -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 @@ shmat(td, uap)
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 @@ shmctl(td, uap)
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;

View File

@ -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);