~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/kernel/rseq.c

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

Diff markup

Differences between /kernel/rseq.c (Version linux-6.12-rc7) and /kernel/rseq.c (Version linux-4.19.323)


  1 // SPDX-License-Identifier: GPL-2.0+                1 // SPDX-License-Identifier: GPL-2.0+
  2 /*                                                  2 /*
  3  * Restartable sequences system call                3  * Restartable sequences system call
  4  *                                                  4  *
  5  * Copyright (C) 2015, Google, Inc.,                5  * Copyright (C) 2015, Google, Inc.,
  6  * Paul Turner <pjt@google.com> and Andrew Hun      6  * Paul Turner <pjt@google.com> and Andrew Hunter <ahh@google.com>
  7  * Copyright (C) 2015-2018, EfficiOS Inc.,          7  * Copyright (C) 2015-2018, EfficiOS Inc.,
  8  * Mathieu Desnoyers <mathieu.desnoyers@effici      8  * Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
  9  */                                                 9  */
 10                                                    10 
 11 #include <linux/sched.h>                           11 #include <linux/sched.h>
 12 #include <linux/uaccess.h>                         12 #include <linux/uaccess.h>
 13 #include <linux/syscalls.h>                        13 #include <linux/syscalls.h>
 14 #include <linux/rseq.h>                            14 #include <linux/rseq.h>
 15 #include <linux/types.h>                           15 #include <linux/types.h>
 16 #include <asm/ptrace.h>                            16 #include <asm/ptrace.h>
 17                                                    17 
 18 #define CREATE_TRACE_POINTS                        18 #define CREATE_TRACE_POINTS
 19 #include <trace/events/rseq.h>                     19 #include <trace/events/rseq.h>
 20                                                    20 
 21 /* The original rseq structure size (including !!  21 #define RSEQ_CS_PREEMPT_MIGRATE_FLAGS (RSEQ_CS_FLAG_NO_RESTART_ON_MIGRATE | \
 22 #define ORIG_RSEQ_SIZE          32             !!  22                                        RSEQ_CS_FLAG_NO_RESTART_ON_PREEMPT)
 23                                                << 
 24 #define RSEQ_CS_NO_RESTART_FLAGS (RSEQ_CS_FLAG << 
 25                                   RSEQ_CS_FLAG << 
 26                                   RSEQ_CS_FLAG << 
 27                                                    23 
 28 /*                                                 24 /*
 29  *                                                 25  *
 30  * Restartable sequences are a lightweight int     26  * Restartable sequences are a lightweight interface that allows
 31  * user-level code to be executed atomically r     27  * user-level code to be executed atomically relative to scheduler
 32  * preemption and signal delivery. Typically u     28  * preemption and signal delivery. Typically used for implementing
 33  * per-cpu operations.                             29  * per-cpu operations.
 34  *                                                 30  *
 35  * It allows user-space to perform update oper     31  * It allows user-space to perform update operations on per-cpu data
 36  * without requiring heavy-weight atomic opera     32  * without requiring heavy-weight atomic operations.
 37  *                                                 33  *
 38  * Detailed algorithm of rseq user-space assem     34  * Detailed algorithm of rseq user-space assembly sequences:
 39  *                                                 35  *
 40  *                     init(rseq_cs)               36  *                     init(rseq_cs)
 41  *                     cpu = TLS->rseq::cpu_id     37  *                     cpu = TLS->rseq::cpu_id_start
 42  *   [1]               TLS->rseq::rseq_cs = rs     38  *   [1]               TLS->rseq::rseq_cs = rseq_cs
 43  *   [start_ip]        -----------------------     39  *   [start_ip]        ----------------------------
 44  *   [2]               if (cpu != TLS->rseq::c     40  *   [2]               if (cpu != TLS->rseq::cpu_id)
 45  *                             goto abort_ip;      41  *                             goto abort_ip;
 46  *   [3]               <last_instruction_in_cs     42  *   [3]               <last_instruction_in_cs>
 47  *   [post_commit_ip]  -----------------------     43  *   [post_commit_ip]  ----------------------------
 48  *                                                 44  *
 49  *   The address of jump target abort_ip must      45  *   The address of jump target abort_ip must be outside the critical
 50  *   region, i.e.:                                 46  *   region, i.e.:
 51  *                                                 47  *
 52  *     [abort_ip] < [start_ip]  || [abort_ip]      48  *     [abort_ip] < [start_ip]  || [abort_ip] >= [post_commit_ip]
 53  *                                                 49  *
 54  *   Steps [2]-[3] (inclusive) need to be a se     50  *   Steps [2]-[3] (inclusive) need to be a sequence of instructions in
 55  *   userspace that can handle being interrupt     51  *   userspace that can handle being interrupted between any of those
 56  *   instructions, and then resumed to the abo     52  *   instructions, and then resumed to the abort_ip.
 57  *                                                 53  *
 58  *   1.  Userspace stores the address of the s     54  *   1.  Userspace stores the address of the struct rseq_cs assembly
 59  *       block descriptor into the rseq_cs fie     55  *       block descriptor into the rseq_cs field of the registered
 60  *       struct rseq TLS area. This update is      56  *       struct rseq TLS area. This update is performed through a single
 61  *       store within the inline assembly inst     57  *       store within the inline assembly instruction sequence.
 62  *       [start_ip]                                58  *       [start_ip]
 63  *                                                 59  *
 64  *   2.  Userspace tests to check whether the      60  *   2.  Userspace tests to check whether the current cpu_id field match
 65  *       the cpu number loaded before start_ip     61  *       the cpu number loaded before start_ip, branching to abort_ip
 66  *       in case of a mismatch.                    62  *       in case of a mismatch.
 67  *                                                 63  *
 68  *       If the sequence is preempted or inter     64  *       If the sequence is preempted or interrupted by a signal
 69  *       at or after start_ip and before post_     65  *       at or after start_ip and before post_commit_ip, then the kernel
 70  *       clears TLS->__rseq_abi::rseq_cs, and      66  *       clears TLS->__rseq_abi::rseq_cs, and sets the user-space return
 71  *       ip to abort_ip before returning to us     67  *       ip to abort_ip before returning to user-space, so the preempted
 72  *       execution resumes at abort_ip.            68  *       execution resumes at abort_ip.
 73  *                                                 69  *
 74  *   3.  Userspace critical section final inst     70  *   3.  Userspace critical section final instruction before
 75  *       post_commit_ip is the commit. The cri     71  *       post_commit_ip is the commit. The critical section is
 76  *       self-terminating.                         72  *       self-terminating.
 77  *       [post_commit_ip]                          73  *       [post_commit_ip]
 78  *                                                 74  *
 79  *   4.  <success>                                 75  *   4.  <success>
 80  *                                                 76  *
 81  *   On failure at [2], or if interrupted by p     77  *   On failure at [2], or if interrupted by preempt or signal delivery
 82  *   between [1] and [3]:                          78  *   between [1] and [3]:
 83  *                                                 79  *
 84  *       [abort_ip]                                80  *       [abort_ip]
 85  *   F1. <failure>                                 81  *   F1. <failure>
 86  */                                                82  */
 87                                                    83 
 88 static int rseq_update_cpu_node_id(struct task !!  84 static int rseq_update_cpu_id(struct task_struct *t)
 89 {                                                  85 {
 90         struct rseq __user *rseq = t->rseq;    << 
 91         u32 cpu_id = raw_smp_processor_id();       86         u32 cpu_id = raw_smp_processor_id();
 92         u32 node_id = cpu_to_node(cpu_id);     << 
 93         u32 mm_cid = task_mm_cid(t);           << 
 94                                                    87 
 95         WARN_ON_ONCE((int) mm_cid < 0);        !!  88         if (put_user(cpu_id, &t->rseq->cpu_id_start))
 96         if (!user_write_access_begin(rseq, t-> !!  89                 return -EFAULT;
 97                 goto efault;                   !!  90         if (put_user(cpu_id, &t->rseq->cpu_id))
 98         unsafe_put_user(cpu_id, &rseq->cpu_id_ !!  91                 return -EFAULT;
 99         unsafe_put_user(cpu_id, &rseq->cpu_id, << 
100         unsafe_put_user(node_id, &rseq->node_i << 
101         unsafe_put_user(mm_cid, &rseq->mm_cid, << 
102         /*                                     << 
103          * Additional feature fields added aft << 
104          * need to be conditionally updated on << 
105          * t->rseq_len != ORIG_RSEQ_SIZE.      << 
106          */                                    << 
107         user_write_access_end();               << 
108         trace_rseq_update(t);                      92         trace_rseq_update(t);
109         return 0;                                  93         return 0;
110                                                << 
111 efault_end:                                    << 
112         user_write_access_end();               << 
113 efault:                                        << 
114         return -EFAULT;                        << 
115 }                                                  94 }
116                                                    95 
117 static int rseq_reset_rseq_cpu_node_id(struct  !!  96 static int rseq_reset_rseq_cpu_id(struct task_struct *t)
118 {                                                  97 {
119         u32 cpu_id_start = 0, cpu_id = RSEQ_CP !!  98         u32 cpu_id_start = 0, cpu_id = RSEQ_CPU_ID_UNINITIALIZED;
120             mm_cid = 0;                        << 
121                                                    99 
122         /*                                        100         /*
123          * Reset cpu_id_start to its initial s    101          * Reset cpu_id_start to its initial state (0).
124          */                                       102          */
125         if (put_user(cpu_id_start, &t->rseq->c    103         if (put_user(cpu_id_start, &t->rseq->cpu_id_start))
126                 return -EFAULT;                   104                 return -EFAULT;
127         /*                                        105         /*
128          * Reset cpu_id to RSEQ_CPU_ID_UNINITI    106          * Reset cpu_id to RSEQ_CPU_ID_UNINITIALIZED, so any user coming
129          * in after unregistration can figure     107          * in after unregistration can figure out that rseq needs to be
130          * registered again.                      108          * registered again.
131          */                                       109          */
132         if (put_user(cpu_id, &t->rseq->cpu_id)    110         if (put_user(cpu_id, &t->rseq->cpu_id))
133                 return -EFAULT;                   111                 return -EFAULT;
134         /*                                     << 
135          * Reset node_id to its initial state  << 
136          */                                    << 
137         if (put_user(node_id, &t->rseq->node_i << 
138                 return -EFAULT;                << 
139         /*                                     << 
140          * Reset mm_cid to its initial state ( << 
141          */                                    << 
142         if (put_user(mm_cid, &t->rseq->mm_cid) << 
143                 return -EFAULT;                << 
144         /*                                     << 
145          * Additional feature fields added aft << 
146          * need to be conditionally reset only << 
147          * t->rseq_len != ORIG_RSEQ_SIZE.      << 
148          */                                    << 
149         return 0;                                 112         return 0;
150 }                                                 113 }
151                                                   114 
152 static int rseq_get_rseq_cs(struct task_struct    115 static int rseq_get_rseq_cs(struct task_struct *t, struct rseq_cs *rseq_cs)
153 {                                                 116 {
154         struct rseq_cs __user *urseq_cs;          117         struct rseq_cs __user *urseq_cs;
155         u64 ptr;                                  118         u64 ptr;
156         u32 __user *usig;                         119         u32 __user *usig;
157         u32 sig;                                  120         u32 sig;
158         int ret;                                  121         int ret;
159                                                   122 
160 #ifdef CONFIG_64BIT                            !! 123         if (copy_from_user(&ptr, &t->rseq->rseq_cs.ptr64, sizeof(ptr)))
161         if (get_user(ptr, &t->rseq->rseq_cs))  << 
162                 return -EFAULT;                << 
163 #else                                          << 
164         if (copy_from_user(&ptr, &t->rseq->rse << 
165                 return -EFAULT;                   124                 return -EFAULT;
166 #endif                                         << 
167         if (!ptr) {                               125         if (!ptr) {
168                 memset(rseq_cs, 0, sizeof(*rse    126                 memset(rseq_cs, 0, sizeof(*rseq_cs));
169                 return 0;                         127                 return 0;
170         }                                         128         }
171         if (ptr >= TASK_SIZE)                     129         if (ptr >= TASK_SIZE)
172                 return -EINVAL;                   130                 return -EINVAL;
173         urseq_cs = (struct rseq_cs __user *)(u    131         urseq_cs = (struct rseq_cs __user *)(unsigned long)ptr;
174         if (copy_from_user(rseq_cs, urseq_cs,     132         if (copy_from_user(rseq_cs, urseq_cs, sizeof(*rseq_cs)))
175                 return -EFAULT;                   133                 return -EFAULT;
176                                                   134 
177         if (rseq_cs->start_ip >= TASK_SIZE ||     135         if (rseq_cs->start_ip >= TASK_SIZE ||
178             rseq_cs->start_ip + rseq_cs->post_    136             rseq_cs->start_ip + rseq_cs->post_commit_offset >= TASK_SIZE ||
179             rseq_cs->abort_ip >= TASK_SIZE ||     137             rseq_cs->abort_ip >= TASK_SIZE ||
180             rseq_cs->version > 0)                 138             rseq_cs->version > 0)
181                 return -EINVAL;                   139                 return -EINVAL;
182         /* Check for overflow. */                 140         /* Check for overflow. */
183         if (rseq_cs->start_ip + rseq_cs->post_    141         if (rseq_cs->start_ip + rseq_cs->post_commit_offset < rseq_cs->start_ip)
184                 return -EINVAL;                   142                 return -EINVAL;
185         /* Ensure that abort_ip is not in the     143         /* Ensure that abort_ip is not in the critical section. */
186         if (rseq_cs->abort_ip - rseq_cs->start    144         if (rseq_cs->abort_ip - rseq_cs->start_ip < rseq_cs->post_commit_offset)
187                 return -EINVAL;                   145                 return -EINVAL;
188                                                   146 
189         usig = (u32 __user *)(unsigned long)(r    147         usig = (u32 __user *)(unsigned long)(rseq_cs->abort_ip - sizeof(u32));
190         ret = get_user(sig, usig);                148         ret = get_user(sig, usig);
191         if (ret)                                  149         if (ret)
192                 return ret;                       150                 return ret;
193                                                   151 
194         if (current->rseq_sig != sig) {           152         if (current->rseq_sig != sig) {
195                 printk_ratelimited(KERN_WARNIN    153                 printk_ratelimited(KERN_WARNING
196                         "Possible attack attem    154                         "Possible attack attempt. Unexpected rseq signature 0x%x, expecting 0x%x (pid=%d, addr=%p).\n",
197                         sig, current->rseq_sig    155                         sig, current->rseq_sig, current->pid, usig);
198                 return -EINVAL;                   156                 return -EINVAL;
199         }                                         157         }
200         return 0;                                 158         return 0;
201 }                                                 159 }
202                                                   160 
203 static bool rseq_warn_flags(const char *str, u << 
204 {                                              << 
205         u32 test_flags;                        << 
206                                                << 
207         if (!flags)                            << 
208                 return false;                  << 
209         test_flags = flags & RSEQ_CS_NO_RESTAR << 
210         if (test_flags)                        << 
211                 pr_warn_once("Deprecated flags << 
212         test_flags = flags & ~RSEQ_CS_NO_RESTA << 
213         if (test_flags)                        << 
214                 pr_warn_once("Unknown flags (% << 
215         return true;                           << 
216 }                                              << 
217                                                << 
218 static int rseq_need_restart(struct task_struc    161 static int rseq_need_restart(struct task_struct *t, u32 cs_flags)
219 {                                                 162 {
220         u32 flags, event_mask;                    163         u32 flags, event_mask;
221         int ret;                                  164         int ret;
222                                                   165 
223         if (rseq_warn_flags("rseq_cs", cs_flag << 
224                 return -EINVAL;                << 
225                                                << 
226         /* Get thread flags. */                   166         /* Get thread flags. */
227         ret = get_user(flags, &t->rseq->flags)    167         ret = get_user(flags, &t->rseq->flags);
228         if (ret)                                  168         if (ret)
229                 return ret;                       169                 return ret;
230                                                   170 
231         if (rseq_warn_flags("rseq", flags))    !! 171         /* Take critical section flags into account. */
                                                   >> 172         flags |= cs_flags;
                                                   >> 173 
                                                   >> 174         /*
                                                   >> 175          * Restart on signal can only be inhibited when restart on
                                                   >> 176          * preempt and restart on migrate are inhibited too. Otherwise,
                                                   >> 177          * a preempted signal handler could fail to restart the prior
                                                   >> 178          * execution context on sigreturn.
                                                   >> 179          */
                                                   >> 180         if (unlikely((flags & RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL) &&
                                                   >> 181                      (flags & RSEQ_CS_PREEMPT_MIGRATE_FLAGS) !=
                                                   >> 182                      RSEQ_CS_PREEMPT_MIGRATE_FLAGS))
232                 return -EINVAL;                   183                 return -EINVAL;
233                                                   184 
234         /*                                        185         /*
235          * Load and clear event mask atomicall    186          * Load and clear event mask atomically with respect to
236          * scheduler preemption.                  187          * scheduler preemption.
237          */                                       188          */
238         preempt_disable();                        189         preempt_disable();
239         event_mask = t->rseq_event_mask;          190         event_mask = t->rseq_event_mask;
240         t->rseq_event_mask = 0;                   191         t->rseq_event_mask = 0;
241         preempt_enable();                         192         preempt_enable();
242                                                   193 
243         return !!event_mask;                   !! 194         return !!(event_mask & ~flags);
244 }                                                 195 }
245                                                   196 
246 static int clear_rseq_cs(struct task_struct *t    197 static int clear_rseq_cs(struct task_struct *t)
247 {                                                 198 {
248         /*                                        199         /*
249          * The rseq_cs field is set to NULL on    200          * The rseq_cs field is set to NULL on preemption or signal
250          * delivery on top of rseq assembly bl    201          * delivery on top of rseq assembly block, as well as on top
251          * of code outside of the rseq assembl    202          * of code outside of the rseq assembly block. This performs
252          * a lazy clear of the rseq_cs field.     203          * a lazy clear of the rseq_cs field.
253          *                                        204          *
254          * Set rseq_cs to NULL.                   205          * Set rseq_cs to NULL.
255          */                                       206          */
256 #ifdef CONFIG_64BIT                            !! 207         if (clear_user(&t->rseq->rseq_cs.ptr64, sizeof(t->rseq->rseq_cs.ptr64)))
257         return put_user(0UL, &t->rseq->rseq_cs << 
258 #else                                          << 
259         if (clear_user(&t->rseq->rseq_cs, size << 
260                 return -EFAULT;                   208                 return -EFAULT;
261         return 0;                                 209         return 0;
262 #endif                                         << 
263 }                                                 210 }
264                                                   211 
265 /*                                                212 /*
266  * Unsigned comparison will be true when ip >=    213  * Unsigned comparison will be true when ip >= start_ip, and when
267  * ip < start_ip + post_commit_offset.            214  * ip < start_ip + post_commit_offset.
268  */                                               215  */
269 static bool in_rseq_cs(unsigned long ip, struc    216 static bool in_rseq_cs(unsigned long ip, struct rseq_cs *rseq_cs)
270 {                                                 217 {
271         return ip - rseq_cs->start_ip < rseq_c    218         return ip - rseq_cs->start_ip < rseq_cs->post_commit_offset;
272 }                                                 219 }
273                                                   220 
274 static int rseq_ip_fixup(struct pt_regs *regs)    221 static int rseq_ip_fixup(struct pt_regs *regs)
275 {                                                 222 {
276         unsigned long ip = instruction_pointer    223         unsigned long ip = instruction_pointer(regs);
277         struct task_struct *t = current;          224         struct task_struct *t = current;
278         struct rseq_cs rseq_cs;                   225         struct rseq_cs rseq_cs;
279         int ret;                                  226         int ret;
280                                                   227 
281         ret = rseq_get_rseq_cs(t, &rseq_cs);      228         ret = rseq_get_rseq_cs(t, &rseq_cs);
282         if (ret)                                  229         if (ret)
283                 return ret;                       230                 return ret;
284                                                   231 
285         /*                                        232         /*
286          * Handle potentially not being within    233          * Handle potentially not being within a critical section.
287          * If not nested over a rseq critical     234          * If not nested over a rseq critical section, restart is useless.
288          * Clear the rseq_cs pointer and retur    235          * Clear the rseq_cs pointer and return.
289          */                                       236          */
290         if (!in_rseq_cs(ip, &rseq_cs))            237         if (!in_rseq_cs(ip, &rseq_cs))
291                 return clear_rseq_cs(t);          238                 return clear_rseq_cs(t);
292         ret = rseq_need_restart(t, rseq_cs.fla    239         ret = rseq_need_restart(t, rseq_cs.flags);
293         if (ret <= 0)                             240         if (ret <= 0)
294                 return ret;                       241                 return ret;
295         ret = clear_rseq_cs(t);                   242         ret = clear_rseq_cs(t);
296         if (ret)                                  243         if (ret)
297                 return ret;                       244                 return ret;
298         trace_rseq_ip_fixup(ip, rseq_cs.start_    245         trace_rseq_ip_fixup(ip, rseq_cs.start_ip, rseq_cs.post_commit_offset,
299                             rseq_cs.abort_ip);    246                             rseq_cs.abort_ip);
300         instruction_pointer_set(regs, (unsigne    247         instruction_pointer_set(regs, (unsigned long)rseq_cs.abort_ip);
301         return 0;                                 248         return 0;
302 }                                                 249 }
303                                                   250 
304 /*                                                251 /*
305  * This resume handler must always be executed    252  * This resume handler must always be executed between any of:
306  * - preemption,                                  253  * - preemption,
307  * - signal delivery,                             254  * - signal delivery,
308  * and return to user-space.                      255  * and return to user-space.
309  *                                                256  *
310  * This is how we can ensure that the entire r !! 257  * This is how we can ensure that the entire rseq critical section,
                                                   >> 258  * consisting of both the C part and the assembly instruction sequence,
311  * will issue the commit instruction only if e    259  * will issue the commit instruction only if executed atomically with
312  * respect to other threads scheduled on the s    260  * respect to other threads scheduled on the same CPU, and with respect
313  * to signal handlers.                            261  * to signal handlers.
314  */                                               262  */
315 void __rseq_handle_notify_resume(struct ksigna    263 void __rseq_handle_notify_resume(struct ksignal *ksig, struct pt_regs *regs)
316 {                                                 264 {
317         struct task_struct *t = current;          265         struct task_struct *t = current;
318         int ret, sig;                             266         int ret, sig;
319                                                   267 
320         if (unlikely(t->flags & PF_EXITING))      268         if (unlikely(t->flags & PF_EXITING))
321                 return;                           269                 return;
322                                                !! 270         if (unlikely(!access_ok(VERIFY_WRITE, t->rseq, sizeof(*t->rseq))))
323         /*                                     !! 271                 goto error;
324          * regs is NULL if and only if the cal !! 272         ret = rseq_ip_fixup(regs);
325          * fixup and leave rseq_cs as is so th !! 273         if (unlikely(ret < 0))
326          * kill a misbehaving userspace on deb !! 274                 goto error;
327          */                                    !! 275         if (unlikely(rseq_update_cpu_id(t)))
328         if (regs) {                            << 
329                 ret = rseq_ip_fixup(regs);     << 
330                 if (unlikely(ret < 0))         << 
331                         goto error;            << 
332         }                                      << 
333         if (unlikely(rseq_update_cpu_node_id(t << 
334                 goto error;                       276                 goto error;
335         return;                                   277         return;
336                                                   278 
337 error:                                            279 error:
338         sig = ksig ? ksig->sig : 0;               280         sig = ksig ? ksig->sig : 0;
339         force_sigsegv(sig);                    !! 281         force_sigsegv(sig, t);
340 }                                                 282 }
341                                                   283 
342 #ifdef CONFIG_DEBUG_RSEQ                          284 #ifdef CONFIG_DEBUG_RSEQ
343                                                   285 
344 /*                                                286 /*
345  * Terminate the process if a syscall is issue    287  * Terminate the process if a syscall is issued within a restartable
346  * sequence.                                      288  * sequence.
347  */                                               289  */
348 void rseq_syscall(struct pt_regs *regs)           290 void rseq_syscall(struct pt_regs *regs)
349 {                                                 291 {
350         unsigned long ip = instruction_pointer    292         unsigned long ip = instruction_pointer(regs);
351         struct task_struct *t = current;          293         struct task_struct *t = current;
352         struct rseq_cs rseq_cs;                   294         struct rseq_cs rseq_cs;
353                                                   295 
354         if (!t->rseq)                             296         if (!t->rseq)
355                 return;                           297                 return;
356         if (rseq_get_rseq_cs(t, &rseq_cs) || i !! 298         if (!access_ok(VERIFY_READ, t->rseq, sizeof(*t->rseq)) ||
357                 force_sig(SIGSEGV);            !! 299             rseq_get_rseq_cs(t, &rseq_cs) || in_rseq_cs(ip, &rseq_cs))
                                                   >> 300                 force_sig(SIGSEGV, t);
358 }                                                 301 }
359                                                   302 
360 #endif                                            303 #endif
361                                                   304 
362 /*                                                305 /*
363  * sys_rseq - setup restartable sequences for     306  * sys_rseq - setup restartable sequences for caller thread.
364  */                                               307  */
365 SYSCALL_DEFINE4(rseq, struct rseq __user *, rs    308 SYSCALL_DEFINE4(rseq, struct rseq __user *, rseq, u32, rseq_len,
366                 int, flags, u32, sig)             309                 int, flags, u32, sig)
367 {                                                 310 {
368         int ret;                                  311         int ret;
369                                                   312 
370         if (flags & RSEQ_FLAG_UNREGISTER) {       313         if (flags & RSEQ_FLAG_UNREGISTER) {
371                 if (flags & ~RSEQ_FLAG_UNREGIS << 
372                         return -EINVAL;        << 
373                 /* Unregister rseq for current    314                 /* Unregister rseq for current thread. */
374                 if (current->rseq != rseq || !    315                 if (current->rseq != rseq || !current->rseq)
375                         return -EINVAL;           316                         return -EINVAL;
376                 if (rseq_len != current->rseq_ !! 317                 if (current->rseq_len != rseq_len)
377                         return -EINVAL;           318                         return -EINVAL;
378                 if (current->rseq_sig != sig)     319                 if (current->rseq_sig != sig)
379                         return -EPERM;            320                         return -EPERM;
380                 ret = rseq_reset_rseq_cpu_node !! 321                 ret = rseq_reset_rseq_cpu_id(current);
381                 if (ret)                          322                 if (ret)
382                         return ret;               323                         return ret;
383                 current->rseq = NULL;             324                 current->rseq = NULL;
384                 current->rseq_sig = 0;         << 
385                 current->rseq_len = 0;            325                 current->rseq_len = 0;
                                                   >> 326                 current->rseq_sig = 0;
386                 return 0;                         327                 return 0;
387         }                                         328         }
388                                                   329 
389         if (unlikely(flags))                      330         if (unlikely(flags))
390                 return -EINVAL;                   331                 return -EINVAL;
391                                                   332 
392         if (current->rseq) {                      333         if (current->rseq) {
393                 /*                                334                 /*
394                  * If rseq is already register    335                  * If rseq is already registered, check whether
395                  * the provided address differ    336                  * the provided address differs from the prior
396                  * one.                           337                  * one.
397                  */                               338                  */
398                 if (current->rseq != rseq || r !! 339                 if (current->rseq != rseq || current->rseq_len != rseq_len)
399                         return -EINVAL;           340                         return -EINVAL;
400                 if (current->rseq_sig != sig)     341                 if (current->rseq_sig != sig)
401                         return -EPERM;            342                         return -EPERM;
402                 /* Already registered. */         343                 /* Already registered. */
403                 return -EBUSY;                    344                 return -EBUSY;
404         }                                         345         }
405                                                   346 
406         /*                                        347         /*
407          * If there was no rseq previously reg !! 348          * If there was no rseq previously registered,
408          * is properly aligned, as communcated !! 349          * ensure the provided rseq is properly aligned and valid.
409          * auxiliary vector AT_RSEQ_ALIGN. If  << 
410          * size, the required alignment is the << 
411          *                                     << 
412          * In order to be valid, rseq_len is e << 
413          * large enough to contain all support << 
414          * user-space through the ELF auxiliar << 
415          */                                       350          */
416         if (rseq_len < ORIG_RSEQ_SIZE ||       !! 351         if (!IS_ALIGNED((unsigned long)rseq, __alignof__(*rseq)) ||
417             (rseq_len == ORIG_RSEQ_SIZE && !IS !! 352             rseq_len != sizeof(*rseq))
418             (rseq_len != ORIG_RSEQ_SIZE && (!I << 
419                                             rs << 
420                 return -EINVAL;                   353                 return -EINVAL;
421         if (!access_ok(rseq, rseq_len))        !! 354         if (!access_ok(VERIFY_WRITE, rseq, rseq_len))
422                 return -EFAULT;                   355                 return -EFAULT;
423         current->rseq = rseq;                     356         current->rseq = rseq;
424         current->rseq_len = rseq_len;             357         current->rseq_len = rseq_len;
425         current->rseq_sig = sig;                  358         current->rseq_sig = sig;
426         /*                                        359         /*
427          * If rseq was previously inactive, an    360          * If rseq was previously inactive, and has just been
428          * registered, ensure the cpu_id_start    361          * registered, ensure the cpu_id_start and cpu_id fields
429          * are updated before returning to use    362          * are updated before returning to user-space.
430          */                                       363          */
431         rseq_set_notify_resume(current);          364         rseq_set_notify_resume(current);
432                                                   365 
433         return 0;                                 366         return 0;
434 }                                                 367 }
435                                                   368 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php