ia64/xen-unstable

changeset 9104:cfbf7332d616

While native code range-checks the requested address, possibly
truncates the range, and then reads/writes page-wise until possibly
encountering a -EFAULT issue, Xen code accessed the whole range in a
single step, thus not allowing partially succeeding accesses.

From: Jan Beulich

Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Thu Mar 02 16:06:51 2006 +0100 (2006-03-02)
parents 4dd325c1d87d
children 5ef601da9c2c
files linux-2.6-xen-sparse/drivers/xen/char/mem.c
line diff
     1.1 --- a/linux-2.6-xen-sparse/drivers/xen/char/mem.c	Thu Mar 02 14:43:24 2006 +0100
     1.2 +++ b/linux-2.6-xen-sparse/drivers/xen/char/mem.c	Thu Mar 02 16:06:51 2006 +0100
     1.3 @@ -43,49 +43,85 @@ static inline int uncached_access(struct
     1.4  static ssize_t read_mem(struct file * file, char __user * buf,
     1.5  			size_t count, loff_t *ppos)
     1.6  {
     1.7 -	unsigned long i, p = *ppos;
     1.8 -	ssize_t read = -EFAULT;
     1.9 +	unsigned long p = *ppos, ignored;
    1.10 +	ssize_t read = 0, sz;
    1.11  	void __iomem *v;
    1.12  
    1.13 -	if ((v = ioremap(p, count)) == NULL) {
    1.14 +	while (count > 0) {
    1.15  		/*
    1.16 -		 * Some programs (e.g., dmidecode) groove off into weird RAM
    1.17 -		 * areas where no table scan possibly exist (because Xen will
    1.18 -		 * have stomped on them!). These programs get rather upset if
    1.19 -                 * we let them know that Xen failed their access, so we fake
    1.20 -                 * out a read of all zeroes. :-)
    1.21 +		 * Handle first page in case it's not aligned
    1.22  		 */
    1.23 -		for (i = 0; i < count; i++)
    1.24 -			if (put_user(0, buf+i))
    1.25 +		if (-p & (PAGE_SIZE - 1))
    1.26 +			sz = -p & (PAGE_SIZE - 1);
    1.27 +		else
    1.28 +			sz = PAGE_SIZE;
    1.29 +
    1.30 +		sz = min_t(unsigned long, sz, count);
    1.31 +
    1.32 +		if ((v = ioremap(p, sz)) == NULL) {
    1.33 +			/*
    1.34 +			 * Some programs (e.g., dmidecode) groove off into weird RAM
    1.35 +			 * areas where no tables can possibly exist (because Xen will
    1.36 +			 * have stomped on them!). These programs get rather upset if
    1.37 +			 * we let them know that Xen failed their access, so we fake
    1.38 +			 * out a read of all zeroes. :-)
    1.39 +			 */
    1.40 +			if (clear_user(buf, count))
    1.41  				return -EFAULT;
    1.42 -		return count;
    1.43 +			read += count;
    1.44 +			break;
    1.45 +		}
    1.46 +
    1.47 +		ignored = copy_to_user(buf, v, sz);
    1.48 +		iounmap(v);
    1.49 +		if (ignored)
    1.50 +			return -EFAULT;
    1.51 +		buf += sz;
    1.52 +		p += sz;
    1.53 +		count -= sz;
    1.54 +		read += sz;
    1.55  	}
    1.56 -	if (copy_to_user(buf, v, count))
    1.57 -		goto out;
    1.58  
    1.59 -	read = count;
    1.60  	*ppos += read;
    1.61 -out:
    1.62 -	iounmap(v);
    1.63  	return read;
    1.64  }
    1.65  
    1.66  static ssize_t write_mem(struct file * file, const char __user * buf, 
    1.67  			 size_t count, loff_t *ppos)
    1.68  {
    1.69 -	unsigned long p = *ppos;
    1.70 -	ssize_t written = -EFAULT;
    1.71 +	unsigned long p = *ppos, ignored;
    1.72 +	ssize_t written = 0, sz;
    1.73  	void __iomem *v;
    1.74  
    1.75 -	if ((v = ioremap(p, count)) == NULL)
    1.76 -		return -EFAULT;
    1.77 -	if (copy_from_user(v, buf, count))
    1.78 -		goto out;
    1.79 +	while (count > 0) {
    1.80 +		/*
    1.81 +		 * Handle first page in case it's not aligned
    1.82 +		 */
    1.83 +		if (-p & (PAGE_SIZE - 1))
    1.84 +			sz = -p & (PAGE_SIZE - 1);
    1.85 +		else
    1.86 +			sz = PAGE_SIZE;
    1.87  
    1.88 -	written = count;
    1.89 +		sz = min_t(unsigned long, sz, count);
    1.90 +
    1.91 +		if ((v = ioremap(p, sz)) == NULL)
    1.92 +			break;
    1.93 +
    1.94 +		ignored = copy_from_user(v, buf, sz);
    1.95 +		iounmap(v);
    1.96 +		if (ignored) {
    1.97 +			written += sz - ignored;
    1.98 +			if (written)
    1.99 +				break;
   1.100 +			return -EFAULT;
   1.101 +		}
   1.102 +		buf += sz;
   1.103 +		p += sz;
   1.104 +		count -= sz;
   1.105 +		written += sz;
   1.106 +	}
   1.107 +
   1.108  	*ppos += written;
   1.109 -out:
   1.110 -	iounmap(v);
   1.111  	return written;
   1.112  }
   1.113