Skip to content

Commit 28621ec

Browse files
KAGA-KOKOPeter Zijlstra
authored andcommitted
rseq: Add prctl() to enable time slice extensions
Implement a prctl() so that tasks can enable the time slice extension mechanism. This fails, when time slice extensions are disabled at compile time or on the kernel command line and when no rseq pointer is registered in the kernel. That allows to implement a single trivial check in the exit to user mode hotpath, to decide whether the whole mechanism needs to be invoked. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://patch.msgid.link/20251215155708.858717691@linutronix.de
1 parent b5b8282 commit 28621ec

File tree

4 files changed

+77
-0
lines changed

4 files changed

+77
-0
lines changed

include/linux/rseq.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,4 +163,13 @@ void rseq_syscall(struct pt_regs *regs);
163163
static inline void rseq_syscall(struct pt_regs *regs) { }
164164
#endif /* !CONFIG_DEBUG_RSEQ */
165165

166+
#ifdef CONFIG_RSEQ_SLICE_EXTENSION
167+
int rseq_slice_extension_prctl(unsigned long arg2, unsigned long arg3);
168+
#else /* CONFIG_RSEQ_SLICE_EXTENSION */
169+
static inline int rseq_slice_extension_prctl(unsigned long arg2, unsigned long arg3)
170+
{
171+
return -ENOTSUPP;
172+
}
173+
#endif /* !CONFIG_RSEQ_SLICE_EXTENSION */
174+
166175
#endif /* _LINUX_RSEQ_H */

include/uapi/linux/prctl.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,4 +386,14 @@ struct prctl_mm_map {
386386
# define PR_FUTEX_HASH_SET_SLOTS 1
387387
# define PR_FUTEX_HASH_GET_SLOTS 2
388388

389+
/* RSEQ time slice extensions */
390+
#define PR_RSEQ_SLICE_EXTENSION 79
391+
# define PR_RSEQ_SLICE_EXTENSION_GET 1
392+
# define PR_RSEQ_SLICE_EXTENSION_SET 2
393+
/*
394+
* Bits for RSEQ_SLICE_EXTENSION_GET/SET
395+
* PR_RSEQ_SLICE_EXT_ENABLE: Enable
396+
*/
397+
# define PR_RSEQ_SLICE_EXT_ENABLE 0x01
398+
389399
#endif /* _LINUX_PRCTL_H */

kernel/rseq.c

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
#define RSEQ_BUILD_SLOW_PATH
7272

7373
#include <linux/debugfs.h>
74+
#include <linux/prctl.h>
7475
#include <linux/ratelimit.h>
7576
#include <linux/rseq_entry.h>
7677
#include <linux/sched.h>
@@ -501,6 +502,57 @@ SYSCALL_DEFINE4(rseq, struct rseq __user *, rseq, u32, rseq_len, int, flags, u32
501502
#ifdef CONFIG_RSEQ_SLICE_EXTENSION
502503
DEFINE_STATIC_KEY_TRUE(rseq_slice_extension_key);
503504

505+
int rseq_slice_extension_prctl(unsigned long arg2, unsigned long arg3)
506+
{
507+
switch (arg2) {
508+
case PR_RSEQ_SLICE_EXTENSION_GET:
509+
if (arg3)
510+
return -EINVAL;
511+
return current->rseq.slice.state.enabled ? PR_RSEQ_SLICE_EXT_ENABLE : 0;
512+
513+
case PR_RSEQ_SLICE_EXTENSION_SET: {
514+
u32 rflags, valid = RSEQ_CS_FLAG_SLICE_EXT_AVAILABLE;
515+
bool enable = !!(arg3 & PR_RSEQ_SLICE_EXT_ENABLE);
516+
517+
if (arg3 & ~PR_RSEQ_SLICE_EXT_ENABLE)
518+
return -EINVAL;
519+
if (!rseq_slice_extension_enabled())
520+
return -ENOTSUPP;
521+
if (!current->rseq.usrptr)
522+
return -ENXIO;
523+
524+
/* No change? */
525+
if (enable == !!current->rseq.slice.state.enabled)
526+
return 0;
527+
528+
if (get_user(rflags, &current->rseq.usrptr->flags))
529+
goto die;
530+
531+
if (current->rseq.slice.state.enabled)
532+
valid |= RSEQ_CS_FLAG_SLICE_EXT_ENABLED;
533+
534+
if ((rflags & valid) != valid)
535+
goto die;
536+
537+
rflags &= ~RSEQ_CS_FLAG_SLICE_EXT_ENABLED;
538+
rflags |= RSEQ_CS_FLAG_SLICE_EXT_AVAILABLE;
539+
if (enable)
540+
rflags |= RSEQ_CS_FLAG_SLICE_EXT_ENABLED;
541+
542+
if (put_user(rflags, &current->rseq.usrptr->flags))
543+
goto die;
544+
545+
current->rseq.slice.state.enabled = enable;
546+
return 0;
547+
}
548+
default:
549+
return -EINVAL;
550+
}
551+
die:
552+
force_sig(SIGSEGV);
553+
return -EFAULT;
554+
}
555+
504556
static int __init rseq_slice_cmdline(char *str)
505557
{
506558
bool on;

kernel/sys.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
#include <linux/time_namespace.h>
5454
#include <linux/binfmts.h>
5555
#include <linux/futex.h>
56+
#include <linux/rseq.h>
5657

5758
#include <linux/sched.h>
5859
#include <linux/sched/autogroup.h>
@@ -2868,6 +2869,11 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
28682869
case PR_FUTEX_HASH:
28692870
error = futex_hash_prctl(arg2, arg3, arg4);
28702871
break;
2872+
case PR_RSEQ_SLICE_EXTENSION:
2873+
if (arg4 || arg5)
2874+
return -EINVAL;
2875+
error = rseq_slice_extension_prctl(arg2, arg3);
2876+
break;
28712877
default:
28722878
trace_task_prctl_unknown(option, arg2, arg3, arg4, arg5);
28732879
error = -EINVAL;

0 commit comments

Comments
 (0)