1 /*
2  * Check decoding of pread64 and pwrite64 syscalls.
3  *
4  * Copyright (c) 2016 Dmitry V. Levin <ldv@altlinux.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #include "tests.h"
31 
32 #include <fcntl.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <unistd.h>
36 
37 static void
dump_str(const char * str,const unsigned int len)38 dump_str(const char *str, const unsigned int len)
39 {
40 	static const char dots[16] = "................";
41 	unsigned int i;
42 
43 	for (i = 0; i < len; i += 16) {
44 		unsigned int n = len - i > 16 ? 16 : len - i;
45 		const char *dump = hexdump_memdup(str + i, n);
46 
47 		tprintf(" | %05x %-49s  %-16.*s |\n",
48 			i, dump, n, dots);
49 
50 		free((void *) dump);
51 	}
52 }
53 
54 static void
print_hex(const char * str,const unsigned int len)55 print_hex(const char *str, const unsigned int len)
56 {
57 	const unsigned char *ustr = (const unsigned char *) str;
58 	unsigned int i;
59 
60 	for (i = 0; i < len; ++i) {
61 		unsigned int c = ustr[i];
62 
63 		switch (c) {
64 		case '\t':
65 			tprintf("\\t"); break;
66 		case '\n':
67 			tprintf("\\n"); break;
68 		case '\v':
69 			tprintf("\\v"); break;
70 		case '\f':
71 			tprintf("\\f"); break;
72 		case '\r':
73 			tprintf("\\r"); break;
74 		default:
75 			tprintf("\\%o", ustr[i]);
76 		}
77 	}
78 }
79 
80 static void
test_dump(const unsigned int len)81 test_dump(const unsigned int len)
82 {
83 	static char *buf;
84 
85 	if (buf) {
86 		size_t ps1 = get_page_size() - 1;
87 		buf = (void *) (((size_t) buf + ps1) & ~ps1) - len;
88 	} else {
89 		buf = tail_alloc(len);
90 	}
91 
92 	const off_t offset = 0xdefaceddeadbeefLL + len;
93 	long rc = pread(0, buf, len, offset);
94 	if (rc != (int) len)
95 		perror_msg_and_fail("pread64: expected %d, returned %ld",
96 				    len, rc);
97 
98 	tprintf("%s(%d, \"", "pread64", 0);
99 	print_hex(buf, len);
100 	tprintf("\", %d, %lld) = %ld\n", len, (long long) offset, rc);
101 	dump_str(buf, len);
102 
103 	unsigned int i;
104 	for (i = 0; i < len; ++i)
105 		buf[i] = i;
106 
107 	rc = pwrite(1, buf, len, offset);
108 	if (rc != (int) len)
109 		perror_msg_and_fail("pwrite64: expected %d, returned %ld",
110 				    len, rc);
111 
112 	tprintf("%s(%d, \"", "pwrite64", 1);
113 	print_hex(buf, len);
114 	tprintf("\", %d, %lld) = %ld\n", len, (long long) offset, rc);
115 	dump_str(buf, len);
116 
117 	if (!len)
118 		buf = 0;
119 }
120 
121 int
main(void)122 main(void)
123 {
124 	tprintf("%s", "");
125 
126 	static char tmp[] = "pread64-pwrite64-tmpfile";
127 	if (open(tmp, O_CREAT|O_RDONLY|O_TRUNC, 0600) != 0)
128 		perror_msg_and_fail("creat: %s", tmp);
129 	if (open(tmp, O_WRONLY) != 1)
130 		perror_msg_and_fail("open: %s", tmp);
131 
132 	char *nil = tail_alloc(1);
133 	*nil = '\0';
134 
135 	static const char w_c[] = "0123456789abcde";
136 	const unsigned int w_len = LENGTH_OF(w_c);
137 	const char *w_d = hexdump_strdup(w_c);
138 	const void *w = tail_memdup(w_c, w_len);
139 
140 	static const char r0_c[] = "01234567";
141 	const char *r0_d = hexdump_strdup(r0_c);
142 	const unsigned int r0_len = (w_len + 1) / 2;
143 	void *r0 = tail_alloc(r0_len);
144 
145 	static const char r1_c[] = "89abcde";
146 	const char *r1_d = hexdump_strdup(r1_c);
147 	const unsigned int r1_len = w_len - r0_len;
148 	void *r1 = tail_alloc(w_len);
149 
150 	void *efault = r1 - get_page_size();
151 
152 	long rc;
153 
154 	rc = pwrite(1, w, 0, 0);
155 	if (rc)
156 		perror_msg_and_fail("pwrite64: expected 0, returned %ld", rc);
157 	tprintf("pwrite64(1, \"\", 0, 0) = 0\n");
158 
159 	rc = pwrite(1, efault, 1, 0);
160 	if (rc != -1)
161 		perror_msg_and_fail("pwrite64: expected -1 EFAULT"
162 				    ", returned %ld", rc);
163 	tprintf("pwrite64(1, %p, 1, 0) = -1 EFAULT (%m)\n", efault);
164 
165 	rc = pwrite(1, nil, 1, -3);
166 	if (rc != -1)
167 		perror_msg_and_fail("pwrite64: expected -1, returned %ld", rc);
168 	tprintf("pwrite64(1, \"\\0\", 1, -3) = -1 EINVAL (%m)\n");
169 
170 	rc = pwrite(1, w, w_len, 0);
171 	if (rc != (int) w_len)
172 		perror_msg_and_fail("pwrite64: expected %u, returned %ld",
173 				    w_len, rc);
174 	tprintf("pwrite64(1, \"%s\", %u, 0) = %ld\n"
175 		" | 00000 %-49s  %-16s |\n",
176 		w_c, w_len, rc, w_d, w_c);
177 	close(1);
178 
179 	rc = pread(0, r0, 0, 0);
180 	if (rc)
181 		perror_msg_and_fail("pread64: expected 0, returned %ld", rc);
182 	tprintf("pread64(0, \"\", 0, 0) = 0\n");
183 
184 	rc = pread(0, efault, 1, 0);
185 	if (rc != -1)
186 		perror_msg_and_fail("pread64: expected -1, returned %ld", rc);
187 	tprintf("pread64(0, %p, 1, 0) = -1 EFAULT (%m)\n", efault);
188 
189 	rc = pread(0, efault, 2, -7);
190 	if (rc != -1)
191 		perror_msg_and_fail("pread64: expected -1, returned %ld", rc);
192 	tprintf("pread64(0, %p, 2, -7) = -1 EINVAL (%m)\n", efault);
193 
194 	rc = pread(0, r0, r0_len, 0);
195 	if (rc != (int) r0_len)
196 		perror_msg_and_fail("pread64: expected %u, returned %ld",
197 				    r0_len, rc);
198 	tprintf("pread64(0, \"%s\", %u, 0) = %ld\n"
199 		" | 00000 %-49s  %-16s |\n",
200 		r0_c, r0_len, rc, r0_d, r0_c);
201 
202 	rc = pread(0, r1, w_len, r0_len);
203 	if (rc != (int) r1_len)
204 		perror_msg_and_fail("pread64: expected %u, returned %ld",
205 				    r1_len, rc);
206 	tprintf("pread64(0, \"%s\", %u, %u) = %ld\n"
207 		" | 00000 %-49s  %-16s |\n",
208 		r1_c, w_len, r0_len, rc, r1_d, r1_c);
209 	close(0);
210 
211 	if (open("/dev/zero", O_RDONLY))
212 		perror_msg_and_fail("open");
213 
214 	if (open("/dev/null", O_WRONLY) != 1)
215 		perror_msg_and_fail("open");
216 
217 	unsigned int i;
218 	for (i = 0; i <= 32; ++i)
219 		test_dump(i);
220 
221 	tprintf("+++ exited with 0 +++\n");
222 	return 0;
223 }
224