Skip to content

Commit 307d522

Browse files
committed
signal/seccomp: Refactor seccomp signal and coredump generation
Factor out force_sig_seccomp from the seccomp signal generation and place it in kernel/signal.c. The function force_sig_seccomp takes a parameter force_coredump to indicate that the sigaction field should be reset to SIGDFL so that a coredump will be generated when the signal is delivered. force_sig_seccomp is then used to replace both seccomp_send_sigsys and seccomp_init_siginfo. force_sig_info_to_task gains an extra parameter to force using the default signal action. With this change seccomp is no longer a special case and there becomes exactly one place do_coredump is called from. Further it no longer becomes necessary for __seccomp_filter to call do_group_exit. Acked-by: Kees Cook <[email protected]> Link: https://lkml.kernel.org/r/87r1gr6qc4.fsf_-_@disp2133 Signed-off-by: "Eric W. Biederman" <[email protected]>
1 parent a3616a3 commit 307d522

File tree

3 files changed

+33
-38
lines changed

3 files changed

+33
-38
lines changed

include/linux/sched/signal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,7 @@ int force_sig_pkuerr(void __user *addr, u32 pkey);
329329
int force_sig_perf(void __user *addr, u32 type, u64 sig_data);
330330

331331
int force_sig_ptrace_errno_trap(int errno, void __user *addr);
332+
int force_sig_seccomp(int syscall, int reason, bool force_coredump);
332333

333334
extern int send_sig_info(int, struct kernel_siginfo *, struct task_struct *);
334335
extern void force_sigsegv(int sig);

kernel/seccomp.c

Lines changed: 6 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -922,30 +922,6 @@ void get_seccomp_filter(struct task_struct *tsk)
922922
refcount_inc(&orig->users);
923923
}
924924

925-
static void seccomp_init_siginfo(kernel_siginfo_t *info, int syscall, int reason)
926-
{
927-
clear_siginfo(info);
928-
info->si_signo = SIGSYS;
929-
info->si_code = SYS_SECCOMP;
930-
info->si_call_addr = (void __user *)KSTK_EIP(current);
931-
info->si_errno = reason;
932-
info->si_arch = syscall_get_arch(current);
933-
info->si_syscall = syscall;
934-
}
935-
936-
/**
937-
* seccomp_send_sigsys - signals the task to allow in-process syscall emulation
938-
* @syscall: syscall number to send to userland
939-
* @reason: filter-supplied reason code to send to userland (via si_errno)
940-
*
941-
* Forces a SIGSYS with a code of SYS_SECCOMP and related sigsys info.
942-
*/
943-
static void seccomp_send_sigsys(int syscall, int reason)
944-
{
945-
struct kernel_siginfo info;
946-
seccomp_init_siginfo(&info, syscall, reason);
947-
force_sig_info(&info);
948-
}
949925
#endif /* CONFIG_SECCOMP_FILTER */
950926

951927
/* For use with seccomp_actions_logged */
@@ -1218,7 +1194,7 @@ static int __seccomp_filter(int this_syscall, const struct seccomp_data *sd,
12181194
/* Show the handler the original registers. */
12191195
syscall_rollback(current, current_pt_regs());
12201196
/* Let the filter pass back 16 bits of data. */
1221-
seccomp_send_sigsys(this_syscall, data);
1197+
force_sig_seccomp(this_syscall, data, false);
12221198
goto skip;
12231199

12241200
case SECCOMP_RET_TRACE:
@@ -1289,18 +1265,14 @@ static int __seccomp_filter(int this_syscall, const struct seccomp_data *sd,
12891265
/* Dump core only if this is the last remaining thread. */
12901266
if (action != SECCOMP_RET_KILL_THREAD ||
12911267
get_nr_threads(current) == 1) {
1292-
kernel_siginfo_t info;
1293-
12941268
/* Show the original registers in the dump. */
12951269
syscall_rollback(current, current_pt_regs());
1296-
/* Trigger a manual coredump since do_exit skips it. */
1297-
seccomp_init_siginfo(&info, this_syscall, data);
1298-
do_coredump(&info);
1299-
}
1300-
if (action == SECCOMP_RET_KILL_THREAD)
1270+
/* Trigger a coredump with SIGSYS */
1271+
force_sig_seccomp(this_syscall, data, true);
1272+
} else {
13011273
do_exit(SIGSYS);
1302-
else
1303-
do_group_exit(SIGSYS);
1274+
}
1275+
return -1; /* skip the syscall go directly to signal handling */
13041276
}
13051277

