[parisc-linux] userspace function pointers in the kernel
David Huggins-Daines
dhd@linuxcare.com
12 Sep 2000 16:12:08 -0400
Hi,
This simple program:
#include <signal.h>
void foo(int signo)
{
psignal(signo, "foo");
}
int main()
{
signal(SIGFPE, foo);
return 0;
}
Now causes the kernel (latest from CVS) to crash where it didn't
before:
Kernel Fault: Code=15 regs=c7c44600 (Addr=00002c04)
PSW : 0006ff0a GR 1 : c0233000 GR 2 : c011dcf0 GR 3 : c7c44518
GR 4 : 20020350 GR 5 : 00000008 GR 6 : 00000007 GR 7 : 00000008
GR 8 : c7c44600 GR 9 : 2002114c GR10 : 20020670 GR11 : 00000040
GR12 : 00000001 GR13 : 00000078 GR14 : 00057000 GR15 : 00057000
GR16 : 00000063 GR17 : 00000020 GR18 : 2002058c GR19 : 00000000
GR20 : 00002c06 GR21 : c7f2387c GR22 : fffffff8 GR23 : c7f23880
GR24 : c7c44528 GR25 : c7c44518 GR26 : 00002c04 GR27 : c027a000
GR28 : fffffff2 GR29 : 00002c06 GR30 : c7c44840 GR31 : c011d7c8
SR0 : 00002002 SR1 : 00002002 SR2 : 00000000 SR3 : 00002002
SR4 : 00000000 SR5 : 00000000 SR6 : 00000000 SR7 : 00000000
IASQ : 00000000 00000000 IAOQ : c02336a0 c02336a4 ORIG_R28 : 00003fff
IIR : 075f11d6 ISR : 00000000 IOR : 00002c04
Which is:
c0233698 <$$sh_func_adrs>:
c0233698: 37 5d 00 00 ldo 0(r26),ret1
c023369c: d7 40 0c 3f depw r0,30,1,r26
c02336a0: 07 5f 11 d6 probe,w (sr0,r26),r31,r22
^^^^^^^^^^^^^^^^^^^^^^^^^ this insn
c02336a4: d2 d6 3b ff extrw,u,= r22,31,1,r22
c02336a8: 0f 40 10 9d ldw 0(sr0,r26),ret1
c02336ac: eb e0 c0 02 bv,n r0(r31)
Following the millicode return pointer takes us to do_signal() in
kernel/signal.c, somewhere around these lines:
if (k->sa.sa_handler == SIG_IGN
|| (k->sa.sa_handler == SIG_DFL
Note that the kernel is trying to compare a function pointer passed in
from userspace with an arbitrary value.
Now, first of all, this means our DTLB miss handler is broken with
respect to the PROBE instructions. According to the architecture
manual,
Notes: If this instruction causes a non-access data TLB miss
fault/non-access data page fault, the operating system's
handler is required to search its page tables for the given
address. If found, it does the appropriate TLB insert and
returns to the interrupting instruction. If not found, the
handler must decode the target field of the instruction, set
that GR to 0, set the IPSW[N] bit to 1, and return to the
interrupting instruction.
Obviously that's not what's happening here.
Next, even if we *weren't* trapping we would still be doing the wrong
thing, because $$sh_func_adrs is actually supposed to give us the
address of the function's code, and it isn't going to do this since
the function lives in a different space.
In the case of sigaction() I think we actually want to compare the
plabel value (rather than the code address) againsr SIG_IGN and
SIG_DFL. However there may be other cases where this will break.
Yes this is yet another side effect of the broken PA-RISC run time
architecture. What do the IA-64 people do about this problem?
In the worst case scenario we may have to hack our millicode in the
kernel somewhat to deal with this.
--
dhd@linuxcare.com, http://www.linuxcare.com/
Linuxcare. Support for the revolution.