~ [ 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-5.16.20)


  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);     !!  87         struct rseq __user *rseq = t->rseq;
 93         u32 mm_cid = task_mm_cid(t);           << 
 94                                                    88 
 95         WARN_ON_ONCE((int) mm_cid < 0);        !!  89         if (!user_write_access_begin(rseq, sizeof(*rseq)))
 96         if (!user_write_access_begin(rseq, t-> << 
 97                 goto efault;                       90                 goto efault;
 98         unsafe_put_user(cpu_id, &rseq->cpu_id_     91         unsafe_put_user(cpu_id, &rseq->cpu_id_start, efault_end);
 99         unsafe_put_user(cpu_id, &rseq->cpu_id,     92         unsafe_put_user(cpu_id, &rseq->cpu_id, efault_end);
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();                   93         user_write_access_end();
108         trace_rseq_update(t);                      94         trace_rseq_update(t);
109         return 0;                                  95         return 0;
110                                                    96 
111 efault_end:                                        97 efault_end:
112         user_write_access_end();                   98         user_write_access_end();
113 efault:                                            99 efault:
114         return -EFAULT;                           100         return -EFAULT;
115 }                                                 101 }
116                                                   102 
117 static int rseq_reset_rseq_cpu_node_id(struct  !! 103 static int rseq_reset_rseq_cpu_id(struct task_struct *t)
118 {                                                 104 {
119         u32 cpu_id_start = 0, cpu_id = RSEQ_CP !! 105         u32 cpu_id_start = 0, cpu_id = RSEQ_CPU_ID_UNINITIALIZED;
120             mm_cid = 0;                        << 
121                                                   106 
122         /*                                        107         /*
123          * Reset cpu_id_start to its initial s    108          * Reset cpu_id_start to its initial state (0).
124          */                                       109          */
125         if (put_user(cpu_id_start, &t->rseq->c    110         if (put_user(cpu_id_start, &t->rseq->cpu_id_start))
126                 return -EFAULT;                   111                 return -EFAULT;
127         /*                                        112         /*
128          * Reset cpu_id to RSEQ_CPU_ID_UNINITI    113          * Reset cpu_id to RSEQ_CPU_ID_UNINITIALIZED, so any user coming
129          * in after unregistration can figure     114          * in after unregistration can figure out that rseq needs to be
130          * registered again.                      115          * registered again.
131          */                                       116          */
132         if (put_user(cpu_id, &t->rseq->cpu_id)    117         if (put_user(cpu_id, &t->rseq->cpu_id))
133                 return -EFAULT;                   118                 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;                                 119         return 0;
150 }                                                 120 }
151                                                   121 
152 static int rseq_get_rseq_cs(struct task_struct    122 static int rseq_get_rseq_cs(struct task_struct *t, struct rseq_cs *rseq_cs)
153 {                                                 123 {
154         struct rseq_cs __user *urseq_cs;          124         struct rseq_cs __user *urseq_cs;
155         u64 ptr;                                  125         u64 ptr;
156         u32 __user *usig;                         126         u32 __user *usig;
157         u32 sig;                                  127         u32 sig;
158         int ret;                                  128         int ret;
159                                                   129 
160 #ifdef CONFIG_64BIT                               130 #ifdef CONFIG_64BIT
161         if (get_user(ptr, &t->rseq->rseq_cs))     131         if (get_user(ptr, &t->rseq->rseq_cs))
162                 return -EFAULT;                   132                 return -EFAULT;
163 #else                                             133 #else
164         if (copy_from_user(&ptr, &t->rseq->rse    134         if (copy_from_user(&ptr, &t->rseq->rseq_cs, sizeof(ptr)))
165                 return -EFAULT;                   135                 return -EFAULT;
166 #endif                                            136 #endif
167         if (!ptr) {                               137         if (!ptr) {
168                 memset(rseq_cs, 0, sizeof(*rse    138                 memset(rseq_cs, 0, sizeof(*rseq_cs));
169                 return 0;                         139                 return 0;
170         }                                         140         }
171         if (ptr >= TASK_SIZE)                     141         if (ptr >= TASK_SIZE)
172                 return -EINVAL;                   142                 return -EINVAL;
173         urseq_cs = (struct rseq_cs __user *)(u    143         urseq_cs = (struct rseq_cs __user *)(unsigned long)ptr;
174         if (copy_from_user(rseq_cs, urseq_cs,     144         if (copy_from_user(rseq_cs, urseq_cs, sizeof(*rseq_cs)))
175                 return -EFAULT;                   145                 return -EFAULT;
176                                                   146 
177         if (rseq_cs->start_ip >= TASK_SIZE ||     147         if (rseq_cs->start_ip >= TASK_SIZE ||
178             rseq_cs->start_ip + rseq_cs->post_    148             rseq_cs->start_ip + rseq_cs->post_commit_offset >= TASK_SIZE ||
179             rseq_cs->abort_ip >= TASK_SIZE ||     149             rseq_cs->abort_ip >= TASK_SIZE ||
180             rseq_cs->version > 0)                 150             rseq_cs->version > 0)
181                 return -EINVAL;                   151                 return -EINVAL;
182         /* Check for overflow. */                 152         /* Check for overflow. */
183         if (rseq_cs->start_ip + rseq_cs->post_    153         if (rseq_cs->start_ip + rseq_cs->post_commit_offset < rseq_cs->start_ip)
184                 return -EINVAL;                   154                 return -EINVAL;
185         /* Ensure that abort_ip is not in the     155         /* Ensure that abort_ip is not in the critical section. */
186         if (rseq_cs->abort_ip - rseq_cs->start    156         if (rseq_cs->abort_ip - rseq_cs->start_ip < rseq_cs->post_commit_offset)
187                 return -EINVAL;                   157                 return -EINVAL;
188                                                   158 
189         usig = (u32 __user *)(unsigned long)(r    159         usig = (u32 __user *)(unsigned long)(rseq_cs->abort_ip - sizeof(u32));
190         ret = get_user(sig, usig);                160         ret = get_user(sig, usig);
191         if (ret)                                  161         if (ret)
192                 return ret;                       162                 return ret;
193                                                   163 
194         if (current->rseq_sig != sig) {           164         if (current->rseq_sig != sig) {
195                 printk_ratelimited(KERN_WARNIN    165                 printk_ratelimited(KERN_WARNING
196                         "Possible attack attem    166                         "Possible attack attempt. Unexpected rseq signature 0x%x, expecting 0x%x (pid=%d, addr=%p).\n",
197                         sig, current->rseq_sig    167                         sig, current->rseq_sig, current->pid, usig);
198                 return -EINVAL;                   168                 return -EINVAL;
199         }                                         169         }
200         return 0;                                 170         return 0;
201 }                                                 171 }
202                                                   172 
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    173 static int rseq_need_restart(struct task_struct *t, u32 cs_flags)
219 {                                                 174 {
220         u32 flags, event_mask;                    175         u32 flags, event_mask;
221         int ret;                                  176         int ret;
222                                                   177 
223         if (rseq_warn_flags("rseq_cs", cs_flag << 
224                 return -EINVAL;                << 
225                                                << 
226         /* Get thread flags. */                   178         /* Get thread flags. */
227         ret = get_user(flags, &t->rseq->flags)    179         ret = get_user(flags, &t->rseq->flags);
228         if (ret)                                  180         if (ret)
229                 return ret;                       181                 return ret;
230                                                   182 
231         if (rseq_warn_flags("rseq", flags))    !! 183         /* Take critical section flags into account. */
                                                   >> 184         flags |= cs_flags;
                                                   >> 185 
                                                   >> 186         /*
                                                   >> 187          * Restart on signal can only be inhibited when restart on
                                                   >> 188          * preempt and restart on migrate are inhibited too. Otherwise,
                                                   >> 189          * a preempted signal handler could fail to restart the prior
                                                   >> 190          * execution context on sigreturn.
                                                   >> 191          */
                                                   >> 192         if (unlikely((flags & RSEQ_CS_FLAG_NO_RESTART_ON_SIGNAL) &&
                                                   >> 193                      (flags & RSEQ_CS_PREEMPT_MIGRATE_FLAGS) !=
                                                   >> 194                      RSEQ_CS_PREEMPT_MIGRATE_FLAGS))
232                 return -EINVAL;                   195                 return -EINVAL;
233                                                   196 
234         /*                                        197         /*
235          * Load and clear event mask atomicall    198          * Load and clear event mask atomically with respect to
236          * scheduler preemption.                  199          * scheduler preemption.
237          */                                       200          */
238         preempt_disable();                        201         preempt_disable();
239         event_mask = t->rseq_event_mask;          202         event_mask = t->rseq_event_mask;
240         t->rseq_event_mask = 0;                   203         t->rseq_event_mask = 0;
241         preempt_enable();                         204         preempt_enable();
242                                                   205 
243         return !!event_mask;                   !! 206         return !!(event_mask & ~flags);
244 }                                                 207 }
245                                                   208 
246 static int clear_rseq_cs(struct task_struct *t    209 static int clear_rseq_cs(struct task_struct *t)
247 {                                                 210 {
248         /*                                        211         /*
249          * The rseq_cs field is set to NULL on    212          * The rseq_cs field is set to NULL on preemption or signal
250          * delivery on top of rseq assembly bl    213          * delivery on top of rseq assembly block, as well as on top
251          * of code outside of the rseq assembl    214          * of code outside of the rseq assembly block. This performs
252          * a lazy clear of the rseq_cs field.     215          * a lazy clear of the rseq_cs field.
253          *                                        216          *
254          * Set rseq_cs to NULL.                   217          * Set rseq_cs to NULL.
255          */                                       218          */
256 #ifdef CONFIG_64BIT                               219 #ifdef CONFIG_64BIT
257         return put_user(0UL, &t->rseq->rseq_cs    220         return put_user(0UL, &t->rseq->rseq_cs);
258 #else                                             221 #else
259         if (clear_user(&t->rseq->rseq_cs, size    222         if (clear_user(&t->rseq->rseq_cs, sizeof(t->rseq->rseq_cs)))
260                 return -EFAULT;                   223                 return -EFAULT;
261         return 0;                                 224         return 0;
262 #endif                                            225 #endif
263 }                                                 226 }
264                                                   227 
265 /*                                                228 /*
266  * Unsigned comparison will be true when ip >=    229  * Unsigned comparison will be true when ip >= start_ip, and when
267  * ip < start_ip + post_commit_offset.            230  * ip < start_ip + post_commit_offset.
268  */                                               231  */
269 static bool in_rseq_cs(unsigned long ip, struc    232 static bool in_rseq_cs(unsigned long ip, struct rseq_cs *rseq_cs)
270 {                                                 233 {
271         return ip - rseq_cs->start_ip < rseq_c    234         return ip - rseq_cs->start_ip < rseq_cs->post_commit_offset;
272 }                                                 235 }
273                                                   236 
274 static int rseq_ip_fixup(struct pt_regs *regs)    237 static int rseq_ip_fixup(struct pt_regs *regs)
275 {                                                 238 {
276         unsigned long ip = instruction_pointer    239         unsigned long ip = instruction_pointer(regs);
277         struct task_struct *t = current;          240         struct task_struct *t = current;
278         struct rseq_cs rseq_cs;                   241         struct rseq_cs rseq_cs;
279         int ret;                                  242         int ret;
280                                                   243 
281         ret = rseq_get_rseq_cs(t, &rseq_cs);      244         ret = rseq_get_rseq_cs(t, &rseq_cs);
282         if (ret)                                  245         if (ret)
283                 return ret;                       246                 return ret;
284                                                   247 
285         /*                                        248         /*
286          * Handle potentially not being within    249          * Handle potentially not being within a critical section.
287          * If not nested over a rseq critical     250          * If not nested over a rseq critical section, restart is useless.
288          * Clear the rseq_cs pointer and retur    251          * Clear the rseq_cs pointer and return.
289          */                                       252          */
290         if (!in_rseq_cs(ip, &rseq_cs))            253         if (!in_rseq_cs(ip, &rseq_cs))
291                 return clear_rseq_cs(t);          254                 return clear_rseq_cs(t);
292         ret = rseq_need_restart(t, rseq_cs.fla    255         ret = rseq_need_restart(t, rseq_cs.flags);
293         if (ret <= 0)                             256         if (ret <= 0)
294                 return ret;                       257                 return ret;
295         ret = clear_rseq_cs(t);                   258         ret = clear_rseq_cs(t);
296         if (ret)                                  259         if (ret)
297                 return ret;                       260                 return ret;
298         trace_rseq_ip_fixup(ip, rseq_cs.start_    261         trace_rseq_ip_fixup(ip, rseq_cs.start_ip, rseq_cs.post_commit_offset,
299                             rseq_cs.abort_ip);    262                             rseq_cs.abort_ip);
300         instruction_pointer_set(regs, (unsigne    263         instruction_pointer_set(regs, (unsigned long)rseq_cs.abort_ip);
301         return 0;                                 264         return 0;
302 }                                                 265 }
303                                                   266 
304 /*                                                267 /*
305  * This resume handler must always be executed    268  * This resume handler must always be executed between any of:
306  * - preemption,                                  269  * - preemption,
307  * - signal delivery,                             270  * - signal delivery,
308  * and return to user-space.                      271  * and return to user-space.
309  *                                                272  *
310  * This is how we can ensure that the entire r    273  * This is how we can ensure that the entire rseq critical section
311  * will issue the commit instruction only if e    274  * will issue the commit instruction only if executed atomically with
312  * respect to other threads scheduled on the s    275  * respect to other threads scheduled on the same CPU, and with respect
313  * to signal handlers.                            276  * to signal handlers.
314  */                                               277  */
315 void __rseq_handle_notify_resume(struct ksigna    278 void __rseq_handle_notify_resume(struct ksignal *ksig, struct pt_regs *regs)
316 {                                                 279 {
317         struct task_struct *t = current;          280         struct task_struct *t = current;
318         int ret, sig;                             281         int ret, sig;
319                                                   282 
320         if (unlikely(t->flags & PF_EXITING))      283         if (unlikely(t->flags & PF_EXITING))
321                 return;                           284                 return;
322                                                   285 
323         /*                                        286         /*
324          * regs is NULL if and only if the cal    287          * regs is NULL if and only if the caller is in a syscall path.  Skip
325          * fixup and leave rseq_cs as is so th    288          * fixup and leave rseq_cs as is so that rseq_sycall() will detect and
326          * kill a misbehaving userspace on deb    289          * kill a misbehaving userspace on debug kernels.
327          */                                       290          */
328         if (regs) {                               291         if (regs) {
329                 ret = rseq_ip_fixup(regs);        292                 ret = rseq_ip_fixup(regs);
330                 if (unlikely(ret < 0))            293                 if (unlikely(ret < 0))
331                         goto error;               294                         goto error;
332         }                                         295         }
333         if (unlikely(rseq_update_cpu_node_id(t !! 296         if (unlikely(rseq_update_cpu_id(t)))
334                 goto error;                       297                 goto error;
335         return;                                   298         return;
336                                                   299 
337 error:                                            300 error:
338         sig = ksig ? ksig->sig : 0;               301         sig = ksig ? ksig->sig : 0;
339         force_sigsegv(sig);                       302         force_sigsegv(sig);
340 }                                                 303 }
341                                                   304 
342 #ifdef CONFIG_DEBUG_RSEQ                          305 #ifdef CONFIG_DEBUG_RSEQ
343                                                   306 
344 /*                                                307 /*
345  * Terminate the process if a syscall is issue    308  * Terminate the process if a syscall is issued within a restartable
346  * sequence.                                      309  * sequence.
347  */                                               310  */
348 void rseq_syscall(struct pt_regs *regs)           311 void rseq_syscall(struct pt_regs *regs)
349 {                                                 312 {
350         unsigned long ip = instruction_pointer    313         unsigned long ip = instruction_pointer(regs);
351         struct task_struct *t = current;          314         struct task_struct *t = current;
352         struct rseq_cs rseq_cs;                   315         struct rseq_cs rseq_cs;
353                                                   316 
354         if (!t->rseq)                             317         if (!t->rseq)
355                 return;                           318                 return;
356         if (rseq_get_rseq_cs(t, &rseq_cs) || i    319         if (rseq_get_rseq_cs(t, &rseq_cs) || in_rseq_cs(ip, &rseq_cs))
357                 force_sig(SIGSEGV);               320                 force_sig(SIGSEGV);
358 }                                                 321 }
359                                                   322 
360 #endif                                            323 #endif
361                                                   324 
362 /*                                                325 /*
363  * sys_rseq - setup restartable sequences for     326  * sys_rseq - setup restartable sequences for caller thread.
364  */                                               327  */
365 SYSCALL_DEFINE4(rseq, struct rseq __user *, rs    328 SYSCALL_DEFINE4(rseq, struct rseq __user *, rseq, u32, rseq_len,
366                 int, flags, u32, sig)             329                 int, flags, u32, sig)
367 {                                                 330 {
368         int ret;                                  331         int ret;
369                                                   332 
370         if (flags & RSEQ_FLAG_UNREGISTER) {       333         if (flags & RSEQ_FLAG_UNREGISTER) {
371                 if (flags & ~RSEQ_FLAG_UNREGIS    334                 if (flags & ~RSEQ_FLAG_UNREGISTER)
372                         return -EINVAL;           335                         return -EINVAL;
373                 /* Unregister rseq for current    336                 /* Unregister rseq for current thread. */
374                 if (current->rseq != rseq || !    337                 if (current->rseq != rseq || !current->rseq)
375                         return -EINVAL;           338                         return -EINVAL;
376                 if (rseq_len != current->rseq_ !! 339                 if (rseq_len != sizeof(*rseq))
377                         return -EINVAL;           340                         return -EINVAL;
378                 if (current->rseq_sig != sig)     341                 if (current->rseq_sig != sig)
379                         return -EPERM;            342                         return -EPERM;
380                 ret = rseq_reset_rseq_cpu_node !! 343                 ret = rseq_reset_rseq_cpu_id(current);
381                 if (ret)                          344                 if (ret)
382                         return ret;               345                         return ret;
383                 current->rseq = NULL;             346                 current->rseq = NULL;
384                 current->rseq_sig = 0;            347                 current->rseq_sig = 0;
385                 current->rseq_len = 0;         << 
386                 return 0;                         348                 return 0;
387         }                                         349         }
388                                                   350 
389         if (unlikely(flags))                      351         if (unlikely(flags))
390                 return -EINVAL;                   352                 return -EINVAL;
391                                                   353 
392         if (current->rseq) {                      354         if (current->rseq) {
393                 /*                                355                 /*
394                  * If rseq is already register    356                  * If rseq is already registered, check whether
395                  * the provided address differ    357                  * the provided address differs from the prior
396                  * one.                           358                  * one.
397                  */                               359                  */
398                 if (current->rseq != rseq || r !! 360                 if (current->rseq != rseq || rseq_len != sizeof(*rseq))
399                         return -EINVAL;           361                         return -EINVAL;
400                 if (current->rseq_sig != sig)     362                 if (current->rseq_sig != sig)
401                         return -EPERM;            363                         return -EPERM;
402                 /* Already registered. */         364                 /* Already registered. */
403                 return -EBUSY;                    365                 return -EBUSY;
404         }                                         366         }
405                                                   367 
406         /*                                        368         /*
407          * If there was no rseq previously reg !! 369          * If there was no rseq previously registered,
408          * is properly aligned, as communcated !! 370          * 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          */                                       371          */
416         if (rseq_len < ORIG_RSEQ_SIZE ||       !! 372         if (!IS_ALIGNED((unsigned long)rseq, __alignof__(*rseq)) ||
417             (rseq_len == ORIG_RSEQ_SIZE && !IS !! 373             rseq_len != sizeof(*rseq))
418             (rseq_len != ORIG_RSEQ_SIZE && (!I << 
419                                             rs << 
420                 return -EINVAL;                   374                 return -EINVAL;
421         if (!access_ok(rseq, rseq_len))           375         if (!access_ok(rseq, rseq_len))
422                 return -EFAULT;                   376                 return -EFAULT;
423         current->rseq = rseq;                     377         current->rseq = rseq;
424         current->rseq_len = rseq_len;          << 
425         current->rseq_sig = sig;                  378         current->rseq_sig = sig;
426         /*                                        379         /*
427          * If rseq was previously inactive, an    380          * If rseq was previously inactive, and has just been
428          * registered, ensure the cpu_id_start    381          * registered, ensure the cpu_id_start and cpu_id fields
429          * are updated before returning to use    382          * are updated before returning to user-space.
430          */                                       383          */
431         rseq_set_notify_resume(current);          384         rseq_set_notify_resume(current);
432                                                   385 
433         return 0;                                 386         return 0;
434 }                                                 387 }
435                                                   388 

~ [ 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