File Index
Files and directories
Sign in
FILE

msgutil.c

File preview with syntax highlighting.

linux-6.19.14/ipc/msgutil.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * linux/ipc/msgutil.c
  4 * Copyright (C) 1999, 2004 Manfred Spraul
  5 */
  6
  7#include <linux/spinlock.h>
  8#include <linux/init.h>
  9#include <linux/security.h>
 10#include <linux/slab.h>
 11#include <linux/ipc.h>
 12#include <linux/msg.h>
 13#include <linux/ipc_namespace.h>
 14#include <linux/utsname.h>
 15#include <linux/proc_ns.h>
 16#include <linux/uaccess.h>
 17#include <linux/sched.h>
 18#include <linux/nstree.h>
 19
 20#include "util.h"
 21
 22DEFINE_SPINLOCK(mq_lock);
 23
 24/*
 25 * The next 2 defines are here bc this is the only file
 26 * compiled when either CONFIG_SYSVIPC and CONFIG_POSIX_MQUEUE
 27 * and not CONFIG_IPC_NS.
 28 */
 29struct ipc_namespace init_ipc_ns = {
 30	.ns = NS_COMMON_INIT(init_ipc_ns),
 31	.user_ns = &init_user_ns,
 32};
 33
 34struct msg_msgseg {
 35	struct msg_msgseg *next;
 36	/* the next part of the message follows immediately */
 37};
 38
 39#define DATALEN_MSG	((size_t)PAGE_SIZE-sizeof(struct msg_msg))
 40#define DATALEN_SEG	((size_t)PAGE_SIZE-sizeof(struct msg_msgseg))
 41
 42static kmem_buckets *msg_buckets __ro_after_init;
 43
 44static int __init init_msg_buckets(void)
 45{
 46	msg_buckets = kmem_buckets_create("msg_msg", SLAB_ACCOUNT,
 47					  sizeof(struct msg_msg),
 48					  DATALEN_MSG, NULL);
 49
 50	return 0;
 51}
 52subsys_initcall(init_msg_buckets);
 53
 54static struct msg_msg *alloc_msg(size_t len)
 55{
 56	struct msg_msg *msg;
 57	struct msg_msgseg **pseg;
 58	size_t alen;
 59
 60	alen = min(len, DATALEN_MSG);
 61	msg = kmem_buckets_alloc(msg_buckets, sizeof(*msg) + alen, GFP_KERNEL);
 62	if (msg == NULL)
 63		return NULL;
 64
 65	msg->next = NULL;
 66	msg->security = NULL;
 67
 68	len -= alen;
 69	pseg = &msg->next;
 70	while (len > 0) {
 71		struct msg_msgseg *seg;
 72
 73		cond_resched();
 74
 75		alen = min(len, DATALEN_SEG);
 76		seg = kmalloc(sizeof(*seg) + alen, GFP_KERNEL_ACCOUNT);
 77		if (seg == NULL)
 78			goto out_err;
 79		*pseg = seg;
 80		seg->next = NULL;
 81		pseg = &seg->next;
 82		len -= alen;
 83	}
 84
 85	return msg;
 86
 87out_err:
 88	free_msg(msg);
 89	return NULL;
 90}
 91
 92struct msg_msg *load_msg(const void __user *src, size_t len)
 93{
 94	struct msg_msg *msg;
 95	struct msg_msgseg *seg;
 96	int err = -EFAULT;
 97	size_t alen;
 98
 99	msg = alloc_msg(len);
100	if (msg == NULL)
101		return ERR_PTR(-ENOMEM);
102
103	alen = min(len, DATALEN_MSG);
104	if (copy_from_user(msg + 1, src, alen))
105		goto out_err;
106
107	for (seg = msg->next; seg != NULL; seg = seg->next) {
108		len -= alen;
109		src = (char __user *)src + alen;
110		alen = min(len, DATALEN_SEG);
111		if (copy_from_user(seg + 1, src, alen))
112			goto out_err;
113	}
114
115	err = security_msg_msg_alloc(msg);
116	if (err)
117		goto out_err;
118
119	return msg;
120
121out_err:
122	free_msg(msg);
123	return ERR_PTR(err);
124}
125#ifdef CONFIG_CHECKPOINT_RESTORE
126struct msg_msg *copy_msg(struct msg_msg *src, struct msg_msg *dst)
127{
128	struct msg_msgseg *dst_pseg, *src_pseg;
129	size_t len = src->m_ts;
130	size_t alen;
131
132	if (src->m_ts > dst->m_ts)
133		return ERR_PTR(-EINVAL);
134
135	alen = min(len, DATALEN_MSG);
136	memcpy(dst + 1, src + 1, alen);
137
138	for (dst_pseg = dst->next, src_pseg = src->next;
139	     src_pseg != NULL;
140	     dst_pseg = dst_pseg->next, src_pseg = src_pseg->next) {
141
142		len -= alen;
143		alen = min(len, DATALEN_SEG);
144		memcpy(dst_pseg + 1, src_pseg + 1, alen);
145	}
146
147	dst->m_type = src->m_type;
148	dst->m_ts = src->m_ts;
149
150	return dst;
151}
152#else
153struct msg_msg *copy_msg(struct msg_msg *src, struct msg_msg *dst)
154{
155	return ERR_PTR(-ENOSYS);
156}
157#endif
158int store_msg(void __user *dest, struct msg_msg *msg, size_t len)
159{
160	size_t alen;
161	struct msg_msgseg *seg;
162
163	alen = min(len, DATALEN_MSG);
164	if (copy_to_user(dest, msg + 1, alen))
165		return -1;
166
167	for (seg = msg->next; seg != NULL; seg = seg->next) {
168		len -= alen;
169		dest = (char __user *)dest + alen;
170		alen = min(len, DATALEN_SEG);
171		if (copy_to_user(dest, seg + 1, alen))
172			return -1;
173	}
174	return 0;
175}
176
177void free_msg(struct msg_msg *msg)
178{
179	struct msg_msgseg *seg;
180
181	security_msg_msg_free(msg);
182
183	seg = msg->next;
184	kfree(msg);
185	while (seg != NULL) {
186		struct msg_msgseg *tmp = seg->next;
187
188		cond_resched();
189		kfree(seg);
190		seg = tmp;
191	}
192}
~/ Read-only file preview.