brintos

brintos / linux-shallow public Read only

0
0
Text · 3.8 KiB · c7be0c7 Raw
196 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * linux/ipc/msgutil.c4 * Copyright (C) 1999, 2004 Manfred Spraul5 */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 file25 * compiled when either CONFIG_SYSVIPC and CONFIG_POSIX_MQUEUE26 * 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_NS33	.ns.ops = &ipcns_operations,34#endif35};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_RESTORE129struct 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#else156struct msg_msg *copy_msg(struct msg_msg *src, struct msg_msg *dst)157{158	return ERR_PTR(-ENOSYS);159}160#endif161int 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}196