xref: /openbmc/linux/ipc/msgutil.c (revision 7490ca1e)
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/ipc_namespace.h>
17 #include <asm/uaccess.h>
18 
19 #include "util.h"
20 
21 DEFINE_SPINLOCK(mq_lock);
22 
23 /*
24  * The next 2 defines are here bc this is the only file
25  * compiled when either CONFIG_SYSVIPC and CONFIG_POSIX_MQUEUE
26  * and not CONFIG_IPC_NS.
27  */
28 struct ipc_namespace init_ipc_ns = {
29 	.count		= ATOMIC_INIT(1),
30 	.user_ns = &init_user_ns,
31 };
32 
33 atomic_t nr_ipc_ns = ATOMIC_INIT(1);
34 
35 struct msg_msgseg {
36 	struct msg_msgseg* next;
37 	/* the next part of the message follows immediately */
38 };
39 
40 #define DATALEN_MSG	(PAGE_SIZE-sizeof(struct msg_msg))
41 #define DATALEN_SEG	(PAGE_SIZE-sizeof(struct msg_msgseg))
42 
43 struct msg_msg *load_msg(const void __user *src, int len)
44 {
45 	struct msg_msg *msg;
46 	struct msg_msgseg **pseg;
47 	int err;
48 	int alen;
49 
50 	alen = len;
51 	if (alen > DATALEN_MSG)
52 		alen = DATALEN_MSG;
53 
54 	msg = kmalloc(sizeof(*msg) + alen, GFP_KERNEL);
55 	if (msg == NULL)
56 		return ERR_PTR(-ENOMEM);
57 
58 	msg->next = NULL;
59 	msg->security = NULL;
60 
61 	if (copy_from_user(msg + 1, src, alen)) {
62 		err = -EFAULT;
63 		goto out_err;
64 	}
65 
66 	len -= alen;
67 	src = ((char __user *)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 		if (copy_from_user(seg + 1, src, alen)) {
83 			err = -EFAULT;
84 			goto out_err;
85 		}
86 		pseg = &seg->next;
87 		len -= alen;
88 		src = ((char __user *)src) + alen;
89 	}
90 
91 	err = security_msg_msg_alloc(msg);
92 	if (err)
93 		goto out_err;
94 
95 	return msg;
96 
97 out_err:
98 	free_msg(msg);
99 	return ERR_PTR(err);
100 }
101 
102 int store_msg(void __user *dest, struct msg_msg *msg, int len)
103 {
104 	int alen;
105 	struct msg_msgseg *seg;
106 
107 	alen = len;
108 	if (alen > DATALEN_MSG)
109 		alen = DATALEN_MSG;
110 	if (copy_to_user(dest, msg + 1, alen))
111 		return -1;
112 
113 	len -= alen;
114 	dest = ((char __user *)dest) + alen;
115 	seg = msg->next;
116 	while (len > 0) {
117 		alen = len;
118 		if (alen > DATALEN_SEG)
119 			alen = DATALEN_SEG;
120 		if (copy_to_user(dest, seg + 1, alen))
121 			return -1;
122 		len -= alen;
123 		dest = ((char __user *)dest) + alen;
124 		seg = seg->next;
125 	}
126 	return 0;
127 }
128 
129 void free_msg(struct msg_msg *msg)
130 {
131 	struct msg_msgseg *seg;
132 
133 	security_msg_msg_free(msg);
134 
135 	seg = msg->next;
136 	kfree(msg);
137 	while (seg != NULL) {
138 		struct msg_msgseg *tmp = seg->next;
139 		kfree(seg);
140 		seg = tmp;
141 	}
142 }
143