[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

copy_from_user() kills RH 6.1 kernel



Hi, this one is driving me mad. We've
built a module that has its own
syscalls,
some of which use copy_from_user() to
bring in the arguments.
However we have found that passing in a
rogue address to these system
calls will kill the kernel.

Indeed we have written a very simple
module that just does the following;

int
init_module(void)
{
 ulong a[6];

 printk("Copying to %p from 0\n", a);

 if (copy_from_user(a, (ulong *)0,
sizeof(ulong)*6) > 0)
     printk("testsyscall: bad arg\n");
 else
     printk("testsyscall: Copied it\n");

 return 0;
}

modprobing this on a stock RH6.1
2.2.13-0.9smp kernel kills the kernel;

Copying to fffffc001c993df8 from 0
Unable to handle kernel paging request
at virtual address 0000000000000000
CPU 1 insmod(664): Oops 0
pc = [<fffffc00004b6bc0>]  ra =
[<fffffe00000681c0>]  ps = 0000
v0 = 0000000000000030  t0 =
0000000000000000  t1 = 0000000000000001
t2 = 0000000000000000  t3 =
0000000000000030  t4 = 0000000100000000
t5 = fffffc001c993df8  t6 =
0000000000000000  t7 = fffffc001c990000
s0 = 0000000000000004  s1 =
fffffe0000068000  s2 = fffffc001d45e000
s3 = 0000000000000004  s4 =
ffffffffffffffea  s5 = fffffe0000068090
s6 = fffffc001c993f00  a0 =
000000000000001f  a1 = 0000000000000000
a2 = 0000000000000115  a3 =
fffffffffffffffe  a4 = fffffc000053fe00
a5 = fffffc000059bc9c  t8 =
0000000000000001  t9 = fffffc00004f8000
t10= fffffc00005bd5c8  t11=
0000000000000002  pv = fffffc00004b6ac0
at = fffffe00000681e8<4>sched.c:30
spinlock stuck in klogd at
fffffc000032cc64(0) owner insmod at
fffffc0000334a20(1) module.c:43
  gp = fffffc00005a0ed8  sp =
fffffc001c993de8
Code:
 f41ffff5  bge v0,.-40
 c3e00013  br .+80
 e480000a  blt t3,.+44
 2fe00000  ldq_u zero,0(v0)
 47ff041f  or zero,zero,zero
 2fe00000  ldq_u zero,0(v0)
*a4270000  ldq t0,0(t6)
 40811524  subq t3,8,t3
Trace: 335078 310d38


The failing pc is in the __copy_user()
code where is it reading from the user
source pointer. However, this
instruction is supposedly protected by
the EXI() macro which should insert the
pc into the _ex_table section. So for
some reason traps in __copy_user() are
not being found and fixed by the
search_exception_table() code.
The first problem I found with this code
was that the #ifndef is wrong in that it
should say CONFIG_MODULES <- note the
'S' on the end. So it has only ever been
scanning the kernel ex_table. However as
__copy_user() lives in the kernel this
doesn't fix my problem.

I've dumped out the whole of the kernel
ex_table and looked for the failing pc's
address (offset from the kernel gp) but
the ex_table gp offsets seem to stop
short of the __copy_user()  kernel
address. I've checked that the size of
the __ex_table section in vmlinux
matches the kernel's ex_table size and
I've also experimented with removing
some of the EX() from copy_user.S to
check they are actually being included
in the vmlunix section.
So my best guess is that the linkage of
these assembler modules is going wrong
and generating incorrect gp offsets ??

Has anyone got any clues on finding this
bug ?

Cheers,
Addy.








[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index] []