(root)/
strace-6.5/
tests/
fcntl-common.c
       1  /*
       2   * Copyright (c) 2015-2016 Dmitry V. Levin <ldv@strace.io>
       3   * Copyright (c) 2015-2021 The strace developers.
       4   * All rights reserved.
       5   *
       6   * SPDX-License-Identifier: GPL-2.0-or-later
       7   */
       8  
       9  #include <stdio.h>
      10  #include <stdint.h>
      11  #include <stdlib.h>
      12  #include <string.h>
      13  #include <unistd.h>
      14  #include <assert.h>
      15  #include <linux/fcntl.h>
      16  #include "pidns.h"
      17  #include "scno.h"
      18  
      19  #define FILE_LEN 4096
      20  
      21  #define TEST_FLOCK_EINVAL(cmd) test_flock_einval(cmd, #cmd)
      22  #define TEST_FLOCK64_EINVAL(cmd) test_flock64_einval(cmd, #cmd)
      23  
      24  #ifndef NEED_TEST_FLOCK64_EINVAL
      25  # if defined F_OFD_GETLK && defined F_OFD_SETLK && defined F_OFD_SETLKW
      26  #  define NEED_TEST_FLOCK64_EINVAL
      27  # endif
      28  #endif
      29  
      30  #ifdef HAVE_TYPEOF
      31  # define TYPEOF_FLOCK_OFF_T typeof(((struct flock *) NULL)->l_len)
      32  #else
      33  # define TYPEOF_FLOCK_OFF_T off_t
      34  #endif
      35  
      36  static const char *errstr;
      37  
      38  static long
      39  invoke_test_syscall(const unsigned int fd, const unsigned int cmd, void *const p)
      40  {
      41  	const kernel_ulong_t kfd = F8ILL_KULONG_MASK | fd;
      42  	const kernel_ulong_t op = F8ILL_KULONG_MASK | cmd;
      43  
      44  	long rc = syscall(TEST_SYSCALL_NR, kfd, op, (uintptr_t) p);
      45  	errstr = sprintrc(rc);
      46  	return rc;
      47  }
      48  
      49  static void
      50  test_flock_einval(const int cmd, const char *name)
      51  {
      52  	TAIL_ALLOC_OBJECT_CONST_PTR(struct flock, fl);
      53  	memset(fl, 0, sizeof(*fl));
      54  	fl->l_type = F_RDLCK;
      55  	fl->l_start = (TYPEOF_FLOCK_OFF_T) 0xdefaced1facefeedULL;
      56  	fl->l_len = (TYPEOF_FLOCK_OFF_T) 0xdefaced2cafef00dULL;
      57  
      58  	invoke_test_syscall(0, cmd, fl);
      59  	pidns_print_leader();
      60  	printf("%s(0, %s, {l_type=F_RDLCK, l_whence=SEEK_SET"
      61  	       ", l_start=%jd, l_len=%jd}) = %s\n", TEST_SYSCALL_STR, name,
      62  	       (intmax_t) fl->l_start, (intmax_t) fl->l_len, errstr);
      63  
      64  	void *const bad_addr = (void *) fl + 1;
      65  	invoke_test_syscall(0, cmd, bad_addr);
      66  	pidns_print_leader();
      67  	printf("%s(0, %s, %p) = %s\n",
      68  	       TEST_SYSCALL_STR, name, bad_addr, errstr);
      69  }
      70  
      71  #ifdef NEED_TEST_FLOCK64_EINVAL
      72  static void
      73  test_flock64_einval(const int cmd, const char *name)
      74  {
      75  	TAIL_ALLOC_OBJECT_CONST_PTR(struct flock64, fl);
      76  	memset(fl, 0, sizeof(*fl));
      77  	fl->l_type = F_RDLCK;
      78  	fl->l_start = (TYPEOF_FLOCK_OFF_T) 0xdefaced1facefeedULL;
      79  	fl->l_len = (TYPEOF_FLOCK_OFF_T) 0xdefaced2cafef00dULL;
      80  
      81  	invoke_test_syscall(0, cmd, fl);
      82  	pidns_print_leader();
      83  	printf("%s(0, %s, {l_type=F_RDLCK, l_whence=SEEK_SET"
      84  	       ", l_start=%jd, l_len=%jd}) = %s\n", TEST_SYSCALL_STR, name,
      85  	       (intmax_t) fl->l_start, (intmax_t) fl->l_len, errstr);
      86  
      87  	void *const bad_addr = (void *) fl + 1;
      88  	invoke_test_syscall(0, cmd, bad_addr);
      89  	pidns_print_leader();
      90  	printf("%s(0, %s, %p) = %s\n",
      91  	       TEST_SYSCALL_STR, name, bad_addr, errstr);
      92  }
      93  #endif /* NEED_TEST_FLOCK64_EINVAL */
      94  
      95  static void
      96  test_flock(void)
      97  {
      98  	TEST_FLOCK_EINVAL(F_SETLK);
      99  	TEST_FLOCK_EINVAL(F_SETLKW);
     100  
     101  	TAIL_ALLOC_OBJECT_CONST_PTR(struct flock, fl);
     102  	memset(fl, 0, sizeof(*fl));
     103  	fl->l_type = F_RDLCK;
     104  	fl->l_len = FILE_LEN;
     105  
     106  	long rc = invoke_test_syscall(0, F_SETLK, fl);
     107  	pidns_print_leader();
     108  	printf("%s(0, F_SETLK, {l_type=F_RDLCK, l_whence=SEEK_SET"
     109  	       ", l_start=0, l_len=%d}) = %s\n",
     110  	       TEST_SYSCALL_STR, FILE_LEN, errstr);
     111  	if (rc)
     112  		return;
     113  
     114  	invoke_test_syscall(0, F_GETLK, fl);
     115  	pidns_print_leader();
     116  	printf("%s(0, F_GETLK, {l_type=F_UNLCK, l_whence=SEEK_SET"
     117  	       ", l_start=0, l_len=%d, l_pid=0}) = 0\n",
     118  	       TEST_SYSCALL_STR, FILE_LEN);
     119  
     120  	invoke_test_syscall(0, F_SETLKW, fl);
     121  	pidns_print_leader();
     122  	printf("%s(0, F_SETLKW, {l_type=F_UNLCK, l_whence=SEEK_SET"
     123  	       ", l_start=0, l_len=%d}) = 0\n",
     124  	       TEST_SYSCALL_STR, FILE_LEN);
     125  }
     126  
     127  static void
     128  test_flock64_ofd(void)
     129  {
     130  #if defined F_OFD_GETLK && defined F_OFD_SETLK && defined F_OFD_SETLKW
     131  	TEST_FLOCK64_EINVAL(F_OFD_SETLK);
     132  	TEST_FLOCK64_EINVAL(F_OFD_SETLKW);
     133  
     134  	TAIL_ALLOC_OBJECT_CONST_PTR(struct flock64, fl);
     135  	memset(fl, 0, sizeof(*fl));
     136  	fl->l_type = F_RDLCK;
     137  	fl->l_len = FILE_LEN;
     138  
     139  	long rc = invoke_test_syscall(0, F_OFD_SETLK, fl);
     140  	pidns_print_leader();
     141  	printf("%s(0, F_OFD_SETLK, {l_type=F_RDLCK, l_whence=SEEK_SET"
     142  	       ", l_start=0, l_len=%d}) = %s\n",
     143  	       TEST_SYSCALL_STR, FILE_LEN, errstr);
     144  	if (rc)
     145  		return;
     146  
     147  	invoke_test_syscall(0, F_OFD_GETLK, fl);
     148  	pidns_print_leader();
     149  	printf("%s(0, F_OFD_GETLK, {l_type=F_UNLCK, l_whence=SEEK_SET"
     150  	       ", l_start=0, l_len=%d, l_pid=0}) = 0\n",
     151  	       TEST_SYSCALL_STR, FILE_LEN);
     152  
     153  	invoke_test_syscall(0, F_OFD_SETLKW, fl);
     154  	pidns_print_leader();
     155  	printf("%s(0, F_OFD_SETLKW, {l_type=F_UNLCK, l_whence=SEEK_SET"
     156  	       ", l_start=0, l_len=%d}) = 0\n",
     157  	       TEST_SYSCALL_STR, FILE_LEN);
     158  #endif /* F_OFD_GETLK && F_OFD_SETLK && F_OFD_SETLKW */
     159  }
     160  
     161  static void test_flock64_lk64(void);
     162  
     163  static void
     164  test_flock64(void)
     165  {
     166  	test_flock64_ofd();
     167  	test_flock64_lk64();
     168  }
     169  
     170  static long
     171  test_f_owner_ex_type_pid(const int cmd, const char *const cmd_name,
     172  			 const int type, const char *const type_name,
     173  			 enum pid_type pid_type, pid_t pid)
     174  {
     175  	TAIL_ALLOC_OBJECT_CONST_PTR(struct f_owner_ex, fo);
     176  
     177  	fo->type = type;
     178  	fo->pid = pid;
     179  	long rc = invoke_test_syscall(0, cmd, fo);
     180  	pidns_print_leader();
     181  	printf("%s(0, %s, {type=%s, pid=%d%s}) = %s\n",
     182  	       TEST_SYSCALL_STR, cmd_name, type_name,
     183  	       fo->pid, pidns_pid2str(pid_type), errstr);
     184  
     185  	void *bad_addr = (void *) fo + 1;
     186  	invoke_test_syscall(0, cmd, bad_addr);
     187  	pidns_print_leader();
     188  	printf("%s(0, %s, %p) = %s\n",
     189  	       TEST_SYSCALL_STR, cmd_name, bad_addr, errstr);
     190  
     191  	return rc;
     192  }
     193  
     194  static void
     195  test_f_owner_ex_umove_or_printaddr(const int type, const char *const type_name,
     196  				   enum pid_type pid_type, pid_t pid)
     197  {
     198  	long rc = test_f_owner_ex_type_pid(ARG_STR(F_SETOWN_EX),
     199  					   type, type_name, pid_type, pid);
     200  	if (!rc)
     201  		test_f_owner_ex_type_pid(ARG_STR(F_GETOWN_EX),
     202  					 type, type_name, pid_type, pid);
     203  }
     204  
     205  static void
     206  test_f_owner_ex(void)
     207  {
     208  	struct {
     209  		int type;
     210  		const char *type_name;
     211  		enum pid_type pid_type;
     212  		pid_t pid;
     213  	} a[] = {
     214  		{ ARG_STR(F_OWNER_TID), PT_NONE, 1234567890 },
     215  		{ ARG_STR(F_OWNER_PID), PT_NONE, 1234567890 },
     216  		{ ARG_STR(F_OWNER_PGRP), PT_NONE, 1234567890 },
     217  		{ ARG_STR(F_OWNER_TID), PT_TID, syscall(__NR_gettid) },
     218  		{ ARG_STR(F_OWNER_PID), PT_TGID, getpid() },
     219  		{ ARG_STR(F_OWNER_PGRP), PT_PGID, getpgid(0) },
     220  	};
     221  
     222  	for (unsigned int i = 0; i < ARRAY_SIZE(a); i++)
     223  		test_f_owner_ex_umove_or_printaddr(a[i].type, a[i].type_name,
     224  			a[i].pid_type, a[i].pid);
     225  }
     226  struct fcntl_cmd_check {
     227  	int fd;
     228  	int cmd;
     229  	const char *cmd_str;
     230  	long arg;
     231  	const char *arg_str;
     232  	void (*print_flags)(long rc);
     233  };
     234  
     235  static void
     236  test_xetown(void)
     237  {
     238  	const int pid = getpid();
     239  	const char *pid_str = pidns_pid2str(PT_TGID);
     240  
     241  	invoke_test_syscall(0, F_SETOWN, (void *) (intptr_t) pid);
     242  	pidns_print_leader();
     243  	printf("%s(0, F_SETOWN, %d%s) = %s\n",
     244  		TEST_SYSCALL_STR, pid, pid_str, errstr);
     245  
     246  	invoke_test_syscall(0, F_GETOWN, NULL);
     247  	pidns_print_leader();
     248  	printf("%s(0, F_GETOWN) = %d%s\n",
     249  		TEST_SYSCALL_STR, pid, pid_str);
     250  }
     251  
     252  static void
     253  print_retval_flags(const struct fcntl_cmd_check *check, long rc)
     254  {
     255  	if (check->print_flags) {
     256  		check->print_flags(rc);
     257  	} else {
     258  		printf("%s", errstr);
     259  	}
     260  	printf("\n");
     261  }
     262  
     263  static void
     264  test_other_set_cmd(const struct fcntl_cmd_check *check)
     265  {
     266  	invoke_test_syscall(check->fd, check->cmd, (void *) check->arg);
     267  	pidns_print_leader();
     268  	printf("%s(%d, %s, %s) = %s\n",
     269  	       TEST_SYSCALL_STR, check->fd,
     270  	       check->cmd_str, check->arg_str, errstr);
     271  
     272  	/* bad file fd */
     273  	invoke_test_syscall(-1, check->cmd, (void *) check->arg);
     274  	pidns_print_leader();
     275  	printf("%s(-1, %s, %s) = %s\n",
     276  	       TEST_SYSCALL_STR, check->cmd_str,
     277  	       check->arg_str, errstr);
     278  }
     279  
     280  static void
     281  test_other_get_cmd(const struct fcntl_cmd_check *check)
     282  {
     283  	long rc = invoke_test_syscall(check->fd, check->cmd, NULL);
     284  	pidns_print_leader();
     285  	printf("%s(%d, %s) = ",
     286  	       TEST_SYSCALL_STR, check->fd, check->cmd_str);
     287  	print_retval_flags(check, rc);
     288  
     289  	/* bad file fd */
     290  	invoke_test_syscall(-1, check->cmd, NULL);
     291  	pidns_print_leader();
     292  	printf("%s(-1, %s) = %s\n",
     293  	       TEST_SYSCALL_STR, check->cmd_str, errstr);
     294  }
     295  
     296  static void
     297  print_flags_getfd(long rc)
     298  {
     299  	assert(rc >= 0);
     300  	printf("%#lx%s", rc, rc & 1 ? " (flags FD_CLOEXEC)" : "");
     301  }
     302  
     303  static void
     304  print_flags_getsig(long rc)
     305  {
     306  	assert(rc >= 0);
     307  
     308  	if (!rc) {
     309  		printf("%ld", rc);
     310  	} else {
     311  		printf("%ld (%s)", rc, signal2name((int) rc));
     312  	}
     313  }
     314  
     315  static void
     316  print_flags_getlease(long rc)
     317  {
     318  	assert(rc >= 0);
     319  	const char *text;
     320  
     321  	switch (rc) {
     322  	case F_RDLCK:
     323  		text = "F_RDLCK";
     324  		break;
     325  	case F_WRLCK:
     326  		text = "F_WRLCK";
     327  		break;
     328  	case F_UNLCK:
     329  		text = "F_UNLCK";
     330  		break;
     331  	default:
     332  		error_msg_and_fail("fcntl returned %#lx, does the"
     333  				   " test have to be updated?", rc);
     334  	}
     335  	printf("%#lx (%s)", rc, text);
     336  }
     337  
     338  static void
     339  test_fcntl_others(void)
     340  {
     341  	static const struct fcntl_cmd_check set_checks[] = {
     342  		{ 0, ARG_STR(F_SETFD), ARG_STR(FD_CLOEXEC) },
     343  		{ 0, ARG_STR(F_SETPIPE_SZ), ARG_STR(4097) },
     344  		{ 0, ARG_STR(F_DUPFD), ARG_STR(0) },
     345  		{ 0, ARG_STR(F_DUPFD_CLOEXEC), ARG_STR(0) },
     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, "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_GETPIPE_SZ) },
     360  		{ 1, ARG_STR(F_GETLEASE), .print_flags = print_flags_getlease },
     361  		{ 0, ARG_STR(F_GETSIG), .print_flags = print_flags_getsig },
     362  		{ 1, ARG_STR(F_GETSIG), .print_flags = print_flags_getsig }
     363  	};
     364  	for (unsigned int j = 0; j < ARRAY_SIZE(get_checks); j++) {
     365  		test_other_get_cmd(get_checks + j);
     366  	}
     367  }
     368  
     369  static void
     370  create_sample(void)
     371  {
     372  	(void) close(0);
     373  	if (ftruncate(create_tmpfile(O_RDWR), FILE_LEN))
     374  		perror_msg_and_fail("ftruncate");
     375  }
     376  
     377  int
     378  main(void)
     379  {
     380  	PIDNS_TEST_INIT;
     381  
     382  	create_sample();
     383  	test_flock();
     384  	test_flock64();
     385  	test_f_owner_ex();
     386  	test_fcntl_others();
     387  	test_xetown();
     388  
     389  	pidns_print_leader();
     390  	puts("+++ exited with 0 +++");
     391  	return 0;
     392  }