162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * This test covers the anonymous VMA naming functionality through prctl calls
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <errno.h>
762306a36Sopenharmony_ci#include <sys/prctl.h>
862306a36Sopenharmony_ci#include <stdio.h>
962306a36Sopenharmony_ci#include <stdlib.h>
1062306a36Sopenharmony_ci#include <sys/mman.h>
1162306a36Sopenharmony_ci#include <string.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include "../kselftest_harness.h"
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#define AREA_SIZE 1024
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#define GOOD_NAME "goodname"
1862306a36Sopenharmony_ci#define BAD_NAME "badname\1"
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#ifndef PR_SET_VMA
2162306a36Sopenharmony_ci#define PR_SET_VMA 0x53564d41
2262306a36Sopenharmony_ci#define PR_SET_VMA_ANON_NAME 0
2362306a36Sopenharmony_ci#endif
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ciint rename_vma(unsigned long addr, unsigned long size, char *name)
2762306a36Sopenharmony_ci{
2862306a36Sopenharmony_ci	int res;
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci	res = prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, addr, size, name);
3162306a36Sopenharmony_ci	if (res < 0)
3262306a36Sopenharmony_ci		return -errno;
3362306a36Sopenharmony_ci	return res;
3462306a36Sopenharmony_ci}
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ciint was_renaming_successful(char *target_name, unsigned long ptr)
3762306a36Sopenharmony_ci{
3862306a36Sopenharmony_ci	FILE *maps_file;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	char line_buf[512], name[128], mode[8];
4162306a36Sopenharmony_ci	unsigned long start_addr, end_addr, offset;
4262306a36Sopenharmony_ci	unsigned int major_id, minor_id, node_id;
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	char target_buf[128];
4562306a36Sopenharmony_ci	int res = 0, sscanf_res;
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	// The entry name in maps will be in format [anon:<target_name>]
4862306a36Sopenharmony_ci	sprintf(target_buf, "[anon:%s]", target_name);
4962306a36Sopenharmony_ci	maps_file = fopen("/proc/self/maps", "r");
5062306a36Sopenharmony_ci	if (!maps_file) {
5162306a36Sopenharmony_ci		printf("## /proc/self/maps file opening error\n");
5262306a36Sopenharmony_ci		return 0;
5362306a36Sopenharmony_ci	}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	// Parse the maps file to find the entry we renamed
5662306a36Sopenharmony_ci	while (fgets(line_buf, sizeof(line_buf), maps_file)) {
5762306a36Sopenharmony_ci		sscanf_res = sscanf(line_buf, "%lx-%lx %7s %lx %u:%u %u %s", &start_addr,
5862306a36Sopenharmony_ci					&end_addr, mode, &offset, &major_id,
5962306a36Sopenharmony_ci					&minor_id, &node_id, name);
6062306a36Sopenharmony_ci		if (sscanf_res == EOF) {
6162306a36Sopenharmony_ci			res = 0;
6262306a36Sopenharmony_ci			printf("## EOF while parsing the maps file\n");
6362306a36Sopenharmony_ci			break;
6462306a36Sopenharmony_ci		}
6562306a36Sopenharmony_ci		if (!strcmp(name, target_buf) && start_addr == ptr) {
6662306a36Sopenharmony_ci			res = 1;
6762306a36Sopenharmony_ci			break;
6862306a36Sopenharmony_ci		}
6962306a36Sopenharmony_ci	}
7062306a36Sopenharmony_ci	fclose(maps_file);
7162306a36Sopenharmony_ci	return res;
7262306a36Sopenharmony_ci}
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ciFIXTURE(vma) {
7562306a36Sopenharmony_ci	void *ptr_anon, *ptr_not_anon;
7662306a36Sopenharmony_ci};
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ciFIXTURE_SETUP(vma) {
7962306a36Sopenharmony_ci	self->ptr_anon = mmap(NULL, AREA_SIZE, PROT_READ | PROT_WRITE,
8062306a36Sopenharmony_ci					MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
8162306a36Sopenharmony_ci	ASSERT_NE(self->ptr_anon, NULL);
8262306a36Sopenharmony_ci	self->ptr_not_anon = mmap(NULL, AREA_SIZE, PROT_READ | PROT_WRITE,
8362306a36Sopenharmony_ci					MAP_PRIVATE, 0, 0);
8462306a36Sopenharmony_ci	ASSERT_NE(self->ptr_not_anon, NULL);
8562306a36Sopenharmony_ci}
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ciFIXTURE_TEARDOWN(vma) {
8862306a36Sopenharmony_ci	munmap(self->ptr_anon, AREA_SIZE);
8962306a36Sopenharmony_ci	munmap(self->ptr_not_anon, AREA_SIZE);
9062306a36Sopenharmony_ci}
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ciTEST_F(vma, renaming) {
9362306a36Sopenharmony_ci	TH_LOG("Try to rename the VMA with correct parameters");
9462306a36Sopenharmony_ci	EXPECT_GE(rename_vma((unsigned long)self->ptr_anon, AREA_SIZE, GOOD_NAME), 0);
9562306a36Sopenharmony_ci	EXPECT_TRUE(was_renaming_successful(GOOD_NAME, (unsigned long)self->ptr_anon));
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	TH_LOG("Try to pass invalid name (with non-printable character \\1) to rename the VMA");
9862306a36Sopenharmony_ci	EXPECT_EQ(rename_vma((unsigned long)self->ptr_anon, AREA_SIZE, BAD_NAME), -EINVAL);
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	TH_LOG("Try to rename non-anonymous VMA");
10162306a36Sopenharmony_ci	EXPECT_EQ(rename_vma((unsigned long) self->ptr_not_anon, AREA_SIZE, GOOD_NAME), -EINVAL);
10262306a36Sopenharmony_ci}
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ciTEST_HARNESS_MAIN
105