Blame view
ipc/msgutil.c
3.56 KB
8e8ccf433 treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-or-later |
1da177e4c Linux-2.6.12-rc2 |
2 |
/* |
f30c22695 fix file specific... |
3 |
* linux/ipc/msgutil.c |
1da177e4c Linux-2.6.12-rc2 |
4 |
* Copyright (C) 1999, 2004 Manfred Spraul |
1da177e4c 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 security: trim se... |
12 |
#include <linux/msg.h> |
614b84cf4 namespaces: mqueu... |
13 |
#include <linux/ipc_namespace.h> |
404015308 security: trim se... |
14 |
#include <linux/utsname.h> |
0bb80f240 proc: Split the n... |
15 |
#include <linux/proc_ns.h> |
1e3c941c5 ipc/msgutil.c: us... |
16 |
#include <linux/uaccess.h> |
d6a2946a8 ipc: prevent lock... |
17 |
#include <linux/sched.h> |
1da177e4c Linux-2.6.12-rc2 |
18 19 |
#include "util.h" |
7eafd7c74 namespaces: ipc n... |
20 |
DEFINE_SPINLOCK(mq_lock); |
614b84cf4 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 ipc: Use generic ... |
27 |
.ns.count = REFCOUNT_INIT(1), |
b515498f5 userns: add a use... |
28 |
.user_ns = &init_user_ns, |
435d5f4bb common object emb... |
29 |
.ns.inum = PROC_IPC_INIT_INO, |
33c429405 copy address of p... |
30 31 32 |
#ifdef CONFIG_IPC_NS .ns.ops = &ipcns_operations, #endif |
614b84cf4 namespaces: mqueu... |
33 |
}; |
1da177e4c Linux-2.6.12-rc2 |
34 |
struct msg_msgseg { |
1e3c941c5 ipc/msgutil.c: us... |
35 |
struct msg_msgseg *next; |
1da177e4c Linux-2.6.12-rc2 |
36 37 |
/* the next part of the message follows immediately */ }; |
4e9b45a19 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 Linux-2.6.12-rc2 |
40 |
|
be5f4b335 ipc: separate msg... |
41 |
|
4e9b45a19 ipc, msg: fix mes... |
42 |
static struct msg_msg *alloc_msg(size_t len) |
1da177e4c Linux-2.6.12-rc2 |
43 44 45 |
{ struct msg_msg *msg; struct msg_msgseg **pseg; |
4e9b45a19 ipc, msg: fix mes... |
46 |
size_t alen; |
1da177e4c Linux-2.6.12-rc2 |
47 |
|
3d8fa456d ipc: clamp with m... |
48 |
alen = min(len, DATALEN_MSG); |
8c8d4d452 ipc: account for ... |
49 |
msg = kmalloc(sizeof(*msg) + alen, GFP_KERNEL_ACCOUNT); |
1da177e4c Linux-2.6.12-rc2 |
50 |
if (msg == NULL) |
be5f4b335 ipc: separate msg... |
51 |
return NULL; |
1da177e4c Linux-2.6.12-rc2 |
52 53 54 |
msg->next = NULL; msg->security = NULL; |
be5f4b335 ipc: separate msg... |
55 56 57 58 |
len -= alen; pseg = &msg->next; while (len > 0) { struct msg_msgseg *seg; |
d6a2946a8 ipc: prevent lock... |
59 60 |
cond_resched(); |
be5f4b335 ipc: separate msg... |
61 |
alen = min(len, DATALEN_SEG); |
8c8d4d452 ipc: account for ... |
62 |
seg = kmalloc(sizeof(*seg) + alen, GFP_KERNEL_ACCOUNT); |
be5f4b335 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 ipc, msg: fix mes... |
77 |
struct msg_msg *load_msg(const void __user *src, size_t len) |
be5f4b335 ipc: separate msg... |
78 79 80 |
{ struct msg_msg *msg; struct msg_msgseg *seg; |
2b3097a29 ipc: set EFAULT a... |
81 |
int err = -EFAULT; |
4e9b45a19 ipc, msg: fix mes... |
82 |
size_t alen; |
be5f4b335 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 ipc: set EFAULT a... |
89 |
if (copy_from_user(msg + 1, src, alen)) |
1da177e4c Linux-2.6.12-rc2 |
90 |
goto out_err; |
1da177e4c Linux-2.6.12-rc2 |
91 |
|
da085d459 ipc: tighten msg ... |
92 93 94 |
for (seg = msg->next; seg != NULL; seg = seg->next) { len -= alen; src = (char __user *)src + alen; |
3d8fa456d ipc: clamp with m... |
95 |
alen = min(len, DATALEN_SEG); |
2b3097a29 ipc: set EFAULT a... |
96 |
if (copy_from_user(seg + 1, src, alen)) |
1da177e4c Linux-2.6.12-rc2 |
97 |
goto out_err; |
1da177e4c 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 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 ipc, msg: fix mes... |
114 115 |
size_t len = src->m_ts; size_t alen; |
4a674f34b ipc: introduce me... |
116 |
|
4a674f34b ipc: introduce me... |
117 118 |
if (src->m_ts > dst->m_ts) return ERR_PTR(-EINVAL); |
3d8fa456d ipc: clamp with m... |
119 |
alen = min(len, DATALEN_MSG); |
4a674f34b ipc: introduce me... |
120 |
memcpy(dst + 1, src + 1, alen); |
da085d459 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 ipc: clamp with m... |
126 |
alen = min(len, DATALEN_SEG); |
4a674f34b ipc: introduce me... |
127 |
memcpy(dst_pseg + 1, src_pseg + 1, alen); |
4a674f34b 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 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 ipc: introduce me... |
140 |
#endif |
4e9b45a19 ipc, msg: fix mes... |
141 |
int store_msg(void __user *dest, struct msg_msg *msg, size_t len) |
1da177e4c Linux-2.6.12-rc2 |
142 |
{ |
4e9b45a19 ipc, msg: fix mes... |
143 |
size_t alen; |
1da177e4c Linux-2.6.12-rc2 |
144 |
struct msg_msgseg *seg; |
3d8fa456d ipc: clamp with m... |
145 |
alen = min(len, DATALEN_MSG); |
1da177e4c Linux-2.6.12-rc2 |
146 147 |
if (copy_to_user(dest, msg + 1, alen)) return -1; |
da085d459 ipc: tighten msg ... |
148 149 150 |
for (seg = msg->next; seg != NULL; seg = seg->next) { len -= alen; dest = (char __user *)dest + alen; |
3d8fa456d ipc: clamp with m... |
151 |
alen = min(len, DATALEN_SEG); |
1da177e4c Linux-2.6.12-rc2 |
152 153 |
if (copy_to_user(dest, seg + 1, alen)) return -1; |
1da177e4c 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 ipc: prevent lock... |
168 169 |
cond_resched(); |
1da177e4c Linux-2.6.12-rc2 |
170 171 172 173 |
kfree(seg); seg = tmp; } } |