Return to BSD News archive
Path: sserve!newshost.anu.edu.au!munnari.oz.au!spool.mu.edu!caen!sdd.hp.com!cs.utexas.edu!wupost!uunet!mcsun!Germany.EU.net!tools!ws
From: ws@tools.de (Wolfgang Solfrank)
Newsgroups: comp.os.386bsd.bugs
Subject: Re: copyout family fixed
Date: 14 May 93 16:55:14
Organization: TooLs GmbH, Bonn, Germany
Lines: 275
Message-ID: <WS.93May14165515@kurt.tools.de>
References: <1sq8gpINNnbb@fstgds01.tu-graz.ac.at>
NNTP-Posting-Host: kurt.tools.de
In-reply-to: chmr@edvz.tu-graz.ac.at's message of 12 May 1993 09:20:57 +0200
While the bug analysis is correct, the fix is a bit overly complicated.
Especially the case where data is transferred from user space into
kernel space can be fixed more easily. Simply use the user data
segment descriptor and the 386 will not allow access to kernel
memory even though it runs in kernel mode.
The case where the transfer is the other way around is a bit
more complicated. This is essentially a design bug in the 386
(and is, to the best of my knowledge, fixed in the 486), namely
that the protection check by using the user segment descriptors
is not propagated to the page level.
For the write case (transfer data from user to kernel) this
is not a problem since there is no address where a kernel read
is allowed and a user read isn't except the kernel data itself.
But this can be (and is) protected on the segment level.
For the read case (transfer data from kernel to user) there is
an additional problem. While the destination page might be there
it might be write protected to allow the correct function of
the copy-on-write mechanism (and possibly allow the selective
write protection of user memory (mprotect et.al.)). This requires
the access check in the copyout routine for every page.
Below are my own copyin/copyout and [fs]u{byte,sword,word} routines.
Sorry, no context diffs, as my version is a heavily hacked locore.s
from the original Net2 tape.
--------------- cut --------------- cut --------------- cut ---------------
.globl _copyout
_copyout:
movl _curpcb, %eax
movl $cpyflt, PCB_ONFAULT(%eax) # in case we page/protection violate
pushl %esi
pushl %edi
pushl %ebx
movl 16(%esp), %esi
movl 20(%esp), %edi
movl 24(%esp), %ebx
push %es
push %ds
/* first, check to see if "write fault" */
1: movl %edi, %eax
shrl $IDXSHIFT, %eax /* fetch pte associated with address */
andb $0xfc, %al
movl _PTmap(%eax), %eax
andb $7, %al /* if we are the one case that won't trap... */
cmpb $5, %al
jne 2f
/* ... then simulate the trap! */
pushl %edi
call _trapwrite /* trapwrite(addr) */
popl %edx
cmpl $0, %eax /* if not ok, return */
jne cpyflt
/* otherwise, continue with reference */
2:
movl %edi, %eax /* calculate remainder this pass */
andl $ NBPG-1, %eax
movl $ NBPG, %ecx
subl %eax, %ecx
cmpl %ecx, %ebx
jge 3f
movl %ebx, %ecx
3: subl %ecx, %ebx
movl %ecx, %edx
mov $0x27,%ax
mov %ax,%es
shrl $2,%ecx /* movem */
cld
rep
movsl
movl %edx, %ecx /* don't depend on ecx here! (why?ws) */
andl $3,%ecx
rep
movsb
cmpl $0, %ebx
jg 1b
pop %ds
pop %es
popl %ebx
popl %edi
popl %esi
xorl %eax,%eax
movl _curpcb,%edx
movl %eax,PCB_ONFAULT(%edx)
ret
.globl _copyin
_copyin:
movl _curpcb,%eax
movl $cpyflt,PCB_ONFAULT(%eax) # in case we page/protection violate
pushl %esi
pushl %edi
pushl %ebx
movl 16(%esp),%esi
movl 20(%esp),%edi
movl 24(%esp),%ecx
movl %ecx,%edx
push %es
push %ds
mov $0x27,%ax
mov %ax,%ds
shrl $2,%ecx
cld
rep
movsl
movl %edx,%ecx
andl $3,%ecx
rep
movsb
pop %ds
pop %es
popl %ebx
popl %edi
popl %esi
xorl %eax,%eax
movl _curpcb,%edx
movl %eax,PCB_ONFAULT(%edx)
ret
cpyflt:
pop %ds
pop %es
popl %ebx
popl %edi
popl %esi
movl _curpcb,%edx
movl $0,PCB_ONFAULT(%edx)
movl $ EFAULT,%eax
ret
--------------- cut --------------- cut --------------- cut ---------------
/*
* {fu,su},{byte,word}
*/
ALTENTRY(fuiword)
ENTRY(fuword)
movw __udatasel,%ax
movw %ax,%gs
movl _curpcb,%ecx
movl $fusufault,PCB_ONFAULT(%ecx)
movl 4(%esp),%edx
gs
movl 0(%edx),%eax
movl $0,PCB_ONFAULT(%ecx)
ret
ENTRY(fusword)
movw __udatasel,%ax
movw %ax,%gs
movl _curpcb,%ecx
movl $fusufault,PCB_ONFAULT(%ecx) #in case we page/protection violate
movl 4(%esp),%edx
gs
movzwl 0(%edx),%eax
movl $0,PCB_ONFAULT(%ecx)
ret
ALTENTRY(fuibyte)
ENTRY(fubyte)
movw __udatasel,%ax
movw %ax,%gs
movl _curpcb,%ecx
movl $fusufault,PCB_ONFAULT(%ecx) #in case we page/protection violate
movl 4(%esp),%edx
gs
movzbl 0(%edx),%eax
movl $0,PCB_ONFAULT(%ecx)
ret
fusufault:
movl _curpcb,%ecx
xorl %eax,%eax
movl %eax,PCB_ONFAULT(%ecx) #in case we page/protection violate
decl %eax
ret
ALTENTRY(suiword)
ENTRY(suword)
movw __udatasel,%ax
movw %ax,%gs
movl _curpcb,%ecx
movl $fusufault,PCB_ONFAULT(%ecx) #in case we page/protection violate
movl 4(%esp),%edx
movl %edx,%edi
shrl $IDXSHIFT, %edx /* fetch pte associated with address */
andb $0xfc, %dl
movl _PTmap(%edx), %edx
andb $7, %dl /* if we are the one case that won't trap... */
cmpb $5 , %edx
jne 1f
/* ... then simulate the trap! */
pushl %edi
call _trapwrite /* trapwrite(addr) */
popl %edx
movl _curpcb, %ecx # restore trashed registers
cmpl $0, %eax /* if not ok, return */
jne fusufault
1:
movl 8(%esp),%eax /* otherwise, continue with reference */
movl 4(%esp),%edx
gs
movl %eax,0(%edx)
xorl %eax,%eax
movl %eax,PCB_ONFAULT(%ecx) #in case we page/protection violate
ret
ENTRY(susword)
movw __udatasel,%ax
movw %ax,%gs
movl _curpcb,%ecx
movl $fusufault,PCB_ONFAULT(%ecx) #in case we page/protection violate
movl 4(%esp),%edx
movl %edx,%edi
shrl $IDXSHIFT, %edx /* calculate pte address */
andb $0xfc, %dl
movl _PTmap(%edx), %edx
andb $7, %edx /* if we are the one case that won't trap... */
cmpb $5 , %edx
jne 1f
/* ..., then simulate the trap! */
pushl %edi
call _trapwrite /* trapwrite(addr) */
popl %edx
movl _curpcb, %ecx # restore trashed registers
cmpl $0, %eax
jne fusufault
1:
movl 8(%esp),%eax
movl 4(%esp),%edx
gs
movw %ax,0(%edx)
xorl %eax,%eax
movl %eax,PCB_ONFAULT(%ecx) #in case we page/protection violate
ret
ALTENTRY(suibyte)
ENTRY(subyte)
movw __udatasel,%ax
movw %ax,%gs
movl _curpcb,%ecx
movl $fusufault,PCB_ONFAULT(%ecx) #in case we page/protection violate
movl 4(%esp),%edx
movl %edx,%edi
shrl $IDXSHIFT, %edx /* calculate pte address */
andb $0xfc, %dl
movl _PTmap(%edx), %edx
andb $7, %edx /* if we are the one case that won't trap... */
cmpb $5 , %edx
jne 1f
/* ..., then simulate the trap! */
pushl %edi
call _trapwrite /* trapwrite(addr) */
popl %edx
movl _curpcb, %ecx # restore trashed registers
cmpl $0, %eax
jne fusufault
1:
movl 8(%esp),%eax
movl 4(%esp),%edx
gs
movb %eax,0(%edx)
xorl %eax,%eax
movl %eax,PCB_ONFAULT(%ecx) #in case we page/protection violate
ret
--
ws@tools.de (Wolfgang Solfrank, TooLs GmbH) +49-228-985800