aboutsummaryrefslogtreecommitdiffstats
path: root/ipc/msgutil.c
diff options
context:
space:
mode:
Diffstat (limited to 'ipc/msgutil.c')
-rw-r--r--ipc/msgutil.c112
1 files changed, 54 insertions, 58 deletions
diff --git a/ipc/msgutil.c b/ipc/msgutil.c
index 5df8e4bf1db0..491e71f2a1b8 100644
--- a/ipc/msgutil.c
+++ b/ipc/msgutil.c
@@ -16,8 +16,8 @@
16#include <linux/msg.h> 16#include <linux/msg.h>
17#include <linux/ipc_namespace.h> 17#include <linux/ipc_namespace.h>
18#include <linux/utsname.h> 18#include <linux/utsname.h>
19#include <linux/proc_fs.h> 19#include <linux/proc_ns.h>
20#include <asm/uaccess.h> 20#include <linux/uaccess.h>
21 21
22#include "util.h" 22#include "util.h"
23 23
@@ -37,59 +37,70 @@ struct ipc_namespace init_ipc_ns = {
37atomic_t nr_ipc_ns = ATOMIC_INIT(1); 37atomic_t nr_ipc_ns = ATOMIC_INIT(1);
38 38
39struct msg_msgseg { 39struct msg_msgseg {
40 struct msg_msgseg* next; 40 struct msg_msgseg *next;
41 /* the next part of the message follows immediately */ 41 /* the next part of the message follows immediately */
42}; 42};
43 43
44#define DATALEN_MSG (PAGE_SIZE-sizeof(struct msg_msg)) 44#define DATALEN_MSG (int)(PAGE_SIZE-sizeof(struct msg_msg))
45#define DATALEN_SEG (PAGE_SIZE-sizeof(struct msg_msgseg)) 45#define DATALEN_SEG (int)(PAGE_SIZE-sizeof(struct msg_msgseg))
46 46
47struct msg_msg *load_msg(const void __user *src, int len) 47
48static struct msg_msg *alloc_msg(int len)
48{ 49{
49 struct msg_msg *msg; 50 struct msg_msg *msg;
50 struct msg_msgseg **pseg; 51 struct msg_msgseg **pseg;
51 int err;
52 int alen; 52 int alen;
53 53
54 alen = len; 54 alen = min(len, DATALEN_MSG);
55 if (alen > DATALEN_MSG)
56 alen = DATALEN_MSG;
57
58 msg = kmalloc(sizeof(*msg) + alen, GFP_KERNEL); 55 msg = kmalloc(sizeof(*msg) + alen, GFP_KERNEL);
59 if (msg == NULL) 56 if (msg == NULL)
60 return ERR_PTR(-ENOMEM); 57 return NULL;
61 58
62 msg->next = NULL; 59 msg->next = NULL;
63 msg->security = NULL; 60 msg->security = NULL;
64 61
65 if (copy_from_user(msg + 1, src, alen)) {
66 err = -EFAULT;
67 goto out_err;
68 }
69
70 len -= alen; 62 len -= alen;
71 src = ((char __user *)src) + alen;
72 pseg = &msg->next; 63 pseg = &msg->next;
73 while (len > 0) { 64 while (len > 0) {
74 struct msg_msgseg *seg; 65 struct msg_msgseg *seg;
75 alen = len; 66 alen = min(len, DATALEN_SEG);
76 if (alen > DATALEN_SEG) 67 seg = kmalloc(sizeof(*seg) + alen, GFP_KERNEL);
77 alen = DATALEN_SEG; 68 if (seg == NULL)
78 seg = kmalloc(sizeof(*seg) + alen,
79 GFP_KERNEL);
80 if (seg == NULL) {
81 err = -ENOMEM;
82 goto out_err; 69 goto out_err;
83 }
84 *pseg = seg; 70 *pseg = seg;
85 seg->next = NULL; 71 seg->next = NULL;
86 if (copy_from_user(seg + 1, src, alen)) {
87 err = -EFAULT;
88 goto out_err;
89 }
90 pseg = &seg->next; 72 pseg = &seg->next;
91 len -= alen; 73 len -= alen;
92 src = ((char __user *)src) + alen; 74 }
75
76 return msg;
77
78out_err:
79 free_msg(msg);
80 return NULL;
81}
82
83struct msg_msg *load_msg(const void __user *src, int len)
84{
85 struct msg_msg *msg;
86 struct msg_msgseg *seg;
87 int err = -EFAULT;
88 int alen;
89
90 msg = alloc_msg(len);
91 if (msg == NULL)
92 return ERR_PTR(-ENOMEM);
93
94 alen = min(len, DATALEN_MSG);
95 if (copy_from_user(msg + 1, src, alen))
96 goto out_err;
97
98 for (seg = msg->next; seg != NULL; seg = seg->next) {
99 len -= alen;
100 src = (char __user *)src + alen;
101 alen = min(len, DATALEN_SEG);
102 if (copy_from_user(seg + 1, src, alen))
103 goto out_err;
93 } 104 }
94 105
95 err = security_msg_msg_alloc(msg); 106 err = security_msg_msg_alloc(msg);
@@ -113,23 +124,16 @@ struct msg_msg *copy_msg(struct msg_msg *src, struct msg_msg *dst)
113 if (src->m_ts > dst->m_ts) 124 if (src->m_ts > dst->m_ts)
114 return ERR_PTR(-EINVAL); 125 return ERR_PTR(-EINVAL);
115 126
116 alen = len; 127 alen = min(len, DATALEN_MSG);
117 if (alen > DATALEN_MSG)
118 alen = DATALEN_MSG;
119
120 memcpy(dst + 1, src + 1, alen); 128 memcpy(dst + 1, src + 1, alen);
121 129
122 len -= alen; 130 for (dst_pseg = dst->next, src_pseg = src->next;
123 dst_pseg = dst->next; 131 src_pseg != NULL;
124 src_pseg = src->next; 132 dst_pseg = dst_pseg->next, src_pseg = src_pseg->next) {
125 while (len > 0) { 133
126 alen = len;
127 if (alen > DATALEN_SEG)
128 alen = DATALEN_SEG;
129 memcpy(dst_pseg + 1, src_pseg + 1, alen);
130 dst_pseg = dst_pseg->next;
131 len -= alen; 134 len -= alen;
132 src_pseg = src_pseg->next; 135 alen = min(len, DATALEN_SEG);
136 memcpy(dst_pseg + 1, src_pseg + 1, alen);
133 } 137 }
134 138
135 dst->m_type = src->m_type; 139 dst->m_type = src->m_type;
@@ -148,24 +152,16 @@ int store_msg(void __user *dest, struct msg_msg *msg, int len)
148 int alen; 152 int alen;
149 struct msg_msgseg *seg; 153 struct msg_msgseg *seg;
150 154
151 alen = len; 155 alen = min(len, DATALEN_MSG);
152 if (alen > DATALEN_MSG)
153 alen = DATALEN_MSG;
154 if (copy_to_user(dest, msg + 1, alen)) 156 if (copy_to_user(dest, msg + 1, alen))
155 return -1; 157 return -1;
156 158
157 len -= alen; 159 for (seg = msg->next; seg != NULL; seg = seg->next) {
158 dest = ((char __user *)dest) + alen; 160 len -= alen;
159 seg = msg->next; 161 dest = (char __user *)dest + alen;
160 while (len > 0) { 162 alen = min(len, DATALEN_SEG);
161 alen = len;
162 if (alen > DATALEN_SEG)
163 alen = DATALEN_SEG;
164 if (copy_to_user(dest, seg + 1, alen)) 163 if (copy_to_user(dest, seg + 1, alen))
165 return -1; 164 return -1;
166 len -= alen;
167 dest = ((char __user *)dest) + alen;
168 seg = seg->next;
169 } 165 }
170 return 0; 166 return 0;
171} 167}