Skip to content

Commit

Permalink
signal: Distinguish between kernel_siginfo and siginfo
Browse files Browse the repository at this point in the history
Linus recently observed that if we did not worry about the padding
member in struct siginfo it is only about 48 bytes, and 48 bytes is
much nicer than 128 bytes for allocating on the stack and copying
around in the kernel.

The obvious thing of only adding the padding when userspace is
including siginfo.h won't work as there are sigframe definitions in
the kernel that embed struct siginfo.

So split siginfo in two; kernel_siginfo and siginfo.  Keeping the
traditional name for the userspace definition.  While the version that
is used internally to the kernel and ultimately will not be padded to
128 bytes is called kernel_siginfo.

The definition of struct kernel_siginfo I have put in include/signal_types.h

A set of buildtime checks has been added to verify the two structures have
the same field offsets.

To make it easy to verify the change kernel_siginfo retains the same
size as siginfo.  The reduction in size comes in a following change.

Signed-off-by: "Eric W. Biederman" <[email protected]>
  • Loading branch information
ebiederm committed Oct 3, 2018
1 parent 4cd2e0e commit ae7795b
Show file tree
Hide file tree
Showing 27 changed files with 165 additions and 110 deletions.
2 changes: 1 addition & 1 deletion arch/x86/include/asm/compat.h
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,6 @@ static inline bool in_compat_syscall(void)

struct compat_siginfo;
int __copy_siginfo_to_user32(struct compat_siginfo __user *to,
const siginfo_t *from, bool x32_ABI);
const kernel_siginfo_t *from, bool x32_ABI);

