Date: Mon, 3 Sep 2007 11:18:37 +1000 (EST) From: Bruce Evans <brde@optusnet.com.au> To: Roman Divacky <rdivacky@freebsd.org> Cc: arch@freebsd.org, i386@freebsd.org Subject: Re: PSL_RF inclusion in PSL_USERCHANGE for i386 Message-ID: <20070903105130.L48985@delplex.bde.org> In-Reply-To: <20070902173953.GA52566@freebsd.org> References: <20070902173953.GA52566@freebsd.org>
next in thread | previous in thread | raw e-mail | index | archive | help
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
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20070903105130.L48985>