PATCH: 2.1.37's new "do_down" and "up" can fault kernel

Kevin Buhr (buhr@stat.wisc.edu)
14 May 1997 17:12:09 -0500


Linus:

The new "do_down" and "up" inline assembly functions in
"linux/arch/include/asm-i386/semaphore.h" aren't quite correct. For
example, "up" passes the jump address "__up_wakeup" using the
specification:
:"c" (sem), "m" (*(unsigned long *)__up_wakeup)
and then jumps using:
"jmp %1\n"

However, this ends up generating the assembly:
jmp *(%eax) ; jump to the word stored at address __up_wakeup
(where %eax == __up_wakeup) rather than the desired assembly:
jmp *%eax ; jump to __up_wakeup

I first noticed the problem when invoking "swapon" on a regular file:
the "down" at the end of "ll_rw_swap_file" jumped to the address
"e8515250", the four bytes of *code* at the start of "__down_failed".

The enclosed patch against 2.1.37 fixes the problem.

Kevin <buhr@stat.wisc.edu>

* * *

--- linux/include/asm-i386/semaphore.h 1997/05/14 14:58:35 1.1.1.2
+++ linux/include/asm-i386/semaphore.h 1997/05/14 22:23:25
@@ -96,7 +96,7 @@
"jmp %1\n"
".previous"
:/* no outputs */
- :"c" (sem), "m" (*(unsigned long *)failed)
+ :"c" (sem), "r" (failed)
:"memory");
}

@@ -124,7 +124,7 @@
"jmp %1\n"
".previous"
:/* no outputs */
- :"c" (sem), "m" (*(unsigned long *)__up_wakeup)
+ :"c" (sem), "r" (__up_wakeup)
:"memory");
}