Branch data Line data Source code
1 : : /*
2 : : * linux/ipc/msgutil.c
3 : : * Copyright (C) 1999, 2004 Manfred Spraul
4 : : *
5 : : * This file is released under GNU General Public Licence version 2 or
6 : : * (at your option) any later version.
7 : : *
8 : : * See the file COPYING for more details.
9 : : */
10 : :
11 : : #include <linux/spinlock.h>
12 : : #include <linux/init.h>
13 : : #include <linux/security.h>
14 : : #include <linux/slab.h>
15 : : #include <linux/ipc.h>
16 : : #include <linux/msg.h>
17 : : #include <linux/ipc_namespace.h>
18 : : #include <linux/utsname.h>
19 : : #include <linux/proc_ns.h>
20 : : #include <linux/uaccess.h>
21 : :
22 : : #include "util.h"
23 : :
24 : : DEFINE_SPINLOCK(mq_lock);
25 : :
26 : : /*
27 : : * The next 2 defines are here bc this is the only file
28 : : * compiled when either CONFIG_SYSVIPC and CONFIG_POSIX_MQUEUE
29 : : * and not CONFIG_IPC_NS.
30 : : */
31 : : struct ipc_namespace init_ipc_ns = {
32 : : .count = ATOMIC_INIT(1),
33 : : .user_ns = &init_user_ns,
34 : : .proc_inum = PROC_IPC_INIT_INO,
35 : : };
36 : :
37 : : atomic_t nr_ipc_ns = ATOMIC_INIT(1);
38 : :
39 : : struct msg_msgseg {
40 : : struct msg_msgseg *next;
41 : : /* the next part of the message follows immediately */
42 : : };
43 : :
44 : : #define DATALEN_MSG ((size_t)PAGE_SIZE-sizeof(struct msg_msg))
45 : : #define DATALEN_SEG ((size_t)PAGE_SIZE-sizeof(struct msg_msgseg))
46 : :
47 : :
48 : 0 : static struct msg_msg *alloc_msg(size_t len)
49 : : {
50 : : struct msg_msg *msg;
51 : : struct msg_msgseg **pseg;
52 : : size_t alen;
53 : :
54 : 23553640 : alen = min(len, DATALEN_MSG);
55 : 23553640 : msg = kmalloc(sizeof(*msg) + alen, GFP_KERNEL);
56 [ + - ]: 23576741 : if (msg == NULL)
57 : : return NULL;
58 : :
59 : 23576741 : msg->next = NULL;
60 : 23576741 : msg->security = NULL;
61 : :
62 : 23576741 : len -= alen;
63 : 23576741 : pseg = &msg->next;
64 [ + + ]: 23576745 : while (len > 0) {
65 : : struct msg_msgseg *seg;
66 : 4 : alen = min(len, DATALEN_SEG);
67 : 4 : seg = kmalloc(sizeof(*seg) + alen, GFP_KERNEL);
68 [ + - ]: 4 : if (seg == NULL)
69 : : goto out_err;
70 : 4 : *pseg = seg;
71 : 4 : seg->next = NULL;
72 : 4 : pseg = &seg->next;
73 : 4 : len -= alen;
74 : : }
75 : :
76 : : return msg;
77 : :
78 : : out_err:
79 : 0 : free_msg(msg);
80 : 0 : return NULL;
81 : : }
82 : :
83 : 0 : struct msg_msg *load_msg(const void __user *src, size_t len)
84 : : {
85 : : struct msg_msg *msg;
86 : : struct msg_msgseg *seg;
87 : : int err = -EFAULT;
88 : : size_t alen;
89 : :
90 : 23554324 : msg = alloc_msg(len);
91 [ + ]: 23573310 : if (msg == NULL)
92 : : return ERR_PTR(-ENOMEM);
93 : :
94 : 23576498 : alen = min(len, DATALEN_MSG);
95 [ + - ]: 47118743 : if (copy_from_user(msg + 1, src, alen))
96 : : goto out_err;
97 : :
98 [ + + ]: 23564423 : for (seg = msg->next; seg != NULL; seg = seg->next) {
99 : 4 : len -= alen;
100 : 4 : src = (char __user *)src + alen;
101 : 4 : alen = min(len, DATALEN_SEG);
102 [ + - ]: 4 : if (copy_from_user(seg + 1, src, alen))
103 : : goto out_err;
104 : : }
105 : :
106 : 23564419 : err = security_msg_msg_alloc(msg);
107 [ + + ]: 23575356 : if (err)
108 : : goto out_err;
109 : :
110 : : return msg;
111 : :
112 : : out_err:
113 : 4979 : free_msg(msg);
114 : 0 : return ERR_PTR(err);
115 : : }
116 : : #ifdef CONFIG_CHECKPOINT_RESTORE
117 : : struct msg_msg *copy_msg(struct msg_msg *src, struct msg_msg *dst)
118 : : {
119 : : struct msg_msgseg *dst_pseg, *src_pseg;
120 : : size_t len = src->m_ts;
121 : : size_t alen;
122 : :
123 : : BUG_ON(dst == NULL);
124 : : if (src->m_ts > dst->m_ts)
125 : : return ERR_PTR(-EINVAL);
126 : :
127 : : alen = min(len, DATALEN_MSG);
128 : : memcpy(dst + 1, src + 1, alen);
129 : :
130 : : for (dst_pseg = dst->next, src_pseg = src->next;
131 : : src_pseg != NULL;
132 : : dst_pseg = dst_pseg->next, src_pseg = src_pseg->next) {
133 : :
134 : : len -= alen;
135 : : alen = min(len, DATALEN_SEG);
136 : : memcpy(dst_pseg + 1, src_pseg + 1, alen);
137 : : }
138 : :
139 : : dst->m_type = src->m_type;
140 : : dst->m_ts = src->m_ts;
141 : :
142 : : return dst;
143 : : }
144 : : #else
145 : 0 : struct msg_msg *copy_msg(struct msg_msg *src, struct msg_msg *dst)
146 : : {
147 : 0 : return ERR_PTR(-ENOSYS);
148 : : }
149 : : #endif
150 : 0 : int store_msg(void __user *dest, struct msg_msg *msg, size_t len)
151 : : {
152 : : size_t alen;
153 : : struct msg_msgseg *seg;
154 : :
155 : 23565656 : alen = min(len, DATALEN_MSG);
156 [ + - ]: 23555804 : if (copy_to_user(dest, msg + 1, alen))
157 : : return -1;
158 : :
159 [ + + ]: 23555808 : for (seg = msg->next; seg != NULL; seg = seg->next) {
160 : 4 : len -= alen;
161 : 4 : dest = (char __user *)dest + alen;
162 : 4 : alen = min(len, DATALEN_SEG);
163 [ + - ]: 4 : if (copy_to_user(dest, seg + 1, alen))
164 : : return -1;
165 : : }
166 : : return 0;
167 : : }
168 : :
169 : 0 : void free_msg(struct msg_msg *msg)
170 : : {
171 : : struct msg_msgseg *seg;
172 : :
173 : 23574239 : security_msg_msg_free(msg);
174 : :
175 : 23581080 : seg = msg->next;
176 : 23581080 : kfree(msg);
177 [ + + ]: 23588700 : while (seg != NULL) {
178 : 4 : struct msg_msgseg *tmp = seg->next;
179 : 4 : kfree(seg);
180 : : seg = tmp;
181 : : }
182 : 23588696 : }
|