• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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