Re: i386: __range_ok

Artur Skawina (skawina@geocities.com)
Tue, 31 Aug 1999 20:44:02 +0200


Thomas Sailer wrote:
>
> i386: __range_ok seems to have a constraint bug.
> When fed with an __u16 size, %3 may become
> a 16 bit register such as %ax.

hmm, yes, it needs an explicit cast, ie:

#define __range_ok(addr,size) ({ \
unsigned long flag,sum; \
asm("addl %3,%1 ; sbbl %0,%0; cmpl %1,%4; sbbl $0,%0" \
:"=&r" (flag), "=r" (sum) \
- :"1" (addr),"g" (size),"g" (current->addr_limit.seg)); \
+ :"1" (addr),"g" ((u32)(size)),"g" (current->addr_limit.seg)); \
flag; })

would work.

note that gcc (incl. 2.95) doesn't generate optimal code for this
construct - eg for many verify_area cases it happily forgets that %3 is
a constant and uses a register. something like the code below makes
the compiler use immediates, and also happens to fix the size issue.
(but this version doesn't properly handle the !CONFIG_X86_WP_WORKS_OK case yet)

--- /img/linux-2.3.12/include/asm-i386/uaccess.h Fri Jul 30 20:55:51 1999
+++ linux-2.3.12as/include/asm-i386/uaccess.h Fri Jul 30 19:28:21 1999
+extern inline unsigned long __range_ok( const void *addr, const unsigned long size )
+{
+ unsigned long flag,sum;
+ asm(
+ " addl %3,%1\n"
+ " sbbl %0,%0\n"
+ " cmpl %1,%4\n"
+ " sbbl $0,%0"
+ :"=&r" (flag), "=r" (sum)
+ :"1" (addr), "g" (size), "g" (current->addr_limit.seg) );
+ return flag;
+}

#ifdef CONFIG_X86_WP_WORKS_OK

@@ -58,11 +95,8 @@ extern int __verify_write(const void *,

#endif /* CPU */

-extern inline int verify_area(int type, const void * addr, unsigned long size)
-{
- return access_ok(type,addr,size) ? 0 : -EFAULT;
-}
-
+/* a define makes the compiler generate better code */
+#define verify_area(type,addr,size) (access_ok((type),(addr),(size)) ? 0 : -EFAULT)

/*
* The exception table consists of pairs of addresses: the first is the

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/