(root)/
strace-6.5/
tests-mx32/
file_handle.c
       1  /*
       2   * Check decoding of name_to_handle_at and open_by_handle_at syscalls.
       3   *
       4   * Copyright (c) 2015-2016 Dmitry V. Levin <ldv@strace.io>
       5   * Copyright (c) 2016 Eugene Syromyatnikov <evgsyr@gmail.com>
       6   * Copyright (c) 2015-2023 The strace developers.
       7   * All rights reserved.
       8   *
       9   * SPDX-License-Identifier: GPL-2.0-or-later
      10   */
      11  
      12  #include "tests.h"
      13  #include "scno.h"
      14  
      15  #include <assert.h>
      16  #include <errno.h>
      17  #include <inttypes.h>
      18  #include <fcntl.h>
      19  #include <stdio.h>
      20  #include <unistd.h>
      21  
      22  #include "secontext.h"
      23  
      24  enum assert_rc {
      25  	ASSERT_NONE,
      26  	ASSERT_SUCCESS,
      27  	ASSERT_ERROR,
      28  };
      29  
      30  #ifndef MAX_HANDLE_SZ
      31  
      32  # define MAX_HANDLE_SZ 128
      33  
      34  struct file_handle {
      35  	unsigned int handle_bytes;
      36  	int handle_type;
      37  	unsigned char f_handle[0];
      38  };
      39  #endif /* !MAX_HANDLE_SZ */
      40  
      41  
      42  static void
      43  print_handle_data(unsigned char *bytes, unsigned int size)
      44  {
      45  	unsigned int len = MIN(size, MAX_HANDLE_SZ);
      46  	print_quoted_hex(bytes, len);
      47  	if (size > len)
      48  		printf("...");
      49  }
      50  
      51  #ifndef TEST_SECONTEXT
      52  static void
      53  do_name_to_handle_at(kernel_ulong_t dirfd, const char *dirfd_str,
      54  		     kernel_ulong_t pathname, const char *pathname_str,
      55  		     kernel_ulong_t handle, const char *handle_str,
      56  		     kernel_ulong_t mount_id,
      57  		     kernel_ulong_t flags, const char *flags_str,
      58  		     enum assert_rc assert_rc, long assert_errno)
      59  {
      60  	long rc;
      61  	const char *errstr;
      62  
      63  	rc = syscall(__NR_name_to_handle_at, dirfd, pathname, handle, mount_id,
      64  		flags);
      65  	errstr = sprintrc(rc);
      66  
      67  	if (assert_rc != ASSERT_NONE)
      68  		assert(rc == (assert_rc == ASSERT_SUCCESS ? 0 : -1));
      69  	if (assert_errno)
      70  		assert(errno != assert_errno);
      71  
      72  	printf("name_to_handle_at(%s, %s, %s",
      73  	       dirfd_str, pathname_str, handle_str);
      74  
      75  	if (rc != -1) {
      76  		struct file_handle *fh =
      77  			(struct file_handle *) (uintptr_t) handle;
      78  		int *mount_id_ptr = (int *) (uintptr_t) mount_id;
      79  
      80  		printf(" => %u, handle_type=%d, f_handle=",
      81  			fh->handle_bytes, fh->handle_type);
      82  		print_handle_data((unsigned char *) fh +
      83  				  sizeof(struct file_handle),
      84  				  fh->handle_bytes);
      85  		printf("}, [%d]", *mount_id_ptr);
      86  	} else {
      87  		if (mount_id)
      88  			printf(", %#llx", (unsigned long long) mount_id);
      89  		else
      90  			printf(", NULL");
      91  	}
      92  
      93  	printf(", %s) = %s\n", flags_str, errstr);
      94  }
      95  
      96  static void
      97  do_open_by_handle_at(kernel_ulong_t mount_fd,
      98  		     kernel_ulong_t handle, bool valid_handle, bool valid_data,
      99  		     kernel_ulong_t flags, const char *flags_str)
     100  {
     101  	long rc;
     102  
     103  	printf("open_by_handle_at(%d, ", (int) mount_fd);
     104  	if (valid_handle) {
     105  		struct file_handle *fh =
     106  			(struct file_handle *) (uintptr_t) handle;
     107  
     108  		printf("{handle_bytes=%u, handle_type=%d", fh->handle_bytes,
     109  		       fh->handle_type);
     110  
     111  		printf(", f_handle=");
     112  		if (valid_data) {
     113  			print_handle_data((unsigned char *) fh +
     114  					  sizeof(struct file_handle),
     115  					  fh->handle_bytes);
     116  		} else {
     117  			printf("???");
     118  		}
     119  
     120  		printf("}");
     121  	} else {
     122  		if (handle)
     123  			printf("%#llx", (unsigned long long) handle);
     124  		else
     125  			printf("NULL");
     126  	}
     127  	printf(", %s) = ", flags_str);
     128  
     129  	rc = syscall(__NR_open_by_handle_at, mount_fd, handle, flags);
     130  
     131  	printf("%s\n", sprintrc(rc));
     132  }
     133  #endif /* !TEST_SECONTEXT */
     134  
     135  struct strval {
     136  	kernel_ulong_t val;
     137  	const char *str;
     138  };
     139  
     140  #define STR16 "0123456789abcdef"
     141  #define STR64 STR16 STR16 STR16 STR16
     142  
     143  int
     144  main(void)
     145  {
     146  	char *my_secontext = SECONTEXT_PID_MY();
     147  	enum {
     148  		PATH1_SIZE = 64,
     149  	};
     150  
     151  	static const kernel_ulong_t fdcwd =
     152  		(kernel_ulong_t) 0x87654321ffffff9cULL;
     153  
     154  	struct file_handle *handle =
     155  		tail_alloc(sizeof(struct file_handle) + MAX_HANDLE_SZ);
     156  	struct file_handle *handle_0 =
     157  		tail_alloc(sizeof(struct file_handle) + 0);
     158  	struct file_handle *handle_8 =
     159  		tail_alloc(sizeof(struct file_handle) + 8);
     160  	struct file_handle *handle_128 =
     161  		tail_alloc(sizeof(struct file_handle) + 128);
     162  	struct file_handle *handle_256 =
     163  		tail_alloc(sizeof(struct file_handle) + 256);
     164  	TAIL_ALLOC_OBJECT_CONST_PTR(int, bogus_mount_id);
     165  
     166  	char handle_0_addr[sizeof("0x") + sizeof(void *) * 2];
     167  
     168  	const int flags = 0x400;
     169  	int mount_id;
     170  
     171  	handle_0->handle_bytes = 256;
     172  	handle_8->handle_bytes = 0;
     173  	handle_128->handle_bytes = 128;
     174  	handle_256->handle_bytes = 256;
     175  
     176  	fill_memory((char *) handle_128 + sizeof(struct file_handle), 128);
     177  	fill_memory((char *) handle_256 + sizeof(struct file_handle), 256);
     178  
     179  	snprintf(handle_0_addr, sizeof(handle_0_addr), "%p",
     180  		handle_0 + sizeof(struct file_handle));
     181  
     182  	handle->handle_bytes = 0;
     183  
     184  	char path[] = ".";
     185  	char *path_secontext = SECONTEXT_FILE(path);
     186  
     187  	assert(syscall(__NR_name_to_handle_at, fdcwd, path, handle, &mount_id,
     188  		flags | 1) == -1);
     189  	if (EINVAL != errno)
     190  		perror_msg_and_skip("name_to_handle_at");
     191  	printf("%s%s(AT_FDCWD, \"%s\"%s, {handle_bytes=0}, %p"
     192  	       ", AT_SYMLINK_FOLLOW|0x1) = -1 EINVAL (%m)\n",
     193  	       my_secontext, "name_to_handle_at",
     194  	       path, path_secontext,
     195  	       &mount_id);
     196  
     197  	assert(syscall(__NR_name_to_handle_at, fdcwd, path, handle, &mount_id,
     198  		flags) == -1);
     199  	if (EOVERFLOW != errno)
     200  		perror_msg_and_skip("name_to_handle_at");
     201  	printf("%s%s(AT_FDCWD, \"%s\"%s, {handle_bytes=0 => %u}"
     202  	       ", %p, AT_SYMLINK_FOLLOW) = -1 EOVERFLOW (%m)\n",
     203  	       my_secontext, "name_to_handle_at",
     204  	       path, path_secontext,
     205  	       handle->handle_bytes, &mount_id);
     206  
     207  	if (syscall(__NR_name_to_handle_at, fdcwd, path, handle, &mount_id,
     208  		    flags)) {
     209  		if (EOVERFLOW == errno)
     210  			perror_msg_and_skip("name_to_handle_at");
     211  		else
     212  			perror_msg_and_fail("name_to_handle_at");
     213  	}
     214  	printf("%s%s(AT_FDCWD, \"%s\"%s, {handle_bytes=%u"
     215  	       ", handle_type=%d, f_handle=",
     216  	       my_secontext, "name_to_handle_at",
     217  	       path, path_secontext,
     218  	       handle->handle_bytes, handle->handle_type);
     219  	print_handle_data(handle->f_handle, handle->handle_bytes);
     220  	printf("}, [%d], AT_SYMLINK_FOLLOW) = 0\n", mount_id);
     221  
     222  	printf("%s%s(-1, {handle_bytes=%u, handle_type=%d, f_handle=",
     223  	       my_secontext, "open_by_handle_at",
     224  	       handle->handle_bytes, handle->handle_type);
     225  	print_handle_data(handle->f_handle, handle->handle_bytes);
     226  	int rc = syscall(__NR_open_by_handle_at, -1, handle,
     227  		O_RDONLY | O_DIRECTORY);
     228  	printf("}, O_RDONLY|O_DIRECTORY) = %d %s (%m)\n", rc, errno2name());
     229  
     230  #ifndef TEST_SECONTEXT
     231  	static const struct strval dirfds[] = {
     232  		{ (kernel_ulong_t) 0xdeadca57badda7a1ULL, "-1159878751" },
     233  		{ (kernel_ulong_t) 0x12345678ffffff9cULL, "AT_FDCWD" },
     234  	};
     235  	static const struct strval name_flags[] = {
     236  		{ (kernel_ulong_t) 0xdeadf15700000000ULL, "0" },
     237  		{ (kernel_ulong_t) 0xbadc0ded00001000ULL,
     238  			"AT_EMPTY_PATH" },
     239  		{ (kernel_ulong_t) 0xdeadc0deda7a1657ULL,
     240  			"AT_HANDLE_FID|AT_SYMLINK_FOLLOW|AT_EMPTY_PATH|0xda7a0057" },
     241  		{ (kernel_ulong_t) 0xdefaced1ffffe9ffULL,
     242  			"0xffffe9ff /* AT_??? */" },
     243  	};
     244  	static const kernel_ulong_t mount_fds[] = {
     245  		(kernel_ulong_t) 0xdeadca5701234567ULL,
     246  		(kernel_ulong_t) 0x12345678ffffff9cULL,
     247  	};
     248  	static const struct strval open_flags[] = {
     249  		{ F8ILL_KULONG_MASK, "O_RDONLY" },
     250  		{ (kernel_ulong_t) 0xdeadbeef80000001ULL,
     251  			"O_WRONLY|0x80000000" }
     252  	};
     253  
     254  	static const char str64[] = STR64;
     255  	char *bogus_path1 = tail_memdup(str64, PATH1_SIZE);
     256  	char *bogus_path2 = tail_memdup(str64, sizeof(str64));
     257  	char bogus_path1_addr[sizeof("0x") + sizeof(void *) * 2];
     258  	char bogus_path1_after_addr[sizeof("0x") + sizeof(void *) * 2];
     259  
     260  	struct strval paths[] = {
     261  		{ (kernel_ulong_t) 0, "NULL" },
     262  		{ (kernel_ulong_t) (uintptr_t) (bogus_path1 + PATH1_SIZE),
     263  			bogus_path1_after_addr },
     264  		{ (kernel_ulong_t) (uintptr_t) bogus_path1, bogus_path1_addr },
     265  		{ (kernel_ulong_t) (uintptr_t) bogus_path2, "\"" STR64 "\"" },
     266  	};
     267  	struct strval name_handles[] = {
     268  		{ (uintptr_t) (handle_0 + sizeof(struct file_handle)),
     269  			handle_0_addr },
     270  		{ (uintptr_t) handle_0,   "{handle_bytes=256}" },
     271  		{ (uintptr_t) handle_8,   "{handle_bytes=0}" },
     272  		{ (uintptr_t) handle_128, "{handle_bytes=128}" },
     273  		{ (uintptr_t) handle_256, "{handle_bytes=256}" },
     274  	};
     275  	struct {
     276  		kernel_ulong_t addr;
     277  		bool valid;
     278  		bool valid_data;
     279  	} open_handles[] = {
     280  		{ 0, false, false },
     281  		{ (uintptr_t) (handle_0 + sizeof(struct file_handle)),
     282  			false, false },
     283  		{ (uintptr_t) handle_0 + 4, false, false },
     284  		{ (uintptr_t) handle_0, true, false },
     285  		{ (uintptr_t) handle_8, true, true },
     286  		{ (uintptr_t) handle_128, true, true },
     287  		{ (uintptr_t) handle_256, true, true },
     288  	};
     289  	kernel_ulong_t mount_ids[] = {
     290  		0,
     291  		(kernel_ulong_t) (uintptr_t) (bogus_mount_id + 1),
     292  		(kernel_ulong_t) (uintptr_t) bogus_mount_id,
     293  	};
     294  
     295  	snprintf(bogus_path1_addr, sizeof(bogus_path1_addr), "%p", bogus_path1);
     296  	snprintf(bogus_path1_after_addr, sizeof(bogus_path1_after_addr), "%p",
     297  		bogus_path1 + PATH1_SIZE);
     298  
     299  	for (unsigned int i = 0;
     300  	     i < ARRAY_SIZE(dirfds); ++i) {
     301  		for (unsigned int j = 0;
     302  		     j < ARRAY_SIZE(paths); ++j) {
     303  			for (unsigned int k = 0;
     304  			     k < ARRAY_SIZE(name_handles); ++k) {
     305  				for (unsigned int l = 0;
     306  				     l < ARRAY_SIZE(mount_ids); ++l) {
     307  					for (unsigned int m = 0;
     308  					     m < ARRAY_SIZE(name_flags); ++m) {
     309  						do_name_to_handle_at(
     310  							dirfds[i].val,
     311  							dirfds[i].str,
     312  							paths[j].val,
     313  							paths[j].str,
     314  							name_handles[k].val,
     315  							name_handles[k].str,
     316  							mount_ids[l],
     317  							name_flags[m].val,
     318  							name_flags[m].str,
     319  							ASSERT_ERROR, 0);
     320  					}
     321  				}
     322  			}
     323  		}
     324  	}
     325  
     326  	for (unsigned int i = 0;
     327  	     i < ARRAY_SIZE(mount_fds); ++i) {
     328  		for (unsigned int j = 0;
     329  		     j < ARRAY_SIZE(open_handles); ++j) {
     330  			for (unsigned int k = 0;
     331  			     k < ARRAY_SIZE(open_flags); ++k) {
     332  				do_open_by_handle_at(mount_fds[i],
     333  						     open_handles[j].addr,
     334  						     open_handles[j].valid,
     335  						     open_handles[j].valid_data,
     336  						     open_flags[k].val,
     337  						     open_flags[k].str);
     338  			}
     339  		}
     340  	}
     341  #endif
     342  
     343  	/*
     344  	 * Tests with dirfd.
     345  	 */
     346  
     347  	int cwd_fd = get_dir_fd(".");
     348  	char *cwd = get_fd_path(cwd_fd);
     349  	char *cwd_secontext = SECONTEXT_FILE(".");
     350  
     351  	assert(syscall(__NR_name_to_handle_at, cwd_fd, path, handle, &mount_id,
     352  		flags) == 0);
     353  	printf("%s%s(%d%s, \"%s\"%s, {handle_bytes=%u, handle_type=%d"
     354  	       ", f_handle=",
     355  	       my_secontext, "name_to_handle_at",
     356  	       cwd_fd, cwd_secontext,
     357  	       path, path_secontext,
     358  	       handle->handle_bytes, handle->handle_type);
     359  	print_handle_data((unsigned char *) handle +
     360  			  sizeof(struct file_handle),
     361  			  handle->handle_bytes);
     362  	printf("}, [%d], AT_SYMLINK_FOLLOW) = 0\n", mount_id);
     363  
     364  	printf("%s%s(-1, {handle_bytes=%u, handle_type=%d, f_handle=",
     365  	       my_secontext, "open_by_handle_at",
     366  	       handle->handle_bytes, handle->handle_type);
     367  	print_handle_data((unsigned char *) handle +
     368  			  sizeof(struct file_handle),
     369  			  handle->handle_bytes);
     370  	rc = syscall(__NR_open_by_handle_at, -1, handle,
     371  		O_RDONLY | O_DIRECTORY);
     372  	printf("}, O_RDONLY|O_DIRECTORY) = %s\n", sprintrc(rc));
     373  
     374  	/* cwd_fd ignored when path is absolute */
     375  	if (chdir(".."))
     376  		perror_msg_and_fail("chdir");
     377  
     378  	assert(syscall(__NR_name_to_handle_at, cwd_fd, cwd, handle, &mount_id,
     379  		flags) == 0);
     380  	printf("%s%s(%d%s, \"%s\"%s, {handle_bytes=%u"
     381  	       ", handle_type=%d, f_handle=",
     382  	       my_secontext, "name_to_handle_at",
     383  	       cwd_fd, cwd_secontext,
     384  	       cwd, cwd_secontext,
     385  	       handle->handle_bytes, handle->handle_type);
     386  	print_handle_data((unsigned char *) handle +
     387  			  sizeof(struct file_handle),
     388  			  handle->handle_bytes);
     389  	printf("}, [%d], AT_SYMLINK_FOLLOW) = 0\n", mount_id);
     390  
     391  	printf("%s%s(-1, {handle_bytes=%u, handle_type=%d, f_handle=",
     392  	       my_secontext, "open_by_handle_at",
     393  	       handle->handle_bytes, handle->handle_type);
     394  	print_handle_data((unsigned char *) handle +
     395  			  sizeof(struct file_handle),
     396  			  handle->handle_bytes);
     397  	rc = syscall(__NR_open_by_handle_at, -1, handle,
     398  		O_RDONLY | O_DIRECTORY);
     399  	printf("}, O_RDONLY|O_DIRECTORY) = %s\n", sprintrc(rc));
     400  
     401  	if (fchdir(cwd_fd))
     402  		perror_msg_and_fail("fchdir");
     403  
     404  	puts("+++ exited with 0 +++");
     405  	return 0;
     406  }