Re: copy_from_user() fix

Jamie Lokier (lkd@tantalophile.demon.co.uk)
Tue, 25 Aug 1998 02:22:35 +0100


On Tue, Aug 25, 1998 at 01:45:12AM +0100, Jamie Lokier wrote:
> Will I don't agree with the feature either, all we're talking about is
> adding one line to the page fault handler: send_sig(SIGSEGV). Nothing
> else needs to change, does it?

I just changed my mind.

I bet no applications at all currently check for EFAULT from system
calls, unless they're really weird and are doing it to behave _as if_
they'd received SIGSEGV. Actually I bet they don't bother because every
syscall would need to be wrapped. I'm theorising that this could screw
up Wine in some unusual but valid cases.

To make matters worse, if they do this by calling the signal handler
directly, the faulting address isn't available. If they do kill
(getpid(),SIGSEGV), a fault may have happened in the mean time so the
faulting address may be wrong or lost. In the latter case, as luck
would have it, probably the operations retry until the right address is
found. But it is a matter of luck, and anything that tried to count
faults could get it wrong in these rare cases.

So...

- EFAULT alone is an anachronism.
- Only a few applications care whether SIGSEGV is raised or not.
- Some emulators and user-space page management depend on SIGSEGV
for page faults, and will behave incorrectly when it is not raised
in syscalls.
- There is no correct workaround other than the kernel raising SIGSEGV.

I propose EFAULT should be retained, but faulting syscalls should _also_
raise SIGSEGV.

Addendum for a related problem: Consider when a syscall, interrupt
etc. (whatever) combination manage to raise more than one signal _at the
same time_, of which one is SIGSEGV due to a page fault. Assume the
program is using user-space page management for something.

A handler for one of the other signals is called first. The handler may
itself fault, causing a SIGSEGV if it is not blocked. Or perhaps
storing the context on the stack might fault. A nested call to the SEGV
handler handles the inner fault. The other handler returns, then a
context the SIGSEGV handler is called for the original fault. Now, the
page fault address from %cr2 (or non-Intel equivalent) is stored in the
context passed to the handler. But it is wrong by now! It is the
address of the inner fault, which has already been handled.

Ho hum.

Perhaps a VM extension could be written, whereby page faults send a
queued real-time signal along with the faulting address, and maybe some
information to identify the faulting region too. That would work
properly because the address can be queued at the time of the fault.

-- Jamie

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.altern.org/andrebalsa/doc/lkml-faq.html