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