[PATCH] IPC namespace - sem
IPC namespace support for IPC sem code. Signed-off-by: Pavel Emelianiov <xemul@openvz.org> Signed-off-by: Kirill Korotaev <dev@openvz.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
parent
1e78693738
commit
e38935341a
201
ipc/sem.c
201
ipc/sem.c
@ -64,6 +64,10 @@
|
|||||||
*
|
*
|
||||||
* support for audit of ipc object properties and permission changes
|
* support for audit of ipc object properties and permission changes
|
||||||
* Dustin Kirkland <dustin.kirkland@us.ibm.com>
|
* Dustin Kirkland <dustin.kirkland@us.ibm.com>
|
||||||
|
*
|
||||||
|
* namespaces support
|
||||||
|
* OpenVZ, SWsoft Inc.
|
||||||
|
* Pavel Emelianov <xemul@openvz.org>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
@ -78,22 +82,25 @@
|
|||||||
#include <linux/capability.h>
|
#include <linux/capability.h>
|
||||||
#include <linux/seq_file.h>
|
#include <linux/seq_file.h>
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
|
#include <linux/nsproxy.h>
|
||||||
|
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
#define sem_ids(ns) (*((ns)->ids[IPC_SEM_IDS]))
|
||||||
|
|
||||||
#define sem_lock(id) ((struct sem_array*)ipc_lock(&sem_ids,id))
|
#define sem_lock(ns, id) ((struct sem_array*)ipc_lock(&sem_ids(ns), id))
|
||||||
#define sem_unlock(sma) ipc_unlock(&(sma)->sem_perm)
|
#define sem_unlock(sma) ipc_unlock(&(sma)->sem_perm)
|
||||||
#define sem_rmid(id) ((struct sem_array*)ipc_rmid(&sem_ids,id))
|
#define sem_rmid(ns, id) ((struct sem_array*)ipc_rmid(&sem_ids(ns), id))
|
||||||
#define sem_checkid(sma, semid) \
|
#define sem_checkid(ns, sma, semid) \
|
||||||
ipc_checkid(&sem_ids,&sma->sem_perm,semid)
|
ipc_checkid(&sem_ids(ns),&sma->sem_perm,semid)
|
||||||
#define sem_buildid(id, seq) \
|
#define sem_buildid(ns, id, seq) \
|
||||||
ipc_buildid(&sem_ids, id, seq)
|
ipc_buildid(&sem_ids(ns), id, seq)
|
||||||
static struct ipc_ids sem_ids;
|
|
||||||
|
|
||||||
static int newary (key_t, int, int);
|
static struct ipc_ids init_sem_ids;
|
||||||
static void freeary (struct sem_array *sma, int id);
|
|
||||||
|
static int newary(struct ipc_namespace *, key_t, int, int);
|
||||||
|
static void freeary(struct ipc_namespace *ns, struct sem_array *sma, int id);
|
||||||
#ifdef CONFIG_PROC_FS
|
#ifdef CONFIG_PROC_FS
|
||||||
static int sysvipc_sem_proc_show(struct seq_file *s, void *it);
|
static int sysvipc_sem_proc_show(struct seq_file *s, void *it);
|
||||||
#endif
|
#endif
|
||||||
@ -110,22 +117,61 @@ static int sysvipc_sem_proc_show(struct seq_file *s, void *it);
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int sem_ctls[4] = {SEMMSL, SEMMNS, SEMOPM, SEMMNI};
|
#define sc_semmsl sem_ctls[0]
|
||||||
#define sc_semmsl (sem_ctls[0])
|
#define sc_semmns sem_ctls[1]
|
||||||
#define sc_semmns (sem_ctls[1])
|
#define sc_semopm sem_ctls[2]
|
||||||
#define sc_semopm (sem_ctls[2])
|
#define sc_semmni sem_ctls[3]
|
||||||
#define sc_semmni (sem_ctls[3])
|
|
||||||
|
|
||||||
static int used_sems;
|
static void __ipc_init __sem_init_ns(struct ipc_namespace *ns, struct ipc_ids *ids)
|
||||||
|
{
|
||||||
|
ns->ids[IPC_SEM_IDS] = ids;
|
||||||
|
ns->sc_semmsl = SEMMSL;
|
||||||
|
ns->sc_semmns = SEMMNS;
|
||||||
|
ns->sc_semopm = SEMOPM;
|
||||||
|
ns->sc_semmni = SEMMNI;
|
||||||
|
ns->used_sems = 0;
|
||||||
|
ipc_init_ids(ids, ns->sc_semmni);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_IPC_NS
|
||||||
|
int sem_init_ns(struct ipc_namespace *ns)
|
||||||
|
{
|
||||||
|
struct ipc_ids *ids;
|
||||||
|
|
||||||
|
ids = kmalloc(sizeof(struct ipc_ids), GFP_KERNEL);
|
||||||
|
if (ids == NULL)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
__sem_init_ns(ns, ids);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sem_exit_ns(struct ipc_namespace *ns)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
struct sem_array *sma;
|
||||||
|
|
||||||
|
mutex_lock(&sem_ids(ns).mutex);
|
||||||
|
for (i = 0; i <= sem_ids(ns).max_id; i++) {
|
||||||
|
sma = sem_lock(ns, i);
|
||||||
|
if (sma == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
freeary(ns, sma, i);
|
||||||
|
}
|
||||||
|
mutex_unlock(&sem_ids(ns).mutex);
|
||||||
|
|
||||||
|
kfree(ns->ids[IPC_SEM_IDS]);
|
||||||
|
ns->ids[IPC_SEM_IDS] = NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void __init sem_init (void)
|
void __init sem_init (void)
|
||||||
{
|
{
|
||||||
used_sems = 0;
|
__sem_init_ns(&init_ipc_ns, &init_sem_ids);
|
||||||
ipc_init_ids(&sem_ids,sc_semmni);
|
|
||||||
ipc_init_proc_interface("sysvipc/sem",
|
ipc_init_proc_interface("sysvipc/sem",
|
||||||
" key semid perms nsems uid gid cuid cgid otime ctime\n",
|
" key semid perms nsems uid gid cuid cgid otime ctime\n",
|
||||||
&sem_ids,
|
IPC_SEM_IDS, sysvipc_sem_proc_show);
|
||||||
sysvipc_sem_proc_show);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -162,7 +208,7 @@ void __init sem_init (void)
|
|||||||
*/
|
*/
|
||||||
#define IN_WAKEUP 1
|
#define IN_WAKEUP 1
|
||||||
|
|
||||||
static int newary (key_t key, int nsems, int semflg)
|
static int newary (struct ipc_namespace *ns, key_t key, int nsems, int semflg)
|
||||||
{
|
{
|
||||||
int id;
|
int id;
|
||||||
int retval;
|
int retval;
|
||||||
@ -171,7 +217,7 @@ static int newary (key_t key, int nsems, int semflg)
|
|||||||
|
|
||||||
if (!nsems)
|
if (!nsems)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (used_sems + nsems > sc_semmns)
|
if (ns->used_sems + nsems > ns->sc_semmns)
|
||||||
return -ENOSPC;
|
return -ENOSPC;
|
||||||
|
|
||||||
size = sizeof (*sma) + nsems * sizeof (struct sem);
|
size = sizeof (*sma) + nsems * sizeof (struct sem);
|
||||||
@ -191,15 +237,15 @@ static int newary (key_t key, int nsems, int semflg)
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
id = ipc_addid(&sem_ids, &sma->sem_perm, sc_semmni);
|
id = ipc_addid(&sem_ids(ns), &sma->sem_perm, ns->sc_semmni);
|
||||||
if(id == -1) {
|
if(id == -1) {
|
||||||
security_sem_free(sma);
|
security_sem_free(sma);
|
||||||
ipc_rcu_putref(sma);
|
ipc_rcu_putref(sma);
|
||||||
return -ENOSPC;
|
return -ENOSPC;
|
||||||
}
|
}
|
||||||
used_sems += nsems;
|
ns->used_sems += nsems;
|
||||||
|
|
||||||
sma->sem_id = sem_buildid(id, sma->sem_perm.seq);
|
sma->sem_id = sem_buildid(ns, id, sma->sem_perm.seq);
|
||||||
sma->sem_base = (struct sem *) &sma[1];
|
sma->sem_base = (struct sem *) &sma[1];
|
||||||
/* sma->sem_pending = NULL; */
|
/* sma->sem_pending = NULL; */
|
||||||
sma->sem_pending_last = &sma->sem_pending;
|
sma->sem_pending_last = &sma->sem_pending;
|
||||||
@ -215,29 +261,32 @@ asmlinkage long sys_semget (key_t key, int nsems, int semflg)
|
|||||||
{
|
{
|
||||||
int id, err = -EINVAL;
|
int id, err = -EINVAL;
|
||||||
struct sem_array *sma;
|
struct sem_array *sma;
|
||||||
|
struct ipc_namespace *ns;
|
||||||
|
|
||||||
if (nsems < 0 || nsems > sc_semmsl)
|
ns = current->nsproxy->ipc_ns;
|
||||||
|
|
||||||
|
if (nsems < 0 || nsems > ns->sc_semmsl)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
mutex_lock(&sem_ids.mutex);
|
mutex_lock(&sem_ids(ns).mutex);
|
||||||
|
|
||||||
if (key == IPC_PRIVATE) {
|
if (key == IPC_PRIVATE) {
|
||||||
err = newary(key, nsems, semflg);
|
err = newary(ns, key, nsems, semflg);
|
||||||
} else if ((id = ipc_findkey(&sem_ids, key)) == -1) { /* key not used */
|
} else if ((id = ipc_findkey(&sem_ids(ns), key)) == -1) { /* key not used */
|
||||||
if (!(semflg & IPC_CREAT))
|
if (!(semflg & IPC_CREAT))
|
||||||
err = -ENOENT;
|
err = -ENOENT;
|
||||||
else
|
else
|
||||||
err = newary(key, nsems, semflg);
|
err = newary(ns, key, nsems, semflg);
|
||||||
} else if (semflg & IPC_CREAT && semflg & IPC_EXCL) {
|
} else if (semflg & IPC_CREAT && semflg & IPC_EXCL) {
|
||||||
err = -EEXIST;
|
err = -EEXIST;
|
||||||
} else {
|
} else {
|
||||||
sma = sem_lock(id);
|
sma = sem_lock(ns, id);
|
||||||
BUG_ON(sma==NULL);
|
BUG_ON(sma==NULL);
|
||||||
if (nsems > sma->sem_nsems)
|
if (nsems > sma->sem_nsems)
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
else if (ipcperms(&sma->sem_perm, semflg))
|
else if (ipcperms(&sma->sem_perm, semflg))
|
||||||
err = -EACCES;
|
err = -EACCES;
|
||||||
else {
|
else {
|
||||||
int semid = sem_buildid(id, sma->sem_perm.seq);
|
int semid = sem_buildid(ns, id, sma->sem_perm.seq);
|
||||||
err = security_sem_associate(sma, semflg);
|
err = security_sem_associate(sma, semflg);
|
||||||
if (!err)
|
if (!err)
|
||||||
err = semid;
|
err = semid;
|
||||||
@ -245,7 +294,7 @@ asmlinkage long sys_semget (key_t key, int nsems, int semflg)
|
|||||||
sem_unlock(sma);
|
sem_unlock(sma);
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_unlock(&sem_ids.mutex);
|
mutex_unlock(&sem_ids(ns).mutex);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -444,7 +493,7 @@ static int count_semzcnt (struct sem_array * sma, ushort semnum)
|
|||||||
* the spinlock for this semaphore set hold. sem_ids.mutex remains locked
|
* the spinlock for this semaphore set hold. sem_ids.mutex remains locked
|
||||||
* on exit.
|
* on exit.
|
||||||
*/
|
*/
|
||||||
static void freeary (struct sem_array *sma, int id)
|
static void freeary (struct ipc_namespace *ns, struct sem_array *sma, int id)
|
||||||
{
|
{
|
||||||
struct sem_undo *un;
|
struct sem_undo *un;
|
||||||
struct sem_queue *q;
|
struct sem_queue *q;
|
||||||
@ -472,10 +521,10 @@ static void freeary (struct sem_array *sma, int id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Remove the semaphore set from the ID array*/
|
/* Remove the semaphore set from the ID array*/
|
||||||
sma = sem_rmid(id);
|
sma = sem_rmid(ns, id);
|
||||||
sem_unlock(sma);
|
sem_unlock(sma);
|
||||||
|
|
||||||
used_sems -= sma->sem_nsems;
|
ns->used_sems -= sma->sem_nsems;
|
||||||
size = sizeof (*sma) + sma->sem_nsems * sizeof (struct sem);
|
size = sizeof (*sma) + sma->sem_nsems * sizeof (struct sem);
|
||||||
security_sem_free(sma);
|
security_sem_free(sma);
|
||||||
ipc_rcu_putref(sma);
|
ipc_rcu_putref(sma);
|
||||||
@ -503,7 +552,8 @@ static unsigned long copy_semid_to_user(void __user *buf, struct semid64_ds *in,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int semctl_nolock(int semid, int semnum, int cmd, int version, union semun arg)
|
static int semctl_nolock(struct ipc_namespace *ns, int semid, int semnum,
|
||||||
|
int cmd, int version, union semun arg)
|
||||||
{
|
{
|
||||||
int err = -EINVAL;
|
int err = -EINVAL;
|
||||||
struct sem_array *sma;
|
struct sem_array *sma;
|
||||||
@ -520,24 +570,24 @@ static int semctl_nolock(int semid, int semnum, int cmd, int version, union semu
|
|||||||
return err;
|
return err;
|
||||||
|
|
||||||
memset(&seminfo,0,sizeof(seminfo));
|
memset(&seminfo,0,sizeof(seminfo));
|
||||||
seminfo.semmni = sc_semmni;
|
seminfo.semmni = ns->sc_semmni;
|
||||||
seminfo.semmns = sc_semmns;
|
seminfo.semmns = ns->sc_semmns;
|
||||||
seminfo.semmsl = sc_semmsl;
|
seminfo.semmsl = ns->sc_semmsl;
|
||||||
seminfo.semopm = sc_semopm;
|
seminfo.semopm = ns->sc_semopm;
|
||||||
seminfo.semvmx = SEMVMX;
|
seminfo.semvmx = SEMVMX;
|
||||||
seminfo.semmnu = SEMMNU;
|
seminfo.semmnu = SEMMNU;
|
||||||
seminfo.semmap = SEMMAP;
|
seminfo.semmap = SEMMAP;
|
||||||
seminfo.semume = SEMUME;
|
seminfo.semume = SEMUME;
|
||||||
mutex_lock(&sem_ids.mutex);
|
mutex_lock(&sem_ids(ns).mutex);
|
||||||
if (cmd == SEM_INFO) {
|
if (cmd == SEM_INFO) {
|
||||||
seminfo.semusz = sem_ids.in_use;
|
seminfo.semusz = sem_ids(ns).in_use;
|
||||||
seminfo.semaem = used_sems;
|
seminfo.semaem = ns->used_sems;
|
||||||
} else {
|
} else {
|
||||||
seminfo.semusz = SEMUSZ;
|
seminfo.semusz = SEMUSZ;
|
||||||
seminfo.semaem = SEMAEM;
|
seminfo.semaem = SEMAEM;
|
||||||
}
|
}
|
||||||
max_id = sem_ids.max_id;
|
max_id = sem_ids(ns).max_id;
|
||||||
mutex_unlock(&sem_ids.mutex);
|
mutex_unlock(&sem_ids(ns).mutex);
|
||||||
if (copy_to_user (arg.__buf, &seminfo, sizeof(struct seminfo)))
|
if (copy_to_user (arg.__buf, &seminfo, sizeof(struct seminfo)))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
return (max_id < 0) ? 0: max_id;
|
return (max_id < 0) ? 0: max_id;
|
||||||
@ -547,12 +597,12 @@ static int semctl_nolock(int semid, int semnum, int cmd, int version, union semu
|
|||||||
struct semid64_ds tbuf;
|
struct semid64_ds tbuf;
|
||||||
int id;
|
int id;
|
||||||
|
|
||||||
if(semid >= sem_ids.entries->size)
|
if(semid >= sem_ids(ns).entries->size)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
memset(&tbuf,0,sizeof(tbuf));
|
memset(&tbuf,0,sizeof(tbuf));
|
||||||
|
|
||||||
sma = sem_lock(semid);
|
sma = sem_lock(ns, semid);
|
||||||
if(sma == NULL)
|
if(sma == NULL)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
@ -564,7 +614,7 @@ static int semctl_nolock(int semid, int semnum, int cmd, int version, union semu
|
|||||||
if (err)
|
if (err)
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
|
|
||||||
id = sem_buildid(semid, sma->sem_perm.seq);
|
id = sem_buildid(ns, semid, sma->sem_perm.seq);
|
||||||
|
|
||||||
kernel_to_ipc64_perm(&sma->sem_perm, &tbuf.sem_perm);
|
kernel_to_ipc64_perm(&sma->sem_perm, &tbuf.sem_perm);
|
||||||
tbuf.sem_otime = sma->sem_otime;
|
tbuf.sem_otime = sma->sem_otime;
|
||||||
@ -584,7 +634,8 @@ out_unlock:
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int semctl_main(int semid, int semnum, int cmd, int version, union semun arg)
|
static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
|
||||||
|
int cmd, int version, union semun arg)
|
||||||
{
|
{
|
||||||
struct sem_array *sma;
|
struct sem_array *sma;
|
||||||
struct sem* curr;
|
struct sem* curr;
|
||||||
@ -593,14 +644,14 @@ static int semctl_main(int semid, int semnum, int cmd, int version, union semun
|
|||||||
ushort* sem_io = fast_sem_io;
|
ushort* sem_io = fast_sem_io;
|
||||||
int nsems;
|
int nsems;
|
||||||
|
|
||||||
sma = sem_lock(semid);
|
sma = sem_lock(ns, semid);
|
||||||
if(sma==NULL)
|
if(sma==NULL)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
nsems = sma->sem_nsems;
|
nsems = sma->sem_nsems;
|
||||||
|
|
||||||
err=-EIDRM;
|
err=-EIDRM;
|
||||||
if (sem_checkid(sma,semid))
|
if (sem_checkid(ns,sma,semid))
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
|
|
||||||
err = -EACCES;
|
err = -EACCES;
|
||||||
@ -802,7 +853,8 @@ static inline unsigned long copy_semid_from_user(struct sem_setbuf *out, void __
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int semctl_down(int semid, int semnum, int cmd, int version, union semun arg)
|
static int semctl_down(struct ipc_namespace *ns, int semid, int semnum,
|
||||||
|
int cmd, int version, union semun arg)
|
||||||
{
|
{
|
||||||
struct sem_array *sma;
|
struct sem_array *sma;
|
||||||
int err;
|
int err;
|
||||||
@ -813,11 +865,11 @@ static int semctl_down(int semid, int semnum, int cmd, int version, union semun
|
|||||||
if(copy_semid_from_user (&setbuf, arg.buf, version))
|
if(copy_semid_from_user (&setbuf, arg.buf, version))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
sma = sem_lock(semid);
|
sma = sem_lock(ns, semid);
|
||||||
if(sma==NULL)
|
if(sma==NULL)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
if (sem_checkid(sma,semid)) {
|
if (sem_checkid(ns,sma,semid)) {
|
||||||
err=-EIDRM;
|
err=-EIDRM;
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
}
|
}
|
||||||
@ -844,7 +896,7 @@ static int semctl_down(int semid, int semnum, int cmd, int version, union semun
|
|||||||
|
|
||||||
switch(cmd){
|
switch(cmd){
|
||||||
case IPC_RMID:
|
case IPC_RMID:
|
||||||
freeary(sma, semid);
|
freeary(ns, sma, semid);
|
||||||
err = 0;
|
err = 0;
|
||||||
break;
|
break;
|
||||||
case IPC_SET:
|
case IPC_SET:
|
||||||
@ -872,17 +924,19 @@ asmlinkage long sys_semctl (int semid, int semnum, int cmd, union semun arg)
|
|||||||
{
|
{
|
||||||
int err = -EINVAL;
|
int err = -EINVAL;
|
||||||
int version;
|
int version;
|
||||||
|
struct ipc_namespace *ns;
|
||||||
|
|
||||||
if (semid < 0)
|
if (semid < 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
version = ipc_parse_version(&cmd);
|
version = ipc_parse_version(&cmd);
|
||||||
|
ns = current->nsproxy->ipc_ns;
|
||||||
|
|
||||||
switch(cmd) {
|
switch(cmd) {
|
||||||
case IPC_INFO:
|
case IPC_INFO:
|
||||||
case SEM_INFO:
|
case SEM_INFO:
|
||||||
case SEM_STAT:
|
case SEM_STAT:
|
||||||
err = semctl_nolock(semid,semnum,cmd,version,arg);
|
err = semctl_nolock(ns,semid,semnum,cmd,version,arg);
|
||||||
return err;
|
return err;
|
||||||
case GETALL:
|
case GETALL:
|
||||||
case GETVAL:
|
case GETVAL:
|
||||||
@ -892,13 +946,13 @@ asmlinkage long sys_semctl (int semid, int semnum, int cmd, union semun arg)
|
|||||||
case IPC_STAT:
|
case IPC_STAT:
|
||||||
case SETVAL:
|
case SETVAL:
|
||||||
case SETALL:
|
case SETALL:
|
||||||
err = semctl_main(semid,semnum,cmd,version,arg);
|
err = semctl_main(ns,semid,semnum,cmd,version,arg);
|
||||||
return err;
|
return err;
|
||||||
case IPC_RMID:
|
case IPC_RMID:
|
||||||
case IPC_SET:
|
case IPC_SET:
|
||||||
mutex_lock(&sem_ids.mutex);
|
mutex_lock(&sem_ids(ns).mutex);
|
||||||
err = semctl_down(semid,semnum,cmd,version,arg);
|
err = semctl_down(ns,semid,semnum,cmd,version,arg);
|
||||||
mutex_unlock(&sem_ids.mutex);
|
mutex_unlock(&sem_ids(ns).mutex);
|
||||||
return err;
|
return err;
|
||||||
default:
|
default:
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@ -986,7 +1040,7 @@ static struct sem_undo *lookup_undo(struct sem_undo_list *ulp, int semid)
|
|||||||
return un;
|
return un;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct sem_undo *find_undo(int semid)
|
static struct sem_undo *find_undo(struct ipc_namespace *ns, int semid)
|
||||||
{
|
{
|
||||||
struct sem_array *sma;
|
struct sem_array *sma;
|
||||||
struct sem_undo_list *ulp;
|
struct sem_undo_list *ulp;
|
||||||
@ -1005,12 +1059,12 @@ static struct sem_undo *find_undo(int semid)
|
|||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
/* no undo structure around - allocate one. */
|
/* no undo structure around - allocate one. */
|
||||||
sma = sem_lock(semid);
|
sma = sem_lock(ns, semid);
|
||||||
un = ERR_PTR(-EINVAL);
|
un = ERR_PTR(-EINVAL);
|
||||||
if(sma==NULL)
|
if(sma==NULL)
|
||||||
goto out;
|
goto out;
|
||||||
un = ERR_PTR(-EIDRM);
|
un = ERR_PTR(-EIDRM);
|
||||||
if (sem_checkid(sma,semid)) {
|
if (sem_checkid(ns,sma,semid)) {
|
||||||
sem_unlock(sma);
|
sem_unlock(sma);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@ -1070,10 +1124,13 @@ asmlinkage long sys_semtimedop(int semid, struct sembuf __user *tsops,
|
|||||||
int undos = 0, alter = 0, max;
|
int undos = 0, alter = 0, max;
|
||||||
struct sem_queue queue;
|
struct sem_queue queue;
|
||||||
unsigned long jiffies_left = 0;
|
unsigned long jiffies_left = 0;
|
||||||
|
struct ipc_namespace *ns;
|
||||||
|
|
||||||
|
ns = current->nsproxy->ipc_ns;
|
||||||
|
|
||||||
if (nsops < 1 || semid < 0)
|
if (nsops < 1 || semid < 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (nsops > sc_semopm)
|
if (nsops > ns->sc_semopm)
|
||||||
return -E2BIG;
|
return -E2BIG;
|
||||||
if(nsops > SEMOPM_FAST) {
|
if(nsops > SEMOPM_FAST) {
|
||||||
sops = kmalloc(sizeof(*sops)*nsops,GFP_KERNEL);
|
sops = kmalloc(sizeof(*sops)*nsops,GFP_KERNEL);
|
||||||
@ -1109,7 +1166,7 @@ asmlinkage long sys_semtimedop(int semid, struct sembuf __user *tsops,
|
|||||||
|
|
||||||
retry_undos:
|
retry_undos:
|
||||||
if (undos) {
|
if (undos) {
|
||||||
un = find_undo(semid);
|
un = find_undo(ns, semid);
|
||||||
if (IS_ERR(un)) {
|
if (IS_ERR(un)) {
|
||||||
error = PTR_ERR(un);
|
error = PTR_ERR(un);
|
||||||
goto out_free;
|
goto out_free;
|
||||||
@ -1117,12 +1174,12 @@ retry_undos:
|
|||||||
} else
|
} else
|
||||||
un = NULL;
|
un = NULL;
|
||||||
|
|
||||||
sma = sem_lock(semid);
|
sma = sem_lock(ns, semid);
|
||||||
error=-EINVAL;
|
error=-EINVAL;
|
||||||
if(sma==NULL)
|
if(sma==NULL)
|
||||||
goto out_free;
|
goto out_free;
|
||||||
error = -EIDRM;
|
error = -EIDRM;
|
||||||
if (sem_checkid(sma,semid))
|
if (sem_checkid(ns,sma,semid))
|
||||||
goto out_unlock_free;
|
goto out_unlock_free;
|
||||||
/*
|
/*
|
||||||
* semid identifies are not unique - find_undo may have
|
* semid identifies are not unique - find_undo may have
|
||||||
@ -1190,7 +1247,7 @@ retry_undos:
|
|||||||
goto out_free;
|
goto out_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
sma = sem_lock(semid);
|
sma = sem_lock(ns, semid);
|
||||||
if(sma==NULL) {
|
if(sma==NULL) {
|
||||||
BUG_ON(queue.prev != NULL);
|
BUG_ON(queue.prev != NULL);
|
||||||
error = -EIDRM;
|
error = -EIDRM;
|
||||||
@ -1267,6 +1324,7 @@ void exit_sem(struct task_struct *tsk)
|
|||||||
{
|
{
|
||||||
struct sem_undo_list *undo_list;
|
struct sem_undo_list *undo_list;
|
||||||
struct sem_undo *u, **up;
|
struct sem_undo *u, **up;
|
||||||
|
struct ipc_namespace *ns;
|
||||||
|
|
||||||
undo_list = tsk->sysvsem.undo_list;
|
undo_list = tsk->sysvsem.undo_list;
|
||||||
if (!undo_list)
|
if (!undo_list)
|
||||||
@ -1275,6 +1333,7 @@ void exit_sem(struct task_struct *tsk)
|
|||||||
if (!atomic_dec_and_test(&undo_list->refcnt))
|
if (!atomic_dec_and_test(&undo_list->refcnt))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
ns = tsk->nsproxy->ipc_ns;
|
||||||
/* There's no need to hold the semundo list lock, as current
|
/* There's no need to hold the semundo list lock, as current
|
||||||
* is the last task exiting for this undo list.
|
* is the last task exiting for this undo list.
|
||||||
*/
|
*/
|
||||||
@ -1288,14 +1347,14 @@ void exit_sem(struct task_struct *tsk)
|
|||||||
|
|
||||||
if(semid == -1)
|
if(semid == -1)
|
||||||
continue;
|
continue;
|
||||||
sma = sem_lock(semid);
|
sma = sem_lock(ns, semid);
|
||||||
if (sma == NULL)
|
if (sma == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (u->semid == -1)
|
if (u->semid == -1)
|
||||||
goto next_entry;
|
goto next_entry;
|
||||||
|
|
||||||
BUG_ON(sem_checkid(sma,u->semid));
|
BUG_ON(sem_checkid(ns,sma,u->semid));
|
||||||
|
|
||||||
/* remove u from the sma->undo list */
|
/* remove u from the sma->undo list */
|
||||||
for (unp = &sma->undo; (un = *unp); unp = &un->id_next) {
|
for (unp = &sma->undo; (un = *unp); unp = &un->id_next) {
|
||||||
|
Loading…
Reference in New Issue
Block a user