Blame view

ipc/msgutil.c 3.65 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  /*
f30c22695   Uwe Zeisberger   fix file specific...
2
   * linux/ipc/msgutil.c
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3
4
5
6
7
8
9
10
11
12
13
14
15
   * Copyright (C) 1999, 2004 Manfred Spraul
   *
   * This file is released under GNU General Public Licence version 2 or
   * (at your option) any later version.
   *
   * See the file COPYING for more details.
   */
  
  #include <linux/spinlock.h>
  #include <linux/init.h>
  #include <linux/security.h>
  #include <linux/slab.h>
  #include <linux/ipc.h>
404015308   Al Viro   security: trim se...
16
  #include <linux/msg.h>
614b84cf4   Serge E. Hallyn   namespaces: mqueu...
17
  #include <linux/ipc_namespace.h>
404015308   Al Viro   security: trim se...
18
  #include <linux/utsname.h>
0bb80f240   David Howells   proc: Split the n...
19
  #include <linux/proc_ns.h>
1e3c941c5   HoSung Jung   ipc/msgutil.c: us...
20
  #include <linux/uaccess.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
22
  
  #include "util.h"
7eafd7c74   Serge E. Hallyn   namespaces: ipc n...
23
  DEFINE_SPINLOCK(mq_lock);
614b84cf4   Serge E. Hallyn   namespaces: mqueu...
24
25
26
27
28
29
  /*
   * The next 2 defines are here bc this is the only file
   * compiled when either CONFIG_SYSVIPC and CONFIG_POSIX_MQUEUE
   * and not CONFIG_IPC_NS.
   */
  struct ipc_namespace init_ipc_ns = {
7eafd7c74   Serge E. Hallyn   namespaces: ipc n...
30
  	.count		= ATOMIC_INIT(1),
b515498f5   Serge E. Hallyn   userns: add a use...
31
  	.user_ns = &init_user_ns,
435d5f4bb   Al Viro   common object emb...
32
  	.ns.inum = PROC_IPC_INIT_INO,
33c429405   Al Viro   copy address of p...
33
34
35
  #ifdef CONFIG_IPC_NS
  	.ns.ops = &ipcns_operations,
  #endif
614b84cf4   Serge E. Hallyn   namespaces: mqueu...
36
37
38
  };
  
  atomic_t nr_ipc_ns = ATOMIC_INIT(1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
  struct msg_msgseg {
1e3c941c5   HoSung Jung   ipc/msgutil.c: us...
40
  	struct msg_msgseg *next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
42
  	/* the next part of the message follows immediately */
  };
4e9b45a19   Mathias Krause   ipc, msg: fix mes...
43
44
  #define DATALEN_MSG	((size_t)PAGE_SIZE-sizeof(struct msg_msg))
  #define DATALEN_SEG	((size_t)PAGE_SIZE-sizeof(struct msg_msgseg))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45

be5f4b335   Peter Hurley   ipc: separate msg...
46

4e9b45a19   Mathias Krause   ipc, msg: fix mes...
47
  static struct msg_msg *alloc_msg(size_t len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
48
49
50
  {
  	struct msg_msg *msg;
  	struct msg_msgseg **pseg;
4e9b45a19   Mathias Krause   ipc, msg: fix mes...
51
  	size_t alen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52

3d8fa456d   Peter Hurley   ipc: clamp with m...
53
  	alen = min(len, DATALEN_MSG);
5cbded585   Robert P. J. Day   [PATCH] getting r...
54
  	msg = kmalloc(sizeof(*msg) + alen, GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
  	if (msg == NULL)
be5f4b335   Peter Hurley   ipc: separate msg...
56
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57
58
59
  
  	msg->next = NULL;
  	msg->security = NULL;
be5f4b335   Peter Hurley   ipc: separate msg...
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
  	len -= alen;
  	pseg = &msg->next;
  	while (len > 0) {
  		struct msg_msgseg *seg;
  		alen = min(len, DATALEN_SEG);
  		seg = kmalloc(sizeof(*seg) + alen, GFP_KERNEL);
  		if (seg == NULL)
  			goto out_err;
  		*pseg = seg;
  		seg->next = NULL;
  		pseg = &seg->next;
  		len -= alen;
  	}
  
  	return msg;
  
  out_err:
  	free_msg(msg);
  	return NULL;
  }
4e9b45a19   Mathias Krause   ipc, msg: fix mes...
80
  struct msg_msg *load_msg(const void __user *src, size_t len)
be5f4b335   Peter Hurley   ipc: separate msg...
81
82
83
  {
  	struct msg_msg *msg;
  	struct msg_msgseg *seg;
2b3097a29   Peter Hurley   ipc: set EFAULT a...
84
  	int err = -EFAULT;
4e9b45a19   Mathias Krause   ipc, msg: fix mes...
85
  	size_t alen;
be5f4b335   Peter Hurley   ipc: separate msg...
86
87
88
89
90
91
  
  	msg = alloc_msg(len);
  	if (msg == NULL)
  		return ERR_PTR(-ENOMEM);
  
  	alen = min(len, DATALEN_MSG);
2b3097a29   Peter Hurley   ipc: set EFAULT a...
92
  	if (copy_from_user(msg + 1, src, alen))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
93
  		goto out_err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
94

da085d459   Peter Hurley   ipc: tighten msg ...
95
96
97
  	for (seg = msg->next; seg != NULL; seg = seg->next) {
  		len -= alen;
  		src = (char __user *)src + alen;
3d8fa456d   Peter Hurley   ipc: clamp with m...
98
  		alen = min(len, DATALEN_SEG);
2b3097a29   Peter Hurley   ipc: set EFAULT a...
99
  		if (copy_from_user(seg + 1, src, alen))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
100
  			goto out_err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
101
102
103
104
105
106
107
108
109
110
111
112
  	}
  
  	err = security_msg_msg_alloc(msg);
  	if (err)
  		goto out_err;
  
  	return msg;
  
  out_err:
  	free_msg(msg);
  	return ERR_PTR(err);
  }
4a674f34b   Stanislav Kinsbursky   ipc: introduce me...
113
114
115
116
  #ifdef CONFIG_CHECKPOINT_RESTORE
  struct msg_msg *copy_msg(struct msg_msg *src, struct msg_msg *dst)
  {
  	struct msg_msgseg *dst_pseg, *src_pseg;
4e9b45a19   Mathias Krause   ipc, msg: fix mes...
117
118
  	size_t len = src->m_ts;
  	size_t alen;
4a674f34b   Stanislav Kinsbursky   ipc: introduce me...
119
120
121
122
  
  	BUG_ON(dst == NULL);
  	if (src->m_ts > dst->m_ts)
  		return ERR_PTR(-EINVAL);
3d8fa456d   Peter Hurley   ipc: clamp with m...
123
  	alen = min(len, DATALEN_MSG);
4a674f34b   Stanislav Kinsbursky   ipc: introduce me...
124
  	memcpy(dst + 1, src + 1, alen);
da085d459   Peter Hurley   ipc: tighten msg ...
125
126
127
128
129
  	for (dst_pseg = dst->next, src_pseg = src->next;
  	     src_pseg != NULL;
  	     dst_pseg = dst_pseg->next, src_pseg = src_pseg->next) {
  
  		len -= alen;
3d8fa456d   Peter Hurley   ipc: clamp with m...
130
  		alen = min(len, DATALEN_SEG);
4a674f34b   Stanislav Kinsbursky   ipc: introduce me...
131
  		memcpy(dst_pseg + 1, src_pseg + 1, alen);
4a674f34b   Stanislav Kinsbursky   ipc: introduce me...
132
133
134
135
136
137
138
  	}
  
  	dst->m_type = src->m_type;
  	dst->m_ts = src->m_ts;
  
  	return dst;
  }
51eeacaa0   Stanislav Kinsbursky   ipc: simplify mes...
139
140
141
142
143
  #else
  struct msg_msg *copy_msg(struct msg_msg *src, struct msg_msg *dst)
  {
  	return ERR_PTR(-ENOSYS);
  }
4a674f34b   Stanislav Kinsbursky   ipc: introduce me...
144
  #endif
4e9b45a19   Mathias Krause   ipc, msg: fix mes...
145
  int store_msg(void __user *dest, struct msg_msg *msg, size_t len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146
  {
4e9b45a19   Mathias Krause   ipc, msg: fix mes...
147
  	size_t alen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
148
  	struct msg_msgseg *seg;
3d8fa456d   Peter Hurley   ipc: clamp with m...
149
  	alen = min(len, DATALEN_MSG);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
150
151
  	if (copy_to_user(dest, msg + 1, alen))
  		return -1;
da085d459   Peter Hurley   ipc: tighten msg ...
152
153
154
  	for (seg = msg->next; seg != NULL; seg = seg->next) {
  		len -= alen;
  		dest = (char __user *)dest + alen;
3d8fa456d   Peter Hurley   ipc: clamp with m...
155
  		alen = min(len, DATALEN_SEG);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
156
157
  		if (copy_to_user(dest, seg + 1, alen))
  			return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
  	}
  	return 0;
  }
  
  void free_msg(struct msg_msg *msg)
  {
  	struct msg_msgseg *seg;
  
  	security_msg_msg_free(msg);
  
  	seg = msg->next;
  	kfree(msg);
  	while (seg != NULL) {
  		struct msg_msgseg *tmp = seg->next;
  		kfree(seg);
  		seg = tmp;
  	}
  }