*BSD News Article 16145


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