diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-07-13 15:50:42 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-07-13 15:50:42 -0400 |
commit | ae4ea3975d97ab61a274718dc3642a8b2b459811 (patch) | |
tree | 3204e4062c65cd81bf248028a1fbd162c1b8e3c0 | |
parent | 4659fc8484b707c161b14324df0e3a2f5d03f050 (diff) | |
parent | 8a46580128a02bdc18d7dcc0cba19d3cea4fb9c4 (diff) |
Merge branch 'core-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull rseq fixes from Ingo Molnar:
"Various rseq ABI fixes and cleanups: use get_user()/put_user(),
validate parameters and use proper uapi types, etc"
* 'core-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
rseq/selftests: cleanup: Update comment above rseq_prepare_unload
rseq: Remove unused types_32_64.h uapi header
rseq: uapi: Declare rseq_cs field as union, update includes
rseq: uapi: Update uapi comments
rseq: Use get_user/put_user rather than __get_user/__put_user
rseq: Use __u64 for rseq_cs fields, validate user inputs
-rw-r--r-- | include/uapi/linux/rseq.h | 102 | ||||
-rw-r--r-- | include/uapi/linux/types_32_64.h | 50 | ||||
-rw-r--r-- | kernel/rseq.c | 41 | ||||
-rw-r--r-- | tools/testing/selftests/rseq/rseq.h | 24 |
4 files changed, 100 insertions, 117 deletions
diff --git a/include/uapi/linux/rseq.h b/include/uapi/linux/rseq.h index d620fa43756c..9a402fdb60e9 100644 --- a/include/uapi/linux/rseq.h +++ b/include/uapi/linux/rseq.h | |||
@@ -10,13 +10,8 @@ | |||
10 | * Copyright (c) 2015-2018 Mathieu Desnoyers <mathieu.desnoyers@efficios.com> | 10 | * Copyright (c) 2015-2018 Mathieu Desnoyers <mathieu.desnoyers@efficios.com> |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #ifdef __KERNEL__ | 13 | #include <linux/types.h> |
14 | # include <linux/types.h> | 14 | #include <asm/byteorder.h> |
15 | #else | ||
16 | # include <stdint.h> | ||
17 | #endif | ||
18 | |||
19 | #include <linux/types_32_64.h> | ||
20 | 15 | ||
21 | enum rseq_cpu_id_state { | 16 | enum rseq_cpu_id_state { |
22 | RSEQ_CPU_ID_UNINITIALIZED = -1, | 17 | RSEQ_CPU_ID_UNINITIALIZED = -1, |
@@ -52,10 +47,10 @@ struct rseq_cs { | |||
52 | __u32 version; | 47 | __u32 version; |
53 | /* enum rseq_cs_flags */ | 48 | /* enum rseq_cs_flags */ |
54 | __u32 flags; | 49 | __u32 flags; |
55 | LINUX_FIELD_u32_u64(start_ip); | 50 | __u64 start_ip; |
56 | /* Offset from start_ip. */ | 51 | /* Offset from start_ip. */ |
57 | LINUX_FIELD_u32_u64(post_commit_offset); | 52 | __u64 post_commit_offset; |
58 | LINUX_FIELD_u32_u64(abort_ip); | 53 | __u64 abort_ip; |
59 | } __attribute__((aligned(4 * sizeof(__u64)))); | 54 | } __attribute__((aligned(4 * sizeof(__u64)))); |
60 | 55 | ||
61 | /* | 56 | /* |
@@ -67,28 +62,30 @@ struct rseq_cs { | |||
67 | struct rseq { | 62 | struct rseq { |
68 | /* | 63 | /* |
69 | * Restartable sequences cpu_id_start field. Updated by the | 64 | * Restartable sequences cpu_id_start field. Updated by the |
70 | * kernel, and read by user-space with single-copy atomicity | 65 | * kernel. Read by user-space with single-copy atomicity |
71 | * semantics. Aligned on 32-bit. Always contains a value in the | 66 | * semantics. This field should only be read by the thread which |
72 | * range of possible CPUs, although the value may not be the | 67 | * registered this data structure. Aligned on 32-bit. Always |
73 | * actual current CPU (e.g. if rseq is not initialized). This | 68 | * contains a value in the range of possible CPUs, although the |
74 | * CPU number value should always be compared against the value | 69 | * value may not be the actual current CPU (e.g. if rseq is not |
75 | * of the cpu_id field before performing a rseq commit or | 70 | * initialized). This CPU number value should always be compared |
76 | * returning a value read from a data structure indexed using | 71 | * against the value of the cpu_id field before performing a rseq |
77 | * the cpu_id_start value. | 72 | * commit or returning a value read from a data structure indexed |
73 | * using the cpu_id_start value. | ||
78 | */ | 74 | */ |
79 | __u32 cpu_id_start; | 75 | __u32 cpu_id_start; |
80 | /* | 76 | /* |
81 | * Restartable sequences cpu_id field. Updated by the kernel, | 77 | * Restartable sequences cpu_id field. Updated by the kernel. |
82 | * and read by user-space with single-copy atomicity semantics. | 78 | * Read by user-space with single-copy atomicity semantics. This |
83 | * Aligned on 32-bit. Values RSEQ_CPU_ID_UNINITIALIZED and | 79 | * field should only be read by the thread which registered this |
84 | * RSEQ_CPU_ID_REGISTRATION_FAILED have a special semantic: the | 80 | * data structure. Aligned on 32-bit. Values |
85 | * former means "rseq uninitialized", and latter means "rseq | 81 | * RSEQ_CPU_ID_UNINITIALIZED and RSEQ_CPU_ID_REGISTRATION_FAILED |
86 | * initialization failed". This value is meant to be read within | 82 | * have a special semantic: the former means "rseq uninitialized", |
87 | * rseq critical sections and compared with the cpu_id_start | 83 | * and latter means "rseq initialization failed". This value is |
88 | * value previously read, before performing the commit instruction, | 84 | * meant to be read within rseq critical sections and compared |
89 | * or read and compared with the cpu_id_start value before returning | 85 | * with the cpu_id_start value previously read, before performing |
90 | * a value loaded from a data structure indexed using the | 86 | * the commit instruction, or read and compared with the |
91 | * cpu_id_start value. | 87 | * cpu_id_start value before returning a value loaded from a data |
88 | * structure indexed using the cpu_id_start value. | ||
92 | */ | 89 | */ |
93 | __u32 cpu_id; | 90 | __u32 cpu_id; |
94 | /* | 91 | /* |
@@ -105,27 +102,44 @@ struct rseq { | |||
105 | * targeted by the rseq_cs. Also needs to be set to NULL by user-space | 102 | * targeted by the rseq_cs. Also needs to be set to NULL by user-space |
106 | * before reclaiming memory that contains the targeted struct rseq_cs. | 103 | * before reclaiming memory that contains the targeted struct rseq_cs. |
107 | * | 104 | * |
108 | * Read and set by the kernel with single-copy atomicity semantics. | 105 | * Read and set by the kernel. Set by user-space with single-copy |
109 | * Set by user-space with single-copy atomicity semantics. Aligned | 106 | * atomicity semantics. This field should only be updated by the |
110 | * on 64-bit. | 107 | * thread which registered this data structure. Aligned on 64-bit. |
111 | */ | 108 | */ |
112 | 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 | |||
113 | /* | 126 | /* |
114 | * - RSEQ_DISABLE flag: | 127 | * Restartable sequences flags field. |
128 | * | ||
129 | * This field should only be updated by the thread which | ||
130 | * registered this data structure. Read by the kernel. | ||
131 | * Mainly used for single-stepping through rseq critical sections | ||
132 | * with debuggers. | ||
115 | * | 133 | * |
116 | * Fallback fast-track flag for single-stepping. | ||
117 | * Set by user-space if lack of progress is detected. | ||
118 | * Cleared by user-space after rseq finish. | ||
119 | * Read by the kernel. | ||
120 | * - RSEQ_CS_FLAG_NO_RESTART_ON_PREEMPT | 134 | * - RSEQ_CS_FLAG_NO_RESTART_ON_PREEMPT |
121 | * Inhibit instruction sequence block restart and event | 135 | * Inhibit instruction sequence block restart on preemption |
122 | * counter increment on preemption for this thread. | 136 | * for this thread. |
123 | * - RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL | 137 | * - RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL |
124 | * Inhibit instruction sequence block restart and event | 138 | * Inhibit instruction sequence block restart on signal |
125 | * counter increment on signal delivery for this thread. | 139 | * delivery for this thread. |
126 | * - RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE | 140 | * - RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE |
127 | * Inhibit instruction sequence block restart and event | 141 | * Inhibit instruction sequence block restart on migration for |
128 | * counter increment on migration for this thread. | 142 | * this thread. |
129 | */ | 143 | */ |
130 | __u32 flags; | 144 | __u32 flags; |
131 | } __attribute__((aligned(4 * sizeof(__u64)))); | 145 | } __attribute__((aligned(4 * sizeof(__u64)))); |
diff --git a/include/uapi/linux/types_32_64.h b/include/uapi/linux/types_32_64.h deleted file mode 100644 index 0a87ace34a57..000000000000 --- a/include/uapi/linux/types_32_64.h +++ /dev/null | |||
@@ -1,50 +0,0 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */ | ||
2 | #ifndef _UAPI_LINUX_TYPES_32_64_H | ||
3 | #define _UAPI_LINUX_TYPES_32_64_H | ||
4 | |||
5 | /* | ||
6 | * linux/types_32_64.h | ||
7 | * | ||
8 | * Integer type declaration for pointers across 32-bit and 64-bit systems. | ||
9 | * | ||
10 | * Copyright (c) 2015-2018 Mathieu Desnoyers <mathieu.desnoyers@efficios.com> | ||
11 | */ | ||
12 | |||
13 | #ifdef __KERNEL__ | ||
14 | # include <linux/types.h> | ||
15 | #else | ||
16 | # include <stdint.h> | ||
17 | #endif | ||
18 | |||
19 | #include <asm/byteorder.h> | ||
20 | |||
21 | #ifdef __BYTE_ORDER | ||
22 | # if (__BYTE_ORDER == __BIG_ENDIAN) | ||
23 | # define LINUX_BYTE_ORDER_BIG_ENDIAN | ||
24 | # else | ||
25 | # define LINUX_BYTE_ORDER_LITTLE_ENDIAN | ||
26 | # endif | ||
27 | #else | ||
28 | # ifdef __BIG_ENDIAN | ||
29 | # define LINUX_BYTE_ORDER_BIG_ENDIAN | ||
30 | # else | ||
31 | # define LINUX_BYTE_ORDER_LITTLE_ENDIAN | ||
32 | # endif | ||
33 | #endif | ||
34 | |||
35 | #ifdef __LP64__ | ||
36 | # define LINUX_FIELD_u32_u64(field) __u64 field | ||
37 | # define LINUX_FIELD_u32_u64_INIT_ONSTACK(field, v) field = (intptr_t)v | ||
38 | #else | ||
39 | # ifdef LINUX_BYTE_ORDER_BIG_ENDIAN | ||
40 | # define LINUX_FIELD_u32_u64(field) __u32 field ## _padding, field | ||
41 | # define LINUX_FIELD_u32_u64_INIT_ONSTACK(field, v) \ | ||
42 | field ## _padding = 0, field = (intptr_t)v | ||
43 | # else | ||
44 | # define LINUX_FIELD_u32_u64(field) __u32 field, field ## _padding | ||
45 | # define LINUX_FIELD_u32_u64_INIT_ONSTACK(field, v) \ | ||
46 | field = (intptr_t)v, field ## _padding = 0 | ||
47 | # endif | ||
48 | #endif | ||
49 | |||
50 | #endif /* _UAPI_LINUX_TYPES_32_64_H */ | ||
diff --git a/kernel/rseq.c b/kernel/rseq.c index 22b6acf1ad63..c6242d8594dc 100644 --- a/kernel/rseq.c +++ b/kernel/rseq.c | |||
@@ -85,9 +85,9 @@ static int rseq_update_cpu_id(struct task_struct *t) | |||
85 | { | 85 | { |
86 | u32 cpu_id = raw_smp_processor_id(); | 86 | u32 cpu_id = raw_smp_processor_id(); |
87 | 87 | ||
88 | if (__put_user(cpu_id, &t->rseq->cpu_id_start)) | 88 | if (put_user(cpu_id, &t->rseq->cpu_id_start)) |
89 | return -EFAULT; | 89 | return -EFAULT; |
90 | if (__put_user(cpu_id, &t->rseq->cpu_id)) | 90 | if (put_user(cpu_id, &t->rseq->cpu_id)) |
91 | return -EFAULT; | 91 | return -EFAULT; |
92 | trace_rseq_update(t); | 92 | trace_rseq_update(t); |
93 | return 0; | 93 | return 0; |
@@ -100,14 +100,14 @@ static int rseq_reset_rseq_cpu_id(struct task_struct *t) | |||
100 | /* | 100 | /* |
101 | * Reset cpu_id_start to its initial state (0). | 101 | * Reset cpu_id_start to its initial state (0). |
102 | */ | 102 | */ |
103 | if (__put_user(cpu_id_start, &t->rseq->cpu_id_start)) | 103 | if (put_user(cpu_id_start, &t->rseq->cpu_id_start)) |
104 | return -EFAULT; | 104 | return -EFAULT; |
105 | /* | 105 | /* |
106 | * Reset cpu_id to RSEQ_CPU_ID_UNINITIALIZED, so any user coming | 106 | * Reset cpu_id to RSEQ_CPU_ID_UNINITIALIZED, so any user coming |
107 | * in after unregistration can figure out that rseq needs to be | 107 | * in after unregistration can figure out that rseq needs to be |
108 | * registered again. | 108 | * registered again. |
109 | */ | 109 | */ |
110 | if (__put_user(cpu_id, &t->rseq->cpu_id)) | 110 | if (put_user(cpu_id, &t->rseq->cpu_id)) |
111 | return -EFAULT; | 111 | return -EFAULT; |
112 | return 0; | 112 | return 0; |
113 | } | 113 | } |
@@ -115,29 +115,36 @@ static int rseq_reset_rseq_cpu_id(struct task_struct *t) | |||
115 | static int rseq_get_rseq_cs(struct task_struct *t, struct rseq_cs *rseq_cs) | 115 | static int rseq_get_rseq_cs(struct task_struct *t, struct rseq_cs *rseq_cs) |
116 | { | 116 | { |
117 | struct rseq_cs __user *urseq_cs; | 117 | struct rseq_cs __user *urseq_cs; |
118 | unsigned long ptr; | 118 | u64 ptr; |
119 | u32 __user *usig; | 119 | u32 __user *usig; |
120 | u32 sig; | 120 | u32 sig; |
121 | int ret; | 121 | int ret; |
122 | 122 | ||
123 | ret = __get_user(ptr, &t->rseq->rseq_cs); | 123 | if (copy_from_user(&ptr, &t->rseq->rseq_cs.ptr64, sizeof(ptr))) |
124 | if (ret) | 124 | return -EFAULT; |
125 | return ret; | ||
126 | if (!ptr) { | 125 | if (!ptr) { |
127 | memset(rseq_cs, 0, sizeof(*rseq_cs)); | 126 | memset(rseq_cs, 0, sizeof(*rseq_cs)); |
128 | return 0; | 127 | return 0; |
129 | } | 128 | } |
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; | ||
131 | if (copy_from_user(rseq_cs, urseq_cs, sizeof(*rseq_cs))) | 132 | if (copy_from_user(rseq_cs, urseq_cs, sizeof(*rseq_cs))) |
132 | return -EFAULT; | 133 | return -EFAULT; |
133 | if (rseq_cs->version > 0) | ||
134 | return -EINVAL; | ||
135 | 134 | ||
135 | if (rseq_cs->start_ip >= TASK_SIZE || | ||
136 | rseq_cs->start_ip + rseq_cs->post_commit_offset >= TASK_SIZE || | ||
137 | rseq_cs->abort_ip >= TASK_SIZE || | ||
138 | rseq_cs->version > 0) | ||
139 | return -EINVAL; | ||
140 | /* Check for overflow. */ | ||
141 | if (rseq_cs->start_ip + rseq_cs->post_commit_offset < rseq_cs->start_ip) | ||
142 | return -EINVAL; | ||
136 | /* Ensure that abort_ip is not in the critical section. */ | 143 | /* Ensure that abort_ip is not in the critical section. */ |
137 | if (rseq_cs->abort_ip - rseq_cs->start_ip < rseq_cs->post_commit_offset) | 144 | if (rseq_cs->abort_ip - rseq_cs->start_ip < rseq_cs->post_commit_offset) |
138 | return -EINVAL; | 145 | return -EINVAL; |
139 | 146 | ||
140 | usig = (u32 __user *)(rseq_cs->abort_ip - sizeof(u32)); | 147 | usig = (u32 __user *)(unsigned long)(rseq_cs->abort_ip - sizeof(u32)); |
141 | ret = get_user(sig, usig); | 148 | ret = get_user(sig, usig); |
142 | if (ret) | 149 | if (ret) |
143 | return ret; | 150 | return ret; |
@@ -146,7 +153,7 @@ static int rseq_get_rseq_cs(struct task_struct *t, struct rseq_cs *rseq_cs) | |||
146 | printk_ratelimited(KERN_WARNING | 153 | printk_ratelimited(KERN_WARNING |
147 | "Possible attack attempt. Unexpected rseq signature 0x%x, expecting 0x%x (pid=%d, addr=%p).\n", | 154 | "Possible attack attempt. Unexpected rseq signature 0x%x, expecting 0x%x (pid=%d, addr=%p).\n", |
148 | sig, current->rseq_sig, current->pid, usig); | 155 | sig, current->rseq_sig, current->pid, usig); |
149 | return -EPERM; | 156 | return -EINVAL; |
150 | } | 157 | } |
151 | return 0; | 158 | return 0; |
152 | } | 159 | } |
@@ -157,7 +164,7 @@ static int rseq_need_restart(struct task_struct *t, u32 cs_flags) | |||
157 | int ret; | 164 | int ret; |
158 | 165 | ||
159 | /* Get thread flags. */ | 166 | /* Get thread flags. */ |
160 | ret = __get_user(flags, &t->rseq->flags); | 167 | ret = get_user(flags, &t->rseq->flags); |
161 | if (ret) | 168 | if (ret) |
162 | return ret; | 169 | return ret; |
163 | 170 | ||
@@ -195,9 +202,11 @@ static int clear_rseq_cs(struct task_struct *t) | |||
195 | * of code outside of the rseq assembly block. This performs | 202 | * of code outside of the rseq assembly block. This performs |
196 | * a lazy clear of the rseq_cs field. | 203 | * a lazy clear of the rseq_cs field. |
197 | * | 204 | * |
198 | * Set rseq_cs to NULL with single-copy atomicity. | 205 | * Set rseq_cs to NULL. |
199 | */ | 206 | */ |
200 | 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; | ||
201 | } | 210 | } |
202 | 211 | ||
203 | /* | 212 | /* |
diff --git a/tools/testing/selftests/rseq/rseq.h b/tools/testing/selftests/rseq/rseq.h index a4684112676c..86ce22417e0d 100644 --- a/tools/testing/selftests/rseq/rseq.h +++ b/tools/testing/selftests/rseq/rseq.h | |||
@@ -133,17 +133,27 @@ static inline uint32_t rseq_current_cpu(void) | |||
133 | return cpu; | 133 | return cpu; |
134 | } | 134 | } |
135 | 135 | ||
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 | |||
136 | /* | 145 | /* |
137 | * rseq_prepare_unload() should be invoked by each thread using rseq_finish*() | 146 | * rseq_prepare_unload() should be invoked by each thread executing a rseq |
138 | * at least once between their last rseq_finish*() and library unload of the | 147 | * critical section at least once between their last critical section and |
139 | * library defining the rseq critical section (struct rseq_cs). This also | 148 | * library unload of the library defining the rseq critical section |
140 | * applies to use of rseq in code generated by JIT: rseq_prepare_unload() | 149 | * (struct rseq_cs). This also applies to use of rseq in code generated by |
141 | * should be invoked at least once by each thread using rseq_finish*() before | 150 | * JIT: rseq_prepare_unload() should be invoked at least once by each |
142 | * reclaim of the memory holding the struct rseq_cs. | 151 | * thread executing a rseq critical section before reclaim of the memory |
152 | * holding the struct rseq_cs. | ||
143 | */ | 153 | */ |
144 | static inline void rseq_prepare_unload(void) | 154 | static inline void rseq_prepare_unload(void) |
145 | { | 155 | { |
146 | __rseq_abi.rseq_cs = 0; | 156 | rseq_clear_rseq_cs(); |
147 | } | 157 | } |
148 | 158 | ||
149 | #endif /* RSEQ_H_ */ | 159 | #endif /* RSEQ_H_ */ |