543 lines
11 KiB
NASM
543 lines
11 KiB
NASM
; gpfix.asm - pointer validation routines
|
|
|
|
include gpfix.inc
|
|
include kernel.inc
|
|
include tdb.inc
|
|
include newexe.inc
|
|
|
|
|
|
sBegin GPFIX0
|
|
__GP label word
|
|
;gpbeg dw 0, 0, 0, 0 ; for use in handler
|
|
public __GP
|
|
sEnd GPFIX0
|
|
|
|
sBegin GPFIX1
|
|
gpend dw 0
|
|
sEnd GPFIX1
|
|
|
|
sBegin DATA
|
|
;this segment is page locked and will be accessible during a GP fault
|
|
;has the names of modules that are allowed to use our funky GP fault handling
|
|
; mechanism. Format: length byte, module name. The table is zero-terminated.
|
|
gp_valid_modules label byte
|
|
db 3, "GDI"
|
|
db 4, "USER"
|
|
db 6, "KERNEL"
|
|
db 6, "PENWIN"
|
|
db 7, "DISPLAY"
|
|
db 8, "MMSYSTEM"
|
|
db 0 ;end of table
|
|
sEnd DATA
|
|
|
|
ifdef DISABLE
|
|
sBegin DATA
|
|
;ExternW wErrorOpts
|
|
sEnd DATA
|
|
endif
|
|
|
|
|
|
;public gpbeg, gpend
|
|
|
|
|
|
sBegin CODE
|
|
assumes CS,CODE
|
|
|
|
externA __AHINCR
|
|
|
|
externNP GetOwner
|
|
externNP EntProcAddress
|
|
externFP GetExePtr
|
|
externFP SetSelectorLimit
|
|
|
|
;===============================================================
|
|
;
|
|
;
|
|
cProc IsBadReadPtr,<PUBLIC,FAR,NONWIN>
|
|
ParmD lp
|
|
ParmW cb
|
|
cBegin
|
|
beg_fault_trap BadRead1
|
|
les bx,lp ; check selector
|
|
mov cx,cb
|
|
jcxz ReadDone1
|
|
dec cx
|
|
add bx,cx
|
|
jc BadRead ; check 16 bit overflow
|
|
mov al,es:[bx] ; check read permission, limit
|
|
end_fault_trap
|
|
ReadDone1:
|
|
xor ax,ax
|
|
ReadDone:
|
|
cEnd
|
|
|
|
BadRead1:
|
|
fault_fix_stack
|
|
BadRead:
|
|
mov ax,1
|
|
jmp short ReadDone
|
|
|
|
;===============================================================
|
|
;
|
|
;
|
|
cProc IsBadWritePtr,<PUBLIC,FAR,NONWIN>
|
|
ParmD lp
|
|
ParmW cb
|
|
cBegin
|
|
beg_fault_trap BadWrite1
|
|
les bx,lp ; check selector
|
|
mov cx,cb
|
|
jcxz WriteDone1
|
|
dec cx
|
|
add bx,cx
|
|
jc BadWrite ; check 16 bit overflow
|
|
or es:byte ptr [bx],0 ; check write permission, limit
|
|
end_fault_trap
|
|
WriteDone1:
|
|
xor ax, ax
|
|
WriteDone:
|
|
cEnd
|
|
|
|
BadWrite1:
|
|
fault_fix_stack
|
|
BadWrite:
|
|
mov ax,1
|
|
jmp short WriteDone
|
|
|
|
;===============================================================
|
|
; BOOL IsBadFlatReadWritePtr(VOID HUGE*lp, DWORD cb, WORD fWrite)
|
|
; This will validate a Flat pointer plus a special hack for Fox Pro
|
|
; to detect their poorly tiled selector (ie. all n selector with
|
|
; limit of 64K) (Our tiling is such that you can access up to end of
|
|
; the block using any one of the intermediate selectors flat)
|
|
; if we detect such a case we will fix up the limit on the first sel
|
|
; so GDI can access all of the memory as a 1st_sel:32-bit offset
|
|
|
|
cProc IsBadFlatReadWritePtr,<PUBLIC,FAR,NONWIN>
|
|
ParmD lp
|
|
ParmD cb
|
|
ParmW fWrite
|
|
cBegin
|
|
beg_fault_trap frp_trap
|
|
les bx,lp ; check selector
|
|
.386p
|
|
|
|
mov eax,cb
|
|
movzx ebx, bx
|
|
|
|
test eax,eax ; cb == 0, all done.
|
|
jz frp_ok
|
|
|
|
add ebx,eax
|
|
dec ebx
|
|
|
|
cmp fWrite, 0
|
|
jne frp_write
|
|
|
|
mov al,es:[ebx] ; read last byte
|
|
jmp frp_ok
|
|
|
|
frp_write:
|
|
or byte ptr es:[ebx], 0 ; write last byte
|
|
|
|
frp_ok:
|
|
xor ax,ax
|
|
end_fault_trap
|
|
frp_exit:
|
|
cEnd
|
|
|
|
frp_trap:
|
|
fault_fix_stack
|
|
frp_bad:
|
|
push ebx
|
|
mov ecx, ebx ; get cb
|
|
shr ecx, 16 ; get high word
|
|
jecxz frp_bade ; if < 64K then bad ptr
|
|
|
|
mov ax, es
|
|
lsl eax, eax ; get limit on 1st sel
|
|
jnz frp_bade ; bad sel?
|
|
cmp ax, 0ffffh ; 1st of poorly tiled sels?
|
|
jne frp_bade ; N: return bad ptr
|
|
; now we have to confirm that this is indeed the first of a bunch
|
|
; of poorly tiled sels and fix up the limit correctly of the first sel
|
|
|
|
movzx ebx, ax ; ebx = lim total of tiled sels
|
|
inc ebx ; make it 10000
|
|
mov dx, es
|
|
|
|
frp_loop:
|
|
|
|
add dx,__AHINCR ; next sel in array
|
|
lsl eax, edx
|
|
jnz frp_bade
|
|
cmp ecx, 1 ; last sel?
|
|
je @f
|
|
; if its not the last sel, then its limit has to be ffffh
|
|
; otherwise it probably is not a poorly tiled sel.
|
|
cmp eax, 0ffffh
|
|
jne frp_bade
|
|
@@:
|
|
add ebx, eax ; upd total limit
|
|
inc ebx ; add 1 for middle sels
|
|
|
|
loop frp_loop
|
|
dec ebx ; take exact limit of last sel
|
|
|
|
pop edx ; get cb
|
|
cmp edx, ebx
|
|
jg frp_bade_cleaned
|
|
|
|
; set limit of 1st sel to be ebx
|
|
push es
|
|
push ebx
|
|
call SetSelectorLimit
|
|
|
|
if KDEBUG
|
|
mov ax, es
|
|
krDebugOut DEB_WARN, "Fixing poorly tiled selector #AX for flat access"
|
|
endif
|
|
|
|
jmp frp_ok
|
|
|
|
|
|
frp_bade:
|
|
pop ebx
|
|
frp_bade_cleaned:
|
|
|
|
.286p
|
|
mov ax,1
|
|
jmp frp_exit
|
|
|
|
;===============================================================
|
|
; BOOL IsBadHugeReadPtr(VOID HUGE*lp, DWORD cb)
|
|
;
|
|
cProc IsBadHugeReadPtr,<PUBLIC,FAR,NONWIN>
|
|
ParmD lp
|
|
ParmD cb
|
|
cBegin
|
|
beg_fault_trap hrp_trap
|
|
les bx,lp ; check selector
|
|
|
|
mov ax,off_cb
|
|
mov cx,seg_cb
|
|
|
|
mov dx,ax ; if cb == 0, then all done.
|
|
or dx,cx
|
|
jz hrp_ok
|
|
|
|
sub ax,1 ; decrement the count
|
|
sbb cx,0
|
|
|
|
add bx,ax ; adjust cx:bx by pointer offset
|
|
adc cx,0
|
|
jc hrp_bad ; (bug #10446, pass in -1L as count)
|
|
|
|
jcxz hrplast ; deal with leftover
|
|
hrploop:
|
|
mov al,es:[0ffffh] ; touch complete segments.
|
|
mov dx,es
|
|
add dx,__AHINCR
|
|
mov es,dx
|
|
loop hrploop
|
|
hrplast:
|
|
mov al,es:[bx]
|
|
hrp_ok:
|
|
xor ax,ax
|
|
end_fault_trap
|
|
hrp_exit:
|
|
cEnd
|
|
|
|
hrp_trap:
|
|
fault_fix_stack
|
|
hrp_bad:
|
|
mov ax,1
|
|
jmp hrp_exit
|
|
|
|
;===============================================================
|
|
; BOOL IsBadHugeWritePtr(VOID HUGE*lp, DWORD cb)
|
|
;
|
|
cProc IsBadHugeWritePtr,<PUBLIC,FAR,NONWIN>
|
|
ParmD lp
|
|
ParmD cb
|
|
cBegin
|
|
beg_fault_trap hwp_trap
|
|
les bx,lp ; check selector
|
|
|
|
mov ax,off_cb
|
|
mov cx,seg_cb
|
|
|
|
mov dx,ax ; if cb == 0, then all done.
|
|
or dx,cx
|
|
jz hwp_ok
|
|
|
|
sub ax,1 ; decrement the count
|
|
sbb cx,0
|
|
|
|
add bx,ax ; adjust cx:bx by pointer offset
|
|
adc cx,0
|
|
jc hwp_bad ; (bug #10446, pass in -1L as count)
|
|
|
|
jcxz hwplast ; deal with leftover
|
|
hwploop:
|
|
or byte ptr es:[0ffffh],0 ; touch complete segments.
|
|
mov dx,es
|
|
add dx,__AHINCR
|
|
mov es,dx
|
|
loop hwploop
|
|
hwplast:
|
|
or byte ptr es:[bx],0
|
|
hwp_ok:
|
|
xor ax,ax
|
|
end_fault_trap
|
|
hwp_exit:
|
|
cEnd
|
|
|
|
hwp_trap:
|
|
fault_fix_stack
|
|
hwp_bad:
|
|
mov ax,1
|
|
jmp hwp_exit
|
|
|
|
;===============================================================
|
|
;
|
|
;
|
|
cProc IsBadCodePtr,<PUBLIC,FAR,NONWIN>
|
|
ParmD lpfn
|
|
cBegin
|
|
beg_fault_trap BadCode1
|
|
mov cx,seg_lpfn
|
|
lar ax,cx
|
|
jnz BadCode ; Oh no, this isn't a selector!
|
|
|
|
test ah, 8
|
|
jz BadCode ; Oh no, this isn't code!
|
|
|
|
mov es,cx ; Validate the pointer
|
|
mov bx,off_lpfn
|
|
mov al,es:[bx]
|
|
|
|
end_fault_trap
|
|
xor ax, ax
|
|
CodeDone:
|
|
cEnd
|
|
|
|
BadCode1:
|
|
fault_fix_stack
|
|
BadCode:
|
|
mov ax,1
|
|
jmp short CodeDone
|
|
|
|
|
|
;========================================================
|
|
;
|
|
; BOOL IsBadStringPtr(LPSTR lpsz, UINT cch);
|
|
;
|
|
cProc IsBadStringPtr,<PUBLIC,FAR,NONWIN>,<DI>
|
|
ParmD lpsz
|
|
ParmW cchMax
|
|
cBegin
|
|
beg_fault_trap BadStr1
|
|
les di,lpsz ; Scan the string.
|
|
xor ax,ax
|
|
mov cx,-1
|
|
cld
|
|
repnz scasb
|
|
end_fault_trap
|
|
neg cx ; cx = string length + 1
|
|
dec cx
|
|
cmp cx,cchMax
|
|
ja BadStr ; if string length > cchMax, then bad string.
|
|
bspexit:
|
|
cEnd
|
|
|
|
BadStr1:
|
|
fault_fix_stack
|
|
BadStr:
|
|
mov ax,1
|
|
jmp bspexit
|
|
|
|
;-----------------------------------------------------------------------;
|
|
; HasGPHandler ;
|
|
; ;
|
|
; See if GP fault handler is registered for faulting address. ;
|
|
; ;
|
|
; This scheme can only be used by registered modules. You register ;
|
|
; a module by adding an entry containing a length byte followed by ;
|
|
; the module name in the gp_valid_modules table defined above. ;
|
|
; ;
|
|
; Arguments: ;
|
|
; parmD lpFaultAdr ;
|
|
; ;
|
|
; Returns: ;
|
|
; AX = New IP of handler ;
|
|
; AX = 0 if no handler registered ;
|
|
; ;
|
|
; Error Returns: ;
|
|
; ;
|
|
; Registers Preserved: ;
|
|
; DI,SI,DS ;
|
|
; ;
|
|
; Registers Destroyed: ;
|
|
; AX,BX,CX,DX,ES ;
|
|
; ;
|
|
; Calls: ;
|
|
; GetOwner ;
|
|
; EntProcAddress ;
|
|
; ;
|
|
; The __GP table has the format of 4 words per entry, plus a ;
|
|
; zero word to terminate the table. The 'seg' value should be ;
|
|
; the actual selector (it must be fixed up by the linker), ;
|
|
; and the offset values should be relative to the start of the ;
|
|
; segment or group. The handler must be in the same code segment ;
|
|
; as the fault range (this ensures that the handler is present ;
|
|
; at GP fault time). ;
|
|
; ;
|
|
; __GP label word ;
|
|
; public __GP ;
|
|
; seg, offset begin, offset end, handler ;
|
|
; ... ;
|
|
; 0 ;
|
|
; ;
|
|
; The symbol '__GP' needs to be in the resident name table, so ;
|
|
; it should be added to the DEF file like this (with an ;
|
|
; appropriate ordinal value): ;
|
|
; ;
|
|
; EXPORTS ;
|
|
; __GP @??? RESIDENTNAME ;
|
|
; ;
|
|
; ;
|
|
; History: ;
|
|
; ?? Jun 91 Don Corbitt [donc] Wrote it ;
|
|
; 30 Jul 91 Don Corbitt [donc] Added support for __GP table ;
|
|
;-----------------------------------------------------------------------;
|
|
|
|
|
|
cProc HasGPHandler,<PUBLIC,FAR,NONWIN>,<ds,si,di>
|
|
ParmD lpfn
|
|
cBegin
|
|
cCall GetOwner, <SEG_lpfn> ; find owner of faulting code
|
|
or ax, ax
|
|
jz to_fail ;HH_fail
|
|
|
|
lar bx, ax ; make sure segment is present
|
|
jnz to_fail ;HH_fail
|
|
test bx, 8000h
|
|
jz to_fail ;HH_fail
|
|
|
|
mov es, ax
|
|
cmp es:[ne_magic], NEMAGIC
|
|
jz @f
|
|
to_fail:
|
|
jmp HH_fail
|
|
@@:
|
|
|
|
; check if the faulting module is allowed to use this scheme
|
|
SetKernelDS
|
|
mov di, es:[ne_restab]
|
|
mov bx, di
|
|
inc bx ; save ptr to module name
|
|
xor cx,cx
|
|
xor ax,ax
|
|
mov si, offset gp_valid_modules
|
|
mov al, es:[di]
|
|
cld
|
|
friend_or_fiend:
|
|
mov cl, [si]
|
|
jcxz HH_fail
|
|
cmp al,cl
|
|
jnz next_friend
|
|
mov di, bx ; need to keep restoring di
|
|
inc si ; skip len byte
|
|
repe cmpsb
|
|
jz we_know_this_chap
|
|
dec si ; point to the mismatch
|
|
next_friend:
|
|
add si, cx
|
|
inc si
|
|
jmp short friend_or_fiend
|
|
we_know_this_chap:
|
|
|
|
xor cx, cx
|
|
mov si, es:[ne_restab] ; restore si
|
|
jmp short @F ; start in middle of code
|
|
|
|
HH_nextSym:
|
|
add si, cx ; skip name
|
|
add si, 3 ; and entry point
|
|
@@: mov cl, es:[si] ; get length of symbol
|
|
jcxz HH_fail ; end of table - not found
|
|
cmp cl, 4 ; name length
|
|
jnz HH_nextSym
|
|
cmp es:[si+1], '__' ; look for '__GP'
|
|
jnz HH_nextSym
|
|
cmp es:[si+3], 'PG'
|
|
jnz HH_nextSym
|
|
mov ax, es:[si+5] ; get ordinal for '__GP'
|
|
if KDEBUG
|
|
cCall EntProcAddress,<es,ax,1>
|
|
else
|
|
cCall EntProcAddress,<es,ax> ; I hate conditional assembly....
|
|
endif
|
|
mov cx, ax
|
|
or cx, dx
|
|
jz HH_fail ; This shouldn't ever fail, but...
|
|
|
|
lar bx, dx ; make sure segment is present
|
|
jnz HH_fail
|
|
test bx, 8000h
|
|
jz HH_fail
|
|
|
|
mov ds, dx
|
|
mov si, ax
|
|
mov ax, SEG_lpfn
|
|
mov dx, OFF_lpfn
|
|
next_fault_val:
|
|
mov cx, [si]
|
|
jcxz HH_fail
|
|
cmp cx, ax ; does segment match?
|
|
jnz gp_mismatch
|
|
cmp [si+2], dx ; block start
|
|
ja gp_mismatch
|
|
cmp [si+4], dx ; block end
|
|
jbe gp_mismatch
|
|
mov ax, [si+6] ; get new IP
|
|
jmp short HH_done
|
|
|
|
gp_mismatch:
|
|
add si, 8
|
|
jmp short next_fault_val
|
|
|
|
HH_fail:
|
|
xor ax, ax
|
|
HH_done:
|
|
cEnd
|
|
|
|
;========================================================================
|
|
;
|
|
; BOOL IsSharedSelector(HGLOBAL h);
|
|
;
|
|
; Makes sure the given selector is shareable. Currently, we just check
|
|
; if it is owned by a DLL. We also need to check GMEM_SHARE bit but
|
|
; this isn't saved...
|
|
;
|
|
cProc IsSharedSelector,<PUBLIC,FAR,NOWIN>
|
|
ParmW sharedsel
|
|
cBegin
|
|
push sharedsel
|
|
call GetExePtr
|
|
or ax,ax ; bogus handle: exit.
|
|
jz ISS_Done
|
|
mov es,ax
|
|
xor ax,ax
|
|
test es:[ne_flags],NENOTP
|
|
jz ISS_Done ; Not a DLL
|
|
inc ax ; Yup a DLL
|
|
|
|
ISS_Done:
|
|
cEnd
|
|
|
|
sEnd CODE
|
|
|
|
end
|