blob: e38479377741d11d2bbc5dcca65ecc12ce6ad57a [file] [log] [blame]
lh9ed821d2023-04-07 01:36:19 -07001/*
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 <asm/uaccess.h>
20
21#include "util.h"
22
23DEFINE_SPINLOCK(mq_lock);
24
25/*
26 * The next 2 defines are here bc this is the only file
27 * compiled when either CONFIG_SYSVIPC and CONFIG_POSIX_MQUEUE
28 * and not CONFIG_IPC_NS.
29 */
30struct ipc_namespace init_ipc_ns = {
31 .count = ATOMIC_INIT(1),
32 .user_ns = &init_user_ns,
33};
34
35atomic_t nr_ipc_ns = ATOMIC_INIT(1);
36
37struct msg_msgseg {
38 struct msg_msgseg* next;
39 /* the next part of the message follows immediately */
40};
41
42#define DATALEN_MSG ((size_t)PAGE_SIZE-sizeof(struct msg_msg))
43#define DATALEN_SEG ((size_t)PAGE_SIZE-sizeof(struct msg_msgseg))
44
lh758261d2023-07-13 05:52:04 -070045#ifdef CONFIG_SYSVIPC_CROSSMSG
46struct msg_msg *load_kmsg(const void *src, size_t len)
47{
48 struct msg_msg *msg;
49 struct msg_msgseg **pseg;
50 int err;
51 size_t alen;
52
53 alen = len;
54 if (alen > DATALEN_MSG)
55 alen = DATALEN_MSG;
56
57 msg = kmalloc(sizeof(*msg) + alen, GFP_KERNEL);
58 if (msg == NULL)
59 return ERR_PTR(-ENOMEM);
60
61 msg->next = NULL;
62 msg->security = NULL;
63
64 memcpy(msg + 1, src, alen);
65
66 len -= alen;
67 src = ((char *)src) + alen;
68 pseg = &msg->next;
69 while (len > 0) {
70 struct msg_msgseg *seg;
71 alen = len;
72 if (alen > DATALEN_SEG)
73 alen = DATALEN_SEG;
74 seg = kmalloc(sizeof(*seg) + alen,
75 GFP_KERNEL);
76 if (seg == NULL) {
77 err = -ENOMEM;
78 goto out_err;
79 }
80 *pseg = seg;
81 seg->next = NULL;
82 memcpy(seg + 1, src, alen);
83 pseg = &seg->next;
84 len -= alen;
85 src = ((char *)src) + alen;
86 }
87
88 err = security_msg_msg_alloc(msg);
89 if (err)
90 goto out_err;
91
92 return msg;
93
94out_err:
95 free_msg(msg);
96 return ERR_PTR(err);
97}
98#endif
99
lh9ed821d2023-04-07 01:36:19 -0700100struct msg_msg *load_msg(const void __user *src, size_t len)
101{
102 struct msg_msg *msg;
103 struct msg_msgseg **pseg;
104 int err;
105 size_t alen;
106
107 alen = len;
108 if (alen > DATALEN_MSG)
109 alen = DATALEN_MSG;
110
111 msg = kmalloc(sizeof(*msg) + alen, GFP_KERNEL);
112 if (msg == NULL)
113 return ERR_PTR(-ENOMEM);
114
115 msg->next = NULL;
116 msg->security = NULL;
117
118 if (copy_from_user(msg + 1, src, alen)) {
119 err = -EFAULT;
120 goto out_err;
121 }
122
123 len -= alen;
124 src = ((char __user *)src) + alen;
125 pseg = &msg->next;
126 while (len > 0) {
127 struct msg_msgseg *seg;
128 alen = len;
129 if (alen > DATALEN_SEG)
130 alen = DATALEN_SEG;
131 seg = kmalloc(sizeof(*seg) + alen,
132 GFP_KERNEL);
133 if (seg == NULL) {
134 err = -ENOMEM;
135 goto out_err;
136 }
137 *pseg = seg;
138 seg->next = NULL;
139 if (copy_from_user(seg + 1, src, alen)) {
140 err = -EFAULT;
141 goto out_err;
142 }
143 pseg = &seg->next;
144 len -= alen;
145 src = ((char __user *)src) + alen;
146 }
147
148 err = security_msg_msg_alloc(msg);
149 if (err)
150 goto out_err;
151
152 return msg;
153
154out_err:
155 free_msg(msg);
156 return ERR_PTR(err);
157}
158
159int store_msg(void __user *dest, struct msg_msg *msg, size_t len)
160{
161 size_t alen;
162 struct msg_msgseg *seg;
163
164 alen = len;
165 if (alen > DATALEN_MSG)
166 alen = DATALEN_MSG;
167 if (copy_to_user(dest, msg + 1, alen))
168 return -1;
169
170 len -= alen;
171 dest = ((char __user *)dest) + alen;
172 seg = msg->next;
173 while (len > 0) {
174 alen = len;
175 if (alen > DATALEN_SEG)
176 alen = DATALEN_SEG;
177 if (copy_to_user(dest, seg + 1, alen))
178 return -1;
179 len -= alen;
180 dest = ((char __user *)dest) + alen;
181 seg = seg->next;
182 }
183 return 0;
184}
185
186void free_msg(struct msg_msg *msg)
187{
188 struct msg_msgseg *seg;
189
190 security_msg_msg_free(msg);
191
192 seg = msg->next;
193 kfree(msg);
194 while (seg != NULL) {
195 struct msg_msgseg *tmp = seg->next;
196 kfree(seg);
197 seg = tmp;
198 }
199}