0001
0002
0003
0004
0005
0006
0007 #include <linux/spinlock.h>
0008 #include <linux/init.h>
0009 #include <linux/security.h>
0010 #include <linux/slab.h>
0011 #include <linux/ipc.h>
0012 #include <linux/msg.h>
0013 #include <linux/ipc_namespace.h>
0014 #include <linux/utsname.h>
0015 #include <linux/proc_ns.h>
0016 #include <linux/uaccess.h>
0017 #include <linux/sched.h>
0018
0019 #include "util.h"
0020
0021 DEFINE_SPINLOCK(mq_lock);
0022
0023
0024
0025
0026
0027
0028 struct ipc_namespace init_ipc_ns = {
0029 .ns.count = REFCOUNT_INIT(1),
0030 .user_ns = &init_user_ns,
0031 .ns.inum = PROC_IPC_INIT_INO,
0032 #ifdef CONFIG_IPC_NS
0033 .ns.ops = &ipcns_operations,
0034 #endif
0035 };
0036
0037 struct msg_msgseg {
0038 struct msg_msgseg *next;
0039
0040 };
0041
0042 #define DATALEN_MSG ((size_t)PAGE_SIZE-sizeof(struct msg_msg))
0043 #define DATALEN_SEG ((size_t)PAGE_SIZE-sizeof(struct msg_msgseg))
0044
0045
0046 static struct msg_msg *alloc_msg(size_t len)
0047 {
0048 struct msg_msg *msg;
0049 struct msg_msgseg **pseg;
0050 size_t alen;
0051
0052 alen = min(len, DATALEN_MSG);
0053 msg = kmalloc(sizeof(*msg) + alen, GFP_KERNEL_ACCOUNT);
0054 if (msg == NULL)
0055 return NULL;
0056
0057 msg->next = NULL;
0058 msg->security = NULL;
0059
0060 len -= alen;
0061 pseg = &msg->next;
0062 while (len > 0) {
0063 struct msg_msgseg *seg;
0064
0065 cond_resched();
0066
0067 alen = min(len, DATALEN_SEG);
0068 seg = kmalloc(sizeof(*seg) + alen, GFP_KERNEL_ACCOUNT);
0069 if (seg == NULL)
0070 goto out_err;
0071 *pseg = seg;
0072 seg->next = NULL;
0073 pseg = &seg->next;
0074 len -= alen;
0075 }
0076
0077 return msg;
0078
0079 out_err:
0080 free_msg(msg);
0081 return NULL;
0082 }
0083
0084 struct msg_msg *load_msg(const void __user *src, size_t len)
0085 {
0086 struct msg_msg *msg;
0087 struct msg_msgseg *seg;
0088 int err = -EFAULT;
0089 size_t alen;
0090
0091 msg = alloc_msg(len);
0092 if (msg == NULL)
0093 return ERR_PTR(-ENOMEM);
0094
0095 alen = min(len, DATALEN_MSG);
0096 if (copy_from_user(msg + 1, src, alen))
0097 goto out_err;
0098
0099 for (seg = msg->next; seg != NULL; seg = seg->next) {
0100 len -= alen;
0101 src = (char __user *)src + alen;
0102 alen = min(len, DATALEN_SEG);
0103 if (copy_from_user(seg + 1, src, alen))
0104 goto out_err;
0105 }
0106
0107 err = security_msg_msg_alloc(msg);
0108 if (err)
0109 goto out_err;
0110
0111 return msg;
0112
0113 out_err:
0114 free_msg(msg);
0115 return ERR_PTR(err);
0116 }
0117 #ifdef CONFIG_CHECKPOINT_RESTORE
0118 struct msg_msg *copy_msg(struct msg_msg *src, struct msg_msg *dst)
0119 {
0120 struct msg_msgseg *dst_pseg, *src_pseg;
0121 size_t len = src->m_ts;
0122 size_t alen;
0123
0124 if (src->m_ts > dst->m_ts)
0125 return ERR_PTR(-EINVAL);
0126
0127 alen = min(len, DATALEN_MSG);
0128 memcpy(dst + 1, src + 1, alen);
0129
0130 for (dst_pseg = dst->next, src_pseg = src->next;
0131 src_pseg != NULL;
0132 dst_pseg = dst_pseg->next, src_pseg = src_pseg->next) {
0133
0134 len -= alen;
0135 alen = min(len, DATALEN_SEG);
0136 memcpy(dst_pseg + 1, src_pseg + 1, alen);
0137 }
0138
0139 dst->m_type = src->m_type;
0140 dst->m_ts = src->m_ts;
0141
0142 return dst;
0143 }
0144 #else
0145 struct msg_msg *copy_msg(struct msg_msg *src, struct msg_msg *dst)
0146 {
0147 return ERR_PTR(-ENOSYS);
0148 }
0149 #endif
0150 int store_msg(void __user *dest, struct msg_msg *msg, size_t len)
0151 {
0152 size_t alen;
0153 struct msg_msgseg *seg;
0154
0155 alen = min(len, DATALEN_MSG);
0156 if (copy_to_user(dest, msg + 1, alen))
0157 return -1;
0158
0159 for (seg = msg->next; seg != NULL; seg = seg->next) {
0160 len -= alen;
0161 dest = (char __user *)dest + alen;
0162 alen = min(len, DATALEN_SEG);
0163 if (copy_to_user(dest, seg + 1, alen))
0164 return -1;
0165 }
0166 return 0;
0167 }
0168
0169 void free_msg(struct msg_msg *msg)
0170 {
0171 struct msg_msgseg *seg;
0172
0173 security_msg_msg_free(msg);
0174
0175 seg = msg->next;
0176 kfree(msg);
0177 while (seg != NULL) {
0178 struct msg_msgseg *tmp = seg->next;
0179
0180 cond_resched();
0181 kfree(seg);
0182 seg = tmp;
0183 }
0184 }