Compat siginfo_t for 64-bit kernels running 32-bit userspace.
RFC 1/1 Compat siginfo_t for 64-bit kernels running 32-bit userspace.
-----------------------------------------------------------
Signal structures, their sizes,
and a generic compatibility
layer for copying siginfo_t into
userspace.
-----------------------------------------------------------
Abstract.
=========
When the Linux kernel has word widths that are different from userspace, certain operations require conversions. In particular we examine signals and their associated data structures. Proposed is an initial framework for copying siginfo_t, in a generic fashion, to a userspace address.
It is the hope of the author to raise awareness, get feedback, and see if anyone else is thinking about similar changes.
Comments welcome, flames welcome :)
Introduction.
=============
I recently cleaned up parisc's signal frame code to account for running a 64-bit kernel and a 32-bit userspace. James Bottomley was kind enough to do the initial work and prompt me to cleanup the really ugly stuff. Matthew Wilcox said "I'm not tall enough to play with signals, email XXXXXXXX, it's the right place."
The process of cleanup wasn't very hard, but my colleagues, noticing I had started work on something that was long left untouched, began poking me in other directions. Apparently siginfo_t, ucontext_t, stack_t and various other structures were not being read properly from userspace signal handlers. The signal handler is passed both a siginfo_t and a ucontext_t (for *context() function calls) from the kernel.
What I did, and what I always do, was to attempt to copy sparc64 :} Unfortunately they had rolled their own support for this, as had ppc64 and many other arches.
I began with something simple. Many arches use the generic siginfo_t, and providing compat would initially simplify the parisc work.
Generic Changes:
================
o Add a generic 'compat_copy_siginfo_to_user' (kernel/compat_signal.c)
o Add a generic siginfo_t (include/asm-generic/compat_siginfo.h)
o Add generic signal structures (include/asm-generic/compat_signal.h)
The current generic kernel/signal.c has the ability to use a per-arch copy_siginfo_to_user function. This function could in general convert the kernels view of siginfo into the userspace required size.
e.g.
* kernel/signal.c (copy_siginfo_to_user):
#ifndef HAVE_ARCH_COPY_SIGINFO_TO_USER copy_siginfo_to_user
{
...
check thread personality
if the thread is PER_LINUX32
return compat_copy_siginfo_to_user
else
Do it the normal way.
...
}
#endif
Cases covered:
- Kernel native, process native.
- Kernel native, process non-native 32-bit.
Pro:
- Generic. Don't have to add special arch code.
Con:
- Extra branch/function in signal delivery fast path.
Thoughts:
- Arches that need speed can and will rewrite their signal path direclty from the syscall layer. However, they can still make use of the generic structures and functions. Normally in parisc we make such code disappear with the use of the __LP64__ macro, can this be done generically? Aside from that just define ARCH_HAVE_COPY_SIGINFO_TO_USER and do what you will.
- The meaning of PER_LINUX32 must be clear. The process is non-native and 32-bit.
- When do the 128-bit processors running compat 64-bit userspace arrive? (PER_LINUX64)
Arch Changes:
=============
o include/asm-parisc/
compat_rt_sigframe.h (Arch dependant rt signal frame) compat_siginfo.h -> #include <asm-generic/compat_siginfo.h> compat_signal.h -> #include <asm-generic/signal.h> compat_ucontext.h (Arch dependant, passed to signal handlers) compat.h (Arch dependant mcontext_t)
o arch/parisc/kernel/signal.c
Check personality on frame setup path, call code in arch/parisc/kernel/signal32.c to setup and restore 32-bit signal contexts (ucontext_t), along with calling the kernels compat_copy_siginfo_to_user to get the job done.
Removed old and crufty arch specific copy_siginfo_to_user.
Defining a compat signal frame is not an easy task and requires converting all the structure elements into compat types. A number of arches including parisc use the generic siginfo_t and benefit immediately from a generic version.
I was *tempted* by trying to define a generic ucontext_t since *most* arches use exactly the same setup. However, the subsequent header untangling left me unable to do it cleanly. Had I the will It might be possible, subsequent to that a generic copy_ucontext_to_user could be written, since it's a similar operation to copying the siginfo.
Thoughts:
I ran into a structure padding problem. There is no real ELF32 ABI for parisc and I had to pad the compat_ucontext structure. This type of massaging might be required for any arch in order to get structures to match. In this case the generic functions are usable, but the generic structures are not.
What's left todo:
=================
Inform other architectures that the framework is in place and let them cleanup their arch code. Most arches are using the generic siginfo_t and will thus benefit. I'm tempted to port another arch to show how it works for two arches.
I keep thinking there has to be a way to do compat, signal handling, and compat signal handling in some easier way.
What's been done:
=================
Please remember this is an RFC, and a first cut at the code, there might be mistakes, and I'm sure someone won't like it :}
I've moved parisc over to the new setup, removed our custom copy_siginfo_to_user. parisc distinguishes between native and non-native processes during the rt frame setup and restore phases and then branches into the compat path.
Diff is generated against -rlinus cvs.parisc-linux.org so it applies to 2.6.
--- include/asm-generic/compat_siginfo.h | 154 +++++++++++++++++++++++++ include/asm-generic/compat_signal.h | 28 ++++ kernel/compat_signal.c | 126 ++++++++++++++++++++ kernel/signal.c | 8 + 4 files changed, 316 insertions(+)
---
2003-12-08 Carlos O'Donell <[email protected]>
* kernel/signal.c (copy_siginfo_to_user): If process is PER_LINUX32 call compat_copy_siginfo_to_user.
* kernel/compat_signal.c: New file.
* include/asm-generic/compat_siginfo.h: New file.
* include/asm-generic/compat_signal.h: New file.
signal.c +8 -0
@@ -24,9 +24,11 @@#include <linux/binfmts.h> #include <linux/security.h> #include <linux/ptrace.h> +#include <linux/personality.h> #include <asm/param.h> #include <asm/uaccess.h> #include <asm/siginfo.h> +#include <asm/compat_siginfo.h> /* * SLAB caches for signal bits.
@@ -2006,6 +2008,12 @@ int copy_siginfo_to_user(siginfo_t __useif (from->si_code <0 )return __copy_to_user (to, from,sizeof (siginfo_t)) ? -EFAULT :0 ; + +/* Use compat_siginfo_t with 32-bit signals */ +if (personality (current->personality) ==PER_LINUX32 ){ +return compat_copy_siginfo_to_user ((compat_siginfo_t __user *)to,from); + } +/* * If you change siginfo_t structure, please be sure * this code is fixed accordingly.
compat_signal.c renamed from compat_signal.c.orig +126 -0
126 lines not on this page · raw message
asm-generic/compat_siginfo.h renamed from asm-generic/compat_siginfo.h.orig +154 -0
154 lines not on this page · raw message
asm-generic/compat_signal.h renamed from asm-generic/compat_signal.h.orig +28 -0
@@ -0,0 +1,28 @@ +#ifndef _ASM_GENERIC_COMPAT_SIGNAL_H +#define _ASM_GENERIC_COMPAT_SIGNAL_H + +# ifndef __ASSEMBLY__ +# include <linux/types.h> + +typedef compat_uptr_t compat_sighandler_t ; + +typedef struct compat_sigaltstack { +compat_uptr_t ss_sp; +compat_int_t ss_flags; +compat_size_t ss_size; +}compat_stack_t ; + +# ifdef __KERNEL__ + +/* Most things should be clean enough to redefine this at will, if care +is taken to make libc match. */ + +struct compat_sigaction { +compat_sighandler_t sa_handler; +compat_uint_t sa_flags; +compat_sigset_t sa_mask;/* mask last for extensibility */ +}; + +# endif /* __KERNEL__ */ +# endif /* !__ASSEMBLY */ +#endif /* _ASM_GENERIC_COMPAT_SIGNAL_H */
----- End forwarded message -----