Skip to content

Commit ec9c82e

Browse files
compudjKAGA-KOKO
authored andcommitted
rseq: uapi: Declare rseq_cs field as union, update includes
Declaring the rseq_cs field as a union between __u64 and two __u32 allows both 32-bit and 64-bit kernels to read the full __u64, and therefore validate that a 32-bit user-space cleared the upper 32 bits, thus ensuring a consistent behavior between native 32-bit kernels and 32-bit compat tasks on 64-bit kernels. Check that the rseq_cs value read is < TASK_SIZE. The asm/byteorder.h header needs to be included by rseq.h, now that it is not using linux/types_32_64.h anymore. Considering that only __32 and __u64 types are declared in linux/rseq.h, the linux/types.h header should always be included for both kernel and user-space code: including stdint.h is just for u64 and u32, which are not used in this header at all. Use copy_from_user()/clear_user() to interact with a 64-bit field, because arm32 does not implement 64-bit __get_user, and ppc32 does not 64-bit get_user. Considering that the rseq_cs pointer does not need to be loaded/stored with single-copy atomicity from the kernel anymore, we can simply use copy_from_user()/clear_user(). Signed-off-by: Mathieu Desnoyers <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Cc: [email protected] Cc: Peter Zijlstra <[email protected]> Cc: "Paul E . McKenney" <[email protected]> Cc: Boqun Feng <[email protected]> Cc: Andy Lutomirski <[email protected]> Cc: Dave Watson <[email protected]> Cc: Paul Turner <[email protected]> Cc: Andrew Morton <[email protected]> Cc: Russell King <[email protected]> Cc: "H . Peter Anvin" <[email protected]> Cc: Andi Kleen <[email protected]> Cc: Chris Lameter <[email protected]> Cc: Ben Maurer <[email protected]> Cc: Steven Rostedt <[email protected]> Cc: Josh Triplett <[email protected]> Cc: Linus Torvalds <[email protected]> Cc: Catalin Marinas <[email protected]> Cc: Will Deacon <[email protected]> Cc: Michael Kerrisk <[email protected]> Cc: Joel Fernandes <[email protected]> Cc: "Paul E. McKenney" <[email protected]> Cc: "H. Peter Anvin" <[email protected]> Link: https://lkml.kernel.org/r/[email protected]
1 parent 0fb9a1a commit ec9c82e

File tree

3 files changed

+38
-15
lines changed

3 files changed

+38
-15
lines changed

include/uapi/linux/rseq.h

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,8 @@
1010
* Copyright (c) 2015-2018 Mathieu Desnoyers <[email protected]>
1111
*/
1212

13-
#ifdef __KERNEL__
14-
# include <linux/types.h>
15-
#else
16-
# include <stdint.h>
17-
#endif
18-
19-
#include <linux/types_32_64.h>
13+
#include <linux/types.h>
14+
#include <asm/byteorder.h>
2015

2116
enum rseq_cpu_id_state {
2217
RSEQ_CPU_ID_UNINITIALIZED = -1,
@@ -111,7 +106,23 @@ struct rseq {
111106
* atomicity semantics. This field should only be updated by the
112107
* thread which registered this data structure. Aligned on 64-bit.
113108
*/
114-
LINUX_FIELD_u32_u64(rseq_cs);
109+
union {
110+
__u64 ptr64;
111+
#ifdef __LP64__
112+
__u64 ptr;
113+
#else
114+
struct {
115+
#if (defined(__BYTE_ORDER) && (__BYTE_ORDER == __BIG_ENDIAN)) || defined(__BIG_ENDIAN)
116+
__u32 padding; /* Initialized to zero. */
117+
__u32 ptr32;
118+
#else /* LITTLE */
119+
__u32 ptr32;
120+
__u32 padding; /* Initialized to zero. */
121+
#endif /* ENDIAN */
122+
} ptr;
123+
#endif
124+
} rseq_cs;
125+
115126
/*
116127
* Restartable sequences flags field.
117128
*

kernel/rseq.c

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -115,19 +115,20 @@ static int rseq_reset_rseq_cpu_id(struct task_struct *t)
115115
static int rseq_get_rseq_cs(struct task_struct *t, struct rseq_cs *rseq_cs)
116116
{
117117
struct rseq_cs __user *urseq_cs;
118-
unsigned long ptr;
118+
u64 ptr;
119119
u32 __user *usig;
120120
u32 sig;
121121
int ret;
122122

123-
ret = get_user(ptr, &t->rseq->rseq_cs);
124-
if (ret)
125-
return ret;
123+
if (copy_from_user(&ptr, &t->rseq->rseq_cs.ptr64, sizeof(ptr)))
124+
return -EFAULT;
126125
if (!ptr) {
127126
memset(rseq_cs, 0, sizeof(*rseq_cs));
128127
return 0;
129128
}
130-
urseq_cs = (struct rseq_cs __user *)ptr;
129+
if (ptr >= TASK_SIZE)
130+
return -EINVAL;
131+
urseq_cs = (struct rseq_cs __user *)(unsigned long)ptr;
131132
if (copy_from_user(rseq_cs, urseq_cs, sizeof(*rseq_cs)))
132133
return -EFAULT;
133134

@@ -203,7 +204,9 @@ static int clear_rseq_cs(struct task_struct *t)
203204
*
204205
* Set rseq_cs to NULL.
205206
*/
206-
return put_user(0UL, &t->rseq->rseq_cs);
207+
if (clear_user(&t->rseq->rseq_cs.ptr64, sizeof(t->rseq->rseq_cs.ptr64)))
208+
return -EFAULT;
209+
return 0;
207210
}
208211

209212
/*

tools/testing/selftests/rseq/rseq.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,15 @@ static inline uint32_t rseq_current_cpu(void)
133133
return cpu;
134134
}
135135

136+
static inline void rseq_clear_rseq_cs(void)
137+
{
138+
#ifdef __LP64__
139+
__rseq_abi.rseq_cs.ptr = 0;
140+
#else
141+
__rseq_abi.rseq_cs.ptr.ptr32 = 0;
142+
#endif
143+
}
144+
136145
/*
137146
* rseq_prepare_unload() should be invoked by each thread using rseq_finish*()
138147
* at least once between their last rseq_finish*() and library unload of the
@@ -143,7 +152,7 @@ static inline uint32_t rseq_current_cpu(void)
143152
*/
144153
static inline void rseq_prepare_unload(void)
145154
{
146-
__rseq_abi.rseq_cs = 0;
155+
rseq_clear_rseq_cs();
147156
}
148157

149158
#endif /* RSEQ_H_ */

0 commit comments

Comments
 (0)