patch-2.4.0-test7 linux/include/asm-arm/uaccess.h

Next file: linux/include/asm-arm/unaligned.h
Previous file: linux/include/asm-arm/termios.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.0-test6/linux/include/asm-arm/uaccess.h linux/include/asm-arm/uaccess.h
@@ -46,7 +46,14 @@
 
 /*
  * Single-value transfer routines.  They automatically use the right
- * size if we just have the right pointer type.
+ * size if we just have the right pointer type.  Note that the functions
+ * which read from user space (*get_*) need to take care not to leak
+ * kernel data even if the calling code is buggy and fails to check
+ * the return value.  This means zeroing out the destination variable
+ * or buffer on error.  Normally this is done out of line by the
+ * fixup code, but there are a few places where it intrudes on the
+ * main code path.  When we only write to user space, there is no
+ * problem.
  *
  * The "__xxx" versions of the user access functions do not verify the
  * address space - it must have been done previously with a separate
@@ -54,24 +61,27 @@
  *
  * The "xxx_ret" versions return constant specified in the third
  * argument if something bad happens.
+ *
+ * The "xxx_error" versions set the third argument to EFAULT if an
+ * error occurs, and leave it unchanged on success.  Note that these
+ * versions are void (ie, don't return a value as such).
  */
 #define get_user(x,p)		__get_user_check((x),(p),sizeof(*(p)))
 #define __get_user(x,p)		__get_user_nocheck((x),(p),sizeof(*(p)))
+#define __get_user_error(x,p,e)	__get_user_nocheck_error((x),(p),sizeof(*(p)),(e))
 #define get_user_ret(x,p,r)	({ if (get_user(x,p)) return r; })
 #define __get_user_ret(x,p,r)	({ if (__get_user(x,p)) return r; })
 
 #define put_user(x,p)		__put_user_check((__typeof(*(p)))(x),(p),sizeof(*(p)))
 #define __put_user(x,p)		__put_user_nocheck((__typeof(*(p)))(x),(p),sizeof(*(p)))
+#define __put_user_error(x,p,e)	__put_user_nocheck_error((x),(p),sizeof(*(p)),(e))
 #define put_user_ret(x,p,r)	({ if (put_user(x,p)) return r; })
 #define __put_user_ret(x,p,r)	({ if (__put_user(x,p)) return r; })
 
 static __inline__ unsigned long copy_from_user(void *to, const void *from, unsigned long n)
 {
-	char *end = (char *)to + n;
-	if (access_ok(VERIFY_READ, from, n)) {
+	if (access_ok(VERIFY_READ, from, n))
 		__do_copy_from_user(to, from, n);
-		if (n) memset(end - n, 0, n);
-	}
 	return n;
 }
 
@@ -147,26 +157,38 @@
 ({									\
 	long __gu_err = -EFAULT, __gu_val = 0;				\
 	const __typeof__(*(ptr)) *__gu_addr = (ptr);			\
-	if (access_ok(VERIFY_READ,__gu_addr,size))			\
+	if (access_ok(VERIFY_READ,__gu_addr,size)) {			\
+		__gu_err = 0;						\
 		__get_user_size(__gu_val,__gu_addr,(size),__gu_err);	\
+	}								\
 	(x) = (__typeof__(*(ptr)))__gu_val;				\
 	__gu_err;							\
 })
 
 #define __get_user_nocheck(x,ptr,size)					\
 ({									\
-	long __gu_err = 0, __gu_val = 0;				\
+	long __gu_err = 0, __gu_val;					\
 	__get_user_size(__gu_val,(ptr),(size),__gu_err);		\
 	(x) = (__typeof__(*(ptr)))__gu_val;				\
 	__gu_err;							\
 })
 
+#define __get_user_nocheck_error(x,ptr,size,err)			\
+({									\
+	long __gu_val;							\
+	__get_user_size(__gu_val,(ptr),(size),(err));			\
+	(x) = (__typeof__(*(ptr)))__gu_val;				\
+	(void) 0;							\
+})
+
 #define __put_user_check(x,ptr,size)					\
 ({									\
 	long __pu_err = -EFAULT;					\
 	__typeof__(*(ptr)) *__pu_addr = (ptr);				\
-	if (access_ok(VERIFY_WRITE,__pu_addr,size))			\
+	if (access_ok(VERIFY_WRITE,__pu_addr,size)) {			\
+		__pu_err = 0;						\
 		__put_user_size((x),__pu_addr,(size),__pu_err);		\
+	}								\
 	__pu_err;							\
 })
 
@@ -177,11 +199,16 @@
 	__pu_err;							\
 })
 
+#define __put_user_nocheck_error(x,ptr,size,err)			\
+({									\
+	__put_user_size((x),(ptr),(size),err);				\
+	(void) 0;							\
+})
+
 extern long __get_user_bad(void);
 
 #define __get_user_size(x,ptr,size,retval)				\
 do {									\
-	retval = 0;							\
 	switch (size) {							\
 	case 1:	__get_user_asm_byte(x,ptr,retval);	break;		\
 	case 2:	__get_user_asm_half(x,ptr,retval);	break;		\
@@ -194,7 +221,6 @@
 
 #define __put_user_size(x,ptr,size,retval)				\
 do {									\
-	retval = 0;							\
 	switch (size) {							\
 	case 1: __put_user_asm_byte(x,ptr,retval);	break;		\
 	case 2: __put_user_asm_half(x,ptr,retval);	break;		\

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)