IPC namespace support for IPC msg 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:
Kirill Korotaev 2006-10-02 02:18:21 -07:00 коммит произвёл Linus Torvalds
Родитель 73ea41302b
Коммит 1e78693738
1 изменённых файлов: 108 добавлений и 53 удалений

161
ipc/msg.c
Просмотреть файл

@ -16,6 +16,10 @@
*
* support for audit of ipc object properties and permission changes
* Dustin Kirkland <dustin.kirkland@us.ibm.com>
*
* namespaces support
* OpenVZ, SWsoft Inc.
* Pavel Emelianov <xemul@openvz.org>
*/
#include <linux/capability.h>
@ -31,16 +35,12 @@
#include <linux/audit.h>
#include <linux/seq_file.h>
#include <linux/mutex.h>
#include <linux/nsproxy.h>
#include <asm/current.h>
#include <asm/uaccess.h>
#include "util.h"
/* sysctl: */
int msg_ctlmax = MSGMAX;
int msg_ctlmnb = MSGMNB;
int msg_ctlmni = MSGMNI;
/*
* one msg_receiver structure for each sleeping receiver:
*/
@ -69,30 +69,75 @@ struct msg_sender {
static atomic_t msg_bytes = ATOMIC_INIT(0);
static atomic_t msg_hdrs = ATOMIC_INIT(0);
static struct ipc_ids msg_ids;
static struct ipc_ids init_msg_ids;
#define msg_lock(id) ((struct msg_queue *)ipc_lock(&msg_ids, id))
#define msg_ids(ns) (*((ns)->ids[IPC_MSG_IDS]))
#define msg_lock(ns, id) ((struct msg_queue*)ipc_lock(&msg_ids(ns), id))
#define msg_unlock(msq) ipc_unlock(&(msq)->q_perm)
#define msg_rmid(id) ((struct msg_queue *)ipc_rmid(&msg_ids, id))
#define msg_checkid(msq, msgid) ipc_checkid(&msg_ids, &msq->q_perm, msgid)
#define msg_buildid(id, seq) ipc_buildid(&msg_ids, id, seq)
#define msg_rmid(ns, id) ((struct msg_queue*)ipc_rmid(&msg_ids(ns), id))
#define msg_checkid(ns, msq, msgid) \
ipc_checkid(&msg_ids(ns), &msq->q_perm, msgid)
#define msg_buildid(ns, id, seq) \
ipc_buildid(&msg_ids(ns), id, seq)
static void freeque(struct msg_queue *msq, int id);
static int newque(key_t key, int msgflg);
static void freeque (struct ipc_namespace *ns, struct msg_queue *msq, int id);
static int newque (struct ipc_namespace *ns, key_t key, int msgflg);
#ifdef CONFIG_PROC_FS
static int sysvipc_msg_proc_show(struct seq_file *s, void *it);
#endif
void __init msg_init(void)
static void __ipc_init __msg_init_ns(struct ipc_namespace *ns, struct ipc_ids *ids)
{
ipc_init_ids(&msg_ids, msg_ctlmni);
ipc_init_proc_interface("sysvipc/msg",
" key msqid perms cbytes qnum lspid lrpid uid gid cuid cgid stime rtime ctime\n",
&msg_ids,
sysvipc_msg_proc_show);
ns->ids[IPC_MSG_IDS] = ids;
ns->msg_ctlmax = MSGMAX;
ns->msg_ctlmnb = MSGMNB;
ns->msg_ctlmni = MSGMNI;
ipc_init_ids(ids, ns->msg_ctlmni);
}
static int newque(key_t key, int msgflg)
#ifdef CONFIG_IPC_NS
int msg_init_ns(struct ipc_namespace *ns)
{
struct ipc_ids *ids;
ids = kmalloc(sizeof(struct ipc_ids), GFP_KERNEL);
if (ids == NULL)
return -ENOMEM;
__msg_init_ns(ns, ids);
return 0;
}
void msg_exit_ns(struct ipc_namespace *ns)
{
int i;
struct msg_queue *msq;
mutex_lock(&msg_ids(ns).mutex);
for (i = 0; i <= msg_ids(ns).max_id; i++) {
msq = msg_lock(ns, i);
if (msq == NULL)
continue;
freeque(ns, msq, i);
}
mutex_unlock(&msg_ids(ns).mutex);
kfree(ns->ids[IPC_MSG_IDS]);
ns->ids[IPC_MSG_IDS] = NULL;
}
#endif
void __init msg_init(void)
{
__msg_init_ns(&init_ipc_ns, &init_msg_ids);
ipc_init_proc_interface("sysvipc/msg",
" key msqid perms cbytes qnum lspid lrpid uid gid cuid cgid stime rtime ctime\n",
IPC_MSG_IDS, sysvipc_msg_proc_show);
}
static int newque (struct ipc_namespace *ns, key_t key, int msgflg)
{
struct msg_queue *msq;
int id, retval;
@ -111,18 +156,18 @@ static int newque(key_t key, int msgflg)
return retval;
}
id = ipc_addid(&msg_ids, &msq->q_perm, msg_ctlmni);
id = ipc_addid(&msg_ids(ns), &msq->q_perm, ns->msg_ctlmni);
if (id == -1) {
security_msg_queue_free(msq);
ipc_rcu_putref(msq);
return -ENOSPC;
}
msq->q_id = msg_buildid(id, msq->q_perm.seq);
msq->q_id = msg_buildid(ns, id, msq->q_perm.seq);
msq->q_stime = msq->q_rtime = 0;
msq->q_ctime = get_seconds();
msq->q_cbytes = msq->q_qnum = 0;
msq->q_qbytes = msg_ctlmnb;
msq->q_qbytes = ns->msg_ctlmnb;
msq->q_lspid = msq->q_lrpid = 0;
INIT_LIST_HEAD(&msq->q_messages);
INIT_LIST_HEAD(&msq->q_receivers);
@ -186,13 +231,13 @@ static void expunge_all(struct msg_queue *msq, int res)
* msg_ids.mutex and the spinlock for this message queue is hold
* before freeque() is called. msg_ids.mutex remains locked on exit.
*/
static void freeque(struct msg_queue *msq, int id)
static void freeque(struct ipc_namespace *ns, struct msg_queue *msq, int id)
{
struct list_head *tmp;
expunge_all(msq, -EIDRM);
ss_wakeup(&msq->q_senders, 1);
msq = msg_rmid(id);
msq = msg_rmid(ns, id);
msg_unlock(msq);
tmp = msq->q_messages.next;
@ -212,24 +257,27 @@ asmlinkage long sys_msgget(key_t key, int msgflg)
{
struct msg_queue *msq;
int id, ret = -EPERM;
struct ipc_namespace *ns;
mutex_lock(&msg_ids.mutex);
ns = current->nsproxy->ipc_ns;
mutex_lock(&msg_ids(ns).mutex);
if (key == IPC_PRIVATE)
ret = newque(key, msgflg);
else if ((id = ipc_findkey(&msg_ids, key)) == -1) { /* key not used */
ret = newque(ns, key, msgflg);
else if ((id = ipc_findkey(&msg_ids(ns), key)) == -1) { /* key not used */
if (!(msgflg & IPC_CREAT))
ret = -ENOENT;
else
ret = newque(key, msgflg);
ret = newque(ns, key, msgflg);
} else if (msgflg & IPC_CREAT && msgflg & IPC_EXCL) {
ret = -EEXIST;
} else {
msq = msg_lock(id);
msq = msg_lock(ns, id);
BUG_ON(msq == NULL);
if (ipcperms(&msq->q_perm, msgflg))
ret = -EACCES;
else {
int qid = msg_buildid(id, msq->q_perm.seq);
int qid = msg_buildid(ns, id, msq->q_perm.seq);
ret = security_msg_queue_associate(msq, msgflg);
if (!ret)
@ -237,7 +285,7 @@ asmlinkage long sys_msgget(key_t key, int msgflg)
}
msg_unlock(msq);
}
mutex_unlock(&msg_ids.mutex);
mutex_unlock(&msg_ids(ns).mutex);
return ret;
}
@ -341,11 +389,13 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf)
struct msq_setbuf setbuf;
struct msg_queue *msq;
int err, version;
struct ipc_namespace *ns;
if (msqid < 0 || cmd < 0)
return -EINVAL;
version = ipc_parse_version(&cmd);
ns = current->nsproxy->ipc_ns;
switch (cmd) {
case IPC_INFO:
@ -366,14 +416,14 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf)
return err;
memset(&msginfo, 0, sizeof(msginfo));
msginfo.msgmni = msg_ctlmni;
msginfo.msgmax = msg_ctlmax;
msginfo.msgmnb = msg_ctlmnb;
msginfo.msgmni = ns->msg_ctlmni;
msginfo.msgmax = ns->msg_ctlmax;
msginfo.msgmnb = ns->msg_ctlmnb;
msginfo.msgssz = MSGSSZ;
msginfo.msgseg = MSGSEG;
mutex_lock(&msg_ids.mutex);
mutex_lock(&msg_ids(ns).mutex);
if (cmd == MSG_INFO) {
msginfo.msgpool = msg_ids.in_use;
msginfo.msgpool = msg_ids(ns).in_use;
msginfo.msgmap = atomic_read(&msg_hdrs);
msginfo.msgtql = atomic_read(&msg_bytes);
} else {
@ -381,8 +431,8 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf)
msginfo.msgpool = MSGPOOL;
msginfo.msgtql = MSGTQL;
}
max_id = msg_ids.max_id;
mutex_unlock(&msg_ids.mutex);
max_id = msg_ids(ns).max_id;
mutex_unlock(&msg_ids(ns).mutex);
if (copy_to_user(buf, &msginfo, sizeof(struct msginfo)))
return -EFAULT;
return (max_id < 0) ? 0 : max_id;
@ -395,20 +445,20 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf)
if (!buf)
return -EFAULT;
if (cmd == MSG_STAT && msqid >= msg_ids.entries->size)
if (cmd == MSG_STAT && msqid >= msg_ids(ns).entries->size)
return -EINVAL;
memset(&tbuf, 0, sizeof(tbuf));
msq = msg_lock(msqid);
msq = msg_lock(ns, msqid);
if (msq == NULL)
return -EINVAL;
if (cmd == MSG_STAT) {
success_return = msg_buildid(msqid, msq->q_perm.seq);
success_return = msg_buildid(ns, msqid, msq->q_perm.seq);
} else {
err = -EIDRM;
if (msg_checkid(msq, msqid))
if (msg_checkid(ns, msq, msqid))
goto out_unlock;
success_return = 0;
}
@ -446,14 +496,14 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf)
return -EINVAL;
}
mutex_lock(&msg_ids.mutex);
msq = msg_lock(msqid);
mutex_lock(&msg_ids(ns).mutex);
msq = msg_lock(ns, msqid);
err = -EINVAL;
if (msq == NULL)
goto out_up;
err = -EIDRM;
if (msg_checkid(msq, msqid))
if (msg_checkid(ns, msq, msqid))
goto out_unlock_up;
ipcp = &msq->q_perm;
@ -481,7 +531,7 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf)
case IPC_SET:
{
err = -EPERM;
if (setbuf.qbytes > msg_ctlmnb && !capable(CAP_SYS_RESOURCE))
if (setbuf.qbytes > ns->msg_ctlmnb && !capable(CAP_SYS_RESOURCE))
goto out_unlock_up;
msq->q_qbytes = setbuf.qbytes;
@ -503,12 +553,12 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf)
break;
}
case IPC_RMID:
freeque(msq, msqid);
freeque(ns, msq, msqid);
break;
}
err = 0;
out_up:
mutex_unlock(&msg_ids.mutex);
mutex_unlock(&msg_ids(ns).mutex);
return err;
out_unlock_up:
msg_unlock(msq);
@ -582,8 +632,11 @@ sys_msgsnd(int msqid, struct msgbuf __user *msgp, size_t msgsz, int msgflg)
struct msg_msg *msg;
long mtype;
int err;
struct ipc_namespace *ns;
if (msgsz > msg_ctlmax || (long) msgsz < 0 || msqid < 0)
ns = current->nsproxy->ipc_ns;
if (msgsz > ns->msg_ctlmax || (long) msgsz < 0 || msqid < 0)
return -EINVAL;
if (get_user(mtype, &msgp->mtype))
return -EFAULT;
@ -597,13 +650,13 @@ sys_msgsnd(int msqid, struct msgbuf __user *msgp, size_t msgsz, int msgflg)
msg->m_type = mtype;
msg->m_ts = msgsz;
msq = msg_lock(msqid);
msq = msg_lock(ns, msqid);
err = -EINVAL;
if (msq == NULL)
goto out_free;
err= -EIDRM;
if (msg_checkid(msq, msqid))
if (msg_checkid(ns, msq, msqid))
goto out_unlock_free;
for (;;) {
@ -694,17 +747,19 @@ asmlinkage long sys_msgrcv(int msqid, struct msgbuf __user *msgp, size_t msgsz,
struct msg_queue *msq;
struct msg_msg *msg;
int mode;
struct ipc_namespace *ns;
if (msqid < 0 || (long) msgsz < 0)
return -EINVAL;
mode = convert_mode(&msgtyp, msgflg);
ns = current->nsproxy->ipc_ns;
msq = msg_lock(msqid);
msq = msg_lock(ns, msqid);
if (msq == NULL)
return -EINVAL;
msg = ERR_PTR(-EIDRM);
if (msg_checkid(msq, msqid))
if (msg_checkid(ns, msq, msqid))
goto out_unlock;
for (;;) {