(root)/
strace-6.5/
tests-mx32/
linkat.c
       1  /*
       2   * Check decoding of linkat syscall.
       3   *
       4   * Copyright (c) 2016-2022 The strace developers.
       5   * All rights reserved.
       6   *
       7   * SPDX-License-Identifier: GPL-2.0-or-later
       8   */
       9  
      10  #include "tests.h"
      11  #include "scno.h"
      12  
      13  #include <errno.h>
      14  #include <fcntl.h>
      15  #include <stdio.h>
      16  #include <stdlib.h>
      17  #include <unistd.h>
      18  #include <sys/stat.h>
      19  #include <string.h>
      20  
      21  #include "secontext.h"
      22  #include "xmalloc.h"
      23  
      24  static void
      25  mangle_secontext_field(const char *path, enum secontext_field field,
      26  		       const char *new_val, const char *fallback_val)
      27  {
      28  	char *orig = get_secontext_field_file(path, field);
      29  	if (!orig)
      30  		return;
      31  
      32  	update_secontext_field(path, field,
      33  			       strcmp(new_val, orig) ? new_val : fallback_val);
      34  
      35  	free(orig);
      36  }
      37  
      38  int
      39  main(void)
      40  {
      41  	/*
      42  	 * Make sure the current workdir of the tracee
      43  	 * is different from the current workdir of the tracer.
      44  	 */
      45  	create_and_enter_subdir("linkat_subdir");
      46  
      47  	static const char sample_1[] = "linkat_sample_old";
      48  	static const char sample_2[] = "linkat_sample_new";
      49  	const long fd_old = (long) 0xdeadbeefffffffffULL;
      50  	const long fd_new = (long) 0xdeadbeeffffffffeULL;
      51  
      52  	char *my_secontext = SECONTEXT_PID_MY();
      53  
      54  	(void) unlink(sample_1);
      55  	(void) unlink(sample_2);
      56  
      57  	long rc = syscall(__NR_linkat, fd_old, sample_1, fd_new, sample_2, 0);
      58  	printf("%s%s(%d, \"%s\", %d, \"%s\", 0) = %ld %s (%m)\n",
      59  	       my_secontext, "linkat",
      60  	       (int) fd_old, sample_1, (int) fd_new, sample_2,
      61  	       rc, errno2name());
      62  
      63  	rc = syscall(__NR_linkat, -100, sample_1, -100, sample_2, -1L);
      64  	printf("%s%s(%s, \"%s\", %s, \"%s\", %s) = %ld %s (%m)\n",
      65  	       my_secontext, "linkat",
      66  	       "AT_FDCWD", sample_1, "AT_FDCWD", sample_2,
      67  	       "AT_SYMLINK_NOFOLLOW|AT_REMOVEDIR|AT_SYMLINK_FOLLOW"
      68  	       "|AT_NO_AUTOMOUNT|AT_EMPTY_PATH|AT_RECURSIVE|0xffff60ff",
      69  	       rc, errno2name());
      70  
      71  	/*
      72  	 * Tests with AT_FDCWD.
      73  	 */
      74  
      75  	int fd_sample_1 = open(sample_1, O_RDONLY | O_CREAT, 0400);
      76  	if (fd_sample_1 < 0)
      77  		perror_msg_and_fail("open");
      78  	if (close(fd_sample_1))
      79  		perror_msg_and_fail("close");
      80  
      81  	char *sample_1_secontext = SECONTEXT_FILE(sample_1);
      82  
      83  	rc = syscall(__NR_linkat, -100, sample_1, -100, sample_2, 0);
      84  	/* no context printed for sample_2 since file doesn't exist yet */
      85  	printf("%s%s(AT_FDCWD, \"%s\"%s, AT_FDCWD, \"%s\", 0) = %s\n",
      86  	       my_secontext, "linkat",
      87  	       sample_1, sample_1_secontext,
      88  	       sample_2,
      89  	       sprintrc(rc));
      90  
      91  	const char *sample_2_secontext = sample_1_secontext;
      92  
      93  	rc = syscall(__NR_linkat, -100, sample_1, -100, sample_2, 0);
      94  	printf("%s%s(AT_FDCWD, \"%s\"%s, AT_FDCWD, \"%s\"%s, 0) = %s\n",
      95  	       my_secontext, "linkat",
      96  	       sample_1, sample_1_secontext,
      97  	       sample_2, sample_2_secontext,
      98  	       sprintrc(rc));
      99  
     100  	int fd_sample_2 = open(sample_2, O_RDONLY | O_CREAT, 0400);
     101  	if (fd_sample_2 < 0)
     102  		perror_msg_and_fail("open");
     103  	if (close(fd_sample_2))
     104  		perror_msg_and_fail("close");
     105  
     106  	if (*sample_1_secontext && strstr(sample_1_secontext, "!!"))
     107  		reset_secontext_file(sample_1);
     108  
     109  	free(sample_1_secontext);
     110  
     111  #ifdef PRINT_SECONTEXT_MISMATCH
     112  	errno = 0;
     113  	mangle_secontext_field(sample_1, SECONTEXT_USER, "system_u",
     114  							 "unconfined_u");
     115  	sample_1_secontext = SECONTEXT_FILE(sample_1);
     116  
     117  # ifdef PRINT_SECONTEXT_FULL
     118  	/* The mismatch should be detected */
     119  	if (*sample_1_secontext && strstr(sample_1_secontext, "!!") == NULL)
     120  		perror_msg_and_fail("Context mismatch not detected: %s",
     121  				    sample_1_secontext);
     122  	if (*sample_1_secontext && strstr(sample_1_secontext, "system_u") == NULL)
     123  		perror_msg_and_fail("Context mismatch not detected: %s",
     124  				    sample_1_secontext);
     125  # else
     126  	/* The mismatch cannot be detected since it's on user part */
     127  	if (*sample_1_secontext && strstr(sample_1_secontext, "!!") != NULL)
     128  		perror_msg_and_fail("Context mismatch detected: %s",
     129  				    sample_1_secontext);
     130  # endif
     131  
     132  	free(sample_1_secontext);
     133  #endif
     134  
     135  	errno = 0;
     136  	mangle_secontext_field(sample_1, SECONTEXT_TYPE, "default_t",
     137  							 "unconfined_t");
     138  	sample_1_secontext = SECONTEXT_FILE(sample_1);
     139  	sample_2_secontext = sample_1_secontext;
     140  
     141  #ifdef PRINT_SECONTEXT_MISMATCH
     142  	if (*sample_1_secontext && strstr(sample_1_secontext, "!!") == NULL)
     143  		perror_msg_and_fail("Context mismatch not detected: %s",
     144  				    sample_1_secontext);
     145  	if (*sample_1_secontext && strstr(sample_1_secontext, "default_t") == NULL)
     146  		perror_msg_and_fail("Context mismatch not detected: %s",
     147  				    sample_1_secontext);
     148  #endif
     149  
     150  	rc = syscall(__NR_linkat, -100, sample_1, -100, sample_2, 0);
     151  	printf("%s%s(AT_FDCWD, \"%s\"%s, AT_FDCWD, \"%s\"%s, 0) = %s\n",
     152  	       my_secontext, "linkat",
     153  	       sample_1, sample_1_secontext,
     154  	       sample_2, sample_2_secontext,
     155  	       sprintrc(rc));
     156  
     157  	if (unlink(sample_2))
     158  		perror_msg_and_fail("unlink: %s", sample_2);
     159  
     160  	/*
     161  	 * Tests with dirfd.
     162  	 */
     163  
     164  	int dfd_old = get_dir_fd(".");
     165  	char *cwd = get_fd_path(dfd_old);
     166  
     167  	errno = 0;
     168  	mangle_secontext_field(".", SECONTEXT_TYPE, "default_t",
     169  						    "unconfined_t");
     170  	char *dfd_old_secontext = SECONTEXT_FILE(".");
     171  
     172  #ifdef PRINT_SECONTEXT_MISMATCH
     173  	if (*dfd_old_secontext && strstr(dfd_old_secontext, "!!") == NULL)
     174  		perror_msg_and_fail("Context mismatch not detected: %s",
     175  				    dfd_old_secontext);
     176  	if (*dfd_old_secontext && strstr(dfd_old_secontext, "default_t") == NULL)
     177  		perror_msg_and_fail("Context mismatch not detected: %s",
     178  				    dfd_old_secontext);
     179  #endif
     180  
     181  	rc = syscall(__NR_linkat, dfd_old, sample_1, -100, sample_2, 0);
     182  	/* no context printed for sample_2 since file doesn't exist yet */
     183  	printf("%s%s(%d%s, \"%s\"%s, AT_FDCWD, \"%s\", 0) = %s\n",
     184  	       my_secontext, "linkat",
     185  	       dfd_old, dfd_old_secontext,
     186  	       sample_1, sample_1_secontext,
     187  	       sample_2,
     188  	       sprintrc(rc));
     189  
     190  	rc = syscall(__NR_linkat, dfd_old, sample_1, -100, sample_2, 0);
     191  	printf("%s%s(%d%s, \"%s\"%s, AT_FDCWD, \"%s\"%s, 0) = %s\n",
     192  	       my_secontext, "linkat",
     193  	       dfd_old, dfd_old_secontext,
     194  	       sample_1, sample_1_secontext,
     195  	       sample_2, sample_2_secontext,
     196  	       sprintrc(rc));
     197  
     198  	if (unlink(sample_2))
     199  		perror_msg_and_fail("unlink: %s", sample_2);
     200  
     201  	static const char new_dir[] = "new";
     202  	char *new_sample_2 = xasprintf("%s/%s", new_dir, sample_2);
     203  
     204  	(void) unlink(new_sample_2);
     205  	(void) rmdir(new_dir);
     206  
     207  	if (mkdir(new_dir, 0700))
     208  		perror_msg_and_fail("mkdir");
     209  	char *new_dir_realpath = xasprintf("%s/%s", cwd, new_dir);
     210  	char *new_dir_secontext = SECONTEXT_FILE(new_dir);
     211  	int dfd_new = get_dir_fd(new_dir);
     212  
     213  	rc = syscall(__NR_linkat, dfd_old, sample_1, dfd_new, sample_2, 0);
     214  	/* no context printed for sample_2 since file doesn't exist yet */
     215  	printf("%s%s(%d%s, \"%s\"%s, %d%s, \"%s\", 0) = %s\n",
     216  	       my_secontext, "linkat",
     217  	       dfd_old, dfd_old_secontext,
     218  	       sample_1, sample_1_secontext,
     219  	       dfd_new, new_dir_secontext,
     220  	       sample_2,
     221  	       sprintrc(rc));
     222  
     223  	rc = syscall(__NR_linkat, dfd_old, sample_1, dfd_new, sample_2, 0);
     224  	printf("%s%s(%d%s, \"%s\"%s, %d%s, \"%s\"%s, 0) = %s\n",
     225  	       my_secontext, "linkat",
     226  	       dfd_old, dfd_old_secontext,
     227  	       sample_1, sample_1_secontext,
     228  	       dfd_new, new_dir_secontext,
     229  	       sample_2, SECONTEXT_FILE(new_sample_2),
     230  	       sprintrc(rc));
     231  
     232  	char *new_sample_2_realpath = xasprintf("%s/%s", new_dir_realpath, sample_2);
     233  
     234  	/* dfd ignored when path is absolute */
     235  	if (chdir("../.."))
     236  		perror_msg_and_fail("chdir");
     237  
     238  	rc = syscall(__NR_linkat, dfd_old, sample_1, -100, new_sample_2_realpath, 0);
     239  	printf("%s%s(%d%s, \"%s\"%s, AT_FDCWD, \"%s\"%s, 0) = %s\n",
     240  	       my_secontext, "linkat",
     241  	       dfd_old, dfd_old_secontext,
     242  	       sample_1, sample_1_secontext,
     243  	       new_sample_2_realpath, SECONTEXT_FILE(new_sample_2_realpath),
     244  	       sprintrc(rc));
     245  
     246  	if (fchdir(dfd_old))
     247  		perror_msg_and_fail("fchdir");
     248  
     249  	if (unlink(sample_1))
     250  		perror_msg_and_fail("unlink: %s", sample_1);
     251  	if (unlink(new_sample_2))
     252  		perror_msg_and_fail("unlink: %s", new_sample_2);
     253  	if (rmdir(new_dir))
     254  		perror_msg_and_fail("rmdir: %s", new_dir);
     255  
     256  	leave_and_remove_subdir();
     257  
     258  	puts("+++ exited with 0 +++");
     259  	return 0;
     260  }