Re: copy_from_user() fixu

Jamie Lokier (lkd@tantalophile.demon.co.uk)
Wed, 26 Aug 1998 20:00:17 +0100


On Tue, Aug 25, 1998 at 05:55:48PM +0100, Chris Evans wrote:
> Doesn't our new posix signals implementation already do this?

There's an si_addr field waiting... but queuing the faulting address
hasn't been implemented yet (2.1.118).

I've had a look at signal delivery in the SEGV case, on i386 only.
Here's what happens.

1. SEGV is sent to the process. If it's the first SEGV pending,
some additional information is available if the process uses SA_SIGINFO.

2. If it's not the first SEGV pending, the additional information
is not included. See the line `if (sig < SIGRTMIN)' in kernel/signal.c.

This can happen in perfectly normal case, where a non-SEGV signal
handler causes a page fault while another SEGV is still pending.

It can also happen if the stack is in an area handled by a user
paging service. Odd I know, but required for correct vm86 emulation
in weird cases.

Note that the current behaviour is the _right_ one if an option is
added to allow the kernel to raise SIGSEGV on faults. Much code in
the kernel does a whole bunch of __put_user etc. then checks the
OR'd error code. This would result in a succession of faults, for
which we're only interested in receiving one signal and one faulting
address.

3. The queued additional information doesn't include the faulting
address, or what sort of access caused the fault. This would
appear trivial to add, at least in the i386 case. (I only looked at
the i386 case).

So adding the faulting address to the queued data, which the user
process can access using SA_SIGINFO, looks easy and wouldn't break
anything. (Normal processes don't get this data because they don't
request it).

The current siginfo_t doesn't have a place to store if it was a
read/write/execute request that caused the fault though. It does have a
place to say whether it's a permission or lack of mapping fault.

This next bit I could be wrong about:

Queuing multiple faults isn't necessary if the program is happy with
retrying in the case of multiple faults, or in the case that it doesn't
get any info. And it's undesirable in the case of kernel-induced
faults.

Current emulators use cr2 from the signal context. In rare cases, this
can be wrong. Once queuing the faulting address is implemented, they
should use SA_SIGINFO, and in the case where they don't get any info,
just return to allow the operation to fault again.

Summary
=======

So I have these requests to keep user-space paging happy:

1. Store the faulting address in sa_addr.
2. Store the type of access that caused the fault.
3. Send SIGSEGV on faults in syscalls, with option to enable/disable.
This could be done with an SA_NOEFAULT flag specific to SIGSEGV.
(There's precedent for this sort of thing with SA_NOCLDSTOP).
4. In case the SEGV handler returns, the syscall should be restarted
or return EFAULT, subject to the usual conditions for restarting.

Oh yeah, and make it all faster ;-)

-- 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