Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 | /* * linux/ipc/msgutil.c * Copyright (C) 1999, 2004 Manfred Spraul * * This file is released under GNU General Public Licence version 2 or * (at your option) any later version. * * See the file COPYING for more details. */ #include <linux/spinlock.h> #include <linux/init.h> #include <linux/security.h> #include <linux/slab.h> #include <linux/ipc.h> #include <linux/ipc_namespace.h> #include <asm/uaccess.h> #include "util.h" DEFINE_SPINLOCK(mq_lock); /* * The next 2 defines are here bc this is the only file * compiled when either CONFIG_SYSVIPC and CONFIG_POSIX_MQUEUE * and not CONFIG_IPC_NS. */ struct ipc_namespace init_ipc_ns = { .count = ATOMIC_INIT(1), #ifdef CONFIG_POSIX_MQUEUE .mq_queues_max = DFLT_QUEUESMAX, .mq_msg_max = DFLT_MSGMAX, .mq_msgsize_max = DFLT_MSGSIZEMAX, #endif }; atomic_t nr_ipc_ns = ATOMIC_INIT(1); struct msg_msgseg { struct msg_msgseg* next; /* the next part of the message follows immediately */ }; #define DATALEN_MSG (PAGE_SIZE-sizeof(struct msg_msg)) #define DATALEN_SEG (PAGE_SIZE-sizeof(struct msg_msgseg)) struct msg_msg *load_msg(const void __user *src, int len) { struct msg_msg *msg; struct msg_msgseg **pseg; int err; int alen; alen = len; if (alen > DATALEN_MSG) alen = DATALEN_MSG; msg = kmalloc(sizeof(*msg) + alen, GFP_KERNEL); if (msg == NULL) return ERR_PTR(-ENOMEM); msg->next = NULL; msg->security = NULL; if (copy_from_user(msg + 1, src, alen)) { err = -EFAULT; goto out_err; } len -= alen; src = ((char __user *)src) + alen; pseg = &msg->next; while (len > 0) { struct msg_msgseg *seg; alen = len; if (alen > DATALEN_SEG) alen = DATALEN_SEG; seg = kmalloc(sizeof(*seg) + alen, GFP_KERNEL); if (seg == NULL) { err = -ENOMEM; goto out_err; } *pseg = seg; seg->next = NULL; if (copy_from_user(seg + 1, src, alen)) { err = -EFAULT; goto out_err; } pseg = &seg->next; len -= alen; src = ((char __user *)src) + alen; } err = security_msg_msg_alloc(msg); if (err) goto out_err; return msg; out_err: free_msg(msg); return ERR_PTR(err); } int store_msg(void __user *dest, struct msg_msg *msg, int len) { int alen; struct msg_msgseg *seg; alen = len; if (alen > DATALEN_MSG) alen = DATALEN_MSG; if (copy_to_user(dest, msg + 1, alen)) return -1; len -= alen; dest = ((char __user *)dest) + alen; seg = msg->next; while (len > 0) { alen = len; if (alen > DATALEN_SEG) alen = DATALEN_SEG; if (copy_to_user(dest, seg + 1, alen)) return -1; len -= alen; dest = ((char __user *)dest) + alen; seg = seg->next; } return 0; } void free_msg(struct msg_msg *msg) { struct msg_msgseg *seg; security_msg_msg_free(msg); seg = msg->next; kfree(msg); while (seg != NULL) { struct msg_msgseg *tmp = seg->next; kfree(seg); seg = tmp; } } |