#endif /* _ASM_X86_COMPAT_H */
4 changes: 2 additions & 2 deletions drivers/usb/core/devio.c
Original file line number Diff line number Diff line change
Expand Up @@ -582,7 +582,7 @@ static void async_completed(struct urb *urb)
{
struct async *as = urb->context;
struct usb_dev_state *ps = as->ps;
struct siginfo sinfo;
struct kernel_siginfo sinfo;
struct pid *pid = NULL;
const struct cred *cred = NULL;
unsigned long flags;
Expand Down Expand Up @@ -2599,7 +2599,7 @@ const struct file_operations usbdev_file_operations = {
static void usbdev_remove(struct usb_device *udev)
{
struct usb_dev_state *ps;
struct siginfo sinfo;
struct kernel_siginfo sinfo;

while (!list_empty(&udev->filelist)) {
ps = list_entry(udev->filelist.next, struct usb_dev_state, list);
Expand Down
6 changes: 3 additions & 3 deletions fs/binfmt_elf.c
Original file line number Diff line number Diff line change
Expand Up @@ -1580,7 +1580,7 @@ static void fill_auxv_note(struct memelfnote *note, struct mm_struct *mm)
}

static void fill_siginfo_note(struct memelfnote *note, user_siginfo_t *csigdata,
const siginfo_t *siginfo)
const kernel_siginfo_t *siginfo)
{
mm_segment_t old_fs = get_fs();
set_fs(KERNEL_DS);
Expand Down Expand Up @@ -1782,7 +1782,7 @@ static int fill_thread_core_info(struct elf_thread_core_info *t,

static int fill_note_info(struct elfhdr *elf, int phdrs,
struct elf_note_info *info,
const siginfo_t *siginfo, struct pt_regs *regs)
const kernel_siginfo_t *siginfo, struct pt_regs *regs)
{
struct task_struct *dump_task = current;
const struct user_regset_view *view = task_user_regset_view(dump_task);
Expand Down Expand Up @@ -2031,7 +2031,7 @@ static int elf_note_info_init(struct elf_note_info *info)

static int fill_note_info(struct elfhdr *elf, int phdrs,
struct elf_note_info *info,
const siginfo_t *siginfo, struct pt_regs *regs)
const kernel_siginfo_t *siginfo, struct pt_regs *regs)
{
struct list_head *t;
struct core_thread *ct;
Expand Down
2 changes: 1 addition & 1 deletion fs/coredump.c
Original file line number Diff line number Diff line change
Expand Up @@ -536,7 +536,7 @@ static int umh_pipe_setup(struct subprocess_info *info, struct cred *new)
return err;
}

void do_coredump(const siginfo_t *siginfo)
void do_coredump(const kernel_siginfo_t *siginfo)
{
struct core_state core_state;
struct core_name cn;
Expand Down
2 changes: 1 addition & 1 deletion fs/fcntl.c
Original file line number Diff line number Diff line change
Expand Up @@ -735,7 +735,7 @@ static void send_sigio_to_task(struct task_struct *p,
return;

switch (signum) {
siginfo_t si;
kernel_siginfo_t si;
default:
/* Queue a rt signal with the appropriate fd as its
value. We use SI_SIGIO as the source, not
Expand Down
6 changes: 3 additions & 3 deletions fs/signalfd.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ static __poll_t signalfd_poll(struct file *file, poll_table *wait)
* Copied from copy_siginfo_to_user() in kernel/signal.c
*/
static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo,
siginfo_t const *kinfo)
kernel_siginfo_t const *kinfo)
{
struct signalfd_siginfo new;

Expand Down Expand Up @@ -163,7 +163,7 @@ static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo,
return sizeof(*uinfo);
}

static ssize_t signalfd_dequeue(struct signalfd_ctx *ctx, siginfo_t *info,
static ssize_t signalfd_dequeue(struct signalfd_ctx *ctx, kernel_siginfo_t *info,
int nonblock)
{
ssize_t ret;
Expand Down Expand Up @@ -215,7 +215,7 @@ static ssize_t signalfd_read(struct file *file, char __user *buf, size_t count,
struct signalfd_siginfo __user *siginfo;
int nonblock = file->f_flags & O_NONBLOCK;
ssize_t ret, total = 0;
siginfo_t info;
kernel_siginfo_t info;

count /= sizeof(struct signalfd_siginfo);
if (!count)
Expand Down
2 changes: 1 addition & 1 deletion include/linux/binfmts.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ struct linux_binprm {

/* Function parameter for binfmt->coredump */
struct coredump_params {
const siginfo_t *siginfo;
const kernel_siginfo_t *siginfo;
struct pt_regs *regs;
struct file *file;
unsigned long limit;
Expand Down
4 changes: 2 additions & 2 deletions include/linux/compat.h
Original file line number Diff line number Diff line change
Expand Up @@ -452,8 +452,8 @@ long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask,
unsigned long bitmap_size);
long compat_put_bitmap(compat_ulong_t __user *umask, unsigned long *mask,
unsigned long bitmap_size);
int copy_siginfo_from_user32(siginfo_t *to, const struct compat_siginfo __user *from);
int copy_siginfo_to_user32(struct compat_siginfo __user *to, const siginfo_t *from);
int copy_siginfo_from_user32(kernel_siginfo_t *to, const struct compat_siginfo __user *from);
int copy_siginfo_to_user32(struct compat_siginfo __user *to, const kernel_siginfo_t *from);
int get_compat_sigevent(struct sigevent *event,
const struct compat_sigevent __user *u_event);

Expand Down
4 changes: 2 additions & 2 deletions include/linux/coredump.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ extern int dump_emit(struct coredump_params *cprm, const void *addr, int nr);
extern int dump_align(struct coredump_params *cprm, int align);
extern void dump_truncate(struct coredump_params *cprm);
#ifdef CONFIG_COREDUMP
extern void do_coredump(const siginfo_t *siginfo);
extern void do_coredump(const kernel_siginfo_t *siginfo);
#else
static inline void do_coredump(const siginfo_t *siginfo) {}
static inline void do_coredump(const kernel_siginfo_t *siginfo) {}
#endif

#endif /* _LINUX_COREDUMP_H */
4 changes: 2 additions & 2 deletions include/linux/lsm_hooks.h
Original file line number Diff line number Diff line change
Expand Up @@ -672,7 +672,7 @@
* Return 0 if permission is granted.
* @task_kill:
* Check permission before sending signal @sig to @p. @info can be NULL,
* the constant 1, or a pointer to a siginfo structure. If @info is 1 or
* the constant 1, or a pointer to a kernel_siginfo structure. If @info is 1 or
* SI_FROMKERNEL(info) is true, then the signal should be viewed as coming
* from the kernel and should typically be permitted.
* SIGIO signals are handled separately by the send_sigiotask hook in
Expand Down Expand Up @@ -1606,7 +1606,7 @@ union security_list_options {
int (*task_setscheduler)(struct task_struct *p);
int (*task_getscheduler)(struct task_struct *p);
int (*task_movememory)(struct task_struct *p);
int (*task_kill)(struct task_struct *p, struct siginfo *info,
int (*task_kill)(struct task_struct *p, struct kernel_siginfo *info,
int sig, const struct cred *cred);
int (*task_prctl)(int option, unsigned long arg2, unsigned long arg3,
unsigned long arg4, unsigned long arg5);
Expand Down
2 changes: 1 addition & 1 deletion include/linux/posix-timers.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,5 +126,5 @@ void set_process_cpu_timer(struct task_struct *task, unsigned int clock_idx,

void update_rlimit_cpu(struct task_struct *task, unsigned long rlim_new);

void posixtimer_rearm(struct siginfo *info);
void posixtimer_rearm(struct kernel_siginfo *info);
#endif
2 changes: 1 addition & 1 deletion include/linux/ptrace.h
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ extern void user_single_step_report(struct pt_regs *regs);
#else
static inline void user_single_step_report(struct pt_regs *regs)
{
siginfo_t info;
kernel_siginfo_t info;
clear_siginfo(&info);
info.si_signo = SIGTRAP;
info.si_errno = 0;
Expand Down
2 changes: 1 addition & 1 deletion include/linux/sched.h
Original file line number Diff line number Diff line change
Expand Up @@ -960,7 +960,7 @@ struct task_struct {

/* Ptrace state: */
unsigned long ptrace_message;
siginfo_t *last_siginfo;
kernel_siginfo_t *last_siginfo;

struct task_io_accounting ioac;
#ifdef CONFIG_TASK_XACCT
Expand Down
18 changes: 9 additions & 9 deletions include/linux/sched/signal.h
Original file line number Diff line number Diff line change
Expand Up @@ -270,12 +270,12 @@ static inline int signal_group_exit(const struct signal_struct *sig)
extern void flush_signals(struct task_struct *);
extern void ignore_signals(struct task_struct *);
extern void flush_signal_handlers(struct task_struct *, int force_default);
extern int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info);
extern int dequeue_signal(struct task_struct *tsk, sigset_t *mask, kernel_siginfo_t *info);

static inline int kernel_dequeue_signal(void)
{
struct task_struct *tsk = current;
siginfo_t __info;
kernel_siginfo_t __info;
int ret;

spin_lock_irq(&tsk->sighand->siglock);
Expand Down Expand Up @@ -322,12 +322,12 @@ int force_sig_pkuerr(void __user *addr, u32 pkey);

int force_sig_ptrace_errno_trap(int errno, void __user *addr);

extern int send_sig_info(int, struct siginfo *, struct task_struct *);
extern int send_sig_info(int, struct kernel_siginfo *, struct task_struct *);
extern void force_sigsegv(int sig, struct task_struct *p);
extern int force_sig_info(int, struct siginfo *, struct task_struct *);
extern int __kill_pgrp_info(int sig, struct siginfo *info, struct pid *pgrp);
extern int kill_pid_info(int sig, struct siginfo *info, struct pid *pid);
extern int kill_pid_info_as_cred(int, struct siginfo *, struct pid *,
extern int force_sig_info(int, struct kernel_siginfo *, struct task_struct *);
extern int __kill_pgrp_info(int sig, struct kernel_siginfo *info, struct pid *pgrp);
extern int kill_pid_info(int sig, struct kernel_siginfo *info, struct pid *pid);
extern int kill_pid_info_as_cred(int, struct kernel_siginfo *, struct pid *,
const struct cred *);
extern int kill_pgrp(struct pid *pid, int sig, int priv);
extern int kill_pid(struct pid *pid, int sig, int priv);
Expand Down Expand Up @@ -475,8 +475,8 @@ static inline int kill_cad_pid(int sig, int priv)
}

/* These can be the second arg to send_sig_info/send_group_sig_info. */
#define SEND_SIG_NOINFO ((struct siginfo *) 0)
#define SEND_SIG_PRIV ((struct siginfo *) 1)
#define SEND_SIG_NOINFO ((struct kernel_siginfo *) 0)
#define SEND_SIG_PRIV ((struct kernel_siginfo *) 1)

/*
* True if we are on the alternate signal stack.
Expand Down
6 changes: 3 additions & 3 deletions include/linux/security.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
struct linux_binprm;
struct cred;
struct rlimit;
struct siginfo;
struct kernel_siginfo;
struct sembuf;
struct kern_ipc_perm;
struct audit_context;
Expand Down Expand Up @@ -361,7 +361,7 @@ int security_task_setrlimit(struct task_struct *p, unsigned int resource,
int security_task_setscheduler(struct task_struct *p);
int security_task_getscheduler(struct task_struct *p);
int security_task_movememory(struct task_struct *p);
int security_task_kill(struct task_struct *p, struct siginfo *info,
int security_task_kill(struct task_struct *p, struct kernel_siginfo *info,
int sig, const struct cred *cred);
int security_task_prctl(int option, unsigned long arg2, unsigned long arg3,
unsigned long arg4, unsigned long arg5);
Expand Down Expand Up @@ -1020,7 +1020,7 @@ static inline int security_task_movememory(struct task_struct *p)
}

static inline int security_task_kill(struct task_struct *p,
struct siginfo *info, int sig,
struct kernel_siginfo *info, int sig,
const struct cred *cred)
{
return 0;
Expand Down
15 changes: 8 additions & 7 deletions include/linux/signal.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,19 @@ struct task_struct;
/* for sysctl */
extern int print_fatal_signals;

static inline void copy_siginfo(struct siginfo *to, const struct siginfo *from)
static inline void copy_siginfo(kernel_siginfo_t *to,
const kernel_siginfo_t *from)
{
memcpy(to, from, sizeof(*to));
}

static inline void clear_siginfo(struct siginfo *info)
static inline void clear_siginfo(kernel_siginfo_t *info)
{
memset(info, 0, sizeof(*info));
}

int copy_siginfo_to_user(struct siginfo __user *to, const struct siginfo *from);
int copy_siginfo_from_user(struct siginfo *to, const struct siginfo __user *from);
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);

enum siginfo_layout {
SIL_KILL,
Expand Down Expand Up @@ -258,11 +259,11 @@ struct pt_regs;
enum pid_type;

extern int next_signal(struct sigpending *pending, sigset_t *mask);
extern int do_send_sig_info(int sig, struct siginfo *info,
extern int do_send_sig_info(int sig, struct kernel_siginfo *info,
struct task_struct *p, enum pid_type type);
extern int group_send_sig_info(int sig, struct siginfo *info,
extern int group_send_sig_info(int sig, struct kernel_siginfo *info,
struct task_struct *p, enum pid_type type);
extern int __group_send_sig_info(int, struct siginfo *, struct task_struct *);
extern int __group_send_sig_info(int, struct kernel_siginfo *, struct task_struct *);
extern int sigprocmask(int, sigset_t *, sigset_t *);
extern void set_current_blocked(sigset_t *);
extern void __set_current_blocked(const sigset_t *);
Expand Down
11 changes: 9 additions & 2 deletions include/linux/signal_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,21 @@
#include <linux/list.h>
#include <uapi/linux/signal.h>

typedef struct kernel_siginfo {
union {
__SIGINFO;
int _si_pad[SI_MAX_SIZE/sizeof(int)];
};
} kernel_siginfo_t;

/*
* Real Time signals may be queued.
*/

struct sigqueue {
struct list_head list;
int flags;
siginfo_t info;
kernel_siginfo_t info;
struct user_struct *user;
};

Expand Down Expand Up @@ -60,7 +67,7 @@ struct old_sigaction {

struct ksignal {
struct k_sigaction ka;
siginfo_t info;
kernel_siginfo_t info;
int sig;
};

Expand Down
4 changes: 2 additions & 2 deletions include/trace/events/signal.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ enum {
*/
TRACE_EVENT(signal_generate,

TP_PROTO(int sig, struct siginfo *info, struct task_struct *task,
TP_PROTO(int sig, struct kernel_siginfo *info, struct task_struct *task,
int group, int result),

TP_ARGS(sig, info, task, group, result),
Expand Down Expand Up @@ -95,7 +95,7 @@ TRACE_EVENT(signal_generate,
*/
TRACE_EVENT(signal_deliver,

TP_PROTO(int sig, struct siginfo *info, struct k_sigaction *ka),
TP_PROTO(int sig, struct kernel_siginfo *info, struct k_sigaction *ka),

TP_ARGS(sig, info, ka),

Expand Down
2 changes: 1 addition & 1 deletion ipc/mqueue.c
Original file line number Diff line number Diff line change
Expand Up @@ -655,7 +655,7 @@ static void __do_notify(struct mqueue_inode_info *info)
* synchronously. */
if (info->notify_owner &&
info->attr.mq_curmsgs == 1) {
struct siginfo sig_i;
struct kernel_siginfo sig_i;
switch (info->notify.sigev_notify) {
case SIGEV_NONE:
break;
Expand Down
10 changes: 5 additions & 5 deletions kernel/ptrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -651,7 +651,7 @@ static int ptrace_setoptions(struct task_struct *child, unsigned long data)
return 0;
}

static int ptrace_getsiginfo(struct task_struct *child, siginfo_t *info)
static int ptrace_getsiginfo(struct task_struct *child, kernel_siginfo_t *info)
{
unsigned long flags;
int error = -ESRCH;
Expand All @@ -667,7 +667,7 @@ static int ptrace_getsiginfo(struct task_struct *child, siginfo_t *info)
return error;
}

static int ptrace_setsiginfo(struct task_struct *child, const siginfo_t *info)
static int ptrace_setsiginfo(struct task_struct *child, const kernel_siginfo_t *info)
{
unsigned long flags;
int error = -ESRCH;
Expand Down Expand Up @@ -709,7 +709,7 @@ static int ptrace_peek_siginfo(struct task_struct *child,
pending = &child->pending;

for (i = 0; i < arg.nr; ) {
siginfo_t info;
kernel_siginfo_t info;
s32 off = arg.off + i;

spin_lock_irq(&child->sighand->siglock);
Expand Down Expand Up @@ -885,7 +885,7 @@ int ptrace_request(struct task_struct *child, long request,
{
bool seized = child->ptrace & PT_SEIZED;
int ret = -EIO;
siginfo_t siginfo, *si;
kernel_siginfo_t siginfo, *si;
void __user *datavp = (void __user *) data;
unsigned long __user *datalp = datavp;
unsigned long flags;
Expand Down Expand Up @@ -1180,7 +1180,7 @@ int compat_ptrace_request(struct task_struct *child, compat_long_t request,
{
compat_ulong_t __user *datap = compat_ptr(data);
compat_ulong_t word;
siginfo_t siginfo;
kernel_siginfo_t siginfo;
int ret;

switch (request) {
Expand Down
Loading

0 comments on commit ae7795b

Please sign in to comment.