(root)/
strace-6.5/
tests-mx32/
kcmp.c
       1  /*
       2   * Check decoding of kcmp syscall.
       3   *
       4   * Copyright (c) 2016-2017 Eugene Syromyatnikov <evgsyr@gmail.com>
       5   * Copyright (c) 2016-2021 The strace developers.
       6   * All rights reserved.
       7   *
       8   * SPDX-License-Identifier: GPL-2.0-or-later
       9   */
      10  
      11  #include "tests.h"
      12  #include "scno.h"
      13  #include "pidns.h"
      14  
      15  #include <fcntl.h>
      16  #include <stdarg.h>
      17  #include <stdint.h>
      18  #include <stdio.h>
      19  #include <string.h>
      20  #include <unistd.h>
      21  #include <linux/kcmp.h>
      22  
      23  #ifndef SKIP_IF_PROC_IS_UNAVAILABLE
      24  # define SKIP_IF_PROC_IS_UNAVAILABLE
      25  #endif
      26  
      27  #ifndef VERBOSE_FD
      28  # define VERBOSE_FD 0
      29  #endif
      30  
      31  static const kernel_ulong_t kcmp_max_type = KCMP_EPOLL_TFD;
      32  
      33  static const char null_path[] = "/dev/null";
      34  static const char zero_path[] = "/dev/zero";
      35  
      36  #define NULL_FD 23
      37  #define ZERO_FD 42
      38  
      39  static void
      40  printpidfd(const char *prefix, pid_t pid, unsigned fd)
      41  {
      42  	const char *path = NULL;
      43  
      44  #if VERBOSE_FD
      45  	if (pid == getpid()) {
      46  		switch (fd)
      47  		{
      48  		case NULL_FD:
      49  			path = null_path;
      50  			break;
      51  		case ZERO_FD:
      52  			path = zero_path;
      53  			break;
      54  		}
      55  	}
      56  #endif
      57  
      58  	if (path)
      59  		printf("%s%d<%s>", prefix, fd, path);
      60  	else
      61  		printf("%s%d", prefix, fd);
      62  }
      63  
      64  /*
      65   * Last argument is optional and is used as follows:
      66   *  * When type is KCMP_EPOLL_TFD, it signalises whether idx2 is a valid
      67   *    pointer.
      68   */
      69  static void
      70  do_kcmp(kernel_ulong_t pid1, kernel_ulong_t pid2, kernel_ulong_t type,
      71  	const char *type_str, kernel_ulong_t idx1, kernel_ulong_t idx2, ...)
      72  {
      73  	long rc;
      74  	const char *errstr;
      75  
      76  	rc = syscall(__NR_kcmp, pid1, pid2, type, idx1, idx2);
      77  	errstr = sprintrc(rc);
      78  
      79  	const char *pid_str = pidns_pid2str(PT_TGID);
      80  	pidns_print_leader();
      81  	printf("kcmp(%d%s, %d%s, ",
      82  		(int) pid1, (int) pid1 == getpid() ? pid_str : "",
      83  		(int) pid2, (int) pid2 == getpid() ? pid_str : "");
      84  
      85  	if (type_str)
      86  		printf("%s", type_str);
      87  	else
      88  		printf("%#x /* KCMP_??? */", (int) type);
      89  
      90  	if (type == KCMP_FILE) {
      91  		printpidfd(", ", pid1, idx1);
      92  		printpidfd(", ", pid2, idx2);
      93  	} else if (type == KCMP_EPOLL_TFD) {
      94  		va_list ap;
      95  		int valid_ptr;
      96  
      97  		va_start(ap, idx2);
      98  		valid_ptr = va_arg(ap, int);
      99  		va_end(ap);
     100  
     101  		printpidfd(", ", pid1, idx1);
     102  		printf(", ");
     103  
     104  		if (valid_ptr) {
     105  			struct kcmp_epoll_slot *slot =
     106  				(struct kcmp_epoll_slot *) (uintptr_t) idx2;
     107  
     108  			printpidfd("{efd=", pid2, slot->efd);
     109  			printpidfd(", tfd=", pid2, slot->tfd);
     110  			printf(", toff=%llu}", (unsigned long long) slot->toff);
     111  		} else {
     112  			if (idx2)
     113  				printf("%#llx", (unsigned long long) idx2);
     114  			else
     115  				printf("NULL");
     116  		}
     117  	} else if (type > kcmp_max_type) {
     118  		printf(", %#llx, %#llx",
     119  		       (unsigned long long) idx1, (unsigned long long) idx2);
     120  	}
     121  
     122  	printf(") = %s\n", errstr);
     123  }
     124  
     125  int
     126  main(void)
     127  {
     128  	SKIP_IF_PROC_IS_UNAVAILABLE;
     129  	PIDNS_TEST_INIT;
     130  
     131  	static const kernel_ulong_t bogus_pid1 =
     132  		(kernel_ulong_t) 0xdeadca75face1057ULL;
     133  	static const kernel_ulong_t bogus_pid2 =
     134  		(kernel_ulong_t) 0xdefaced1defaced2ULL;
     135  	static const kernel_ulong_t bogus_type =
     136  		(kernel_ulong_t) 0xbadc0dedda7adeadULL;
     137  	static const kernel_ulong_t bogus_idx1 =
     138  		(kernel_ulong_t) 0xdec0ded3dec0ded4ULL;
     139  	static const kernel_ulong_t bogus_idx2 =
     140  		(kernel_ulong_t) 0xba5e1e55deadc0deULL;
     141  	static const struct kcmp_epoll_slot slot_data[] = {
     142  		{ 0xdeadc0de, 0xfacef157, 0xbadc0ded },
     143  		{ NULL_FD, ZERO_FD, 0 },
     144  		{ 0, 0, 0 },
     145  	};
     146  	static kernel_ulong_t ptr_check =
     147  		F8ILL_KULONG_SUPPORTED ? F8ILL_KULONG_MASK : 0;
     148  
     149  	int fd;
     150  	TAIL_ALLOC_OBJECT_CONST_PTR(struct kcmp_epoll_slot, slot);
     151  
     152  	/* Open some files to test printpidfd */
     153  	fd = open(null_path, O_RDONLY);
     154  	if (fd < 0)
     155  		perror_msg_and_fail("open(\"%s\")", null_path);
     156  	if (fd != NULL_FD) {
     157  		if (dup2(fd, NULL_FD) < 0)
     158  			perror_msg_and_fail("dup2(fd, NULL_FD)");
     159  		close(fd);
     160  	}
     161  
     162  	fd = open(zero_path, O_RDONLY);
     163  	if (fd < 0)
     164  		perror_msg_and_fail("open(\"%s\")", zero_path);
     165  	if (fd != ZERO_FD) {
     166  		if (dup2(fd, ZERO_FD) < 0)
     167  			perror_msg_and_fail("dup2(fd, ZERO_FD)");
     168  		close(fd);
     169  	}
     170  
     171  	close(0);
     172  
     173  	/* Invalid values */
     174  	do_kcmp(bogus_pid1, bogus_pid2, bogus_type, NULL, bogus_idx1,
     175  		bogus_idx2);
     176  	do_kcmp(F8ILL_KULONG_MASK, F8ILL_KULONG_MASK, kcmp_max_type + 1, NULL,
     177  		0, 0);
     178  
     179  	/* KCMP_FILE is the only type which has additional args */
     180  	do_kcmp(3141592653U, 2718281828U, ARG_STR(KCMP_FILE), bogus_idx1,
     181  		bogus_idx2);
     182  	do_kcmp(getpid(), getpid(), ARG_STR(KCMP_FILE), NULL_FD, ZERO_FD);
     183  
     184  	/* Types without additional args */
     185  	do_kcmp(-1, -1, ARG_STR(KCMP_VM), bogus_idx1, bogus_idx2);
     186  	do_kcmp(-1, -1, ARG_STR(KCMP_FILES), bogus_idx1, bogus_idx2);
     187  	do_kcmp(-1, -1, ARG_STR(KCMP_FS), bogus_idx1, bogus_idx2);
     188  	do_kcmp(-1, -1, ARG_STR(KCMP_SIGHAND), bogus_idx1, bogus_idx2);
     189  	do_kcmp(-1, -1, ARG_STR(KCMP_IO), bogus_idx1, bogus_idx2);
     190  	do_kcmp(-1, -1, ARG_STR(KCMP_SYSVSEM), bogus_idx1, bogus_idx2);
     191  
     192  	/* KCMP_EPOLL_TFD checks */
     193  	do_kcmp(-1, -1, ARG_STR(KCMP_EPOLL_TFD),
     194  		F8ILL_KULONG_MASK | 2718281828U, ptr_check, 0);
     195  	do_kcmp(-1, -1, ARG_STR(KCMP_EPOLL_TFD),
     196  		3141592653U, (uintptr_t) slot + 1, 0);
     197  
     198  	for (unsigned int i = 0; i < ARRAY_SIZE(slot_data); ++i) {
     199  		memcpy(slot, slot_data + i, sizeof(*slot));
     200  
     201  		do_kcmp(getpid(), -1, ARG_STR(KCMP_EPOLL_TFD), NULL_FD,
     202  			(uintptr_t) slot, 1);
     203  	}
     204  
     205  	pidns_print_leader();
     206  	puts("+++ exited with 0 +++");
     207  
     208  	return 0;
     209  }