cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

msgutil.c (3647B)


      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}