@@ -78,24 +78,24 @@ static int rseq_validate_ro_fields(struct task_struct *t)
7878 return - EFAULT ;
7979}
8080
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+
8991#else
9092static int rseq_validate_ro_fields (struct task_struct * t )
9193{
9294 return 0 ;
9395}
9496
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)
9999#endif
100100
101101/*
@@ -173,17 +173,18 @@ static int rseq_update_cpu_node_id(struct task_struct *t)
173173 WARN_ON_ONCE ((int ) mm_cid < 0 );
174174 if (!user_write_access_begin (rseq , t -> rseq_len ))
175175 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+
180182 /*
181183 * Additional feature fields added after ORIG_RSEQ_SIZE
182184 * need to be conditionally updated only if
183185 * t->rseq_len != ORIG_RSEQ_SIZE.
184186 */
185187 user_write_access_end ();
186- rseq_set_ro_fields (t , cpu_id , cpu_id , node_id , mm_cid );
187188 trace_rseq_update (t );
188189 return 0 ;
189190
@@ -195,45 +196,44 @@ static int rseq_update_cpu_node_id(struct task_struct *t)
195196
196197static int rseq_reset_rseq_cpu_node_id (struct task_struct * t )
197198{
199+ struct rseq __user * rseq = t -> rseq ;
198200 u32 cpu_id_start = 0 , cpu_id = RSEQ_CPU_ID_UNINITIALIZED , node_id = 0 ,
199201 mm_cid = 0 ;
200202
201203 /*
202204 * Validate read-only rseq fields.
203205 */
204206 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+
223212 /*
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.
225219 */
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 );
230224
231225 /*
232226 * Additional feature fields added after ORIG_RSEQ_SIZE
233227 * need to be conditionally reset only if
234228 * t->rseq_len != ORIG_RSEQ_SIZE.
235229 */
230+ user_write_access_end ();
236231 return 0 ;
232+
233+ efault_end :
234+ user_write_access_end ();
235+ efault :
236+ return - EFAULT ;
237237}
238238
239239static int rseq_get_rseq_cs (struct task_struct * t , struct rseq_cs * rseq_cs )
0 commit comments