• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2015-2016 Dmitry V. Levin <ldv@altlinux.org>
3  * Copyright (c) 2015-2018 The strace developers.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <stdio.h>
30 #include <stdint.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include <assert.h>
35 #include "flock.h"
36 
37 #define FILE_LEN 4096
38 
39 #define TEST_FLOCK_EINVAL(cmd) test_flock_einval(cmd, #cmd)
40 #define TEST_FLOCK64_EINVAL(cmd) test_flock64_einval(cmd, #cmd)
41 
42 #ifdef HAVE_TYPEOF
43 # define TYPEOF_FLOCK_OFF_T typeof(((struct_kernel_flock *) NULL)->l_len)
44 #else
45 # define TYPEOF_FLOCK_OFF_T off_t
46 #endif
47 
48 static const char *errstr;
49 
50 static long
invoke_test_syscall(const unsigned int fd,const unsigned int cmd,void * const p)51 invoke_test_syscall(const unsigned int fd, const unsigned int cmd, void *const p)
52 {
53 	const kernel_ulong_t kfd = F8ILL_KULONG_MASK | fd;
54 	const kernel_ulong_t op = F8ILL_KULONG_MASK | cmd;
55 
56 	long rc = syscall(TEST_SYSCALL_NR, kfd, op, (uintptr_t) p);
57 	errstr = sprintrc(rc);
58 	return rc;
59 }
60 
61 static void
test_flock_einval(const int cmd,const char * name)62 test_flock_einval(const int cmd, const char *name)
63 {
64 	TAIL_ALLOC_OBJECT_CONST_PTR(struct_kernel_flock, fl);
65 	memset(fl, 0, sizeof(*fl));
66 	fl->l_type = F_RDLCK;
67 	fl->l_start = (TYPEOF_FLOCK_OFF_T) 0xdefaced1facefeedULL;
68 	fl->l_len = (TYPEOF_FLOCK_OFF_T) 0xdefaced2cafef00dULL;
69 
70 	invoke_test_syscall(0, cmd, fl);
71 	printf("%s(0, %s, {l_type=F_RDLCK, l_whence=SEEK_SET"
72 	       ", l_start=%jd, l_len=%jd}) = %s\n", TEST_SYSCALL_STR, name,
73 	       (intmax_t) fl->l_start, (intmax_t) fl->l_len, errstr);
74 
75 	void *const bad_addr = (void *) fl + 1;
76 	invoke_test_syscall(0, cmd, bad_addr);
77 	printf("%s(0, %s, %p) = %s\n",
78 	       TEST_SYSCALL_STR, name, bad_addr, errstr);
79 }
80 
81 /*
82  * This function is not declared static to avoid potential
83  * "defined but not used" warning when included by fcntl.c
84  */
85 void
test_flock64_einval(const int cmd,const char * name)86 test_flock64_einval(const int cmd, const char *name)
87 {
88 	TAIL_ALLOC_OBJECT_CONST_PTR(struct_kernel_flock64, fl);
89 	memset(fl, 0, sizeof(*fl));
90 	fl->l_type = F_RDLCK;
91 	fl->l_start = (TYPEOF_FLOCK_OFF_T) 0xdefaced1facefeedULL;
92 	fl->l_len = (TYPEOF_FLOCK_OFF_T) 0xdefaced2cafef00dULL;
93 
94 	invoke_test_syscall(0, cmd, fl);
95 	printf("%s(0, %s, {l_type=F_RDLCK, l_whence=SEEK_SET"
96 	       ", l_start=%jd, l_len=%jd}) = %s\n", TEST_SYSCALL_STR, name,
97 	       (intmax_t) fl->l_start, (intmax_t) fl->l_len, errstr);
98 
99 	void *const bad_addr = (void *) fl + 1;
100 	invoke_test_syscall(0, cmd, bad_addr);
101 	printf("%s(0, %s, %p) = %s\n",
102 	       TEST_SYSCALL_STR, name, bad_addr, errstr);
103 }
104 
105 static void
test_flock(void)106 test_flock(void)
107 {
108 	TEST_FLOCK_EINVAL(F_SETLK);
109 	TEST_FLOCK_EINVAL(F_SETLKW);
110 
111 	TAIL_ALLOC_OBJECT_CONST_PTR(struct_kernel_flock, fl);
112 	memset(fl, 0, sizeof(*fl));
113 	fl->l_type = F_RDLCK;
114 	fl->l_len = FILE_LEN;
115 
116 	long rc = invoke_test_syscall(0, F_SETLK, fl);
117 	printf("%s(0, F_SETLK, {l_type=F_RDLCK, l_whence=SEEK_SET"
118 	       ", l_start=0, l_len=%d}) = %s\n",
119 	       TEST_SYSCALL_STR, FILE_LEN, errstr);
120 	if (rc)
121 		return;
122 
123 	invoke_test_syscall(0, F_GETLK, fl);
124 	printf("%s(0, F_GETLK, {l_type=F_UNLCK, l_whence=SEEK_SET"
125 	       ", l_start=0, l_len=%d, l_pid=0}) = 0\n",
126 	       TEST_SYSCALL_STR, FILE_LEN);
127 
128 	invoke_test_syscall(0, F_SETLKW, fl);
129 	printf("%s(0, F_SETLKW, {l_type=F_UNLCK, l_whence=SEEK_SET"
130 	       ", l_start=0, l_len=%d}) = 0\n",
131 	       TEST_SYSCALL_STR, FILE_LEN);
132 }
133 
134 static void
test_flock64_ofd(void)135 test_flock64_ofd(void)
136 {
137 #if defined F_OFD_GETLK && defined F_OFD_SETLK && defined F_OFD_SETLKW
138 	TEST_FLOCK64_EINVAL(F_OFD_SETLK);
139 	TEST_FLOCK64_EINVAL(F_OFD_SETLKW);
140 
141 	TAIL_ALLOC_OBJECT_CONST_PTR(struct_kernel_flock64, fl);
142 	memset(fl, 0, sizeof(*fl));
143 	fl->l_type = F_RDLCK;
144 	fl->l_len = FILE_LEN;
145 
146 	long rc = invoke_test_syscall(0, F_OFD_SETLK, fl);
147 	printf("%s(0, F_OFD_SETLK, {l_type=F_RDLCK, l_whence=SEEK_SET"
148 	       ", l_start=0, l_len=%d}) = %s\n",
149 	       TEST_SYSCALL_STR, FILE_LEN, errstr);
150 	if (rc)
151 		return;
152 
153 	invoke_test_syscall(0, F_OFD_GETLK, fl);
154 	printf("%s(0, F_OFD_GETLK, {l_type=F_UNLCK, l_whence=SEEK_SET"
155 	       ", l_start=0, l_len=%d, l_pid=0}) = 0\n",
156 	       TEST_SYSCALL_STR, FILE_LEN);
157 
158 	invoke_test_syscall(0, F_OFD_SETLKW, fl);
159 	printf("%s(0, F_OFD_SETLKW, {l_type=F_UNLCK, l_whence=SEEK_SET"
160 	       ", l_start=0, l_len=%d}) = 0\n",
161 	       TEST_SYSCALL_STR, FILE_LEN);
162 #endif /* F_OFD_GETLK && F_OFD_SETLK && F_OFD_SETLKW */
163 }
164 
165 static void test_flock64_lk64(void);
166 
167 static void
test_flock64(void)168 test_flock64(void)
169 {
170 	test_flock64_ofd();
171 	test_flock64_lk64();
172 }
173 
174 /*
175  * F_[GS]ETOWN_EX had conflicting values with F_[SG]ETLK64
176  * in kernel revisions v2.6.32-rc1~96..v2.6.32-rc7~23.
177  */
178 #undef TEST_F_OWNER_EX
179 #if defined F_GETOWN_EX && defined F_SETOWN_EX \
180  && (F_GETOWN_EX != F_SETLK64) && (F_SETOWN_EX != F_GETLK64)
181 # define TEST_F_OWNER_EX
182 #endif
183 
184 #ifdef TEST_F_OWNER_EX
185 # include "f_owner_ex.h"
186 
187 static long
test_f_owner_ex_type_pid(const int cmd,const char * const cmd_name,const int type,const char * const type_name,pid_t pid)188 test_f_owner_ex_type_pid(const int cmd, const char *const cmd_name,
189 			 const int type, const char *const type_name,
190 			 pid_t pid)
191 {
192 	TAIL_ALLOC_OBJECT_CONST_PTR(struct_kernel_f_owner_ex, fo);
193 
194 	fo->type = type;
195 	fo->pid = pid;
196 	long rc = invoke_test_syscall(0, cmd, fo);
197 	printf("%s(0, %s, {type=%s, pid=%d}) = %s\n",
198 	       TEST_SYSCALL_STR, cmd_name, type_name, fo->pid, errstr);
199 
200 	void *bad_addr = (void *) fo + 1;
201 	invoke_test_syscall(0, cmd, bad_addr);
202 	printf("%s(0, %s, %p) = %s\n",
203 	       TEST_SYSCALL_STR, cmd_name, bad_addr, errstr);
204 
205 	return rc;
206 }
207 
208 static void
test_f_owner_ex_umove_or_printaddr(const int type,const char * const type_name,pid_t pid)209 test_f_owner_ex_umove_or_printaddr(const int type, const char *const type_name,
210 				   pid_t pid)
211 {
212 	long rc = test_f_owner_ex_type_pid(ARG_STR(F_SETOWN_EX),
213 					   type, type_name, pid);
214 	if (!rc)
215 		test_f_owner_ex_type_pid(ARG_STR(F_GETOWN_EX),
216 					 type, type_name, pid);
217 }
218 
219 static void
test_f_owner_ex(void)220 test_f_owner_ex(void)
221 {
222 	static const struct {
223 		int type;
224 		const char *type_name;
225 		pid_t pid[2];
226 	} a[] = {
227 		{ ARG_STR(F_OWNER_TID), { 1234567890, 20 } },
228 		{ ARG_STR(F_OWNER_PID), { 1298126790, 30 } },
229 		{ ARG_STR(F_OWNER_PGRP), { 1294567890, 40 } }
230 	};
231 
232 	for (unsigned int i = 0; i < ARRAY_SIZE(a); i++) {
233 		for (unsigned int j = 0; j < ARRAY_SIZE(a[0].pid); j++) {
234 			test_f_owner_ex_umove_or_printaddr(a[i].type,
235 							   a[i].type_name,
236 							   a[i].pid[j]);
237 		}
238 	}
239 }
240 #endif /* TEST_F_OWNER_EX */
241 
242 struct fcntl_cmd_check {
243 	int fd;
244 	int cmd;
245 	const char *cmd_str;
246 	long arg;
247 	const char *arg_str;
248 	void (*print_flags)(long rc);
249 };
250 
251 static void
print_retval_flags(const struct fcntl_cmd_check * check,long rc)252 print_retval_flags(const struct fcntl_cmd_check *check, long rc)
253 {
254 	if (check->print_flags) {
255 		check->print_flags(rc);
256 	} else {
257 		printf("%s", errstr);
258 	}
259 	printf("\n");
260 }
261 
262 static void
test_other_set_cmd(const struct fcntl_cmd_check * check)263 test_other_set_cmd(const struct fcntl_cmd_check *check)
264 {
265 	invoke_test_syscall(check->fd, check->cmd, (void *) check->arg);
266 	printf("%s(%d, %s, %s) = %s\n",
267 	       TEST_SYSCALL_STR, check->fd,
268 	       check->cmd_str, check->arg_str, errstr);
269 
270 	/* bad file fd */
271 	invoke_test_syscall(-1, check->cmd, (void *) check->arg);
272 	printf("%s(-1, %s, %s) = %s\n",
273 	       TEST_SYSCALL_STR, check->cmd_str,
274 	       check->arg_str, errstr);
275 }
276 
277 static void
test_other_get_cmd(const struct fcntl_cmd_check * check)278 test_other_get_cmd(const struct fcntl_cmd_check *check)
279 {
280 	long rc = invoke_test_syscall(check->fd, check->cmd, NULL);
281 	printf("%s(%d, %s) = ",
282 	       TEST_SYSCALL_STR, check->fd, check->cmd_str);
283 	print_retval_flags(check, rc);
284 
285 	/* bad file fd */
286 	invoke_test_syscall(-1, check->cmd, NULL);
287 	printf("%s(-1, %s) = %s\n",
288 	       TEST_SYSCALL_STR, check->cmd_str, errstr);
289 }
290 
291 static void
print_flags_getfd(long rc)292 print_flags_getfd(long rc)
293 {
294 	assert(rc >= 0);
295 	printf("%#lx%s", rc, rc & 1 ? " (flags FD_CLOEXEC)" : "");
296 }
297 
298 static void
print_flags_getsig(long rc)299 print_flags_getsig(long rc)
300 {
301 	assert(rc >= 0);
302 
303 	if (!rc) {
304 		printf("%ld", rc);
305 	} else {
306 		printf("%ld (%s)", rc, signal2name((int) rc));
307 	}
308 }
309 
310 static void
print_flags_getlease(long rc)311 print_flags_getlease(long rc)
312 {
313 	assert(rc >= 0);
314 	const char *text;
315 
316 	switch (rc) {
317 	case F_RDLCK:
318 		text = "F_RDLCK";
319 		break;
320 	case F_WRLCK:
321 		text = "F_WRLCK";
322 		break;
323 	case F_UNLCK:
324 		text = "F_UNLCK";
325 		break;
326 	default:
327 		error_msg_and_fail("fcntl returned %#lx, does the"
328 				   " test have to be updated?", rc);
329 	}
330 	printf("%#lx (%s)", rc, text);
331 }
332 
333 static void
test_fcntl_others(void)334 test_fcntl_others(void)
335 {
336 	static const struct fcntl_cmd_check set_checks[] = {
337 		{ 0, ARG_STR(F_SETFD), ARG_STR(FD_CLOEXEC) },
338 		{ 0, ARG_STR(F_SETOWN), ARG_STR(20) },
339 #ifdef F_SETPIPE_SZ
340 		{ 0, ARG_STR(F_SETPIPE_SZ), ARG_STR(4097) },
341 #endif
342 		{ 0, ARG_STR(F_DUPFD), ARG_STR(0) },
343 #ifdef F_DUPFD_CLOEXEC
344 		{ 0, ARG_STR(F_DUPFD_CLOEXEC), ARG_STR(0) },
345 #endif
346 		{ 0, ARG_STR(F_SETFL), ARG_STR(O_RDWR|O_LARGEFILE) },
347 		{ 0, ARG_STR(F_NOTIFY), ARG_STR(DN_ACCESS) },
348 		{ 1, ARG_STR(F_SETLEASE), ARG_STR(F_RDLCK) },
349 		{ 0, ARG_STR(F_SETSIG), 0, "SIG_0" },
350 		{ 1, ARG_STR(F_SETSIG), 1, "SIGHUP" }
351 	};
352 	for (unsigned int i = 0; i < ARRAY_SIZE(set_checks); i++) {
353 		test_other_set_cmd(set_checks + i);
354 	}
355 
356 	static const struct fcntl_cmd_check get_checks[] = {
357 		{ 0, ARG_STR(F_GETFD), .print_flags = print_flags_getfd },
358 		{ 1, ARG_STR(F_GETFD), .print_flags = print_flags_getfd },
359 		{ 0, ARG_STR(F_GETOWN) },
360 #ifdef F_GETPIPE_SZ
361 		{ 0, ARG_STR(F_GETPIPE_SZ) },
362 #endif
363 		{ 1, ARG_STR(F_GETLEASE), .print_flags = print_flags_getlease },
364 		{ 0, ARG_STR(F_GETSIG), .print_flags = print_flags_getsig },
365 		{ 1, ARG_STR(F_GETSIG), .print_flags = print_flags_getsig }
366 	};
367 	for (unsigned int j = 0; j < ARRAY_SIZE(get_checks); j++) {
368 		test_other_get_cmd(get_checks + j);
369 	}
370 }
371 
372 static void
create_sample(void)373 create_sample(void)
374 {
375 	char fname[] = TEST_SYSCALL_STR "_XXXXXX";
376 
377 	(void) close(0);
378 	if (mkstemp(fname))
379 		perror_msg_and_fail("mkstemp: %s", fname);
380 	if (unlink(fname))
381 		perror_msg_and_fail("unlink: %s", fname);
382 	if (ftruncate(0, FILE_LEN))
383 		perror_msg_and_fail("ftruncate");
384 }
385 
386 int
main(void)387 main(void)
388 {
389 	create_sample();
390 	test_flock();
391 	test_flock64();
392 #ifdef TEST_F_OWNER_EX
393 	test_f_owner_ex();
394 #endif
395 	test_fcntl_others();
396 
397 	puts("+++ exited with 0 +++");
398 	return 0;
399 }
400