public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Stefani Seibold <stefani@seibold.net>
To: Andi Kleen <andi@firstfloor.org>
Cc: linux-kernel@vger.kernel.org, akpm@osdl.org
Subject: Re: [PATCH] [3/6] kfifo: Sanitize *_user error handling
Date: Sun, 27 Dec 2009 22:38:00 +0100	[thread overview]
Message-ID: <1261949880.25298.21.camel@wall-e> (raw)
In-Reply-To: <20091227210313.A8E7BB17C3@basil.firstfloor.org>

Am Sonntag, den 27.12.2009, 22:03 +0100 schrieb Andi Kleen:
> Right now for kfifo_*_user it's not easily possible to distingush between a 
> user copy failing and the FIFO not containing enough data. The problem 
> is that both conditions are multiplexed into the same return code.
> 
> Avoid this by moving the "copy length" into a separate output parameter
> and only return 0/-EFAULT in the main return value.
> 

I don't like this idea. kfifo_from_user and kfifo_to_user should have
the same semantics as copy_from_user and copy_to_user. 

> I didn't fully adapt the weird "record" variants, those seem 
> to be unused anyways and were rather messy (should they be just removed?)
> 

Believe it or not, it will be used in future. 

> I would appreciate some double checking if I did all the conversions
> correctly.
> 
> Signed-off-by: Andi Kleen <ak@linux.intel.com>
> 
> ---
>  include/linux/kfifo.h |    8 ++---
>  kernel/kfifo.c        |   76 ++++++++++++++++++++++++++++++++------------------
>  2 files changed, 53 insertions(+), 31 deletions(-)
> 
> Index: linux/include/linux/kfifo.h
> ===================================================================
> --- linux.orig/include/linux/kfifo.h
> +++ linux/include/linux/kfifo.h
> @@ -243,11 +243,11 @@ static inline __must_check unsigned int
>  
>  extern void kfifo_skip(struct kfifo *fifo, unsigned int len);
>  
> -extern __must_check unsigned int kfifo_from_user(struct kfifo *fifo,
> -	const void __user *from, unsigned int n);
> +extern __must_check int kfifo_from_user(struct kfifo *fifo,
> +	const void __user *from, unsigned int n, unsigned *lenout);
>  
> -extern __must_check unsigned int kfifo_to_user(struct kfifo *fifo,
> -	void __user *to, unsigned int n);
> +extern __must_check int kfifo_to_user(struct kfifo *fifo,
> +	void __user *to, unsigned int n, unsigned *lenout);
>  
>  /**
>   * __kfifo_add_out internal helper function for updating the out offset
> Index: linux/kernel/kfifo.c
> ===================================================================
> --- linux.orig/kernel/kfifo.c
> +++ linux/kernel/kfifo.c
> @@ -159,8 +159,9 @@ static inline void __kfifo_out_data(stru
>  	memcpy(to + l, fifo->buffer, len - l);
>  }
>  
> -static inline unsigned int __kfifo_from_user_data(struct kfifo *fifo,
> -	 const void __user *from, unsigned int len, unsigned int off)
> +static inline int __kfifo_from_user_data(struct kfifo *fifo,
> +	 const void __user *from, unsigned int len, unsigned int off,
> +	 unsigned *lenout)
>  {
>  	unsigned int l;
>  	int ret;
> @@ -177,16 +178,20 @@ static inline unsigned int __kfifo_from_
>  	/* first put the data starting from fifo->in to buffer end */
>  	l = min(len, fifo->size - off);
>  	ret = copy_from_user(fifo->buffer + off, from, l);
> -
> -	if (unlikely(ret))
> -		return ret + len - l;
> +	if (unlikely(ret)) {
> +		*lenout = ret;
> +		return -EFAULT;
> +	}
> +	*lenout = l;
>  
>  	/* then put the rest (if any) at the beginning of the buffer */
> -	return copy_from_user(fifo->buffer, from + l, len - l);
> +	ret = copy_from_user(fifo->buffer, from + l, len - l);
> +	*lenout += ret ? ret : len - l;
> +	return ret ? -EFAULT : 0;
>  }
>  
> -static inline unsigned int __kfifo_to_user_data(struct kfifo *fifo,
> -		void __user *to, unsigned int len, unsigned int off)
> +static inline int __kfifo_to_user_data(struct kfifo *fifo,
> +		void __user *to, unsigned int len, unsigned int off, unsigned *lenout)
>  {
>  	unsigned int l;
>  	int ret;
> @@ -203,12 +208,21 @@ static inline unsigned int __kfifo_to_us
>  	/* first get the data from fifo->out until the end of the buffer */
>  	l = min(len, fifo->size - off);
>  	ret = copy_to_user(to, fifo->buffer + off, l);
> -
> -	if (unlikely(ret))
> -		return ret + len - l;
> +	*lenout = l;
> +	if (unlikely(ret)) {
> +		*lenout -= ret;
> +		return -EFAULT;
> +	}
>  
>  	/* then get the rest (if any) from the beginning of the buffer */
> -	return copy_to_user(to + l, fifo->buffer, len - l);
> +	len -= l;
> +	ret = copy_to_user(to + l, fifo->buffer, len);
> +	if (unlikely(ret)) {
> +		*lenout += len - ret;
> +		return -EFAULT;
> +	}
> +	*lenout += len;
> +	return 0;
>  }
>  
>  unsigned int __kfifo_in_n(struct kfifo *fifo,
> @@ -298,10 +312,13 @@ EXPORT_SYMBOL(__kfifo_out_generic);
>  unsigned int __kfifo_from_user_n(struct kfifo *fifo,
>  	const void __user *from, unsigned int len, unsigned int recsize)
>  {
> +	unsigned total;
> +
>  	if (kfifo_avail(fifo) < len + recsize)
>  		return len + 1;
>  
> -	return __kfifo_from_user_data(fifo, from, len, recsize);
> +	__kfifo_from_user_data(fifo, from, len, recsize, &total);
> +	return total;
>  }
>  EXPORT_SYMBOL(__kfifo_from_user_n);
>  
> @@ -312,18 +329,21 @@ EXPORT_SYMBOL(__kfifo_from_user_n);
>   * @len: the length of the data to be added.
>   *
>   * This function copies at most @len bytes from the @from into the
> - * FIFO depending and returns the number of copied bytes.
> + * FIFO depending and returns -EFAULT/0.
>   *
>   * Note that with only one concurrent reader and one concurrent
>   * writer, you don't need extra locking to use these functions.
>   */
> -unsigned int kfifo_from_user(struct kfifo *fifo,
> -	const void __user *from, unsigned int len)
> +int kfifo_from_user(struct kfifo *fifo,
> +        const void __user *from, unsigned int len, unsigned *total)
>  {
> +	int ret;
>  	len = min(kfifo_avail(fifo), len);
> -	len -= __kfifo_from_user_data(fifo, from, len, 0);
> +	ret = __kfifo_from_user_data(fifo, from, len, 0, total);
> +	if (ret)
> +		return ret;
>  	__kfifo_add_in(fifo, len);
> -	return len;
> +	return 0;
>  }
>  EXPORT_SYMBOL(kfifo_from_user);
>  
> @@ -338,17 +358,17 @@ unsigned int __kfifo_to_user_n(struct kf
>  	void __user *to, unsigned int len, unsigned int reclen,
>  	unsigned int recsize)
>  {
> -	unsigned int ret;
> +	unsigned int ret, total;
>  
>  	if (kfifo_len(fifo) < reclen + recsize)
>  		return len;
>  
> -	ret = __kfifo_to_user_data(fifo, to, reclen, recsize);
> +	ret = __kfifo_to_user_data(fifo, to, reclen, recsize, &total);
>  
>  	if (likely(ret == 0))
>  		__kfifo_add_out(fifo, reclen + recsize);
>  
> -	return ret;
> +	return total;
>  }
>  EXPORT_SYMBOL(__kfifo_to_user_n);
>  
> @@ -357,20 +377,22 @@ EXPORT_SYMBOL(__kfifo_to_user_n);
>   * @fifo: the fifo to be used.
>   * @to: where the data must be copied.
>   * @len: the size of the destination buffer.
> + @ @lenout: pointer to output variable with copied data
>   *
>   * This function copies at most @len bytes from the FIFO into the
> - * @to buffer and returns the number of copied bytes.
> + * @to buffer and 0 or -EFAULT.
>   *
>   * Note that with only one concurrent reader and one concurrent
>   * writer, you don't need extra locking to use these functions.
>   */
> -unsigned int kfifo_to_user(struct kfifo *fifo,
> -	void __user *to, unsigned int len)
> +int kfifo_to_user(struct kfifo *fifo,
> +	void __user *to, unsigned int len, unsigned *lenout)
>  {
> +	int ret;
>  	len = min(kfifo_len(fifo), len);
> -	len -= __kfifo_to_user_data(fifo, to, len, 0);
> -	__kfifo_add_out(fifo, len);
> -	return len;
> +	ret = __kfifo_to_user_data(fifo, to, len, 0, lenout);
> +	__kfifo_add_out(fifo, *lenout);
> +	return ret;
>  }
>  EXPORT_SYMBOL(kfifo_to_user);
>  



  reply	other threads:[~2009-12-27 21:38 UTC|newest]

Thread overview: 53+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-12-27 21:03 [PATCH] [0/6] kfifo fixes/improvements Andi Kleen
2009-12-27 21:03 ` [PATCH] [1/6] kfifo: Use void * pointers for user buffers Andi Kleen
2009-12-27 21:48   ` Stefani Seibold
2009-12-27 21:03 ` [PATCH] [2/6] kfifo: Make kfifo_in atomic Andi Kleen
2009-12-27 21:46   ` Stefani Seibold
2009-12-27 21:03 ` [PATCH] [3/6] kfifo: Sanitize *_user error handling Andi Kleen
2009-12-27 21:38   ` Stefani Seibold [this message]
2009-12-27 23:34     ` Andi Kleen
2009-12-28  7:10       ` Stefani Seibold
2010-01-04 22:33   ` Stefani Seibold
2009-12-27 21:03 ` [PATCH] [4/6] kfifo: add kfifo_out_peek Andi Kleen
2009-12-27 21:49   ` Stefani Seibold
2009-12-27 23:41     ` Andi Kleen
2009-12-28  7:09       ` Stefani Seibold
2010-01-04 21:57       ` Andrew Morton
2010-01-04 22:24         ` Alan Cox
2010-01-04 22:47           ` Stefani Seibold
2010-01-05  0:14             ` Alan Cox
2009-12-27 21:03 ` [PATCH] [5/6] kfifo: Add kfifo_initialized Andi Kleen
2009-12-27 21:53   ` Stefani Seibold
2009-12-27 21:03 ` [PATCH] [6/6] kfifo: Document everywhere that size has to be power of two Andi Kleen
2009-12-27 21:50   ` Stefani Seibold
2009-12-27 22:14     ` Dmitry Torokhov
2009-12-27 22:23       ` Stefani Seibold
2009-12-27 23:34       ` Andi Kleen
2009-12-27 21:36 ` [PATCH] [0/6] kfifo fixes/improvements Stefani Seibold
2009-12-27 23:38   ` Andi Kleen
2009-12-28  6:49     ` Stefani Seibold
2009-12-28  7:42     ` Stefani Seibold
2009-12-28 14:57       ` Andi Kleen
2009-12-28 16:08         ` Stefani Seibold
2009-12-28 17:26           ` Andi Kleen
2009-12-28 20:04             ` Stefani Seibold
2009-12-28 20:40               ` Andi Kleen
2009-12-29  8:40                 ` Stefani Seibold
2009-12-29 22:27                   ` Dmitry Torokhov
2009-12-30  1:18                     ` Vikram Dhillon
2009-12-30  2:08                       ` Dmitry Torokhov
2009-12-30  9:29                         ` Stefani Seibold
2009-12-30 10:43                           ` Dmitry Torokhov
2009-12-30 10:52                             ` Stefani Seibold
2009-12-30 11:07                               ` Dmitry Torokhov
2009-12-30 11:32                                 ` Stefani Seibold
2009-12-30 17:29                         ` Andy Walls
2009-12-31  7:35                           ` Dmitry Torokhov
2009-12-31  8:59                             ` Stefani Seibold
2009-12-31  9:33                               ` Dmitry Torokhov
2009-12-31 18:03                             ` Andy Walls
2009-12-30 17:15                     ` Andy Walls
2009-12-28  0:12   ` Roland Dreier
2009-12-28  1:41     ` Andi Kleen
2009-12-28  7:06       ` Stefani Seibold
2009-12-28 14:56         ` Andi Kleen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1261949880.25298.21.camel@wall-e \
    --to=stefani@seibold.net \
    --cc=akpm@osdl.org \
    --cc=andi@firstfloor.org \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox