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