1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 /*
3 * Copyright (c) 2017-2018 Richard Palethorpe <rpalethorpe@suse.com>
4 */
5 /**
6 * @file tst_fuzzy_sync.h
7 * Fuzzy Synchronisation - abbreviated to fzsync
8 *
9 * This library is intended to help reproduce race conditions by synchronising
10 * two threads at a given place by marking the range a race may occur
11 * in. Because the exact place where any race occurs is within the kernel,
12 * and therefore impossible to mark accurately, the library may add randomised
13 * delays to either thread in order to help find the exact race timing.
14 *
15 * Currently only two way races are explicitly supported, that is races
16 * involving two threads or processes. We refer to the main test thread as
17 * thread A and the child thread as thread B.
18 *
19 * In each thread you need a simple while- or for-loop which the tst_fzsync_*
20 * functions are called in. In the simplest case thread A will look something
21 * like:
22 *
23 * tst_fzsync_pair_reset(&pair, run_thread_b);
24 * while (tst_fzsync_run_a(&pair)) {
25 * // Perform some setup which must happen before the race
26 * tst_fzsync_start_race_a(&pair);
27 * // Do some dodgy syscall
28 * tst_fzsync_end_race_a(&pair);
29 * }
30 *
31 * Then in thread B (run_thread_b):
32 *
33 * while (tst_fzsync_run_b(&pair)) {
34 * tst_fzsync_start_race_b(&pair);
35 * // Do something which can race with the dodgy syscall in A
36 * tst_fzsync_end_race_b(&pair)
37 * }
38 *
39 * The calls to tst_fzsync_start/end_race and tst_fzsync_run_a/b block (at
40 * least) until both threads have enter them. These functions can only be
41 * called once for each iteration, but further synchronisation points can be
42 * added by calling tst_fzsync_wait_a() and tst_fzsync_wait_b() in each
43 * thread.
44 *
45 * The execution of the loops in threads A and B are bounded by both iteration
46 * count and time. A slow machine is likely to be limited by time and a fast
47 * one by iteration count. The user can use the -i parameter to run the test
48 * multiple times or LTP_TIMEOUT_MUL to give the test more time.
49 *
50 * It is possible to use the library just for tst_fzsync_pair_wait() to get a
51 * basic spin wait. However if you are actually testing a race condition then
52 * it is recommended to use tst_fzsync_start_race_a/b even if the
53 * randomisation is not needed. It provides some semantic information which
54 * may be useful in the future.
55 *
56 * For a usage example see testcases/cve/cve-2016-7117.c or just run
57 * 'git grep tst_fuzzy_sync.h'
58 *
59 * @sa tst_fzsync_pair
60 */
61
62 #include <sys/time.h>
63 #include <time.h>
64 #include <math.h>
65 #include <stdlib.h>
66 #include "tst_atomic.h"
67 #include "tst_timer.h"
68 #include "tst_safe_pthread.h"
69
70 #ifndef TST_FUZZY_SYNC_H__
71 #define TST_FUZZY_SYNC_H__
72
73 /* how much of exec time is sampling allowed to take */
74 #define SAMPLING_SLICE 0.5f
75
76 /** Some statistics for a variable */
77 struct tst_fzsync_stat {
78 float avg;
79 float avg_dev;
80 float dev_ratio;
81 };
82
83 /**
84 * The state of a two way synchronisation or race.
85 *
86 * This contains all the necessary state for approximately synchronising two
87 * sections of code in different threads.
88 *
89 * Some of the fields can be configured before calling
90 * tst_fzsync_pair_reset(), however this is mainly for debugging purposes. If
91 * a test requires one of the parameters to be modified, we should consider
92 * finding a way of automatically selecting an appropriate value at runtime.
93 *
94 * Internal fields should only be accessed by library functions.
95 */
96 struct tst_fzsync_pair {
97 /**
98 * The rate at which old diff samples are forgotten
99 *
100 * Defaults to 0.25.
101 */
102 float avg_alpha;
103 /** Internal; Thread A start time */
104 struct timespec a_start;
105 /** Internal; Thread B start time */
106 struct timespec b_start;
107 /** Internal; Thread A end time */
108 struct timespec a_end;
109 /** Internal; Thread B end time */
110 struct timespec b_end;
111 /** Internal; Avg. difference between a_start and b_start */
112 struct tst_fzsync_stat diff_ss;
113 /** Internal; Avg. difference between a_start and a_end */
114 struct tst_fzsync_stat diff_sa;
115 /** Internal; Avg. difference between b_start and b_end */
116 struct tst_fzsync_stat diff_sb;
117 /** Internal; Avg. difference between a_end and b_end */
118 struct tst_fzsync_stat diff_ab;
119 /** Internal; Number of spins while waiting for the slower thread */
120 int spins;
121 struct tst_fzsync_stat spins_avg;
122 /**
123 * Internal; Number of spins to use in the delay.
124 *
125 * A negative value delays thread A and a positive delays thread B.
126 */
127 int delay;
128 int delay_bias;
129 /**
130 * Internal; The number of samples left or the sampling state.
131 *
132 * A positive value is the number of remaining mandatory
133 * samples. Zero or a negative indicate some other state.
134 */
135 int sampling;
136 /**
137 * The Minimum number of statistical samples which must be collected.
138 *
139 * The minimum number of iterations which must be performed before a
140 * random delay can be calculated. Defaults to 1024.
141 */
142 int min_samples;
143 /**
144 * The maximum allowed proportional average deviation.
145 *
146 * A value in the range (0, 1) which gives the maximum average
147 * deviation which must be attained before random delays can be
148 * calculated.
149 *
150 * It is a ratio of (average_deviation / total_time). The default is
151 * 0.1, so this allows an average deviation of at most 10%.
152 */
153 float max_dev_ratio;
154
155 /** Internal; Atomic counter used by fzsync_pair_wait() */
156 int a_cntr;
157 /** Internal; Atomic counter used by fzsync_pair_wait() */
158 int b_cntr;
159 /** Internal; Used by tst_fzsync_pair_exit() and fzsync_pair_wait() */
160 int exit;
161 /**
162 * The maximum desired execution time as a proportion of the timeout
163 *
164 * A value x so that 0 < x < 1 which decides how long the test should
165 * be run for (assuming the loop limit is not exceeded first).
166 *
167 * Defaults to 0.5 (~150 seconds with default timeout).
168 */
169 float exec_time_p;
170 /** Internal; The test time remaining on tst_fzsync_pair_reset() */
171 float exec_time_start;
172 /**
173 * The maximum number of iterations to execute during the test
174 *
175 * Defaults to a large number, but not too large.
176 */
177 int exec_loops;
178 /** Internal; The current loop index */
179 int exec_loop;
180 /** Internal; The second thread or 0 */
181 pthread_t thread_b;
182 };
183
184 #define CHK(param, low, hi, def) do { \
185 pair->param = (pair->param ? pair->param : def); \
186 if (pair->param < low) \
187 tst_brk(TBROK, #param " is less than the lower bound " #low); \
188 if (pair->param > hi) \
189 tst_brk(TBROK, #param " is more than the upper bound " #hi); \
190 } while (0)
191 /**
192 * Ensures that any Fuzzy Sync parameters are properly set
193 *
194 * @relates tst_fzsync_pair
195 *
196 * Usually called from the setup function, it sets default parameter values or
197 * validates any existing non-defaults.
198 *
199 * @sa tst_fzsync_pair_reset()
200 */
tst_fzsync_pair_init(struct tst_fzsync_pair * pair)201 static void tst_fzsync_pair_init(struct tst_fzsync_pair *pair)
202 {
203 CHK(avg_alpha, 0, 1, 0.25);
204 CHK(min_samples, 20, INT_MAX, 1024);
205 CHK(max_dev_ratio, 0, 1, 0.1);
206 CHK(exec_time_p, 0, 1, 0.5);
207 CHK(exec_loops, 20, INT_MAX, 3000000);
208 }
209 #undef CHK
210
211 /**
212 * Exit and join thread B if necessary.
213 *
214 * @relates tst_fzsync_pair
215 *
216 * Call this from your cleanup function.
217 */
tst_fzsync_pair_cleanup(struct tst_fzsync_pair * pair)218 static void tst_fzsync_pair_cleanup(struct tst_fzsync_pair *pair)
219 {
220 if (pair->thread_b) {
221 tst_atomic_store(1, &pair->exit);
222 SAFE_PTHREAD_JOIN(pair->thread_b, NULL);
223 pair->thread_b = 0;
224 }
225 }
226
227 /**
228 * Zero some stat fields
229 *
230 * @relates tst_fzsync_stat
231 */
tst_init_stat(struct tst_fzsync_stat * s)232 static void tst_init_stat(struct tst_fzsync_stat *s)
233 {
234 s->avg = 0;
235 s->avg_dev = 0;
236 }
237
238 /**
239 * Reset or initialise fzsync.
240 *
241 * @relates tst_fzsync_pair
242 * @param pair The state structure initialised with TST_FZSYNC_PAIR_INIT.
243 * @param run_b The function defining thread B or NULL.
244 *
245 * Call this from your main test function (thread A), just before entering the
246 * main loop. It will (re)set any variables needed by fzsync and (re)start
247 * thread B using the function provided.
248 *
249 * If you need to use fork or clone to start the second thread/process then
250 * you can pass NULL to run_b and handle starting and stopping thread B
251 * yourself. You may need to place tst_fzsync_pair in some shared memory as
252 * well.
253 *
254 * @sa tst_fzsync_pair_init()
255 */
tst_fzsync_pair_reset(struct tst_fzsync_pair * pair,void * (* run_b)(void *))256 static void tst_fzsync_pair_reset(struct tst_fzsync_pair *pair,
257 void *(*run_b)(void *))
258 {
259 tst_fzsync_pair_cleanup(pair);
260
261 tst_init_stat(&pair->diff_ss);
262 tst_init_stat(&pair->diff_sa);
263 tst_init_stat(&pair->diff_sb);
264 tst_init_stat(&pair->diff_ab);
265 tst_init_stat(&pair->spins_avg);
266 pair->delay = 0;
267 pair->sampling = pair->min_samples;
268
269 pair->exec_loop = 0;
270
271 pair->a_cntr = 0;
272 pair->b_cntr = 0;
273 pair->exit = 0;
274 if (run_b)
275 SAFE_PTHREAD_CREATE(&pair->thread_b, 0, run_b, 0);
276
277 pair->exec_time_start = (float)tst_timeout_remaining();
278 }
279
280 /**
281 * Print stat
282 *
283 * @relates tst_fzsync_stat
284 */
tst_fzsync_stat_info(struct tst_fzsync_stat stat,char * unit,char * name)285 static inline void tst_fzsync_stat_info(struct tst_fzsync_stat stat,
286 char *unit, char *name)
287 {
288 tst_res(TINFO,
289 "%1$-17s: { avg = %3$5.0f%2$s, avg_dev = %4$5.0f%2$s, dev_ratio = %5$.2f }",
290 name, unit, stat.avg, stat.avg_dev, stat.dev_ratio);
291 }
292
293 /**
294 * Print some synchronisation statistics
295 *
296 * @relates tst_fzsync_pair
297 */
tst_fzsync_pair_info(struct tst_fzsync_pair * pair)298 static void tst_fzsync_pair_info(struct tst_fzsync_pair *pair)
299 {
300 tst_res(TINFO, "loop = %d, delay_bias = %d",
301 pair->exec_loop, pair->delay_bias);
302 tst_fzsync_stat_info(pair->diff_ss, "ns", "start_a - start_b");
303 tst_fzsync_stat_info(pair->diff_sa, "ns", "end_a - start_a");
304 tst_fzsync_stat_info(pair->diff_sb, "ns", "end_b - start_b");
305 tst_fzsync_stat_info(pair->diff_ab, "ns", "end_a - end_b");
306 tst_fzsync_stat_info(pair->spins_avg, " ", "spins");
307 }
308
309 /** Wraps clock_gettime */
tst_fzsync_time(struct timespec * t)310 static inline void tst_fzsync_time(struct timespec *t)
311 {
312 #ifdef CLOCK_MONOTONIC_RAW
313 clock_gettime(CLOCK_MONOTONIC_RAW, t);
314 #else
315 clock_gettime(CLOCK_MONOTONIC, t);
316 #endif
317 }
318
319 /**
320 * Exponential moving average
321 *
322 * @param alpha The preference for recent samples over old ones.
323 * @param sample The current sample
324 * @param prev_avg The average of the all the previous samples
325 *
326 * @return The average including the current sample.
327 */
tst_exp_moving_avg(float alpha,float sample,float prev_avg)328 static inline float tst_exp_moving_avg(float alpha,
329 float sample,
330 float prev_avg)
331 {
332 return alpha * sample + (1.0 - alpha) * prev_avg;
333 }
334
335 /**
336 * Update a stat with a new sample
337 *
338 * @relates tst_fzsync_stat
339 */
tst_upd_stat(struct tst_fzsync_stat * s,float alpha,float sample)340 static inline void tst_upd_stat(struct tst_fzsync_stat *s,
341 float alpha,
342 float sample)
343 {
344 s->avg = tst_exp_moving_avg(alpha, sample, s->avg);
345 s->avg_dev = tst_exp_moving_avg(alpha,
346 fabs(s->avg - sample), s->avg_dev);
347 s->dev_ratio = fabs(s->avg ? s->avg_dev / s->avg : 0);
348 }
349
350 /**
351 * Update a stat with a new diff sample
352 *
353 * @relates tst_fzsync_stat
354 */
tst_upd_diff_stat(struct tst_fzsync_stat * s,float alpha,struct timespec t1,struct timespec t2)355 static inline void tst_upd_diff_stat(struct tst_fzsync_stat *s,
356 float alpha,
357 struct timespec t1,
358 struct timespec t2)
359 {
360 tst_upd_stat(s, alpha, tst_timespec_diff_ns(t1, t2));
361 }
362
363 /**
364 * Calculate various statistics and the delay
365 *
366 * This function helps create the fuzz in fuzzy sync. Imagine we have the
367 * following timelines in threads A and B:
368 *
369 * start_race_a
370 * ^ end_race_a (a)
371 * | ^
372 * | |
373 * - --+------------------------+-- - -
374 * | Syscall A | Thread A
375 * - --+------------------------+-- - -
376 * - --+----------------+-------+-- - -
377 * | Syscall B | spin | Thread B
378 * - --+----------------+-------+-- - -
379 * | |
380 * ^ ^
381 * start_race_b end_race_b
382 *
383 * Here we have synchronised the calls to syscall A and B with start_race_{a,
384 * b} so that they happen at approximately the same time in threads A and
385 * B. If the race condition occurs during the entry code for these two
386 * functions then we will quickly hit it. If it occurs during the exit code of
387 * B and mid way through A, then we will quickly hit it.
388 *
389 * However if the exit paths of A and B need to be aligned and (end_race_a -
390 * end_race_b) is large relative to the variation in call times, the
391 * probability of hitting the race condition is close to zero. To solve this
392 * scenario (and others) a randomised delay is introduced before the syscalls
393 * in A and B. Given enough time the following should happen where the exit
394 * paths are now synchronised:
395 *
396 * start_race_a
397 * ^ end_race_a (a)
398 * | ^
399 * | |
400 * - --+------------------------+-- - -
401 * | Syscall A | Thread A
402 * - --+------------------------+-- - -
403 * - --+-------+----------------+-- - -
404 * | delay | Syscall B | Thread B
405 * - --+-------+----------------+-- - -
406 * | |
407 * ^ ^
408 * start_race_b end_race_b
409 *
410 * The delay is not introduced immediately and the delay range is only
411 * calculated once the average relative deviation has dropped below some
412 * percentage of the total time.
413 *
414 * The delay range is chosen so that any point in Syscall A could be
415 * synchronised with any point in Syscall B using a value from the
416 * range. Because the delay range may be too large for a linear search, we use
417 * an evenly distributed random function to pick a value from it.
418 *
419 * The delay range goes from positive to negative. A negative delay will delay
420 * thread A and a positive one will delay thread B. The range is bounded by
421 * the point where the entry code to Syscall A is synchronised with the exit
422 * to Syscall B and the entry code to Syscall B is synchronised with the exit
423 * of A.
424 *
425 * In order to calculate the lower bound (the max delay of A) we can simply
426 * negate the execution time of Syscall B and convert it to a spin count. For
427 * the upper bound (the max delay of B), we just take the execution time of A
428 * and convert it to a spin count.
429 *
430 * In order to calculate spin count we need to know approximately how long a
431 * spin takes and divide the delay time with it. We find this by first
432 * counting how many spins one thread spends waiting for the other during
433 * end_race[1]. We also know when each syscall exits so we can take the
434 * difference between the exit times and divide it with the number of spins
435 * spent waiting.
436 *
437 * All the times and counts we use in the calculation are averaged over a
438 * variable number of iterations. There is an initial sampling period where we
439 * simply collect time and count samples then calculate their averages. When a
440 * minimum number of samples have been collected, and if the average deviation
441 * is below some proportion of the average sample magnitude, then the sampling
442 * period is ended. On all further iterations a random delay is calculated and
443 * applied, but the averages are not updated.
444 *
445 * [1] This assumes there is always a significant difference. The algorithm
446 * may fail to introduce a delay (when one is needed) in situations where
447 * Syscall A and B finish at approximately the same time.
448 *
449 * @relates tst_fzsync_pair
450 */
tst_fzsync_pair_update(struct tst_fzsync_pair * pair)451 static void tst_fzsync_pair_update(struct tst_fzsync_pair *pair)
452 {
453 float alpha = pair->avg_alpha;
454 float per_spin_time, time_delay;
455 float max_dev = pair->max_dev_ratio;
456 int over_max_dev;
457
458 pair->delay = pair->delay_bias;
459
460 over_max_dev = pair->diff_ss.dev_ratio > max_dev
461 || pair->diff_sa.dev_ratio > max_dev
462 || pair->diff_sb.dev_ratio > max_dev
463 || pair->diff_ab.dev_ratio > max_dev
464 || pair->spins_avg.dev_ratio > max_dev;
465
466 if (pair->sampling > 0 || over_max_dev) {
467 tst_upd_diff_stat(&pair->diff_ss, alpha,
468 pair->a_start, pair->b_start);
469 tst_upd_diff_stat(&pair->diff_sa, alpha,
470 pair->a_end, pair->a_start);
471 tst_upd_diff_stat(&pair->diff_sb, alpha,
472 pair->b_end, pair->b_start);
473 tst_upd_diff_stat(&pair->diff_ab, alpha,
474 pair->a_end, pair->b_end);
475 tst_upd_stat(&pair->spins_avg, alpha, pair->spins);
476 if (pair->sampling > 0 && --pair->sampling == 0) {
477 tst_res(TINFO, "Minimum sampling period ended");
478 tst_fzsync_pair_info(pair);
479 }
480 } else if (fabsf(pair->diff_ab.avg) >= 1 && pair->spins_avg.avg >= 1) {
481 per_spin_time = fabsf(pair->diff_ab.avg) / pair->spins_avg.avg;
482 time_delay = drand48() * (pair->diff_sa.avg + pair->diff_sb.avg)
483 - pair->diff_sb.avg;
484 pair->delay += (int)(time_delay / per_spin_time);
485
486 if (!pair->sampling) {
487 tst_res(TINFO,
488 "Reached deviation ratios < %.2f, introducing randomness",
489 pair->max_dev_ratio);
490 tst_res(TINFO, "Delay range is [-%d, %d]",
491 (int)(pair->diff_sb.avg / per_spin_time) + pair->delay_bias,
492 (int)(pair->diff_sa.avg / per_spin_time) - pair->delay_bias);
493 tst_fzsync_pair_info(pair);
494 pair->sampling = -1;
495 }
496 } else if (!pair->sampling) {
497 tst_res(TWARN, "Can't calculate random delay");
498 pair->sampling = -1;
499 }
500
501 pair->spins = 0;
502 }
503
504 /**
505 * Wait for the other thread
506 *
507 * @relates tst_fzsync_pair
508 * @param our_cntr The counter for the thread we are on
509 * @param other_cntr The counter for the thread we are synchronising with
510 * @param spins A pointer to the spin counter or NULL
511 *
512 * Used by tst_fzsync_pair_wait_a(), tst_fzsync_pair_wait_b(),
513 * tst_fzsync_start_race_a(), etc. If the calling thread is ahead of the other
514 * thread, then it will spin wait. Unlike pthread_barrier_wait it will never
515 * use futex and can count the number of spins spent waiting.
516 *
517 * @return A non-zero value if the thread should continue otherwise the
518 * calling thread should exit.
519 */
tst_fzsync_pair_wait(int * our_cntr,int * other_cntr,int * spins)520 static inline void tst_fzsync_pair_wait(int *our_cntr,
521 int *other_cntr,
522 int *spins)
523 {
524 if (tst_atomic_inc(other_cntr) == INT_MAX) {
525 /*
526 * We are about to break the invariant that the thread with
527 * the lowest count is in front of the other. So we must wait
528 * here to ensure the other thread has at least reached the
529 * line above before doing that. If we are in rear position
530 * then our counter may already have been set to zero.
531 */
532 while (tst_atomic_load(our_cntr) > 0
533 && tst_atomic_load(our_cntr) < INT_MAX) {
534 if (spins)
535 (*spins)++;
536 }
537
538 tst_atomic_store(0, other_cntr);
539 /*
540 * Once both counters have been set to zero the invariant
541 * is restored and we can continue.
542 */
543 while (tst_atomic_load(our_cntr) > 1)
544 ;
545 } else {
546 /*
547 * If our counter is less than the other thread's we are ahead
548 * of it and need to wait.
549 */
550 while (tst_atomic_load(our_cntr) < tst_atomic_load(other_cntr)) {
551 if (spins)
552 (*spins)++;
553 }
554 }
555 }
556
557 /**
558 * Wait in thread A
559 *
560 * @relates tst_fzsync_pair
561 * @sa tst_fzsync_pair_wait
562 */
tst_fzsync_wait_a(struct tst_fzsync_pair * pair)563 static inline void tst_fzsync_wait_a(struct tst_fzsync_pair *pair)
564 {
565 tst_fzsync_pair_wait(&pair->a_cntr, &pair->b_cntr, NULL);
566 }
567
568 /**
569 * Wait in thread B
570 *
571 * @relates tst_fzsync_pair
572 * @sa tst_fzsync_pair_wait
573 */
tst_fzsync_wait_b(struct tst_fzsync_pair * pair)574 static inline void tst_fzsync_wait_b(struct tst_fzsync_pair *pair)
575 {
576 tst_fzsync_pair_wait(&pair->b_cntr, &pair->a_cntr, NULL);
577 }
578
579 /**
580 * Decide whether to continue running thread A
581 *
582 * @relates tst_fzsync_pair
583 *
584 * Checks some values and decides whether it is time to break the loop of
585 * thread A.
586 *
587 * @return True to continue and false to break.
588 * @sa tst_fzsync_run_a
589 */
tst_fzsync_run_a(struct tst_fzsync_pair * pair)590 static inline int tst_fzsync_run_a(struct tst_fzsync_pair *pair)
591 {
592 int exit = 0;
593 float rem_p = 1 - tst_timeout_remaining() / pair->exec_time_start;
594
595 if ((pair->exec_time_p * SAMPLING_SLICE < rem_p)
596 && (pair->sampling > 0)) {
597 tst_res(TINFO, "Stopped sampling at %d (out of %d) samples, "
598 "sampling time reached 50%% of the total time limit",
599 pair->exec_loop, pair->min_samples);
600 pair->sampling = 0;
601 tst_fzsync_pair_info(pair);
602 }
603
604 if (pair->exec_time_p < rem_p) {
605 tst_res(TINFO,
606 "Exceeded execution time, requesting exit");
607 exit = 1;
608 }
609
610 if (++pair->exec_loop > pair->exec_loops) {
611 tst_res(TINFO,
612 "Exceeded execution loops, requesting exit");
613 exit = 1;
614 }
615
616 tst_atomic_store(exit, &pair->exit);
617 tst_fzsync_wait_a(pair);
618
619 if (exit) {
620 tst_fzsync_pair_cleanup(pair);
621 return 0;
622 }
623
624 return 1;
625 }
626
627 /**
628 * Decide whether to continue running thread B
629 *
630 * @relates tst_fzsync_pair
631 * @sa tst_fzsync_run_a
632 */
tst_fzsync_run_b(struct tst_fzsync_pair * pair)633 static inline int tst_fzsync_run_b(struct tst_fzsync_pair *pair)
634 {
635 tst_fzsync_wait_b(pair);
636 return !tst_atomic_load(&pair->exit);
637 }
638
639 /**
640 * Marks the start of a race region in thread A
641 *
642 * @relates tst_fzsync_pair
643 *
644 * This should be placed just before performing whatever action can cause a
645 * race condition. Usually it is placed just before a syscall and
646 * tst_fzsync_end_race_a() is placed just afterwards.
647 *
648 * A corresponding call to tst_fzsync_start_race_b() should be made in thread
649 * B.
650 *
651 * @return A non-zero value if the calling thread should continue to loop. If
652 * it returns zero then tst_fzsync_exit() has been called and you must exit
653 * the thread.
654 *
655 * @sa tst_fzsync_pair_update
656 */
tst_fzsync_start_race_a(struct tst_fzsync_pair * pair)657 static inline void tst_fzsync_start_race_a(struct tst_fzsync_pair *pair)
658 {
659 volatile int delay;
660
661 tst_fzsync_pair_update(pair);
662
663 tst_fzsync_wait_a(pair);
664
665 delay = pair->delay;
666 while (delay < 0)
667 delay++;
668
669 tst_fzsync_time(&pair->a_start);
670 }
671
672 /**
673 * Marks the end of a race region in thread A
674 *
675 * @relates tst_fzsync_pair
676 * @sa tst_fzsync_start_race_a
677 */
tst_fzsync_end_race_a(struct tst_fzsync_pair * pair)678 static inline void tst_fzsync_end_race_a(struct tst_fzsync_pair *pair)
679 {
680 tst_fzsync_time(&pair->a_end);
681 tst_fzsync_pair_wait(&pair->a_cntr, &pair->b_cntr, &pair->spins);
682 }
683
684 /**
685 * Marks the start of a race region in thread B
686 *
687 * @relates tst_fzsync_pair
688 * @sa tst_fzsync_start_race_a
689 */
tst_fzsync_start_race_b(struct tst_fzsync_pair * pair)690 static inline void tst_fzsync_start_race_b(struct tst_fzsync_pair *pair)
691 {
692 volatile int delay;
693
694 tst_fzsync_wait_b(pair);
695
696 delay = pair->delay;
697 while (delay > 0)
698 delay--;
699
700 tst_fzsync_time(&pair->b_start);
701 }
702
703 /**
704 * Marks the end of a race region in thread B
705 *
706 * @relates tst_fzsync_pair
707 * @sa tst_fzsync_start_race_a
708 */
tst_fzsync_end_race_b(struct tst_fzsync_pair * pair)709 static inline void tst_fzsync_end_race_b(struct tst_fzsync_pair *pair)
710 {
711 tst_fzsync_time(&pair->b_end);
712 tst_fzsync_pair_wait(&pair->b_cntr, &pair->a_cntr, &pair->spins);
713 }
714
715 /**
716 * Add some amount to the delay bias
717 *
718 * @relates tst_fzsync_pair
719 * @param change The amount to add, can be negative
720 *
721 * A positive change delays thread B and a negative one delays thread
722 * A.
723 *
724 * It is intended to be used in tests where the time taken by syscall A and/or
725 * B are significantly affected by their chronological order. To the extent
726 * that the delay range will not include the correct values if too many of the
727 * initial samples are taken when the syscalls (or operations within the
728 * syscalls) happen in the wrong order.
729 *
730 * An example of this is cve/cve-2016-7117.c where a call to close() is racing
731 * with a call to recvmmsg(). If close() happens before recvmmsg() has chance
732 * to check if the file descriptor is open then recvmmsg() completes very
733 * quickly. If the call to close() happens once recvmmsg() has already checked
734 * the descriptor it takes much longer. The sample where recvmmsg() completes
735 * quickly is essentially invalid for our purposes. The test uses the simple
736 * heuristic of whether recvmmsg() returns EBADF, to decide if it should call
737 * tst_fzsync_pair_add_bias() to further delay syscall B.
738 */
tst_fzsync_pair_add_bias(struct tst_fzsync_pair * pair,int change)739 static inline void tst_fzsync_pair_add_bias(struct tst_fzsync_pair *pair, int change)
740 {
741 if (pair->sampling > 0)
742 pair->delay_bias += change;
743 }
744
745 #endif /* TST_FUZZY_SYNC_H__ */
746