0001
0002
0003
0004
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
0025
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
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
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
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
0103
0104
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
0123
0124
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
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
0157
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
0172
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
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
0229
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
0268
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
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
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
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
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
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
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
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
0371
0372
0373
0374
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 };