If we examine the assembly instructions of vno_rw() , we see that it does pass the valid vnode pointer to fifo_rdwr() . vno_rw,10/ia _vno_rw: _vno_rw: save %sp, -0x60, %sp _vno_rw+4: ld [%i0 + 0x10], %i4 <--- Load vp into %i4 _vno_rw+8: cmp %i1, 0x1 _vno_rw+0xc: bne,a _vno_rw + 0x30 _vno_rw+0x10: ld [%i2 + 0x10], %i3 _vno_rw+0x14: call _isrofile <--- Is vp pointing to read-only file? _vno_rw+0x18: mov %i4, %o0 <--- Copy vp into %o0 during call delay _vno_rw+0x1c: orcc %g0, %o0, %g0 _vno_rw+0x20: be,a _vno_rw + 0x30 <--- Read write, branch to 30 _vno_rw+0x24: ld [%i2 + 0x10], %i3 _vno_rw+0x28: ba _vno_rw + 0xf4 <--- Read-only, branch to return _vno_rw+0x2c: mov 0x1e, %i5 _vno_rw+0x30: ld [%i4 + 0x18], %o0 <--- Using %o0 as a local register _vno_rw+0x34: clr %i5 now. Watch how it is used _vno_rw+0x38: cmp %o0, 0x1 but is reset to the vp just _vno_rw+0x3c: bne,a _vno_rw + 0x4c as we jump into a vnode _vno_rw+0x40: operations routine later on. +,10/ia _vno_rw+0x40: ld [%i0], %o1 _vno_rw+0x44: mov 0x1, %i5 _vno_rw+0x48: ld [%i0], %o1 _vno_rw+0x4c: andcc %o1, 0x8, %g0 _vno_rw+0x50: be,a _vno_rw + 0x60 _vno_rw+0x54: ld [%i0], %o2 _vno_rw+0x58: or %i5, 0x2, %i5 _vno_rw+0x5c: ld [%i0], %o2 _vno_rw+0x60: sethi %hi(0x2000), %o3 _vno_rw+0x64: andcc %o2, %o3, %g0 _vno_rw+0x68: be,a _vno_rw + 0x78 _vno_rw+0x6c: ld [%i0], %o4 _vno_rw+0x70: or %i5, 0x4, %i5 _vno_rw+0x74: ld [%i0], %o4 _vno_rw+0x78: sethi %hi(0x1000), %o5 _vno_rw+0x7c: andcc %o4, %o5, %g0 _vno_rw+0x80: +,10/ia _vno_rw+0x80: be,a _vno_rw + 0x90 _vno_rw+0x84: ld [%i4 + 0xc], %g1 <--- This area of code is using a table _vno_rw+0x88: or %i5, 0x10, %i5 of file system operations to figure _vno_rw+0x8c: ld [%i4 + 0xc], %g1 out where we want to jump, based _vno_rw+0x90: mov %i5, %o3 on our file system type. The final _vno_rw+0x94: ld [%g1 + 0x8], %g1 address is in %g1. _vno_rw+0x98: ld [%i0 + 0x18], %o4 <--- Start preparing calling parameters. _vno_rw+0x9c: mov %i1, %o2 _vno_rw+0xa0: mov %i2, %o1 _vno_rw+0xa4: jmpl %g1, %o7 <--- Jump into fifo_rdwr, moving vp _vno_rw+0xa8: mov %i4, %o0 <--- into %o1 during the jmpl delay. _vno_rw+0xac: mov %o0, %i5 _vno_rw+0xb0: orcc %g0, %i5, %g0 _vno_rw+0xb4: bne _vno_rw + 0xf4 _vno_rw+0xb8: nop _vno_rw+0xbc: ld [%i0], %l0 _vno_rw+0xc0: +,10/ia _vno_rw+0xc0: andcc %l0, 0x8, %g0 _vno_rw+0xc4: bne,a _vno_rw + 0xe0 _vno_rw+0xc8: ld [%i2 + 0x10], %l4 _vno_rw+0xcc: ld [%i4 + 0x18], %i4 _vno_rw+0xd0: cmp %i4, 0x8 _vno_rw+0xd4: bne,a _vno_rw + 0xf4 _vno_rw+0xd8: clr %i5 _vno_rw+0xdc: ld [%i2 + 0x10], %l4 _vno_rw+0xe0: ld [%i2 + 0x8], %i2 _vno_rw+0xe4: sub %i3, %l4, %l4 _vno_rw+0xe8: sub %i2, %l4, %l4 _vno_rw+0xec: st %l4, [%i0 + 0x14] _vno_rw+0xf0: clr %i5 _vno_rw+0xf4: ret _vno_rw+0xf8: restore %g0, %i5, %o0 _vno_ioctl: _vno_ioctl: save %sp, -0xb8, %sp _vno_ioctl+4: So far, it appears that a good vnode pointer was given to fifo_rdwr() . What about the other calling parameters? Since vno_rw() is a somewhat short and rather easy-to-follow routine, we can also check the parameters without going through too much pain. Refer to the assembly code above. $c _panic(0xf8120eb1,0xf86e8cbc,0xffffffff,0x30,0x7c375,0xf7fffdf0) + 6c _trap(0x7,0xf86e8cbc,0xffffffff,0x30,0x0,0x0) + 2a0 st_have_window(?) _uiomove(0x0,0x0,0x1000,0x2,0x1002,0x2) + 98 _fifo_rdwr(0xfceaccb0,0xf86e8eac,0x0,0xfceb2525,0x2,0x0) + 5ac _vno_rw(0xf835bac8,0x1,0xf86e8eac,0x1000,0xfceaccb4,0x0) + a4 _rwuio(0xf835bac8,0xf86e8eac,0xf86e8ea4,0x1000,0x1000,0xf86e8eac) + 2b0 _write(0xf86e8fe0,0x20,0xf8114ad0,0xf8114af0,0xf86e9000,0xf8114af0) + 34 _syscall(0xf86e9000) + 3b4 0xf835bac8+18/X 0xf835bae0: ff1c1514 <---- See vno_rw+0x98. %o4 points to a credentials structure. ff1c1514$<ucred 0xff1c1514: ref uid gid 5 0 1 0xff1c1520: groups 0 -1 -1 -1 -1 -1 -1 -1 0xff1c151c: ruid rgid 0 1 0xf86e8eac$<uio <---- See vno_rw+0xa0. %o1 contains a uio pointer. 0xf86e8eac: iovcnt offset seg resid 1 4096 0 0 0xf86e8ea4: base 7630 len 0 7630/X 0x7630: ff8 As we can see, when vno_rw() called fifo_rdwr() , three apparently valid pointers were sent as parameters vp , uiop , and cred . The other two parameters, rw and ioflag , are both small values. Ioflag was created on-the-fly by vno_rw() and rw was simply forwarded. We can safely assume things were going along well until we were executing the fifo_rdwr() routine. But, where exactly did things go wrong? Since fifo_rdwr() i s a long routine, without source code this question is not easily answered . |