~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/ipc/msgutil.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 
 21 DEFINE_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  */
 28 struct 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 
 37 struct 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 static kmem_buckets *msg_buckets __ro_after_init;
 46 
 47 static 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 }
 55 subsys_initcall(init_msg_buckets);
 56 
 57 static 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 
 90 out_err:
 91         free_msg(msg);
 92         return NULL;
 93 }
 94 
 95 struct 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 
124 out_err:
125         free_msg(msg);
126         return ERR_PTR(err);
127 }
128 #ifdef CONFIG_CHECKPOINT_RESTORE
129 struct 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
156 struct msg_msg *copy_msg(struct msg_msg *src, struct msg_msg *dst)
157 {
158         return ERR_PTR(-ENOSYS);
159 }
160 #endif
161 int 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 
180 void 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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php