11da177e4SLinus Torvalds /* 2f30c2269SUwe Zeisberger * linux/ipc/msgutil.c 31da177e4SLinus Torvalds * Copyright (C) 1999, 2004 Manfred Spraul 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * This file is released under GNU General Public Licence version 2 or 61da177e4SLinus Torvalds * (at your option) any later version. 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * See the file COPYING for more details. 91da177e4SLinus Torvalds */ 101da177e4SLinus Torvalds 111da177e4SLinus Torvalds #include <linux/spinlock.h> 121da177e4SLinus Torvalds #include <linux/init.h> 131da177e4SLinus Torvalds #include <linux/security.h> 141da177e4SLinus Torvalds #include <linux/slab.h> 151da177e4SLinus Torvalds #include <linux/ipc.h> 1640401530SAl Viro #include <linux/msg.h> 17614b84cfSSerge E. Hallyn #include <linux/ipc_namespace.h> 1840401530SAl Viro #include <linux/utsname.h> 190bb80f24SDavid Howells #include <linux/proc_ns.h> 201e3c941cSHoSung Jung #include <linux/uaccess.h> 211da177e4SLinus Torvalds 221da177e4SLinus Torvalds #include "util.h" 231da177e4SLinus Torvalds 247eafd7c7SSerge E. Hallyn DEFINE_SPINLOCK(mq_lock); 257eafd7c7SSerge E. Hallyn 26614b84cfSSerge E. Hallyn /* 27614b84cfSSerge E. Hallyn * The next 2 defines are here bc this is the only file 28614b84cfSSerge E. Hallyn * compiled when either CONFIG_SYSVIPC and CONFIG_POSIX_MQUEUE 29614b84cfSSerge E. Hallyn * and not CONFIG_IPC_NS. 30614b84cfSSerge E. Hallyn */ 31614b84cfSSerge E. Hallyn struct ipc_namespace init_ipc_ns = { 327eafd7c7SSerge E. Hallyn .count = ATOMIC_INIT(1), 33b515498fSSerge E. Hallyn .user_ns = &init_user_ns, 34435d5f4bSAl Viro .ns.inum = PROC_IPC_INIT_INO, 35*33c42940SAl Viro #ifdef CONFIG_IPC_NS 36*33c42940SAl Viro .ns.ops = &ipcns_operations, 37*33c42940SAl Viro #endif 38614b84cfSSerge E. Hallyn }; 39614b84cfSSerge E. Hallyn 40614b84cfSSerge E. Hallyn atomic_t nr_ipc_ns = ATOMIC_INIT(1); 41614b84cfSSerge E. Hallyn 421da177e4SLinus Torvalds struct msg_msgseg { 431da177e4SLinus Torvalds struct msg_msgseg *next; 441da177e4SLinus Torvalds /* the next part of the message follows immediately */ 451da177e4SLinus Torvalds }; 461da177e4SLinus Torvalds 474e9b45a1SMathias Krause #define DATALEN_MSG ((size_t)PAGE_SIZE-sizeof(struct msg_msg)) 484e9b45a1SMathias Krause #define DATALEN_SEG ((size_t)PAGE_SIZE-sizeof(struct msg_msgseg)) 491da177e4SLinus Torvalds 50be5f4b33SPeter Hurley 514e9b45a1SMathias Krause static struct msg_msg *alloc_msg(size_t len) 521da177e4SLinus Torvalds { 531da177e4SLinus Torvalds struct msg_msg *msg; 541da177e4SLinus Torvalds struct msg_msgseg **pseg; 554e9b45a1SMathias Krause size_t alen; 561da177e4SLinus Torvalds 573d8fa456SPeter Hurley alen = min(len, DATALEN_MSG); 585cbded58SRobert P. J. Day msg = kmalloc(sizeof(*msg) + alen, GFP_KERNEL); 591da177e4SLinus Torvalds if (msg == NULL) 60be5f4b33SPeter Hurley return NULL; 611da177e4SLinus Torvalds 621da177e4SLinus Torvalds msg->next = NULL; 631da177e4SLinus Torvalds msg->security = NULL; 641da177e4SLinus Torvalds 65be5f4b33SPeter Hurley len -= alen; 66be5f4b33SPeter Hurley pseg = &msg->next; 67be5f4b33SPeter Hurley while (len > 0) { 68be5f4b33SPeter Hurley struct msg_msgseg *seg; 69be5f4b33SPeter Hurley alen = min(len, DATALEN_SEG); 70be5f4b33SPeter Hurley seg = kmalloc(sizeof(*seg) + alen, GFP_KERNEL); 71be5f4b33SPeter Hurley if (seg == NULL) 72be5f4b33SPeter Hurley goto out_err; 73be5f4b33SPeter Hurley *pseg = seg; 74be5f4b33SPeter Hurley seg->next = NULL; 75be5f4b33SPeter Hurley pseg = &seg->next; 76be5f4b33SPeter Hurley len -= alen; 77be5f4b33SPeter Hurley } 78be5f4b33SPeter Hurley 79be5f4b33SPeter Hurley return msg; 80be5f4b33SPeter Hurley 81be5f4b33SPeter Hurley out_err: 82be5f4b33SPeter Hurley free_msg(msg); 83be5f4b33SPeter Hurley return NULL; 84be5f4b33SPeter Hurley } 85be5f4b33SPeter Hurley 864e9b45a1SMathias Krause struct msg_msg *load_msg(const void __user *src, size_t len) 87be5f4b33SPeter Hurley { 88be5f4b33SPeter Hurley struct msg_msg *msg; 89be5f4b33SPeter Hurley struct msg_msgseg *seg; 902b3097a2SPeter Hurley int err = -EFAULT; 914e9b45a1SMathias Krause size_t alen; 92be5f4b33SPeter Hurley 93be5f4b33SPeter Hurley msg = alloc_msg(len); 94be5f4b33SPeter Hurley if (msg == NULL) 95be5f4b33SPeter Hurley return ERR_PTR(-ENOMEM); 96be5f4b33SPeter Hurley 97be5f4b33SPeter Hurley alen = min(len, DATALEN_MSG); 982b3097a2SPeter Hurley if (copy_from_user(msg + 1, src, alen)) 991da177e4SLinus Torvalds goto out_err; 1001da177e4SLinus Torvalds 101da085d45SPeter Hurley for (seg = msg->next; seg != NULL; seg = seg->next) { 1021da177e4SLinus Torvalds len -= alen; 103da085d45SPeter Hurley src = (char __user *)src + alen; 1043d8fa456SPeter Hurley alen = min(len, DATALEN_SEG); 1052b3097a2SPeter Hurley if (copy_from_user(seg + 1, src, alen)) 1061da177e4SLinus Torvalds goto out_err; 1071da177e4SLinus Torvalds } 1081da177e4SLinus Torvalds 1091da177e4SLinus Torvalds err = security_msg_msg_alloc(msg); 1101da177e4SLinus Torvalds if (err) 1111da177e4SLinus Torvalds goto out_err; 1121da177e4SLinus Torvalds 1131da177e4SLinus Torvalds return msg; 1141da177e4SLinus Torvalds 1151da177e4SLinus Torvalds out_err: 1161da177e4SLinus Torvalds free_msg(msg); 1171da177e4SLinus Torvalds return ERR_PTR(err); 1181da177e4SLinus Torvalds } 1194a674f34SStanislav Kinsbursky #ifdef CONFIG_CHECKPOINT_RESTORE 1204a674f34SStanislav Kinsbursky struct msg_msg *copy_msg(struct msg_msg *src, struct msg_msg *dst) 1214a674f34SStanislav Kinsbursky { 1224a674f34SStanislav Kinsbursky struct msg_msgseg *dst_pseg, *src_pseg; 1234e9b45a1SMathias Krause size_t len = src->m_ts; 1244e9b45a1SMathias Krause size_t alen; 1251da177e4SLinus Torvalds 1264a674f34SStanislav Kinsbursky BUG_ON(dst == NULL); 1274a674f34SStanislav Kinsbursky if (src->m_ts > dst->m_ts) 1284a674f34SStanislav Kinsbursky return ERR_PTR(-EINVAL); 1294a674f34SStanislav Kinsbursky 1303d8fa456SPeter Hurley alen = min(len, DATALEN_MSG); 1314a674f34SStanislav Kinsbursky memcpy(dst + 1, src + 1, alen); 1324a674f34SStanislav Kinsbursky 133da085d45SPeter Hurley for (dst_pseg = dst->next, src_pseg = src->next; 134da085d45SPeter Hurley src_pseg != NULL; 135da085d45SPeter Hurley dst_pseg = dst_pseg->next, src_pseg = src_pseg->next) { 136da085d45SPeter Hurley 1374a674f34SStanislav Kinsbursky len -= alen; 1383d8fa456SPeter Hurley alen = min(len, DATALEN_SEG); 1394a674f34SStanislav Kinsbursky memcpy(dst_pseg + 1, src_pseg + 1, alen); 1404a674f34SStanislav Kinsbursky } 1414a674f34SStanislav Kinsbursky 1424a674f34SStanislav Kinsbursky dst->m_type = src->m_type; 1434a674f34SStanislav Kinsbursky dst->m_ts = src->m_ts; 1444a674f34SStanislav Kinsbursky 1454a674f34SStanislav Kinsbursky return dst; 1464a674f34SStanislav Kinsbursky } 14751eeacaaSStanislav Kinsbursky #else 14851eeacaaSStanislav Kinsbursky struct msg_msg *copy_msg(struct msg_msg *src, struct msg_msg *dst) 14951eeacaaSStanislav Kinsbursky { 15051eeacaaSStanislav Kinsbursky return ERR_PTR(-ENOSYS); 15151eeacaaSStanislav Kinsbursky } 1524a674f34SStanislav Kinsbursky #endif 1534e9b45a1SMathias Krause int store_msg(void __user *dest, struct msg_msg *msg, size_t len) 1541da177e4SLinus Torvalds { 1554e9b45a1SMathias Krause size_t alen; 1561da177e4SLinus Torvalds struct msg_msgseg *seg; 1571da177e4SLinus Torvalds 1583d8fa456SPeter Hurley alen = min(len, DATALEN_MSG); 1591da177e4SLinus Torvalds if (copy_to_user(dest, msg + 1, alen)) 1601da177e4SLinus Torvalds return -1; 1611da177e4SLinus Torvalds 162da085d45SPeter Hurley for (seg = msg->next; seg != NULL; seg = seg->next) { 1631da177e4SLinus Torvalds len -= alen; 164da085d45SPeter Hurley dest = (char __user *)dest + alen; 1653d8fa456SPeter Hurley alen = min(len, DATALEN_SEG); 1661da177e4SLinus Torvalds if (copy_to_user(dest, seg + 1, alen)) 1671da177e4SLinus Torvalds return -1; 1681da177e4SLinus Torvalds } 1691da177e4SLinus Torvalds return 0; 1701da177e4SLinus Torvalds } 1711da177e4SLinus Torvalds 1721da177e4SLinus Torvalds void free_msg(struct msg_msg *msg) 1731da177e4SLinus Torvalds { 1741da177e4SLinus Torvalds struct msg_msgseg *seg; 1751da177e4SLinus Torvalds 1761da177e4SLinus Torvalds security_msg_msg_free(msg); 1771da177e4SLinus Torvalds 1781da177e4SLinus Torvalds seg = msg->next; 1791da177e4SLinus Torvalds kfree(msg); 1801da177e4SLinus Torvalds while (seg != NULL) { 1811da177e4SLinus Torvalds struct msg_msgseg *tmp = seg->next; 1821da177e4SLinus Torvalds kfree(seg); 1831da177e4SLinus Torvalds seg = tmp; 1841da177e4SLinus Torvalds } 1851da177e4SLinus Torvalds } 186