11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
2f30c2269544bffc7bf1b0d7c0abe5be1be83b8cbUwe Zeisberger * linux/ipc/msgutil.c
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 1999, 2004 Manfred Spraul
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This file is released under GNU General Public Licence version 2 or
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (at your option) any later version.
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * See the file COPYING for more details.
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/spinlock.h>
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/security.h>
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h>
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ipc.h>
164040153087478993cbf0809f444400a3c808074cAl Viro#include <linux/msg.h>
17614b84cf4e4a920d2af32b8f147ea1e3b8c27ea6Serge E. Hallyn#include <linux/ipc_namespace.h>
184040153087478993cbf0809f444400a3c808074cAl Viro#include <linux/utsname.h>
190bb80f240520c4148b623161e7856858c021696dDavid Howells#include <linux/proc_ns.h>
201e3c941c52eab70c8acb2f77829c24673445c858HoSung Jung#include <linux/uaccess.h>
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "util.h"
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
247eafd7c74c3f2e67c27621b987b28397110d643fSerge E. HallynDEFINE_SPINLOCK(mq_lock);
257eafd7c74c3f2e67c27621b987b28397110d643fSerge E. Hallyn
26614b84cf4e4a920d2af32b8f147ea1e3b8c27ea6Serge E. Hallyn/*
27614b84cf4e4a920d2af32b8f147ea1e3b8c27ea6Serge E. Hallyn * The next 2 defines are here bc this is the only file
28614b84cf4e4a920d2af32b8f147ea1e3b8c27ea6Serge E. Hallyn * compiled when either CONFIG_SYSVIPC and CONFIG_POSIX_MQUEUE
29614b84cf4e4a920d2af32b8f147ea1e3b8c27ea6Serge E. Hallyn * and not CONFIG_IPC_NS.
30614b84cf4e4a920d2af32b8f147ea1e3b8c27ea6Serge E. Hallyn */
31614b84cf4e4a920d2af32b8f147ea1e3b8c27ea6Serge E. Hallynstruct ipc_namespace init_ipc_ns = {
327eafd7c74c3f2e67c27621b987b28397110d643fSerge E. Hallyn	.count		= ATOMIC_INIT(1),
33b515498f5bb5f38fc0e390b4ff7d00b6077de127Serge E. Hallyn	.user_ns = &init_user_ns,
3498f842e675f96ffac96e6c50315790912b2812beEric W. Biederman	.proc_inum = PROC_IPC_INIT_INO,
35614b84cf4e4a920d2af32b8f147ea1e3b8c27ea6Serge E. Hallyn};
36614b84cf4e4a920d2af32b8f147ea1e3b8c27ea6Serge E. Hallyn
37614b84cf4e4a920d2af32b8f147ea1e3b8c27ea6Serge E. Hallynatomic_t nr_ipc_ns = ATOMIC_INIT(1);
38614b84cf4e4a920d2af32b8f147ea1e3b8c27ea6Serge E. Hallyn
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct msg_msgseg {
401e3c941c52eab70c8acb2f77829c24673445c858HoSung Jung	struct msg_msgseg *next;
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* the next part of the message follows immediately */
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
444e9b45a19241354daec281d7a785739829b52359Mathias Krause#define DATALEN_MSG	((size_t)PAGE_SIZE-sizeof(struct msg_msg))
454e9b45a19241354daec281d7a785739829b52359Mathias Krause#define DATALEN_SEG	((size_t)PAGE_SIZE-sizeof(struct msg_msgseg))
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
47be5f4b335f6e05df1b5c24b7e7d79ff52d7b8dbcPeter Hurley
484e9b45a19241354daec281d7a785739829b52359Mathias Krausestatic struct msg_msg *alloc_msg(size_t len)
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct msg_msg *msg;
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct msg_msgseg **pseg;
524e9b45a19241354daec281d7a785739829b52359Mathias Krause	size_t alen;
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
543d8fa456d5ed22ce8db085a89a037b87568b2b64Peter Hurley	alen = min(len, DATALEN_MSG);
555cbded585d129d0226cb48ac4202b253c781be26Robert P. J. Day	msg = kmalloc(sizeof(*msg) + alen, GFP_KERNEL);
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (msg == NULL)
57be5f4b335f6e05df1b5c24b7e7d79ff52d7b8dbcPeter Hurley		return NULL;
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	msg->next = NULL;
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	msg->security = NULL;
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
62be5f4b335f6e05df1b5c24b7e7d79ff52d7b8dbcPeter Hurley	len -= alen;
63be5f4b335f6e05df1b5c24b7e7d79ff52d7b8dbcPeter Hurley	pseg = &msg->next;
64be5f4b335f6e05df1b5c24b7e7d79ff52d7b8dbcPeter Hurley	while (len > 0) {
65be5f4b335f6e05df1b5c24b7e7d79ff52d7b8dbcPeter Hurley		struct msg_msgseg *seg;
66be5f4b335f6e05df1b5c24b7e7d79ff52d7b8dbcPeter Hurley		alen = min(len, DATALEN_SEG);
67be5f4b335f6e05df1b5c24b7e7d79ff52d7b8dbcPeter Hurley		seg = kmalloc(sizeof(*seg) + alen, GFP_KERNEL);
68be5f4b335f6e05df1b5c24b7e7d79ff52d7b8dbcPeter Hurley		if (seg == NULL)
69be5f4b335f6e05df1b5c24b7e7d79ff52d7b8dbcPeter Hurley			goto out_err;
70be5f4b335f6e05df1b5c24b7e7d79ff52d7b8dbcPeter Hurley		*pseg = seg;
71be5f4b335f6e05df1b5c24b7e7d79ff52d7b8dbcPeter Hurley		seg->next = NULL;
72be5f4b335f6e05df1b5c24b7e7d79ff52d7b8dbcPeter Hurley		pseg = &seg->next;
73be5f4b335f6e05df1b5c24b7e7d79ff52d7b8dbcPeter Hurley		len -= alen;
74be5f4b335f6e05df1b5c24b7e7d79ff52d7b8dbcPeter Hurley	}
75be5f4b335f6e05df1b5c24b7e7d79ff52d7b8dbcPeter Hurley
76be5f4b335f6e05df1b5c24b7e7d79ff52d7b8dbcPeter Hurley	return msg;
77be5f4b335f6e05df1b5c24b7e7d79ff52d7b8dbcPeter Hurley
78be5f4b335f6e05df1b5c24b7e7d79ff52d7b8dbcPeter Hurleyout_err:
79be5f4b335f6e05df1b5c24b7e7d79ff52d7b8dbcPeter Hurley	free_msg(msg);
80be5f4b335f6e05df1b5c24b7e7d79ff52d7b8dbcPeter Hurley	return NULL;
81be5f4b335f6e05df1b5c24b7e7d79ff52d7b8dbcPeter Hurley}
82be5f4b335f6e05df1b5c24b7e7d79ff52d7b8dbcPeter Hurley
834e9b45a19241354daec281d7a785739829b52359Mathias Krausestruct msg_msg *load_msg(const void __user *src, size_t len)
84be5f4b335f6e05df1b5c24b7e7d79ff52d7b8dbcPeter Hurley{
85be5f4b335f6e05df1b5c24b7e7d79ff52d7b8dbcPeter Hurley	struct msg_msg *msg;
86be5f4b335f6e05df1b5c24b7e7d79ff52d7b8dbcPeter Hurley	struct msg_msgseg *seg;
872b3097a294b6daaf390010de14ca50bfccbc6fb6Peter Hurley	int err = -EFAULT;
884e9b45a19241354daec281d7a785739829b52359Mathias Krause	size_t alen;
89be5f4b335f6e05df1b5c24b7e7d79ff52d7b8dbcPeter Hurley
90be5f4b335f6e05df1b5c24b7e7d79ff52d7b8dbcPeter Hurley	msg = alloc_msg(len);
91be5f4b335f6e05df1b5c24b7e7d79ff52d7b8dbcPeter Hurley	if (msg == NULL)
92be5f4b335f6e05df1b5c24b7e7d79ff52d7b8dbcPeter Hurley		return ERR_PTR(-ENOMEM);
93be5f4b335f6e05df1b5c24b7e7d79ff52d7b8dbcPeter Hurley
94be5f4b335f6e05df1b5c24b7e7d79ff52d7b8dbcPeter Hurley	alen = min(len, DATALEN_MSG);
952b3097a294b6daaf390010de14ca50bfccbc6fb6Peter Hurley	if (copy_from_user(msg + 1, src, alen))
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out_err;
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
98da085d4591a6fe11eac2e1f659f25b655e9f2e53Peter Hurley	for (seg = msg->next; seg != NULL; seg = seg->next) {
99da085d4591a6fe11eac2e1f659f25b655e9f2e53Peter Hurley		len -= alen;
100da085d4591a6fe11eac2e1f659f25b655e9f2e53Peter Hurley		src = (char __user *)src + alen;
1013d8fa456d5ed22ce8db085a89a037b87568b2b64Peter Hurley		alen = min(len, DATALEN_SEG);
1022b3097a294b6daaf390010de14ca50bfccbc6fb6Peter Hurley		if (copy_from_user(seg + 1, src, alen))
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto out_err;
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = security_msg_msg_alloc(msg);
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (err)
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		goto out_err;
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return msg;
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_err:
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	free_msg(msg);
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ERR_PTR(err);
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1164a674f34ba04a002244edaf891b5da7fc1473ae8Stanislav Kinsbursky#ifdef CONFIG_CHECKPOINT_RESTORE
1174a674f34ba04a002244edaf891b5da7fc1473ae8Stanislav Kinsburskystruct msg_msg *copy_msg(struct msg_msg *src, struct msg_msg *dst)
1184a674f34ba04a002244edaf891b5da7fc1473ae8Stanislav Kinsbursky{
1194a674f34ba04a002244edaf891b5da7fc1473ae8Stanislav Kinsbursky	struct msg_msgseg *dst_pseg, *src_pseg;
1204e9b45a19241354daec281d7a785739829b52359Mathias Krause	size_t len = src->m_ts;
1214e9b45a19241354daec281d7a785739829b52359Mathias Krause	size_t alen;
1224a674f34ba04a002244edaf891b5da7fc1473ae8Stanislav Kinsbursky
1234a674f34ba04a002244edaf891b5da7fc1473ae8Stanislav Kinsbursky	BUG_ON(dst == NULL);
1244a674f34ba04a002244edaf891b5da7fc1473ae8Stanislav Kinsbursky	if (src->m_ts > dst->m_ts)
1254a674f34ba04a002244edaf891b5da7fc1473ae8Stanislav Kinsbursky		return ERR_PTR(-EINVAL);
1264a674f34ba04a002244edaf891b5da7fc1473ae8Stanislav Kinsbursky
1273d8fa456d5ed22ce8db085a89a037b87568b2b64Peter Hurley	alen = min(len, DATALEN_MSG);
1284a674f34ba04a002244edaf891b5da7fc1473ae8Stanislav Kinsbursky	memcpy(dst + 1, src + 1, alen);
1294a674f34ba04a002244edaf891b5da7fc1473ae8Stanislav Kinsbursky
130da085d4591a6fe11eac2e1f659f25b655e9f2e53Peter Hurley	for (dst_pseg = dst->next, src_pseg = src->next;
131da085d4591a6fe11eac2e1f659f25b655e9f2e53Peter Hurley	     src_pseg != NULL;
132da085d4591a6fe11eac2e1f659f25b655e9f2e53Peter Hurley	     dst_pseg = dst_pseg->next, src_pseg = src_pseg->next) {
133da085d4591a6fe11eac2e1f659f25b655e9f2e53Peter Hurley
134da085d4591a6fe11eac2e1f659f25b655e9f2e53Peter Hurley		len -= alen;
1353d8fa456d5ed22ce8db085a89a037b87568b2b64Peter Hurley		alen = min(len, DATALEN_SEG);
1364a674f34ba04a002244edaf891b5da7fc1473ae8Stanislav Kinsbursky		memcpy(dst_pseg + 1, src_pseg + 1, alen);
1374a674f34ba04a002244edaf891b5da7fc1473ae8Stanislav Kinsbursky	}
1384a674f34ba04a002244edaf891b5da7fc1473ae8Stanislav Kinsbursky
1394a674f34ba04a002244edaf891b5da7fc1473ae8Stanislav Kinsbursky	dst->m_type = src->m_type;
1404a674f34ba04a002244edaf891b5da7fc1473ae8Stanislav Kinsbursky	dst->m_ts = src->m_ts;
1414a674f34ba04a002244edaf891b5da7fc1473ae8Stanislav Kinsbursky
1424a674f34ba04a002244edaf891b5da7fc1473ae8Stanislav Kinsbursky	return dst;
1434a674f34ba04a002244edaf891b5da7fc1473ae8Stanislav Kinsbursky}
14451eeacaa07d1372a7bc9612548ffe6cd846f4f2fStanislav Kinsbursky#else
14551eeacaa07d1372a7bc9612548ffe6cd846f4f2fStanislav Kinsburskystruct msg_msg *copy_msg(struct msg_msg *src, struct msg_msg *dst)
14651eeacaa07d1372a7bc9612548ffe6cd846f4f2fStanislav Kinsbursky{
14751eeacaa07d1372a7bc9612548ffe6cd846f4f2fStanislav Kinsbursky	return ERR_PTR(-ENOSYS);
14851eeacaa07d1372a7bc9612548ffe6cd846f4f2fStanislav Kinsbursky}
1494a674f34ba04a002244edaf891b5da7fc1473ae8Stanislav Kinsbursky#endif
1504e9b45a19241354daec281d7a785739829b52359Mathias Krauseint store_msg(void __user *dest, struct msg_msg *msg, size_t len)
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1524e9b45a19241354daec281d7a785739829b52359Mathias Krause	size_t alen;
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct msg_msgseg *seg;
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1553d8fa456d5ed22ce8db085a89a037b87568b2b64Peter Hurley	alen = min(len, DATALEN_MSG);
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (copy_to_user(dest, msg + 1, alen))
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
159da085d4591a6fe11eac2e1f659f25b655e9f2e53Peter Hurley	for (seg = msg->next; seg != NULL; seg = seg->next) {
160da085d4591a6fe11eac2e1f659f25b655e9f2e53Peter Hurley		len -= alen;
161da085d4591a6fe11eac2e1f659f25b655e9f2e53Peter Hurley		dest = (char __user *)dest + alen;
1623d8fa456d5ed22ce8db085a89a037b87568b2b64Peter Hurley		alen = min(len, DATALEN_SEG);
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (copy_to_user(dest, seg + 1, alen))
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return -1;
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid free_msg(struct msg_msg *msg)
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct msg_msgseg *seg;
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	security_msg_msg_free(msg);
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	seg = msg->next;
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(msg);
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (seg != NULL) {
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		struct msg_msgseg *tmp = seg->next;
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		kfree(seg);
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		seg = tmp;
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
183