Blame view

ipc/msgutil.c 2.66 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),
b515498f5   Serge E. Hallyn   userns: add a use...
28
  	.user_ns = &init_user_ns,
614b84cf4   Serge E. Hallyn   namespaces: mqueu...
29
30
31
  };
  
  atomic_t nr_ipc_ns = ATOMIC_INIT(1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
  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...
50
  	msg = kmalloc(sizeof(*msg) + alen, GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
  	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...
70
  		seg = kmalloc(sizeof(*seg) + alen,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
71
72
73
74
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
  						 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;
  	}
  }