diff options
Diffstat (limited to 'ipc/msgutil.c')
-rw-r--r-- | ipc/msgutil.c | 112 |
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 = { | |||
37 | atomic_t nr_ipc_ns = ATOMIC_INIT(1); | 37 | atomic_t nr_ipc_ns = ATOMIC_INIT(1); |
38 | 38 | ||
39 | struct msg_msgseg { | 39 | struct 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 | ||
47 | struct msg_msg *load_msg(const void __user *src, int len) | 47 | |
48 | static 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 | |||
78 | out_err: | ||
79 | free_msg(msg); | ||
80 | return NULL; | ||
81 | } | ||
82 | |||
83 | struct 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 | } |