tools/testing/selftests/powerpc/ptrace/ptrace-pkey.c

Source file repositories/reference/linux-study-clean/tools/testing/selftests/powerpc/ptrace/ptrace-pkey.c

File Facts

System
Linux kernel
Corpus path
tools/testing/selftests/powerpc/ptrace/ptrace-pkey.c
Extension
.c
Size
8403 bytes
Lines
307
Domain
Support Tooling And Documentation
Bucket
tools
Inferred role
Support Tooling And Documentation: implementation source
Status
source implementation candidate

Why This File Exists

Repository support layer: documentation, build tooling, samples, user-space helper tools, generated initramfs support, licenses, and validation utilities.

Dependency Surface

Detected Declarations

Annotated Snippet

struct shared_info {
	struct child_sync child_sync;

	/* AMR value the parent expects to read from the child. */
	unsigned long amr1;

	/* AMR value the parent is expected to write to the child. */
	unsigned long amr2;

	/* AMR value that ptrace should refuse to write to the child. */
	unsigned long invalid_amr;

	/* IAMR value the parent expects to read from the child. */
	unsigned long expected_iamr;

	/* UAMOR value the parent expects to read from the child. */
	unsigned long expected_uamor;

	/*
	 * IAMR and UAMOR values that ptrace should refuse to write to the child
	 * (even though they're valid ones) because userspace doesn't have
	 * access to those registers.
	 */
	unsigned long invalid_iamr;
	unsigned long invalid_uamor;
};

static int child(struct shared_info *info)
{
	unsigned long reg;
	bool disable_execute = true;
	int pkey1, pkey2, pkey3;
	int ret;

	/* Wait until parent fills out the initial register values. */
	ret = wait_parent(&info->child_sync);
	if (ret)
		return ret;

	/* Get some pkeys so that we can change their bits in the AMR. */
	pkey1 = sys_pkey_alloc(0, PKEY_DISABLE_EXECUTE);
	if (pkey1 < 0) {
		pkey1 = sys_pkey_alloc(0, PKEY_UNRESTRICTED);
		CHILD_FAIL_IF(pkey1 < 0, &info->child_sync);

		disable_execute = false;
	}

	pkey2 = sys_pkey_alloc(0, PKEY_UNRESTRICTED);
	CHILD_FAIL_IF(pkey2 < 0, &info->child_sync);

	pkey3 = sys_pkey_alloc(0, PKEY_UNRESTRICTED);
	CHILD_FAIL_IF(pkey3 < 0, &info->child_sync);

	info->amr1 |= 3ul << pkeyshift(pkey1);
	info->amr2 |= 3ul << pkeyshift(pkey2);
	/*
	 * invalid amr value where we try to force write
	 * things which are deined by a uamor setting.
	 */
	info->invalid_amr = info->amr2 | (~0x0UL & ~info->expected_uamor);

	/*
	 * if PKEY_DISABLE_EXECUTE succeeded we should update the expected_iamr
	 */
	if (disable_execute)
		info->expected_iamr |= 1ul << pkeyshift(pkey1);
	else
		info->expected_iamr &= ~(1ul << pkeyshift(pkey1));

	/*
	 * We allocated pkey2 and pkey 3 above. Clear the IAMR bits.
	 */
	info->expected_iamr &= ~(1ul << pkeyshift(pkey2));
	info->expected_iamr &= ~(1ul << pkeyshift(pkey3));

	/*
	 * Create an IAMR value different from expected value.
	 * Kernel will reject an IAMR and UAMOR change.
	 */
	info->invalid_iamr = info->expected_iamr | (1ul << pkeyshift(pkey1) | 1ul << pkeyshift(pkey2));
	info->invalid_uamor = info->expected_uamor & ~(0x3ul << pkeyshift(pkey1));

	printf("%-30s AMR: %016lx pkey1: %d pkey2: %d pkey3: %d\n",
	       user_write, info->amr1, pkey1, pkey2, pkey3);

	set_amr(info->amr1);

	/* Wait for parent to read our AMR value and write a new one. */
	ret = prod_parent(&info->child_sync);

Annotation

Implementation Notes