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 <asm/uaccess.h>
17
18 #include "util.h"
19
20 struct msg_msgseg {
21 struct msg_msgseg* next;
22 /* the next part of the message follows immediately */
23 };
24
25 #define DATALEN_MSG (PAGE_SIZE-sizeof(struct msg_msg))
26 #define DATALEN_SEG (PAGE_SIZE-sizeof(struct msg_msgseg))
27
load_msg(const void __user * src,int len)28 struct msg_msg *load_msg(const void __user *src, int len)
29 {
30 struct msg_msg *msg;
31 struct msg_msgseg **pseg;
32 int err;
33 int alen;
34
35 alen = len;
36 if (alen > DATALEN_MSG)
37 alen = DATALEN_MSG;
38
39 msg = kmalloc(sizeof(*msg) + alen, GFP_KERNEL);
40 if (msg == NULL)
41 return ERR_PTR(-ENOMEM);
42
43 msg->next = NULL;
44 msg->security = NULL;
45
46 if (copy_from_user(msg + 1, src, alen)) {
47 err = -EFAULT;
48 goto out_err;
49 }
50
51 len -= alen;
52 src = ((char __user *)src) + alen;
53 pseg = &msg->next;
54 while (len > 0) {
55 struct msg_msgseg *seg;
56 alen = len;
57 if (alen > DATALEN_SEG)
58 alen = DATALEN_SEG;
59 seg = kmalloc(sizeof(*seg) + alen,
60 GFP_KERNEL);
61 if (seg == NULL) {
62 err = -ENOMEM;
63 goto out_err;
64 }
65 *pseg = seg;
66 seg->next = NULL;
67 if (copy_from_user(seg + 1, src, alen)) {
68 err = -EFAULT;
69 goto out_err;
70 }
71 pseg = &seg->next;
72 len -= alen;
73 src = ((char __user *)src) + alen;
74 }
75
76 err = security_msg_msg_alloc(msg);
77 if (err)
78 goto out_err;
79
80 return msg;
81
82 out_err:
83 free_msg(msg);
84 return ERR_PTR(err);
85 }
86
store_msg(void __user * dest,struct msg_msg * msg,int len)87 int store_msg(void __user *dest, struct msg_msg *msg, int len)
88 {
89 int alen;
90 struct msg_msgseg *seg;
91
92 alen = len;
93 if (alen > DATALEN_MSG)
94 alen = DATALEN_MSG;
95 if (copy_to_user(dest, msg + 1, alen))
96 return -1;
97
98 len -= alen;
99 dest = ((char __user *)dest) + alen;
100 seg = msg->next;
101 while (len > 0) {
102 alen = len;
103 if (alen > DATALEN_SEG)
104 alen = DATALEN_SEG;
105 if (copy_to_user(dest, seg + 1, alen))
106 return -1;
107 len -= alen;
108 dest = ((char __user *)dest) + alen;
109 seg = seg->next;
110 }
111 return 0;
112 }
113
free_msg(struct msg_msg * msg)114 void free_msg(struct msg_msg *msg)
115 {
116 struct msg_msgseg *seg;
117
118 security_msg_msg_free(msg);
119
120 seg = msg->next;
121 kfree(msg);
122 while (seg != NULL) {
123 struct msg_msgseg *tmp = seg->next;
124 kfree(seg);
125 seg = tmp;
126 }
127 }
128