Blame view

ipc/msgutil.c 3.56 KB
8e8ccf433   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
  /*
f30c22695   Uwe Zeisberger   fix file specific...
3
   * linux/ipc/msgutil.c
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4
   * Copyright (C) 1999, 2004 Manfred Spraul
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5
6
7
8
9
10
11
   */
  
  #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...
12
  #include <linux/msg.h>
614b84cf4   Serge E. Hallyn   namespaces: mqueu...
13
  #include <linux/ipc_namespace.h>
404015308   Al Viro   security: trim se...
14
  #include <linux/utsname.h>
0bb80f240   David Howells   proc: Split the n...
15
  #include <linux/proc_ns.h>
1e3c941c5   HoSung Jung   ipc/msgutil.c: us...
16
  #include <linux/uaccess.h>
d6a2946a8   Li Rongqing   ipc: prevent lock...
17
  #include <linux/sched.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
19
  
  #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 = {
137ec390f   Kirill Tkhai   ipc: Use generic ...
27
  	.ns.count = REFCOUNT_INIT(1),
b515498f5   Serge E. Hallyn   userns: add a use...
28
  	.user_ns = &init_user_ns,
435d5f4bb   Al Viro   common object emb...
29
  	.ns.inum = PROC_IPC_INIT_INO,
33c429405   Al Viro   copy address of p...
30
31
32
  #ifdef CONFIG_IPC_NS
  	.ns.ops = &ipcns_operations,
  #endif
614b84cf4   Serge E. Hallyn   namespaces: mqueu...
33
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
  struct msg_msgseg {
1e3c941c5   HoSung Jung   ipc/msgutil.c: us...
35
  	struct msg_msgseg *next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
37
  	/* the next part of the message follows immediately */
  };
4e9b45a19   Mathias Krause   ipc, msg: fix mes...
38
39
  #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
40

be5f4b335   Peter Hurley   ipc: separate msg...
41

