Linux Audio

Check our new training course

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