Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
msgutil.c
Go to the documentation of this file.
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 <linux/msg.h>
17 #include <linux/ipc_namespace.h>
18 #include <linux/utsname.h>
19 #include <asm/uaccess.h>
20 
21 #include "util.h"
22 
23 DEFINE_SPINLOCK(mq_lock);
24 
25 /*
26  * The next 2 defines are here bc this is the only file
27  * compiled when either CONFIG_SYSVIPC and CONFIG_POSIX_MQUEUE
28  * and not CONFIG_IPC_NS.
29  */
31  .count = ATOMIC_INIT(1),
32  .user_ns = &init_user_ns,
33 };
34 
36 
37 struct msg_msgseg {
38  struct msg_msgseg* next;
39  /* the next part of the message follows immediately */
40 };
41 
42 #define DATALEN_MSG (PAGE_SIZE-sizeof(struct msg_msg))
43 #define DATALEN_SEG (PAGE_SIZE-sizeof(struct msg_msgseg))
44 
45 struct msg_msg *load_msg(const void __user *src, int len)
46 {
47  struct msg_msg *msg;
48  struct msg_msgseg **pseg;
49  int err;
50  int alen;
51 
52  alen = len;
53  if (alen > DATALEN_MSG)
54  alen = DATALEN_MSG;
55 
56  msg = kmalloc(sizeof(*msg) + alen, GFP_KERNEL);
57  if (msg == NULL)
58  return ERR_PTR(-ENOMEM);
59 
60  msg->next = NULL;
61  msg->security = NULL;
62 
63  if (copy_from_user(msg + 1, src, alen)) {
64  err = -EFAULT;
65  goto out_err;
66  }
67 
68  len -= alen;
69  src = ((char __user *)src) + alen;
70  pseg = &msg->next;
71  while (len > 0) {
72  struct msg_msgseg *seg;
73  alen = len;
74  if (alen > DATALEN_SEG)
75  alen = DATALEN_SEG;
76  seg = kmalloc(sizeof(*seg) + alen,
77  GFP_KERNEL);
78  if (seg == NULL) {
79  err = -ENOMEM;
80  goto out_err;
81  }
82  *pseg = seg;
83  seg->next = NULL;
84  if (copy_from_user(seg + 1, src, alen)) {
85  err = -EFAULT;
86  goto out_err;
87  }
88  pseg = &seg->next;
89  len -= alen;
90  src = ((char __user *)src) + alen;
91  }
92 
93  err = security_msg_msg_alloc(msg);
94  if (err)
95  goto out_err;
96 
97  return msg;
98 
99 out_err:
100  free_msg(msg);
101  return ERR_PTR(err);
102 }
103 
104 int store_msg(void __user *dest, struct msg_msg *msg, int len)
105 {
106  int alen;
107  struct msg_msgseg *seg;
108 
109  alen = len;
110  if (alen > DATALEN_MSG)
111  alen = DATALEN_MSG;
112  if (copy_to_user(dest, msg + 1, alen))
113  return -1;
114 
115  len -= alen;
116  dest = ((char __user *)dest) + alen;
117  seg = msg->next;
118  while (len > 0) {
119  alen = len;
120  if (alen > DATALEN_SEG)
121  alen = DATALEN_SEG;
122  if (copy_to_user(dest, seg + 1, alen))
123  return -1;
124  len -= alen;
125  dest = ((char __user *)dest) + alen;
126  seg = seg->next;
127  }
128  return 0;
129 }
130 
131 void free_msg(struct msg_msg *msg)
132 {
133  struct msg_msgseg *seg;
134 
136 
137  seg = msg->next;
138  kfree(msg);
139  while (seg != NULL) {
140  struct msg_msgseg *tmp = seg->next;
141  kfree(seg);
142  seg = tmp;
143  }
144 }