4e9b45a19   Mathias Krause   ipc, msg: fix mes...
42
  static struct msg_msg *alloc_msg(size_t len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
44
45
  {
  	struct msg_msg *msg;
  	struct msg_msgseg **pseg;
4e9b45a19   Mathias Krause   ipc, msg: fix mes...
46
  	size_t alen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47

3d8fa456d   Peter Hurley   ipc: clamp with m...
48
  	alen = min(len, DATALEN_MSG);
8c8d4d452   Aristeu Rozanski   ipc: account for ...
49
  	msg = kmalloc(sizeof(*msg) + alen, GFP_KERNEL_ACCOUNT);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50
  	if (msg == NULL)
be5f4b335   Peter Hurley   ipc: separate msg...
51
  		return NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
53
54
  
  	msg->next = NULL;
  	msg->security = NULL;
be5f4b335   Peter Hurley   ipc: separate msg...
55
56
57
58
  	len -= alen;
  	pseg = &msg->next;
  	while (len > 0) {
  		struct msg_msgseg *seg;
d6a2946a8   Li Rongqing   ipc: prevent lock...
59
60
  
  		cond_resched();
be5f4b335   Peter Hurley   ipc: separate msg...
61
  		alen = min(len, DATALEN_SEG);
8c8d4d452   Aristeu Rozanski   ipc: account for ...
62
  		seg = kmalloc(sizeof(*seg) + alen, GFP_KERNEL_ACCOUNT);
be5f4b335   Peter Hurley   ipc: separate msg...
63
64
65
66
67
68
69
70
71
72
73
74
75
76
  		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...
77
  struct msg_msg *load_msg(const void __user *src, size_t len)
be5f4b335   Peter Hurley   ipc: separate msg...
78
79
80
  {
  	struct msg_msg *msg;
  	struct msg_msgseg *seg;
2b3097a29   Peter Hurley   ipc: set EFAULT a...
81
  	int err = -EFAULT;
4e9b45a19   Mathias Krause   ipc, msg: fix mes...
82
  	size_t alen;
be5f4b335   Peter Hurley   ipc: separate msg...
83
84
85
86
87
88
  
  	msg = alloc_msg(len);
  	if (msg == NULL)
  		return ERR_PTR(-ENOMEM);
  
  	alen = min(len, DATALEN_MSG);
2b3097a29   Peter Hurley   ipc: set EFAULT a...
89
  	if (copy_from_user(msg + 1, src, alen))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
90
  		goto out_err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
91

da085d459   Peter Hurley   ipc: tighten msg ...
92
93
94
  	for (seg = msg->next; seg != NULL; seg = seg->next) {
  		len -= alen;
  		src = (char __user *)src + alen;
3d8fa456d   Peter Hurley   ipc: clamp with m...
95
  		alen = min(len, DATALEN_SEG);
2b3097a29   Peter Hurley   ipc: set EFAULT a...
96
  		if (copy_from_user(seg + 1, src, alen))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
97
  			goto out_err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
98
99
100
101
102
103
104
105
106
107
108
109
  	}
  
  	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...
110
111
112
113
  #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...
114
115
  	size_t len = src->m_ts;
  	size_t alen;
4a674f34b   Stanislav Kinsbursky   ipc: introduce me...
116

4a674f34b   Stanislav Kinsbursky   ipc: introduce me...
117
118
  	if (src->m_ts > dst->m_ts)
  		return ERR_PTR(-EINVAL);
3d8fa456d   Peter Hurley   ipc: clamp with m...
119
  	alen = min(len, DATALEN_MSG);
4a674f34b   Stanislav Kinsbursky   ipc: introduce me...
120
  	memcpy(dst + 1, src + 1, alen);
da085d459   Peter Hurley   ipc: tighten msg ...
121
122
123
124
125
  	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...
126
  		alen = min(len, DATALEN_SEG);
4a674f34b   Stanislav Kinsbursky   ipc: introduce me...
127
  		memcpy(dst_pseg + 1, src_pseg + 1, alen);
4a674f34b   Stanislav Kinsbursky   ipc: introduce me...
128
129
130
131
132
133
134
  	}
  
  	dst->m_type = src->m_type;
  	dst->m_ts = src->m_ts;
  
  	return dst;
  }
51eeacaa0   Stanislav Kinsbursky   ipc: simplify mes...
135
136
137
138
139
  #else
  struct msg_msg *copy_msg(struct msg_msg *src, struct msg_msg *dst)
  {
  	return ERR_PTR(-ENOSYS);
  }
4a674f34b   Stanislav Kinsbursky   ipc: introduce me...
140
  #endif
4e9b45a19   Mathias Krause   ipc, msg: fix mes...
141
  int store_msg(void __user *dest, struct msg_msg *msg, size_t len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
142
  {
4e9b45a19   Mathias Krause   ipc, msg: fix mes...
143
  	size_t alen;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
  	struct msg_msgseg *seg;
3d8fa456d   Peter Hurley   ipc: clamp with m...
145
  	alen = min(len, DATALEN_MSG);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
146
147
  	if (copy_to_user(dest, msg + 1, alen))
  		return -1;
da085d459   Peter Hurley   ipc: tighten msg ...
148
149
150
  	for (seg = msg->next; seg != NULL; seg = seg->next) {
  		len -= alen;
  		dest = (char __user *)dest + alen;
3d8fa456d   Peter Hurley   ipc: clamp with m...
151
  		alen = min(len, DATALEN_SEG);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152
153
  		if (copy_to_user(dest, seg + 1, alen))
  			return -1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154
155
156
157
158
159
160
161
162
163
164
165
166
167
  	}
  	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;
d6a2946a8   Li Rongqing   ipc: prevent lock...
168
169
  
  		cond_resched();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
170
171
172
173
  		kfree(seg);
  		seg = tmp;
  	}
  }