tech-kern archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Softfloat userland needing to properly deliver SIGFPE traps
After Christos recently added sigqueue and friends to -current, I tried to
use them to fix a long standing softfloat userland problem. One variant of
the problem shows up in sparc64 atf test runs (sparc64 uses softfloat
for 128 bit long double): the userland software, and our atf tests, expect
to get proper details about the SIGFPE it caught, but softloat only did a
raise(SIGFPE), so no siginfo is available.
The userland change looked straight forward:
Index: softfloat-specialize
===================================================================
RCS file: /cvsroot/src/lib/libc/softfloat/softfloat-specialize,v
retrieving revision 1.4
diff -c -u -p -r1.4 softfloat-specialize
--- softfloat-specialize 26 Sep 2004 21:13:27 -0000 1.4
+++ softfloat-specialize 14 Jan 2011 09:40:15 -0000
@@ -56,11 +59,26 @@ should be simply `float_exception_flags
fp_except float_exception_mask = 0;
void float_raise( fp_except flags )
{
+ siginfo_t info;
float_exception_flags |= flags;
if ( flags & float_exception_mask ) {
- raise( SIGFPE );
+ memset(&info, 0, sizeof info);
+ info.si_signo = SIGFPE;
+ info.si_pid = getpid();
+ info.si_uid = geteuid();
+ if (flags & float_flag_underflow)
+ info.si_code = FPE_FLTUND;
+ else if (flags & float_flag_overflow)
+ info.si_code = FPE_FLTOVF;
+ else if (flags & float_flag_divbyzero)
+ info.si_code = FPE_FLTDIV;
+ else if (flags & float_flag_invalid)
+ info.si_code = FPE_FLTINV;
+ else if (flags & float_flag_inexact)
+ info.si_code = FPE_FLTRES;
+ sigqueueinfo(getpid(), &info);
}
}
But: looking at the kernel code, this is not allowed. Only SI_USER and
SI_QUEUE request are passed through. For testing, I disabled this
security check like this:
Index: sys_sig.c
===================================================================
RCS file: /cvsroot/src/sys/kern/sys_sig.c,v
retrieving revision 1.30
diff -c -u -p -r1.30 sys_sig.c
--- sys_sig.c 10 Jan 2011 04:39:18 -0000 1.30
+++ sys_sig.c 14 Jan 2011 09:40:38 -0000
@@ -229,14 +229,16 @@ kill1(struct lwp *l, pid_t pid, ksiginfo
if (ksi->ksi_uid != kauth_cred_geteuid(l->l_cred))
return EPERM;
- switch (ksi->ksi_code) {
- case SI_USER:
- case SI_QUEUE:
- break;
- default:
- return EPERM;
+ if (ksi->ksi_signo != SIGFPE) {
+ switch (ksi->ksi_code) {
+ case SI_USER:
+ case SI_QUEUE:
+ break;
+ default:
+ return EPERM;
+ }
}
-
+
if (pid > 0) {
/* kill single process */
mutex_enter(proc_lock);
This change makes it work for me, but of course it is a horrible hack, not
acceptable for commit. We need to have the possibility to SI_USER/
SI_QUEUE a SIGFPE, but given the mostly union content of ksiginfo, I
don't see an obvious way how to do it properly.
I'd like to suggest a special SI_SELFSIGFPE ksi_code, which overrides
the pid/uid tests, only allows sending to the same process, and encodes
the final (kernel internal) ksi_code as ksi_signo, while passing on the
rest of ksiginfo untouched (so userland could, if possible, fill in
struct fault).
Userland call would look like this:
+ memset(&info, 0, sizeof info);
+ info.si_code = SI_SELFSIGFPE;
+ if (flags & float_flag_underflow)
+ info.si_signo = FPE_FLTUND;
+ else if (flags & float_flag_overflow)
+ info.si_signo = FPE_FLTOVF;
+ else if (flags & float_flag_divbyzero)
+ info.si_signo = FPE_FLTDIV;
+ else if (flags & float_flag_invalid)
+ info.si_signo = FPE_FLTINV;
+ else if (flags & float_flag_inexact)
+ info.si_signo = FPE_FLTRES;
+ sigqueueinfo(getpid(), &info);
and kernel would move si_signo to ksi_code, set signo to SIGFPE, and pass
the remaining siginfo on untouched.
Still a hack, but I don't have better ideas (besides creating another special
purpose syscall for this).
Martin
Home |
Main Index |
Thread Index |
Old Index