drivers/misc/lkdtm/refcount.c

Source file repositories/reference/linux-study-clean/drivers/misc/lkdtm/refcount.c

File Facts

System
Linux kernel
Corpus path
drivers/misc/lkdtm/refcount.c
Extension
.c
Size
11404 bytes
Lines
436
Domain
Driver Families
Bucket
drivers/misc
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

// 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)
{
	switch (refcount_read(ref)) {
	case REFCOUNT_SATURATED:
		pr_info("Overflow detected: saturated\n");
		break;
	case REFCOUNT_MAX:
		pr_warn("Overflow detected: unsafely reset to max\n");
		break;
	default:
		pr_err("Fail: refcount wrapped to %d\n", refcount_read(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_t over = REFCOUNT_INIT(REFCOUNT_MAX - 1);

	pr_info("attempting good refcount_inc() without overflow\n");
	refcount_dec(&over);
	refcount_inc(&over);

	pr_info("attempting bad refcount_inc() overflow\n");
	refcount_inc(&over);
	refcount_inc(&over);

	overflow_check(&over);
}

/* refcount_add() should behave just like refcount_inc() above. */
static void lkdtm_REFCOUNT_ADD_OVERFLOW(void)
{
	refcount_t over = REFCOUNT_INIT(REFCOUNT_MAX - 1);

	pr_info("attempting good refcount_add() without overflow\n");
	refcount_dec(&over);
	refcount_dec(&over);
	refcount_dec(&over);
	refcount_dec(&over);
	refcount_add(4, &over);

	pr_info("attempting bad refcount_add() overflow\n");
	refcount_add(4, &over);

	overflow_check(&over);
}

/* refcount_inc_not_zero() should behave just like refcount_inc() above. */
static void lkdtm_REFCOUNT_INC_NOT_ZERO_OVERFLOW(void)
{
	refcount_t over = REFCOUNT_INIT(REFCOUNT_MAX);

	pr_info("attempting bad refcount_inc_not_zero() overflow\n");
	if (!refcount_inc_not_zero(&over))
		pr_warn("Weird: refcount_inc_not_zero() reported zero\n");

	overflow_check(&over);
}

/* refcount_add_not_zero() should behave just like refcount_inc() above. */
static void lkdtm_REFCOUNT_ADD_NOT_ZERO_OVERFLOW(void)
{
	refcount_t over = REFCOUNT_INIT(REFCOUNT_MAX);

	pr_info("attempting bad refcount_add_not_zero() overflow\n");
	if (!refcount_add_not_zero(6, &over))
		pr_warn("Weird: refcount_add_not_zero() reported zero\n");

	overflow_check(&over);
}

static void check_zero(refcount_t *ref)
{
	switch (refcount_read(ref)) {
	case REFCOUNT_SATURATED:
		pr_info("Zero detected: saturated\n");
		break;
	case REFCOUNT_MAX:

Annotation

Implementation Notes