@@ -22,8 +22,6 @@ static inline void clear_siginfo(kernel_siginfo_t *info)
memset(info, 0, sizeof(*info));
}
-#define SI_EXPANSION_SIZE (sizeof(struct siginfo) - sizeof(struct kernel_siginfo))
-
int copy_siginfo_to_user(siginfo_t __user *to, const kernel_siginfo_t *from);
int copy_siginfo_from_user(kernel_siginfo_t *to, const siginfo_t __user *from);
@@ -11,6 +11,9 @@
typedef struct kernel_siginfo {
__SIGINFO;
+#ifdef __ARCH_HAS_PRIVATE_SIGINFO
+ struct arch_private_siginfo arch;
+#endif
} kernel_siginfo_t;
/*
@@ -3180,15 +3180,21 @@ enum siginfo_layout siginfo_layout(unsigned sig, int si_code)
return layout;
}
+struct shared_siginfo {
+ __SIGINFO;
+};
+
+#define SI_EXPANSION_SIZE (sizeof(struct siginfo) - sizeof(struct shared_siginfo))
+
static inline char __user *si_expansion(const siginfo_t __user *info)
{
- return ((char __user *)info) + sizeof(struct kernel_siginfo);
+ return ((char __user *)info) + sizeof(struct shared_siginfo);
}
int copy_siginfo_to_user(siginfo_t __user *to, const kernel_siginfo_t *from)
{
char __user *expansion = si_expansion(to);
- if (copy_to_user(to, from , sizeof(struct kernel_siginfo)))
+ if (copy_to_user(to, from , sizeof(struct shared_siginfo)))
return -EFAULT;
if (clear_user(expansion, SI_EXPANSION_SIZE))
return -EFAULT;
@@ -3198,6 +3204,9 @@ int copy_siginfo_to_user(siginfo_t __user *to, const kernel_siginfo_t *from)
static int post_copy_siginfo_from_user(kernel_siginfo_t *info,
const siginfo_t __user *from)
{
+#ifdef __ARCH_HAS_PRIVATE_SIGINFO
+ memset(&info->arch, 0, sizeof(info->arch));
+#endif
if (unlikely(!known_siginfo_layout(info->si_signo, info->si_code))) {
char __user *expansion = si_expansion(from);
char buf[SI_EXPANSION_SIZE];
@@ -3221,7 +3230,7 @@ static int post_copy_siginfo_from_user(kernel_siginfo_t *info,
static int __copy_siginfo_from_user(int signo, kernel_siginfo_t *to,
const siginfo_t __user *from)
{
- if (copy_from_user(to, from, sizeof(struct kernel_siginfo)))
+ if (copy_from_user(to, from, sizeof(struct shared_siginfo)))
return -EFAULT;
to->si_signo = signo;
return post_copy_siginfo_from_user(to, from);
@@ -3229,7 +3238,7 @@ static int __copy_siginfo_from_user(int signo, kernel_siginfo_t *to,
int copy_siginfo_from_user(kernel_siginfo_t *to, const siginfo_t __user *from)
{
- if (copy_from_user(to, from, sizeof(struct kernel_siginfo)))
+ if (copy_from_user(to, from, sizeof(struct shared_siginfo)))
return -EFAULT;
return post_copy_siginfo_from_user(to, from);
}
In some cases we would like to store architecture-specific data in the kernel's siginfo but not in the userspace one. This is generally data is conceptually part of siginfo but is not stored there for one reason or another. For example, on arm64, the arch-specific fault code register ESR_EL1 is exposed to signal handlers, but since it is associated with many different types of signals it does not fit well into siginfo and appears in sigcontext instead. Currently this data is stored in thread_struct, which is error-prone because the data is associated with the signal itself and not the task, and as a result it could get out of sync with the signal that is currently being delivered. To help avoid these types of errors, introduce a way for architectures to store architecture-specific data in the kernel_siginfo. This part of the kernel_siginfo is not exposed to userspace so the architecture can use it in any way that it likes without ABI concerns. A follow-up change will start using this mechanism on arm64 to store the fault code and fault address. Signed-off-by: Peter Collingbourne <pcc@google.com> --- include/linux/signal.h | 2 -- include/linux/signal_types.h | 3 +++ kernel/signal.c | 17 +++++++++++++---- 3 files changed, 16 insertions(+), 6 deletions(-)