13061278
unreachable();

kernel/signal.c

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
#include <asm/unistd.h>
5555
#include <asm/siginfo.h>
5656
#include <asm/cacheflush.h>
57+
#include <asm/syscall.h> /* for syscall_get_* */
5758

5859
/*
5960
* SLAB caches for signal bits.
@@ -1322,7 +1323,7 @@ int do_send_sig_info(int sig, struct kernel_siginfo *info, struct task_struct *p
13221323
* that is why we also clear SIGNAL_UNKILLABLE.
13231324
*/
13241325
static int
1325-
force_sig_info_to_task(struct kernel_siginfo *info, struct task_struct *t)
1326+
force_sig_info_to_task(struct kernel_siginfo *info, struct task_struct *t, bool sigdfl)
13261327
{
13271328
unsigned long int flags;
13281329
int ret, blocked, ignored;
@@ -1333,7 +1334,7 @@ force_sig_info_to_task(struct kernel_siginfo *info, struct task_struct *t)
13331334
action = &t->sighand->action[sig-1];
13341335
ignored = action->sa.sa_handler == SIG_IGN;
13351336
blocked = sigismember(&t->blocked, sig);
1336-
if (blocked || ignored) {
1337+
if (blocked || ignored || sigdfl) {
13371338
action->sa.sa_handler = SIG_DFL;
13381339
if (blocked) {
13391340
sigdelset(&t->blocked, sig);
@@ -1354,7 +1355,7 @@ force_sig_info_to_task(struct kernel_siginfo *info, struct task_struct *t)
13541355

13551356
int force_sig_info(struct kernel_siginfo *info)
13561357
{
1357-
return force_sig_info_to_task(info, current);
1358+
return force_sig_info_to_task(info, current, false);
13581359
}
13591360

13601361
/*
@@ -1685,7 +1686,7 @@ int force_sig_fault_to_task(int sig, int code, void __user *addr
16851686
info.si_flags = flags;
16861687
info.si_isr = isr;
16871688
#endif
1688-
return force_sig_info_to_task(&info, t);
1689+
return force_sig_info_to_task(&info, t, false);
16891690
}
16901691

16911692
int force_sig_fault(int sig, int code, void __user *addr
@@ -1793,6 +1794,27 @@ int force_sig_perf(void __user *addr, u32 type, u64 sig_data)
17931794
return force_sig_info(&info);
17941795
}
17951796

1797+
/**
1798+
* force_sig_seccomp - signals the task to allow in-process syscall emulation
1799+
* @syscall: syscall number to send to userland
1800+
* @reason: filter-supplied reason code to send to userland (via si_errno)
1801+
*
1802+
* Forces a SIGSYS with a code of SYS_SECCOMP and related sigsys info.
1803+
*/
1804+
int force_sig_seccomp(int syscall, int reason, bool force_coredump)
1805+
{
1806+
struct kernel_siginfo info;
1807+
1808+
clear_siginfo(&info);
1809+
info.si_signo = SIGSYS;
1810+
info.si_code = SYS_SECCOMP;
1811+
info.si_call_addr = (void __user *)KSTK_EIP(current);
1812+
info.si_errno = reason;
1813+
info.si_arch = syscall_get_arch(current);
1814+
info.si_syscall = syscall;
1815+
return force_sig_info_to_task(&info, current, force_coredump);
1816+
}
1817+
17961818
/* For the crazy architectures that include trap information in
17971819
* the errno field, instead of an actual errno value.
17981820
*/

0 commit comments

Comments
 (0)