I have addressed this issue before, and I do it again, because we have a
potential kernel crash situation, if this isn't fixed.
The __access_ok macro in include/asm-mips64/uaccess.h and the check_axs
macro in arch/mips64/kernel/unaligned.c need to be changed in order to
work correctly, it's a copy from the 32-bit kernel. It's not good enough
to simply check for the "sign bit" of the address.
The area between USEG (XUSEG) and KSEG0 will in 64-bit addressing mode
generate an address error, if accessed.
The size of the area depend on the number of virtual addressing bits
implemented in the CPU.
Please take a look at the patch below.
I think Ralf had some objection the last time I send it, about the fix,
not being efficient enough (performance vice), but I think we need to
consider stability and functionality over performance. So until someone
comes up with a better solution, I think we need this fix.
_ _ ____ ___ Carsten Langgaard Mailto:email@example.com
|\ /|||___)(___ MIPS Denmark Direct: +45 4486 5527
| \/ ||| ____) Lautrupvang 4B Switch: +45 4486 5555
TECHNOLOGIES 2750 Ballerup Fax...: +45 4486 5556
RCS file: /home/cvs/linux/arch/mips64/kernel/unaligned.c,v
retrieving revision 184.108.40.206
diff -u -r220.127.116.11 unaligned.c
--- arch/mips64/kernel/unaligned.c 5 Dec 2002 03:09:58 -0000 18.104.22.168
+++ arch/mips64/kernel/unaligned.c 5 Dec 2002 15:06:59 -0000
@@ -89,11 +89,14 @@
#define __STR(x) #x
- * User code may only access USEG; kernel code may access the
- * entire address space.
+ * User code may only access USEG;
+ * Kernel code may access the entire address space, except the area between
+ * USEG (XUSEG) and KSEG0.
-#define check_axs(pc,a,s) \
- if ((long)(~(pc) & ((a) | ((a)+(s)))) < 0) \
+#define check_axs(pc,a,s) \
+ if (((pc < KUSIZE) && (((a) | ((a)+(s))) >= KUSIZE)) ||
+ ((((a) | ((a)+(s))) < K0BASE) && \
+ (((a) | ((a)+(s))) >= KUSIZE))) \
static inline int emulate_load_store_insn(struct pt_regs *regs,
RCS file: /home/cvs/linux/include/asm-mips64/uaccess.h,v
retrieving revision 22.214.171.124
diff -u -r126.96.36.199 uaccess.h
--- include/asm-mips64/uaccess.h 1 Jul 2002 15:27:31 -0000 188.8.131.52
+++ include/asm-mips64/uaccess.h 5 Dec 2002 15:07:11 -0000
@@ -40,16 +40,23 @@
* than tests.
* Address valid if:
- * - "addr" doesn't have any high-bits set
- * - AND "size" doesn't have any high-bits set
- * - AND "addr+size" doesn't have any high-bits set
- * - OR we are in kernel mode.
+ * - In user mode and "addr" and "addr+size" in USEG (or XUSEG).
+ * - OR we are in kernel mode and "addr" and "addr+size" isn't in the
+ * area between USEG (XUSEG) and KSEG0.
(__builtin_constant_p(size) && (signed long) (size) > 0 ? 0 : (size))
-#define __access_ok(addr,size,mask) \
- (((signed long)((mask)&(addr | (addr + size) | __ua_size(size)))) >= 0)
+static inline int
+__access_ok(unsigned long addr, unsigned long size, long mask)
+ if (((mask) && ((addr | (addr+size)) >= KUSIZE)) ||
+ (((addr | (addr+size)) < K0BASE) &&
+ ((addr | (addr+size)) >= KUSIZE)))
+ return 0;
+ return 1;
#define __access_mask ((long)(get_fs().seg))