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 * 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/capability.h> #include <linux/capability.h>
@ -31,16 +35,12 @@
#include <linux/audit.h> #include <linux/audit.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/current.h> #include <asm/current.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include "util.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: * 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_bytes = ATOMIC_INIT(0);
static atomic_t msg_hdrs = 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_unlock(msq) ipc_unlock(&(msq)->q_perm)
#define msg_rmid(id) ((struct msg_queue *)ipc_rmid(&msg_ids, id)) #define msg_rmid(ns, id) ((struct msg_queue*)ipc_rmid(&msg_ids(ns), id))
#define msg_checkid(msq, msgid) ipc_checkid(&msg_ids, &msq->q_perm, msgid) #define msg_checkid(ns, msq, msgid) \
#define msg_buildid(id, seq) ipc_buildid(&msg_ids, id, seq) 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 void freeque (struct ipc_namespace *ns, struct msg_queue *msq, int id);
static int newque(key_t key, int msgflg); static int newque (struct ipc_namespace *ns, key_t key, int msgflg);
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
static int sysvipc_msg_proc_show(struct seq_file *s, void *it); static int sysvipc_msg_proc_show(struct seq_file *s, void *it);
#endif #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); ns->ids[IPC_MSG_IDS] = ids;
ipc_init_proc_interface("sysvipc/msg", ns->msg_ctlmax = MSGMAX;
" key msqid perms cbytes qnum lspid lrpid uid gid cuid cgid stime rtime ctime\n", ns->msg_ctlmnb = MSGMNB;
&msg_ids, ns->msg_ctlmni = MSGMNI;
sysvipc_msg_proc_show); 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; struct msg_queue *msq;
int id, retval; int id, retval;
@ -111,18 +156,18 @@ static int newque(key_t key, int msgflg)
return retval; 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) { if (id == -1) {
security_msg_queue_free(msq); security_msg_queue_free(msq);
ipc_rcu_putref(msq); ipc_rcu_putref(msq);
return -ENOSPC; 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_stime = msq->q_rtime = 0;
msq->q_ctime = get_seconds(); msq->q_ctime = get_seconds();
msq->q_cbytes = msq->q_qnum = 0; 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; msq->q_lspid = msq->q_lrpid = 0;
INIT_LIST_HEAD(&msq->q_messages); INIT_LIST_HEAD(&msq->q_messages);
INIT_LIST_HEAD(&msq->q_receivers); 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 * msg_ids.mutex and the spinlock for this message queue is hold
* before freeque() is called. msg_ids.mutex remains locked on exit. * 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; struct list_head *tmp;
expunge_all(msq, -EIDRM); expunge_all(msq, -EIDRM);
ss_wakeup(&msq->q_senders, 1); ss_wakeup(&msq->q_senders, 1);
msq = msg_rmid(id); msq = msg_rmid(ns, id);
msg_unlock(msq); msg_unlock(msq);
tmp = msq->q_messages.next; tmp = msq->q_messages.next;
@ -212,24 +257,27 @@ asmlinkage long sys_msgget(key_t key, int msgflg)
{ {
struct msg_queue *msq; struct msg_queue *msq;
int id, ret = -EPERM; 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) if (key == IPC_PRIVATE)
ret = newque(key, msgflg); ret = newque(ns, key, msgflg);
else if ((id = ipc_findkey(&msg_ids, key)) == -1) { /* key not used */ else if ((id = ipc_findkey(&msg_ids(ns), key)) == -1) { /* key not used */
if (!(msgflg & IPC_CREAT)) if (!(msgflg & IPC_CREAT))
ret = -ENOENT; ret = -ENOENT;
else else
ret = newque(key, msgflg); ret = newque(ns, key, msgflg);
} else if (msgflg & IPC_CREAT && msgflg & IPC_EXCL) { } else if (msgflg & IPC_CREAT && msgflg & IPC_EXCL) {
ret = -EEXIST; ret = -EEXIST;
} else { } else {
msq = msg_lock(id); msq = msg_lock(ns, id);
BUG_ON(msq == NULL); BUG_ON(msq == NULL);
if (ipcperms(&msq->q_perm, msgflg)) if (ipcperms(&msq->q_perm, msgflg))
ret = -EACCES; ret = -EACCES;
else { 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); ret = security_msg_queue_associate(msq, msgflg);
if (!ret) if (!ret)
@ -237,7 +285,7 @@ asmlinkage long sys_msgget(key_t key, int msgflg)
} }
msg_unlock(msq); msg_unlock(msq);
} }
mutex_unlock(&msg_ids.mutex); mutex_unlock(&msg_ids(ns).mutex);
return ret; return ret;
} }
@ -341,11 +389,13 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf)
struct msq_setbuf setbuf; struct msq_setbuf setbuf;
struct msg_queue *msq; struct msg_queue *msq;
int err, version; int err, version;
struct ipc_namespace *ns;
if (msqid < 0 || cmd < 0) if (msqid < 0 || cmd < 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:
@ -366,14 +416,14 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf)
return err; return err;
memset(&msginfo, 0, sizeof(msginfo)); memset(&msginfo, 0, sizeof(msginfo));
msginfo.msgmni = msg_ctlmni; msginfo.msgmni = ns->msg_ctlmni;
msginfo.msgmax = msg_ctlmax; msginfo.msgmax = ns->msg_ctlmax;
msginfo.msgmnb = msg_ctlmnb; msginfo.msgmnb = ns->msg_ctlmnb;
msginfo.msgssz = MSGSSZ; msginfo.msgssz = MSGSSZ;
msginfo.msgseg = MSGSEG; msginfo.msgseg = MSGSEG;
mutex_lock(&msg_ids.mutex); mutex_lock(&msg_ids(ns).mutex);
if (cmd == MSG_INFO) { if (cmd == MSG_INFO) {
msginfo.msgpool = msg_ids.in_use; msginfo.msgpool = msg_ids(ns).in_use;
msginfo.msgmap = atomic_read(&msg_hdrs); msginfo.msgmap = atomic_read(&msg_hdrs);
msginfo.msgtql = atomic_read(&msg_bytes); msginfo.msgtql = atomic_read(&msg_bytes);
} else { } else {
@ -381,8 +431,8 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf)
msginfo.msgpool = MSGPOOL; msginfo.msgpool = MSGPOOL;
msginfo.msgtql = MSGTQL; msginfo.msgtql = MSGTQL;
} }
max_id = msg_ids.max_id; max_id = msg_ids(ns).max_id;
mutex_unlock(&msg_ids.mutex); mutex_unlock(&msg_ids(ns).mutex);
if (copy_to_user(buf, &msginfo, sizeof(struct msginfo))) if (copy_to_user(buf, &msginfo, sizeof(struct msginfo)))
return -EFAULT; return -EFAULT;
return (max_id < 0) ? 0 : max_id; 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) if (!buf)
return -EFAULT; return -EFAULT;
if (cmd == MSG_STAT && msqid >= msg_ids.entries->size) if (cmd == MSG_STAT && msqid >= msg_ids(ns).entries->size)
return -EINVAL; return -EINVAL;
memset(&tbuf, 0, sizeof(tbuf)); memset(&tbuf, 0, sizeof(tbuf));
msq = msg_lock(msqid); msq = msg_lock(ns, msqid);
if (msq == NULL) if (msq == NULL)
return -EINVAL; return -EINVAL;
if (cmd == MSG_STAT) { if (cmd == MSG_STAT) {
success_return = msg_buildid(msqid, msq->q_perm.seq); success_return = msg_buildid(ns, msqid, msq->q_perm.seq);
} else { } else {
err = -EIDRM; err = -EIDRM;
if (msg_checkid(msq, msqid)) if (msg_checkid(ns, msq, msqid))
goto out_unlock; goto out_unlock;
success_return = 0; success_return = 0;
} }
@ -446,14 +496,14 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf)
return -EINVAL; return -EINVAL;
} }
mutex_lock(&msg_ids.mutex); mutex_lock(&msg_ids(ns).mutex);
msq = msg_lock(msqid); msq = msg_lock(ns, msqid);
err = -EINVAL; err = -EINVAL;
if (msq == NULL) if (msq == NULL)
goto out_up; goto out_up;
err = -EIDRM; err = -EIDRM;
if (msg_checkid(msq, msqid)) if (msg_checkid(ns, msq, msqid))
goto out_unlock_up; goto out_unlock_up;
ipcp = &msq->q_perm; ipcp = &msq->q_perm;
@ -481,7 +531,7 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf)
case IPC_SET: case IPC_SET:
{ {
err = -EPERM; 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; goto out_unlock_up;
msq->q_qbytes = setbuf.qbytes; msq->q_qbytes = setbuf.qbytes;
@ -503,12 +553,12 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf)
break; break;
} }
case IPC_RMID: case IPC_RMID:
freeque(msq, msqid); freeque(ns, msq, msqid);
break; break;
} }
err = 0; err = 0;
out_up: out_up:
mutex_unlock(&msg_ids.mutex); mutex_unlock(&msg_ids(ns).mutex);
return err; return err;
out_unlock_up: out_unlock_up:
msg_unlock(msq); msg_unlock(msq);
@ -582,8 +632,11 @@ sys_msgsnd(int msqid, struct msgbuf __user *msgp, size_t msgsz, int msgflg)
struct msg_msg *msg; struct msg_msg *msg;
long mtype; long mtype;
int err; 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; return -EINVAL;
if (get_user(mtype, &msgp->mtype)) if (get_user(mtype, &msgp->mtype))
return -EFAULT; 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_type = mtype;
msg->m_ts = msgsz; msg->m_ts = msgsz;
msq = msg_lock(msqid); msq = msg_lock(ns, msqid);
err = -EINVAL; err = -EINVAL;
if (msq == NULL) if (msq == NULL)
goto out_free; goto out_free;
err= -EIDRM; err= -EIDRM;
if (msg_checkid(msq, msqid)) if (msg_checkid(ns, msq, msqid))
goto out_unlock_free; goto out_unlock_free;
for (;;) { for (;;) {
@ -694,17 +747,19 @@ asmlinkage long sys_msgrcv(int msqid, struct msgbuf __user *msgp, size_t msgsz,
struct msg_queue *msq; struct msg_queue *msq;
struct msg_msg *msg; struct msg_msg *msg;
int mode; int mode;
struct ipc_namespace *ns;
if (msqid < 0 || (long) msgsz < 0) if (msqid < 0 || (long) msgsz < 0)
return -EINVAL; return -EINVAL;
mode = convert_mode(&msgtyp, msgflg); mode = convert_mode(&msgtyp, msgflg);
ns = current->nsproxy->ipc_ns;
msq = msg_lock(msqid); msq = msg_lock(ns, msqid);
if (msq == NULL) if (msq == NULL)
return -EINVAL; return -EINVAL;
msg = ERR_PTR(-EIDRM); msg = ERR_PTR(-EIDRM);
if (msg_checkid(msq, msqid)) if (msg_checkid(ns, msq, msqid))
goto out_unlock; goto out_unlock;
for (;;) { for (;;) {