1 /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 /* 3 * Copyright (c) 2017-2018 Richard Palethorpe <rpalethorpe (at) 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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