// SPDX-License-Identifier: GPL-2.0 /* * This is for all the tests related to refcount bugs (e.g. overflow, * underflow, reaching zero untested, etc). */ #include "lkdtm.h" #include <linux/refcount.h> static void overflow_check(refcount_t *ref) { … } /* * A refcount_inc() above the maximum value of the refcount implementation, * should at least saturate, and at most also WARN. */ static void lkdtm_REFCOUNT_INC_OVERFLOW(void) { … } /* refcount_add() should behave just like refcount_inc() above. */ static void lkdtm_REFCOUNT_ADD_OVERFLOW(void) { … } /* refcount_inc_not_zero() should behave just like refcount_inc() above. */ static void lkdtm_REFCOUNT_INC_NOT_ZERO_OVERFLOW(void) { … } /* refcount_add_not_zero() should behave just like refcount_inc() above. */ static void lkdtm_REFCOUNT_ADD_NOT_ZERO_OVERFLOW(void) { … } static void check_zero(refcount_t *ref) { … } /* * A refcount_dec(), as opposed to a refcount_dec_and_test(), when it hits * zero it should either saturate (when inc-from-zero isn't protected) * or stay at zero (when inc-from-zero is protected) and should WARN for both. */ static void lkdtm_REFCOUNT_DEC_ZERO(void) { … } static void check_negative(refcount_t *ref, int start) { … } /* A refcount_dec() going negative should saturate and may WARN. */ static void lkdtm_REFCOUNT_DEC_NEGATIVE(void) { … } /* * A refcount_dec_and_test() should act like refcount_dec() above when * going negative. */ static void lkdtm_REFCOUNT_DEC_AND_TEST_NEGATIVE(void) { … } /* * A refcount_sub_and_test() should act like refcount_dec_and_test() * above when going negative. */ static void lkdtm_REFCOUNT_SUB_AND_TEST_NEGATIVE(void) { … } static void check_from_zero(refcount_t *ref) { … } /* * A refcount_inc() from zero should pin to zero or saturate and may WARN. */ static void lkdtm_REFCOUNT_INC_ZERO(void) { … } /* * A refcount_add() should act like refcount_inc() above when starting * at zero. */ static void lkdtm_REFCOUNT_ADD_ZERO(void) { … } static void check_saturated(refcount_t *ref) { … } /* * A refcount_inc() from a saturated value should at most warn about * being saturated already. */ static void lkdtm_REFCOUNT_INC_SATURATED(void) { … } /* Should act like refcount_inc() above from saturated. */ static void lkdtm_REFCOUNT_DEC_SATURATED(void) { … } /* Should act like refcount_inc() above from saturated. */ static void lkdtm_REFCOUNT_ADD_SATURATED(void) { … } /* Should act like refcount_inc() above from saturated. */ static void lkdtm_REFCOUNT_INC_NOT_ZERO_SATURATED(void) { … } /* Should act like refcount_inc() above from saturated. */ static void lkdtm_REFCOUNT_ADD_NOT_ZERO_SATURATED(void) { … } /* Should act like refcount_inc() above from saturated. */ static void lkdtm_REFCOUNT_DEC_AND_TEST_SATURATED(void) { … } /* Should act like refcount_inc() above from saturated. */ static void lkdtm_REFCOUNT_SUB_AND_TEST_SATURATED(void) { … } /* Used to time the existing atomic_t when used for reference counting */ static void lkdtm_ATOMIC_TIMING(void) { … } /* * This can be compared to ATOMIC_TIMING when implementing fast refcount * protections. Looking at the number of CPU cycles tells the real story * about performance. For example: * cd /sys/kernel/debug/provoke-crash * perf stat -B -- cat <(echo REFCOUNT_TIMING) > DIRECT */ static void lkdtm_REFCOUNT_TIMING(void) { … } static struct crashtype crashtypes[] = …; struct crashtype_category refcount_crashtypes = …;