From b0b89a94f37242c002fff381971fd178cc2b9dbf Mon Sep 17 00:00:00 2001 From: Bhavik Sachdev Date: Sat, 25 Apr 2026 03:29:31 +0530 Subject: [PATCH] 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 --- test/zdtm/static/Makefile | 2 + test/zdtm/static/get_smaps_bits.c | 2 +- test/zdtm/static/get_smaps_bits.h | 1 + test/zdtm/static/reservation_mmaps.c | 132 +++++++++++++++++++++++++++ 4 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 test/zdtm/static/reservation_mmaps.c diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index c2eeb7e99..947cafd37 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -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 diff --git a/test/zdtm/static/get_smaps_bits.c b/test/zdtm/static/get_smaps_bits.c index 3d952ac95..69e51d340 100644 --- a/test/zdtm/static/get_smaps_bits.c +++ b/test/zdtm/static/get_smaps_bits.c @@ -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)) diff --git a/test/zdtm/static/get_smaps_bits.h b/test/zdtm/static/get_smaps_bits.h index ce1070daf..ec4e79fb1 100644 --- a/test/zdtm/static/get_smaps_bits.h +++ b/test/zdtm/static/get_smaps_bits.h @@ -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_ */ diff --git a/test/zdtm/static/reservation_mmaps.c b/test/zdtm/static/reservation_mmaps.c new file mode 100644 index 000000000..c544d0c1f --- /dev/null +++ b/test/zdtm/static/reservation_mmaps.c @@ -0,0 +1,132 @@ +#include + +#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 "; + +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; +}