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