Blame view

ipc/msgutil.c 2.77 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>
614b84cf4   Serge E. Hallyn   namespaces: mqueu...
16
  #include <linux/ipc_namespace.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
18
19
  #include <asm/uaccess.h>
  
  #include "util.h"
7eafd7c74   Serge E. Hallyn   namespaces: ipc n...
20
  DEFINE_SPINLOCK(mq_lock);
614b84cf4   Serge E. Hallyn   namespaces: mqueu...
21
22
23
24
25
26
  /*
   * 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...
27
  	.count		= ATOMIC_INIT(1),
614b84cf4   Serge E. Hallyn   namespaces: mqueu...
28
  #ifdef CONFIG_POSIX_MQUEUE
614b84cf4   Serge E. Hallyn   namespaces: mqueu...
29
30
31
32
33
34
35
  	.mq_queues_max   = DFLT_QUEUESMAX,
  	.mq_msg_max      = DFLT_MSGMAX,
  	.mq_msgsize_max  = DFLT_MSGSIZEMAX,
  #endif
  };
  
  atomic_t nr_ipc_ns = ATOMIC_INIT(1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
  struct msg_msgseg {
  	struct msg_msgseg* next;
  	/* the next part of the message follows immediately */
  };
  
  #define DATALEN_MSG	(PAGE_SIZE-sizeof(struct msg_msg))
  #define DATALEN_SEG	(PAGE_SIZE-sizeof(struct msg_msgseg))
  
  struct msg_msg *load_msg(const void __user *src, int len)
  {
  	struct msg_msg *msg;
  	struct msg_msgseg **pseg;
  	int err;
  	int alen;
  
  	alen = len;
  	if (alen > DATALEN_MSG)
  		alen = 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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
  	if (msg == NULL)
  		return ERR_PTR(-ENOMEM);
  
  	msg->next = NULL;
  	msg->security = NULL;
  
  	if (copy_from_user(msg + 1, src, alen)) {
  		err = -EFAULT;
  		goto out_err;
  	}
  
  	len -= alen;
  	src = ((char __user *)src) + alen;
  	pseg = &msg->next;
  	while (len > 0) {
  		struct msg_msgseg *seg;
  		alen = len;
  		if (alen > DATALEN_SEG)
  			alen = DATALEN_SEG;
5cbded585   Robert P. J. Day   [PATCH] getting r...
74
  		seg = kmalloc(sizeof(*seg) + alen,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
  						 GFP_KERNEL);
  		if (seg == NULL) {
  			err = -ENOMEM;
  			goto out_err;
  		}
  		*pseg = seg;
  		seg->next = NULL;
  		if (copy_from_user(seg + 1, src, alen)) {
  			err = -EFAULT;
  			goto out_err;
  		}
  		pseg = &seg->next;
  		len -= alen;
  		src = ((char __user *)src) + alen;
  	}
  
  	err = security_msg_msg_alloc(msg);
  	if (err)
  		goto out_err;
  
  	return msg;
  
  out_err:
  	free_msg(msg);
  	return ERR_PTR(err);
  }
  
  int store_msg(void __user *dest, struct msg_msg *msg, int len)
  {
  	int alen;
  	struct msg_msgseg *seg;
  
  	alen = len;
  	if (alen > DATALEN_MSG)
  		alen = DATALEN_MSG;
  	if (copy_to_user(dest, msg + 1, alen))
  		return -1;
  
  	len -= alen;
  	dest = ((char __user *)dest) + alen;
  	seg = msg->next;
  	while (len > 0) {
  		alen = len;
  		if (alen > DATALEN_SEG)
  			alen = DATALEN_SEG;
  		if (copy_to_user(dest, seg + 1, alen))
  			return -1;
  		len -= alen;
  		dest = ((char __user *)dest) + alen;
  		seg = seg->next;
  	}
  	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;
  	}
  }