zdtm: check reservation mmaps are restored correctly

mmaps done just for reserving address space something like

void *addr = mmap(NULL, SIZE, PROT_NONE,
	      MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);

Ensure that these do not have ac flag set in /proc/pid/smaps.

Signed-off-by: Bhavik Sachdev <b.sachdev1904@gmail.com>
This commit is contained in:
Bhavik Sachdev 2026-04-25 03:29:31 +05:30 committed by Andrei Vagin
parent 7daaa11aa0
commit b0b89a94f3
4 changed files with 136 additions and 1 deletions

View file

@ -215,6 +215,7 @@ TST_NOFILE := \
dumpable02 \
remap_dead_pid \
remap_dead_pid_root \
reservation_mmaps \
scm00 \
scm01 \
scm02 \
@ -663,6 +664,7 @@ mntns_root_bind02: CFLAGS += -DROOT_BIND02
maps02: get_smaps_bits.o
mlock_setuid: get_smaps_bits.o
thp_disable: get_smaps_bits.o
reservation_mmaps: get_smaps_bits.o
inotify01: CFLAGS += -DINOTIFY01
unlink_fstat01+: CFLAGS += -DUNLINK_OVER
unlink_fstat04: CFLAGS += -DUNLINK_FSTAT04

View file

@ -80,7 +80,7 @@ static void parse_vmflags(char *buf, unsigned long *flags, unsigned long *madv)
#define is_hex_digit(c) (((c) >= '0' && (c) <= '9') || ((c) >= 'a' && (c) <= 'f') || ((c) >= 'A' && (c) <= 'F'))
static int is_vma_range_fmt(char *line, unsigned long *start, unsigned long *end)
int is_vma_range_fmt(char *line, unsigned long *start, unsigned long *end)
{
char *p = line;
while (*line && is_hex_digit(*line))

View file

@ -2,5 +2,6 @@
#define ZDTM_GET_SMAPS_BITS_H_
extern int get_smaps_bits(unsigned long where, unsigned long *flags, unsigned long *madv);
extern int is_vma_range_fmt(char *line, unsigned long *start, unsigned long *end);
#endif /* ZDTM_GET_SMAPS_BITS_H_ */

View file

@ -0,0 +1,132 @@
#include <sys/mman.h>
#include "zdtmtst.h"
#include "get_smaps_bits.h"
#define SIZE (4UL * (1UL << 20)) /* 4MB */
const char *test_doc = "Check mmaps done for reserving virtual address space, do not have ac flag set in /proc/pid/smaps\n";
const char *test_author = "Bhavik Sachdev <b.sachdev1904@gmail.com>";
static void check_ac_flag(char *buf, bool *no_ac)
{
char *tok;
if (!buf[0])
return;
*no_ac = true;
tok = strtok(buf, " \n");
if (!tok)
return;
#define _vmflag_match(_t, _s) (_t[0] == _s[0] && _t[1] == _s[1])
do {
if (_vmflag_match(tok, "ac")) {
*no_ac = false;
return;
}
/*
* Anything else is just ignored.
*/
} while ((tok = strtok(NULL, " \n")));
#undef _vmflag_match
return;
}
static int is_accountable(unsigned long where, bool *no_ac)
{
unsigned long start = 0, end = 0;
FILE *smaps = NULL;
char buf[1024];
int found = 0;
if (!where)
return 0;
smaps = fopen("/proc/self/smaps", "r");
if (!smaps) {
pr_perror("Can't open smaps");
return -1;
}
while (fgets(buf, sizeof(buf), smaps)) {
is_vma_range_fmt(buf, &start, &end);
if (!strncmp(buf, "VmFlags: ", 9) && start <= where && where < end) {
found = 1;
check_ac_flag(buf, no_ac);
break;
}
}
fclose(smaps);
if (!found) {
pr_perror("VmFlags not found for %lx", where);
return -1;
}
return 0;
}
int main(int argc, char **argv)
{
uint32_t crc = ~0;
uint8_t *data_mmap, *reservation_mmap;
bool no_ac;
test_init(argc, argv);
data_mmap = mmap(NULL, SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
if (data_mmap == MAP_FAILED) {
pr_perror("Failed to mmap %lu Mb memory", SIZE >> 20);
return 1;
}
reservation_mmap = mmap(NULL, SIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
if (reservation_mmap == MAP_FAILED) {
pr_perror("Failed to mmap %lu Mb memory", SIZE >> 20);
return 1;
}
datagen(data_mmap, SIZE, &crc);
if (mprotect(data_mmap, SIZE, PROT_NONE)) {
pr_perror("Failed to set protections on %p", data_mmap);
return 1;
}
test_daemon();
test_waitsig();
/*
* check that a mmap whose memory protection got changed
* to PROT_NONE still has the data stored in it.
*/
if (mprotect(data_mmap, SIZE, PROT_READ)) {
pr_perror("Failed to set protections on %p", data_mmap);
return 1;
}
crc = ~0;
if (datachk(data_mmap, SIZE, &crc)) {
fail("Data mismatch");
return 1;
}
/* reservation_mmap should not have ac flag set in /proc/pid/smaps */
if (is_accountable((unsigned long)reservation_mmap, &no_ac)) {
fail("could not check for no ac flag on reservation mmap");
return 1;
}
if (!no_ac) {
fail("reservation mmap has ac flag set");
return 1;
}
pass();
return 0;
}