aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2018-07-13 15:50:42 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2018-07-13 15:50:42 -0400
commitae4ea3975d97ab61a274718dc3642a8b2b459811 (patch)
tree3204e4062c65cd81bf248028a1fbd162c1b8e3c0
parent4659fc8484b707c161b14324df0e3a2f5d03f050 (diff)
parent8a46580128a02bdc18d7dcc0cba19d3cea4fb9c4 (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.h102
-rw-r--r--include/uapi/linux/types_32_64.h50
-rw-r--r--kernel/rseq.c41
-rw-r--r--tools/testing/selftests/rseq/rseq.h24
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
21enum rseq_cpu_id_state { 16enum 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 {
67struct rseq { 62struct 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)
115static int rseq_get_rseq_cs(struct task_struct *t, struct rseq_cs *rseq_cs) 115static 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
136static 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 */
144static inline void rseq_prepare_unload(void) 154static 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_ */