diff options
Diffstat (limited to 'ipc/msgutil.c')
| -rw-r--r-- | ipc/msgutil.c | 52 | 
1 files changed, 38 insertions, 14 deletions
diff --git a/ipc/msgutil.c b/ipc/msgutil.c index 98b1c2b476c..0a5c8a95c25 100644 --- a/ipc/msgutil.c +++ b/ipc/msgutil.c @@ -44,21 +44,54 @@ struct msg_msgseg {  #define DATALEN_MSG	(int)(PAGE_SIZE-sizeof(struct msg_msg))  #define DATALEN_SEG	(int)(PAGE_SIZE-sizeof(struct msg_msgseg)) -struct msg_msg *load_msg(const void __user *src, int len) + +static struct msg_msg *alloc_msg(int len)  {  	struct msg_msg *msg;  	struct msg_msgseg **pseg; -	int err;  	int alen;  	alen = min(len, DATALEN_MSG);  	msg = kmalloc(sizeof(*msg) + alen, GFP_KERNEL);  	if (msg == NULL) -		return ERR_PTR(-ENOMEM); +		return NULL;  	msg->next = NULL;  	msg->security = NULL; +	len -= alen; +	pseg = &msg->next; +	while (len > 0) { +		struct msg_msgseg *seg; +		alen = min(len, DATALEN_SEG); +		seg = kmalloc(sizeof(*seg) + alen, GFP_KERNEL); +		if (seg == NULL) +			goto out_err; +		*pseg = seg; +		seg->next = NULL; +		pseg = &seg->next; +		len -= alen; +	} + +	return msg; + +out_err: +	free_msg(msg); +	return NULL; +} + +struct msg_msg *load_msg(const void __user *src, int len) +{ +	struct msg_msg *msg; +	struct msg_msgseg *seg; +	int err; +	int alen; + +	msg = alloc_msg(len); +	if (msg == NULL) +		return ERR_PTR(-ENOMEM); + +	alen = min(len, DATALEN_MSG);  	if (copy_from_user(msg + 1, src, alen)) {  		err = -EFAULT;  		goto out_err; @@ -66,23 +99,14 @@ struct msg_msg *load_msg(const void __user *src, int len)  	len -= alen;  	src = ((char __user *)src) + alen; -	pseg = &msg->next; +	seg = msg->next;  	while (len > 0) { -		struct msg_msgseg *seg;  		alen = min(len, 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; +		seg = seg->next;  		len -= alen;  		src = ((char __user *)src) + alen;  	}  |