@@ -78,24 +78,24 @@ static int rseq_validate_ro_fields(struct task_struct *t)
78
78
return - EFAULT ;
79
79
}
80
80
81
- static void rseq_set_ro_fields (struct task_struct * t , u32 cpu_id_start , u32 cpu_id ,
82
- u32 node_id , u32 mm_cid )
83
- {
84
- rseq_kernel_fields (t )-> cpu_id_start = cpu_id ;
85
- rseq_kernel_fields (t )-> cpu_id = cpu_id ;
86
- rseq_kernel_fields (t )-> node_id = node_id ;
87
- rseq_kernel_fields (t )-> mm_cid = mm_cid ;
88
- }
81
+ /*
82
+ * Update an rseq field and its in-kernel copy in lock-step to keep a coherent
83
+ * state.
84
+ */
85
+ #define rseq_unsafe_put_user (t , value , field , error_label ) \
86
+ do { \
87
+ unsafe_put_user(value, &t->rseq->field, error_label); \
88
+ rseq_kernel_fields(t)->field = value; \
89
+ } while (0)
90
+
89
91
#else
90
92
static int rseq_validate_ro_fields (struct task_struct * t )
91
93
{
92
94
return 0 ;
93
95
}
94
96
95
- static void rseq_set_ro_fields (struct task_struct * t , u32 cpu_id_start , u32 cpu_id ,
96
- u32 node_id , u32 mm_cid )
97
- {
98
- }
97
+ #define rseq_unsafe_put_user (t , value , field , error_label ) \
98
+ unsafe_put_user(value, &t->rseq->field, error_label)
99
99
#endif
100
100
101
101
/*
@@ -173,17 +173,18 @@ static int rseq_update_cpu_node_id(struct task_struct *t)
173
173
WARN_ON_ONCE ((int ) mm_cid < 0 );
174
174
if (!user_write_access_begin (rseq , t -> rseq_len ))
175
175
goto efault ;
176
- unsafe_put_user (cpu_id , & rseq -> cpu_id_start , efault_end );
177
- unsafe_put_user (cpu_id , & rseq -> cpu_id , efault_end );
178
- unsafe_put_user (node_id , & rseq -> node_id , efault_end );
179
- unsafe_put_user (mm_cid , & rseq -> mm_cid , efault_end );
176
+
177
+ rseq_unsafe_put_user (t , cpu_id , cpu_id_start , efault_end );
178
+ rseq_unsafe_put_user (t , cpu_id , cpu_id , efault_end );
179
+ rseq_unsafe_put_user (t , node_id , node_id , efault_end );
180
+ rseq_unsafe_put_user (t , mm_cid , mm_cid , efault_end );
181
+
180
182
/*
181
183
* Additional feature fields added after ORIG_RSEQ_SIZE
182
184
* need to be conditionally updated only if
183
185
* t->rseq_len != ORIG_RSEQ_SIZE.
184
186
*/
185
187
user_write_access_end ();
186
- rseq_set_ro_fields (t , cpu_id , cpu_id , node_id , mm_cid );
187
188
trace_rseq_update (t );
188
189
return 0 ;
189
190
@@ -195,45 +196,44 @@ static int rseq_update_cpu_node_id(struct task_struct *t)
195
196
196
197
static int rseq_reset_rseq_cpu_node_id (struct task_struct * t )
197
198
{
199
+ struct rseq __user * rseq = t -> rseq ;
198
200
u32 cpu_id_start = 0 , cpu_id = RSEQ_CPU_ID_UNINITIALIZED , node_id = 0 ,
199
201
mm_cid = 0 ;
200
202
201
203
/*
202
204
* Validate read-only rseq fields.
203
205
*/
204
206
if (rseq_validate_ro_fields (t ))
205
- return - EFAULT ;
206
- /*
207
- * Reset cpu_id_start to its initial state (0).
208
- */
209
- if (put_user (cpu_id_start , & t -> rseq -> cpu_id_start ))
210
- return - EFAULT ;
211
- /*
212
- * Reset cpu_id to RSEQ_CPU_ID_UNINITIALIZED, so any user coming
213
- * in after unregistration can figure out that rseq needs to be
214
- * registered again.
215
- */
216
- if (put_user (cpu_id , & t -> rseq -> cpu_id ))
217
- return - EFAULT ;
218
- /*
219
- * Reset node_id to its initial state (0).
220
- */
221
- if (put_user (node_id , & t -> rseq -> node_id ))
222
- return - EFAULT ;
207
+ goto efault ;
208
+
209
+ if (!user_write_access_begin (rseq , t -> rseq_len ))
210
+ goto efault ;
211
+
223
212
/*
224
- * Reset mm_cid to its initial state (0).
213
+ * Reset all fields to their initial state.
214
+ *
215
+ * All fields have an initial state of 0 except cpu_id which is set to
216
+ * RSEQ_CPU_ID_UNINITIALIZED, so that any user coming in after
217
+ * unregistration can figure out that rseq needs to be registered
218
+ * again.
225
219
*/
226
- if ( put_user ( mm_cid , & t -> rseq -> mm_cid ))
227
- return - EFAULT ;
228
-
229
- rseq_set_ro_fields (t , cpu_id_start , cpu_id , node_id , mm_cid );
220
+ rseq_unsafe_put_user ( t , cpu_id_start , cpu_id_start , efault_end );
221
+ rseq_unsafe_put_user ( t , cpu_id , cpu_id , efault_end ) ;
222
+ rseq_unsafe_put_user ( t , node_id , node_id , efault_end );
223
+ rseq_unsafe_put_user (t , mm_cid , mm_cid , efault_end );
230
224
231
225
/*
232
226
* Additional feature fields added after ORIG_RSEQ_SIZE
233
227
* need to be conditionally reset only if
234
228
* t->rseq_len != ORIG_RSEQ_SIZE.
235
229
*/
230
+ user_write_access_end ();
236
231
return 0 ;
232
+
233
+ efault_end :
234
+ user_write_access_end ();
235
+ efault :
236
+ return - EFAULT ;
237
237
}
238
238
239
239
static int rseq_get_rseq_cs (struct task_struct * t , struct rseq_cs * rseq_cs )
0 commit comments