Subject: FPU context clobbered by signals

From: "Mike Klar" <[email-masked]>
Date: Sun, 4 Mar 2001 17:56:38 -0800

Back in September, Atsushi Nemoto reported a problem with the way signal
handling was handling FPU contexts in the 2.2 kernel.  I think I'm seeing
the same thing in the 2.4 kernel.  The behavior I observe is that a user
process that is using floating point registers sees those registers get
whacked when another process gets a signal.  Just executing an arbitrary
command from a bash shell (while running floating point test app in the
background) is enough to demonstrate this.

Looking at setup_sigcontext() and restore_sigcontext() in
arch/mips/kernel/signal.c, the handling of FPU context certainly looks
wrong.  If nothing else, setting current->used_math to 0 will cause FPU
context to be reinitialized the next time that process reacquires the FPU
context.  I was going to fix this, but I really can't figure out what this
code is trying to do.

Currently setup_sigcontext() appears to behave as follows:
If the current process owns the FPU context, sc_ownedfp is set to 1 in the
sigcontext passed to the signal handler, and the floating point registers
are saved in that sigcontext.  This makes sense.
If the current process does not own the FPU context, but did at one point
execute FPU operations (which all glibc apps will do for initialization),
sc_ownedfp in the sigcontext is set to 0, and the floating point registers
are still saved.  This is, at the very least, a security hole, since those
registers belong to a different process at that point.

And restore_sigcontext() appears to behave thusly:
If sc_ownedfp is set in the sigcontext that is passed back from the signal
handler, the FPU context is restored from the sigcontext, and FPU context
ownership is given to the current process, without saving the old context.
Either I'm misunderstanding this, or there is a possibility that this will
simply forget about some other process' FPU context.

So what _is_ the desired behavior here?  The current behavior (again, unless
I'm misunderstanding something) gives the signal handler access to some
other process' FPU context in the case that the signaled process did not own
the FPU.  Should it:
1) Only pass the floating point registers in sigcontext if the signaled
process owned the FPU.  or
2) Always pass the signaled process' floating point registers if it had ever
used FPU operations.  This would require getting those registers from the
context saved on the stack instead of the current FP registers if the
current process does not own the FPU.

I guess what I'm trying to figure out here is the significance of sc_ownedfp
in struct sigcontext.  Option 1 would have it mean whether or not the
floating point register values in sigcontext are meaningful, but this seems
wrong.  The signal handler may want to know what the process' floating point
registers were at the time of the signal, unconditionally of whether it
owned the FPU context at the time.  Option 2 would have it mean... ummm...
I'm not sure.  I'm not sure why the signal handler would really care about
whether or not this process owned the FPU or some other process did, as long
as the floating point registers saved in sigcontext belong to the signaled
process.  It also doesn't seem all that useful to have the signal handler be
able to change the FPU ownership by changing the value of sc_ownedfp.

Mike Klar

---

From: "Kevin D. Kissell" <[email-masked]>
Date: Mon, 5 Mar 2001 10:07:20 +0100

> registers belong to a different process at that point.

I'm speaking from first principles here, not from an analysis
of the code on non-MIPS architectures, but what *should*
happen on a signal to a process that is not the current/latest
user of the FPU is that the FPU sigcontext information should
be copied from the saved thread context state.

> simply forget about some other process' FPU context.

The behavior described sort-of makes sense, if one is willing
to take it on faith that the signal handler did not trash the
sigcontext information (which I personally consider unwise).
If the signal was sent to the current owner of the FPU, the
post-signal thread FPU  state needs to represent the pre-signal
state of the FPU, which was saved in the sigcontext structure.

> So what _is_ the desired behavior here?

The desired behavior (IMHO) is that signals are dispatched
with the FPU state corresponding to the last known FPU
state of the thread taking the signal.  If the only copy of that
state prior to signal dispatch resides in the FPU, that state
needs to be saved before signal dispatch and restored
after signal return.

Or, to put it another way, the semantics of signals with
respect to FP registers should be the same as the
semantics with respect to general purpose registers.
The only wrinkle is the lazy FPU context switch logic,
which creates two anomolous situations: one where
the current contents of the FPU does not belong to
the current thread (because the current thread has
not executed any FP instructions), and one where the
FP register state of a non-current thread is not yet saved
in the thread state of that thread (because no subsequent
thread has executed any FP instructions).

            Kevin K.