Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * This is for all the tests related to refcount bugs (e.g. overflow,
0004  * underflow, reaching zero untested, etc).
0005  */
0006 #include "lkdtm.h"
0007 #include <linux/refcount.h>
0008 
0009 static void overflow_check(refcount_t *ref)
0010 {
0011     switch (refcount_read(ref)) {
0012     case REFCOUNT_SATURATED:
0013         pr_info("Overflow detected: saturated\n");
0014         break;
0015     case REFCOUNT_MAX:
0016         pr_warn("Overflow detected: unsafely reset to max\n");
0017         break;
0018     default:
0019         pr_err("Fail: refcount wrapped to %d\n", refcount_read(ref));
0020     }
0021 }
0022 
0023 /*
0024  * A refcount_inc() above the maximum value of the refcount implementation,
0025  * should at least saturate, and at most also WARN.
0026  */
0027 static void lkdtm_REFCOUNT_INC_OVERFLOW(void)
0028 {
0029     refcount_t over = REFCOUNT_INIT(REFCOUNT_MAX - 1);
0030 
0031     pr_info("attempting good refcount_inc() without overflow\n");
0032     refcount_dec(&over);
0033     refcount_inc(&over);
0034 
0035     pr_info("attempting bad refcount_inc() overflow\n");
0036     refcount_inc(&over);
0037     refcount_inc(&over);
0038 
0039     overflow_check(&over);
0040 }
0041 
0042 /* refcount_add() should behave just like refcount_inc() above. */
0043 static void lkdtm_REFCOUNT_ADD_OVERFLOW(void)
0044 {
0045     refcount_t over = REFCOUNT_INIT(REFCOUNT_MAX - 1);
0046 
0047     pr_info("attempting good refcount_add() without overflow\n");
0048     refcount_dec(&over);
0049     refcount_dec(&over);
0050     refcount_dec(&over);
0051     refcount_dec(&over);
0052     refcount_add(4, &over);
0053 
0054     pr_info("attempting bad refcount_add() overflow\n");
0055     refcount_add(4, &over);
0056 
0057     overflow_check(&over);
0058 }
0059 
0060 /* refcount_inc_not_zero() should behave just like refcount_inc() above. */
0061 static void lkdtm_REFCOUNT_INC_NOT_ZERO_OVERFLOW(void)
0062 {
0063     refcount_t over = REFCOUNT_INIT(REFCOUNT_MAX);
0064 
0065     pr_info("attempting bad refcount_inc_not_zero() overflow\n");
0066     if (!refcount_inc_not_zero(&over))
0067         pr_warn("Weird: refcount_inc_not_zero() reported zero\n");
0068 
0069     overflow_check(&over);
0070 }
0071 
0072 /* refcount_add_not_zero() should behave just like refcount_inc() above. */
0073 static void lkdtm_REFCOUNT_ADD_NOT_ZERO_OVERFLOW(void)
0074 {
0075     refcount_t over = REFCOUNT_INIT(REFCOUNT_MAX);
0076 
0077     pr_info("attempting bad refcount_add_not_zero() overflow\n");
0078     if (!refcount_add_not_zero(6, &over))
0079         pr_warn("Weird: refcount_add_not_zero() reported zero\n");
0080 
0081     overflow_check(&over);
0082 }
0083 
0084 static void check_zero(refcount_t *ref)
0085 {
0086     switch (refcount_read(ref)) {
0087     case REFCOUNT_SATURATED:
0088         pr_info("Zero detected: saturated\n");
0089         break;
0090     case REFCOUNT_MAX:
0091         pr_warn("Zero detected: unsafely reset to max\n");
0092         break;
0093     case 0:
0094         pr_warn("Still at zero: refcount_inc/add() must not inc-from-0\n");
0095         break;
0096     default:
0097         pr_err("Fail: refcount went crazy: %d\n", refcount_read(ref));
0098     }
0099 }
0100 
0101 /*
0102  * A refcount_dec(), as opposed to a refcount_dec_and_test(), when it hits
0103  * zero it should either saturate (when inc-from-zero isn't protected)
0104  * or stay at zero (when inc-from-zero is protected) and should WARN for both.
0105  */
0106 static void lkdtm_REFCOUNT_DEC_ZERO(void)
0107 {
0108     refcount_t zero = REFCOUNT_INIT(2);
0109 
0110     pr_info("attempting good refcount_dec()\n");
0111     refcount_dec(&zero);
0112 
0113     pr_info("attempting bad refcount_dec() to zero\n");
0114     refcount_dec(&zero);
0115 
0116     check_zero(&zero);
0117 }
0118 
0119 static void check_negative(refcount_t *ref, int start)
0120 {
0121     /*
0122      * refcount_t refuses to move a refcount at all on an
0123      * over-sub, so we have to track our starting position instead of
0124      * looking only at zero-pinning.
0125      */
0126     if (refcount_read(ref) == start) {
0127         pr_warn("Still at %d: refcount_inc/add() must not inc-from-0\n",
0128             start);
0129         return;
0130     }
0131 
0132     switch (refcount_read(ref)) {
0133     case REFCOUNT_SATURATED:
0134         pr_info("Negative detected: saturated\n");
0135         break;
0136     case REFCOUNT_MAX:
0137         pr_warn("Negative detected: unsafely reset to max\n");
0138         break;
0139     default:
0140         pr_err("Fail: refcount went crazy: %d\n", refcount_read(ref));
0141     }
0142 }
0143 
0144 /* A refcount_dec() going negative should saturate and may WARN. */
0145 static void lkdtm_REFCOUNT_DEC_NEGATIVE(void)
0146 {
0147     refcount_t neg = REFCOUNT_INIT(0);
0148 
0149     pr_info("attempting bad refcount_dec() below zero\n");
0150     refcount_dec(&neg);
0151 
0152     check_negative(&neg, 0);
0153 }
0154 
0155 /*
0156  * A refcount_dec_and_test() should act like refcount_dec() above when
0157  * going negative.
0158  */
0159 static void lkdtm_REFCOUNT_DEC_AND_TEST_NEGATIVE(void)
0160 {
0161     refcount_t neg = REFCOUNT_INIT(0);
0162 
0163     pr_info("attempting bad refcount_dec_and_test() below zero\n");
0164     if (refcount_dec_and_test(&neg))
0165         pr_warn("Weird: refcount_dec_and_test() reported zero\n");
0166 
0167     check_negative(&neg, 0);
0168 }
0169 
0170 /*
0171  * A refcount_sub_and_test() should act like refcount_dec_and_test()
0172  * above when going negative.
0173  */
0174 static void lkdtm_REFCOUNT_SUB_AND_TEST_NEGATIVE(void)
0175 {
0176     refcount_t neg = REFCOUNT_INIT(3);
0177 
0178     pr_info("attempting bad refcount_sub_and_test() below zero\n");
0179     if (refcount_sub_and_test(5, &neg))
0180         pr_warn("Weird: refcount_sub_and_test() reported zero\n");
0181 
0182     check_negative(&neg, 3);
0183 }
0184 
0185 static void check_from_zero(refcount_t *ref)
0186 {
0187     switch (refcount_read(ref)) {
0188     case 0:
0189         pr_info("Zero detected: stayed at zero\n");
0190         break;
0191     case REFCOUNT_SATURATED:
0192         pr_info("Zero detected: saturated\n");
0193         break;
0194     case REFCOUNT_MAX:
0195         pr_warn("Zero detected: unsafely reset to max\n");
0196         break;
0197     default:
0198         pr_info("Fail: zero not detected, incremented to %d\n",
0199             refcount_read(ref));
0200     }
0201 }
0202 
0203 /*
0204  * A refcount_inc() from zero should pin to zero or saturate and may WARN.
0205  */
0206 static void lkdtm_REFCOUNT_INC_ZERO(void)
0207 {
0208     refcount_t zero = REFCOUNT_INIT(0);
0209 
0210     pr_info("attempting safe refcount_inc_not_zero() from zero\n");
0211     if (!refcount_inc_not_zero(&zero)) {
0212         pr_info("Good: zero detected\n");
0213         if (refcount_read(&zero) == 0)
0214             pr_info("Correctly stayed at zero\n");
0215         else
0216             pr_err("Fail: refcount went past zero!\n");
0217     } else {
0218         pr_err("Fail: Zero not detected!?\n");
0219     }
0220 
0221     pr_info("attempting bad refcount_inc() from zero\n");
0222     refcount_inc(&zero);
0223 
0224     check_from_zero(&zero);
0225 }
0226 
0227 /*
0228  * A refcount_add() should act like refcount_inc() above when starting
0229  * at zero.
0230  */
0231 static void lkdtm_REFCOUNT_ADD_ZERO(void)
0232 {
0233     refcount_t zero = REFCOUNT_INIT(0);
0234 
0235     pr_info("attempting safe refcount_add_not_zero() from zero\n");
0236     if (!refcount_add_not_zero(3, &zero)) {
0237         pr_info("Good: zero detected\n");
0238         if (refcount_read(&zero) == 0)
0239             pr_info("Correctly stayed at zero\n");
0240         else
0241             pr_err("Fail: refcount went past zero\n");
0242     } else {
0243         pr_err("Fail: Zero not detected!?\n");
0244     }
0245 
0246     pr_info("attempting bad refcount_add() from zero\n");
0247     refcount_add(3, &zero);
0248 
0249     check_from_zero(&zero);
0250 }
0251 
0252 static void check_saturated(refcount_t *ref)
0253 {
0254     switch (refcount_read(ref)) {
0255     case REFCOUNT_SATURATED:
0256         pr_info("Saturation detected: still saturated\n");
0257         break;
0258     case REFCOUNT_MAX:
0259         pr_warn("Saturation detected: unsafely reset to max\n");
0260         break;
0261     default:
0262         pr_err("Fail: refcount went crazy: %d\n", refcount_read(ref));
0263     }
0264 }
0265 
0266 /*
0267  * A refcount_inc() from a saturated value should at most warn about
0268  * being saturated already.
0269  */
0270 static void lkdtm_REFCOUNT_INC_SATURATED(void)
0271 {
0272     refcount_t sat = REFCOUNT_INIT(REFCOUNT_SATURATED);
0273 
0274     pr_info("attempting bad refcount_inc() from saturated\n");
0275     refcount_inc(&sat);
0276 
0277     check_saturated(&sat);
0278 }
0279 
0280 /* Should act like refcount_inc() above from saturated. */
0281 static void lkdtm_REFCOUNT_DEC_SATURATED(void)
0282 {
0283     refcount_t sat = REFCOUNT_INIT(REFCOUNT_SATURATED);
0284 
0285     pr_info("attempting bad refcount_dec() from saturated\n");
0286     refcount_dec(&sat);
0287 
0288     check_saturated(&sat);
0289 }
0290 
0291 /* Should act like refcount_inc() above from saturated. */
0292 static void lkdtm_REFCOUNT_ADD_SATURATED(void)
0293 {
0294     refcount_t sat = REFCOUNT_INIT(REFCOUNT_SATURATED);
0295 
0296     pr_info("attempting bad refcount_dec() from saturated\n");
0297     refcount_add(8, &sat);
0298 
0299     check_saturated(&sat);
0300 }
0301 
0302 /* Should act like refcount_inc() above from saturated. */
0303 static void lkdtm_REFCOUNT_INC_NOT_ZERO_SATURATED(void)
0304 {
0305     refcount_t sat = REFCOUNT_INIT(REFCOUNT_SATURATED);
0306 
0307     pr_info("attempting bad refcount_inc_not_zero() from saturated\n");
0308     if (!refcount_inc_not_zero(&sat))
0309         pr_warn("Weird: refcount_inc_not_zero() reported zero\n");
0310 
0311     check_saturated(&sat);
0312 }
0313 
0314 /* Should act like refcount_inc() above from saturated. */
0315 static void lkdtm_REFCOUNT_ADD_NOT_ZERO_SATURATED(void)
0316 {
0317     refcount_t sat = REFCOUNT_INIT(REFCOUNT_SATURATED);
0318 
0319     pr_info("attempting bad refcount_add_not_zero() from saturated\n");
0320     if (!refcount_add_not_zero(7, &sat))
0321         pr_warn("Weird: refcount_add_not_zero() reported zero\n");
0322 
0323     check_saturated(&sat);
0324 }
0325 
0326 /* Should act like refcount_inc() above from saturated. */
0327 static void lkdtm_REFCOUNT_DEC_AND_TEST_SATURATED(void)
0328 {
0329     refcount_t sat = REFCOUNT_INIT(REFCOUNT_SATURATED);
0330 
0331     pr_info("attempting bad refcount_dec_and_test() from saturated\n");
0332     if (refcount_dec_and_test(&sat))
0333         pr_warn("Weird: refcount_dec_and_test() reported zero\n");
0334 
0335     check_saturated(&sat);
0336 }
0337 
0338 /* Should act like refcount_inc() above from saturated. */
0339 static void lkdtm_REFCOUNT_SUB_AND_TEST_SATURATED(void)
0340 {
0341     refcount_t sat = REFCOUNT_INIT(REFCOUNT_SATURATED);
0342 
0343     pr_info("attempting bad refcount_sub_and_test() from saturated\n");
0344     if (refcount_sub_and_test(8, &sat))
0345         pr_warn("Weird: refcount_sub_and_test() reported zero\n");
0346 
0347     check_saturated(&sat);
0348 }
0349 
0350 /* Used to time the existing atomic_t when used for reference counting */
0351 static void lkdtm_ATOMIC_TIMING(void)
0352 {
0353     unsigned int i;
0354     atomic_t count = ATOMIC_INIT(1);
0355 
0356     for (i = 0; i < INT_MAX - 1; i++)
0357         atomic_inc(&count);
0358 
0359     for (i = INT_MAX; i > 0; i--)
0360         if (atomic_dec_and_test(&count))
0361             break;
0362 
0363     if (i != 1)
0364         pr_err("atomic timing: out of sync up/down cycle: %u\n", i - 1);
0365     else
0366         pr_info("atomic timing: done\n");
0367 }
0368 
0369 /*
0370  * This can be compared to ATOMIC_TIMING when implementing fast refcount
0371  * protections. Looking at the number of CPU cycles tells the real story
0372  * about performance. For example:
0373  *    cd /sys/kernel/debug/provoke-crash
0374  *    perf stat -B -- cat <(echo REFCOUNT_TIMING) > DIRECT
0375  */
0376 static void lkdtm_REFCOUNT_TIMING(void)
0377 {
0378     unsigned int i;
0379     refcount_t count = REFCOUNT_INIT(1);
0380 
0381     for (i = 0; i < INT_MAX - 1; i++)
0382         refcount_inc(&count);
0383 
0384     for (i = INT_MAX; i > 0; i--)
0385         if (refcount_dec_and_test(&count))
0386             break;
0387 
0388     if (i != 1)
0389         pr_err("refcount: out of sync up/down cycle: %u\n", i - 1);
0390     else
0391         pr_info("refcount timing: done\n");
0392 }
0393 
0394 static struct crashtype crashtypes[] = {
0395     CRASHTYPE(REFCOUNT_INC_OVERFLOW),
0396     CRASHTYPE(REFCOUNT_ADD_OVERFLOW),
0397     CRASHTYPE(REFCOUNT_INC_NOT_ZERO_OVERFLOW),
0398     CRASHTYPE(REFCOUNT_ADD_NOT_ZERO_OVERFLOW),
0399     CRASHTYPE(REFCOUNT_DEC_ZERO),
0400     CRASHTYPE(REFCOUNT_DEC_NEGATIVE),
0401     CRASHTYPE(REFCOUNT_DEC_AND_TEST_NEGATIVE),
0402     CRASHTYPE(REFCOUNT_SUB_AND_TEST_NEGATIVE),
0403     CRASHTYPE(REFCOUNT_INC_ZERO),
0404     CRASHTYPE(REFCOUNT_ADD_ZERO),
0405     CRASHTYPE(REFCOUNT_INC_SATURATED),
0406     CRASHTYPE(REFCOUNT_DEC_SATURATED),
0407     CRASHTYPE(REFCOUNT_ADD_SATURATED),
0408     CRASHTYPE(REFCOUNT_INC_NOT_ZERO_SATURATED),
0409     CRASHTYPE(REFCOUNT_ADD_NOT_ZERO_SATURATED),
0410     CRASHTYPE(REFCOUNT_DEC_AND_TEST_SATURATED),
0411     CRASHTYPE(REFCOUNT_SUB_AND_TEST_SATURATED),
0412     CRASHTYPE(ATOMIC_TIMING),
0413     CRASHTYPE(REFCOUNT_TIMING),
0414 };
0415 
0416 struct crashtype_category refcount_crashtypes = {
0417     .crashtypes = crashtypes,
0418     .len        = ARRAY_SIZE(crashtypes),
0419 };