PSL_RF inclusion in PSL_USERCHANGE for i386

Bruce Evans brde at optusnet.com.au
Mon Sep 3 16:17:36 PDT 2007


On Sun, 2 Sep 2007, Roman Divacky wrote:

> in i386/i386/machdep.c the set_regs() function sets i386 registers (called
> by ptrace for example). it checks what eflags are being changed and compares
> that with a mask of allowed flags to be changed. the mask is defined in psl.h
> like this:
>
> #define PSL_USERCHANGE (PSL_C | PSL_PF | PSL_AF | PSL_Z | PSL_N | PSL_T \
>                        | PSL_D | PSL_V | PSL_NT | PSL_AC | PSL_ID)
>
> PSL_RF (Flag to ensure single-step only happens once per instruction.). Can someone
> tell me why this is omitted? I think its because of having in-kernel debugger.

I think it is just because user mode cannot set this flag directly,
except probably in vm86 mode (vm86 support code already has special
cases for it).  (Old) docs say that it can be set by popfl and iret,
but popfl doesn't set it for me now and user mode cannot execute iret (?).

> User-mode Linux requires this to be allowed. So I wonder why this is disabled in FreeBSD.
> (Linux itself does not check the eflags in any way).
>
> thanks for answer, and/or pointer to answer

FreeBSD allows setting or at least preserving it in sigreturn().  See
my large comment in sigreturn().  The comment has been copied ad nauseum
into 3 versions of sigreturn(), so removing this special case would
be a large cleanup.  According to the comment, for user mode it is the
CPU that sets PSL_RF for faults (for all faults or only for debug
faults, so that faults can be restarted without interference from
debuggers.

I think the CPU also automatically clears PSL_RF after executing 1
instruction, so it is hard to observe it as set and hard to see how
setting it in set_regs() could have any effect.  Well, set_regs() is
just an easier way to set registers than sigreturn().  sigreturn()
omits PSL_RF from its security check, so there there is no possibility
of a _new_ security hole from omitting the check in set_regs() too.
(But better put PSL_RF in PSL_USERCHANGE and remove all the special
cases).  After return to user mode with PSL_RF set, I think PSL_RF
affects only the first instruction in user mode, so any changes in
effects would be observable only there.  Please check that something
reasonable happens.  The user mode code is something like:

 	int	$0x80		# syscall
 	xxx			# some instruction -- what happens for
 				# hardware breakpoints, etc., on this
 				# instruction.

I vaguely remember problems (perhaps under another OS) with debugging
the first instruction after a syscall returns.  Perhaps they are still
there and are caused by precisely the resume flag, if the resume flag
is set automatically by int $N or if the kernel sets it.  Allowing
set_regs() to set the resume flag might cause the same problem for
just the ptrace/procfs calls that use set_regs() if it doesn't affect
all syscalls.  It's hard to see how this problem could actually be a
feature.  To use it as a feature, userland would have to ensure that
the xxx in the above is a certain instruction that benefits from this
behaviour.

Bruce


More information about the freebsd-arch mailing list