1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) International Business Machines Corp., 2001
4 * Copyright (c) 2024 Ricardo B. Marliere <rbm@suse.com>
5 * 07/2001 Ported by Wayne Boyer
6 */
7
8 /*\
9 * [Description]
10 *
11 * Verify that mmap() succeeds when used to map a file where size of the
12 * file is not a multiple of the page size, the memory area beyond the end
13 * of the file to the end of the page is accessible. Also, verify that
14 * this area is all zeroed and the modifications done to this area are
15 * not written to the file.
16 *
17 * mmap() should succeed returning the address of the mapped region.
18 * The memory area beyond the end of file to the end of page should be
19 * filled with zero. The changes beyond the end of file should not get
20 * written to the file.
21 */
22
23 #include "tst_test.h"
24
25 #define TEMPFILE "mmapfile"
26 #define STRING "hello world\n"
27
28 static char *addr;
29 static char *dummy;
30 static size_t page_sz;
31 static size_t file_sz;
32 static int fildes;
33
check_file(void)34 static void check_file(void)
35 {
36 int i, fildes, buf_len = sizeof(STRING) + 3;
37 char buf[buf_len];
38 ssize_t len;
39
40 fildes = SAFE_OPEN(TEMPFILE, O_RDONLY);
41 len = SAFE_READ(0, fildes, buf, sizeof(buf));
42 SAFE_CLOSE(fildes);
43
44 if (len != strlen(STRING)) {
45 tst_res(TFAIL, "Read %zi expected %zu", len, strlen(STRING));
46 return;
47 }
48
49 for (i = 0; i < len; i++)
50 if (buf[i] == 'X' || buf[i] == 'Y' || buf[i] == 'Z')
51 break;
52
53 if (i == len)
54 tst_res(TPASS, "Specified pattern not found in file");
55 else
56 tst_res(TFAIL, "Specified pattern found in file");
57 }
58
set_file(void)59 static void set_file(void)
60 {
61 char *write_buf = STRING;
62 struct stat stat_buf;
63
64 /* Reset file */
65 if (fildes > 0) {
66 SAFE_CLOSE(fildes);
67 SAFE_UNLINK(TEMPFILE);
68 }
69
70 /* Create a temporary file used for mapping */
71 fildes = SAFE_OPEN(TEMPFILE, O_RDWR | O_CREAT, 0666);
72
73 /* Write some data into temporary file */
74 SAFE_WRITE(SAFE_WRITE_ALL, fildes, write_buf, strlen(write_buf));
75
76 /* Get the size of temporary file */
77 SAFE_STAT(TEMPFILE, &stat_buf);
78 file_sz = stat_buf.st_size;
79 }
80
run(void)81 static void run(void)
82 {
83 set_file();
84
85 addr = SAFE_MMAP(NULL, page_sz, PROT_READ | PROT_WRITE,
86 MAP_FILE | MAP_SHARED, fildes, 0);
87
88 /*
89 * Check if mapped memory area beyond EOF are zeros and changes beyond
90 * EOF are not written to file.
91 */
92 if (memcmp(&addr[file_sz], dummy, page_sz - file_sz))
93 tst_brk(TFAIL, "mapped memory area contains invalid data");
94
95 /*
96 * Initialize memory beyond file size
97 */
98 addr[file_sz] = 'X';
99 addr[file_sz + 1] = 'Y';
100 addr[file_sz + 2] = 'Z';
101
102 /*
103 * Synchronize the mapped memory region with the file.
104 */
105 SAFE_MSYNC(addr, page_sz, MS_SYNC);
106
107 /*
108 * Now, search for the pattern 'XYZ' in the temporary file.
109 * The pattern should not be found and the return value should be 1.
110 */
111 if (!SAFE_FORK()) {
112 check_file();
113 SAFE_MUNMAP(addr, page_sz);
114 exit(0);
115 }
116
117 SAFE_MUNMAP(addr, page_sz);
118 }
119
cleanup(void)120 static void cleanup(void)
121 {
122 if (dummy)
123 free(dummy);
124
125 if (fildes > 0)
126 SAFE_CLOSE(fildes);
127 }
128
setup(void)129 static void setup(void)
130 {
131 page_sz = getpagesize();
132
133 /* Allocate and initialize dummy string of system page size bytes */
134 dummy = SAFE_CALLOC(page_sz, 1);
135 }
136
137 static struct tst_test test = {
138 .setup = setup,
139 .cleanup = cleanup,
140 .needs_tmpdir = 1,
141 .test_all = run,
142 .forks_child = 1,
143 };
144