mm/kfence/kfence_test.c

Source file repositories/reference/linux-study-clean/mm/kfence/kfence_test.c

File Facts

System
Linux kernel
Corpus path
mm/kfence/kfence_test.c
Extension
.c
Size
24490 bytes
Lines
875
Domain
Core OS
Bucket
Memory Management
Inferred role
Core OS: implementation source
Status
source implementation candidate

Why This File Exists

Core operating-system implementation surface: boot, tasks, memory, VFS, syscall-facing interfaces, synchronization, credentials, and isolation.

Dependency Surface

Detected Declarations

Annotated Snippet

struct expect_report {
	enum kfence_error_type type; /* The type or error. */
	void *fn; /* Function pointer to expected function where access occurred. */
	char *addr; /* Address at which the bad access occurred. */
	bool is_write; /* Is access a write. */
};

static const char *get_access_type(const struct expect_report *r)
{
	return str_write_read(r->is_write);
}

/* Check observed report matches information in @r. */
static bool report_matches(const struct expect_report *r)
{
	unsigned long addr = (unsigned long)r->addr;
	bool ret = false;
	unsigned long flags;
	typeof(observed.lines) expect;
	const char *end;
	char *cur;

	/* Doubled-checked locking. */
	if (!report_available())
		return false;

	/* Generate expected report contents. */

	/* Title */
	cur = expect[0];
	end = ARRAY_END(expect[0]);
	switch (r->type) {
	case KFENCE_ERROR_OOB:
		cur += scnprintf(cur, end - cur, "BUG: KFENCE: out-of-bounds %s",
				 get_access_type(r));
		break;
	case KFENCE_ERROR_UAF:
		cur += scnprintf(cur, end - cur, "BUG: KFENCE: use-after-free %s",
				 get_access_type(r));
		break;
	case KFENCE_ERROR_CORRUPTION:
		cur += scnprintf(cur, end - cur, "BUG: KFENCE: memory corruption");
		break;
	case KFENCE_ERROR_INVALID:
		cur += scnprintf(cur, end - cur, "BUG: KFENCE: invalid %s",
				 get_access_type(r));
		break;
	case KFENCE_ERROR_INVALID_FREE:
		cur += scnprintf(cur, end - cur, "BUG: KFENCE: invalid free");
		break;
	}

	scnprintf(cur, end - cur, " in %pS", r->fn);
	/* The exact offset won't match, remove it; also strip module name. */
	cur = strchr(expect[0], '+');
	if (cur)
		*cur = '\0';

	/* Access information */
	cur = expect[1];
	end = ARRAY_END(expect[1]);

	switch (r->type) {
	case KFENCE_ERROR_OOB:
		cur += scnprintf(cur, end - cur, "Out-of-bounds %s at", get_access_type(r));
		addr = arch_kfence_test_address(addr);
		break;
	case KFENCE_ERROR_UAF:
		cur += scnprintf(cur, end - cur, "Use-after-free %s at", get_access_type(r));
		addr = arch_kfence_test_address(addr);
		break;
	case KFENCE_ERROR_CORRUPTION:
		cur += scnprintf(cur, end - cur, "Corrupted memory at");
		break;
	case KFENCE_ERROR_INVALID:
		cur += scnprintf(cur, end - cur, "Invalid %s at", get_access_type(r));
		addr = arch_kfence_test_address(addr);
		break;
	case KFENCE_ERROR_INVALID_FREE:
		cur += scnprintf(cur, end - cur, "Invalid free of");
		break;
	}

	cur += scnprintf(cur, end - cur, " 0x%p", (void *)addr);

	spin_lock_irqsave(&observed.lock, flags);
	if (!report_available())
		goto out; /* A new report is being captured. */

	/* Finally match expected output to what we actually observed. */

Annotation

Implementation Notes