signal: Align the sigset_t size passed to from user space to kernel.
Pass kernel space sigset_t size to __rt_sigprocmask to workaround the miss-match of NSIG/sigset_t definition between kernel and bionic. Note: Patch originally from Google... Change-Id: I4840fdc56d0b90d7ce2334250f04a84caffcba2a Signed-off-by: Chenyang Du <chenyang.du@intel.com> Signed-off-by: Bruce Beare <bruce.j.beare@intel.com>
This commit is contained in:
parent
cb1df91616
commit
e4a21c89a8
1 changed files with 37 additions and 8 deletions
|
@ -1861,7 +1861,21 @@ int pthread_kill(pthread_t tid, int sig)
|
|||
return ret;
|
||||
}
|
||||
|
||||
extern int __rt_sigprocmask(int, const sigset_t *, sigset_t *, size_t);
|
||||
/* Despite the fact that our kernel headers define sigset_t explicitly
|
||||
* as a 32-bit integer, the kernel system call really expects a 64-bit
|
||||
* bitmap for the signal set, or more exactly an array of two-32-bit
|
||||
* values (see $KERNEL/arch/$ARCH/include/asm/signal.h for details).
|
||||
*
|
||||
* Unfortunately, we cannot fix the sigset_t definition without breaking
|
||||
* the C library ABI, so perform a little runtime translation here.
|
||||
*/
|
||||
typedef union {
|
||||
sigset_t bionic;
|
||||
uint32_t kernel[2];
|
||||
} kernel_sigset_t;
|
||||
|
||||
/* this is a private syscall stub */
|
||||
extern int __rt_sigprocmask(int, const kernel_sigset_t *, kernel_sigset_t *, size_t);
|
||||
|
||||
int pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
|
||||
{
|
||||
|
@ -1870,16 +1884,31 @@ int pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
|
|||
*/
|
||||
int ret, old_errno = errno;
|
||||
|
||||
/* Use NSIG which corresponds to the number of signals in
|
||||
* our 32-bit sigset_t implementation. As such, this function, or
|
||||
* anything that deals with sigset_t cannot manage real-time signals
|
||||
* (signo >= 32). We might want to introduce sigset_rt_t as an
|
||||
* extension to do so in the future.
|
||||
*/
|
||||
ret = __rt_sigprocmask(how, set, oset, NSIG / 8);
|
||||
/* We must convert *set into a kernel_sigset_t */
|
||||
kernel_sigset_t in_set, *in_set_ptr;
|
||||
kernel_sigset_t out_set;
|
||||
|
||||
in_set.kernel[0] = in_set.kernel[1] = 0;
|
||||
out_set.kernel[0] = out_set.kernel[1] = 0;
|
||||
|
||||
/* 'in_set_ptr' is the second parameter to __rt_sigprocmask. It must be NULL
|
||||
* if 'set' is NULL to ensure correct semantics (which in this case would
|
||||
* be to ignore 'how' and return the current signal set into 'oset'.
|
||||
*/
|
||||
if (set == NULL) {
|
||||
in_set_ptr = NULL;
|
||||
} else {
|
||||
in_set.bionic = *set;
|
||||
in_set_ptr = &in_set;
|
||||
}
|
||||
|
||||
ret = __rt_sigprocmask(how, in_set_ptr, &out_set, sizeof(kernel_sigset_t));
|
||||
if (ret < 0)
|
||||
ret = errno;
|
||||
|
||||
if (oset)
|
||||
*oset = out_set.bionic;
|
||||
|
||||
errno = old_errno;
|
||||
return ret;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue