1 // SPDX-License-Identifier: GPL-2.0 2 #define _GNU_SOURCE 3 4 #include <stdio.h> 5 #include <stdlib.h> 6 #include <signal.h> 7 #include <limits.h> 8 #include <unistd.h> 9 #include <errno.h> 10 #include <string.h> 11 #include <fcntl.h> 12 #include <linux/unistd.h> 13 #include <linux/kcmp.h> 14 15 #include <sys/syscall.h> 16 #include <sys/types.h> 17 #include <sys/stat.h> 18 #include <sys/wait.h> 19 #include <sys/epoll.h> 20 21 #include "../kselftest.h" 22 23 static long sys_kcmp(int pid1, int pid2, int type, unsigned long fd1, unsigned long fd2) 24 { 25 return syscall(__NR_kcmp, pid1, pid2, type, fd1, fd2); 26 } 27 28 static const unsigned int duped_num = 64; 29 30 int main(int argc, char **argv) 31 { 32 const char kpath[] = "kcmp-test-file"; 33 struct kcmp_epoll_slot epoll_slot; 34 struct epoll_event ev; 35 int pid1, pid2; 36 int pipefd[2]; 37 int fd1, fd2; 38 int epollfd; 39 int status; 40 int fddup; 41 42 fd1 = open(kpath, O_RDWR | O_CREAT | O_TRUNC, 0644); 43 pid1 = getpid(); 44 45 if (fd1 < 0) { 46 perror("Can't create file"); 47 ksft_exit_fail(); 48 } 49 50 if (pipe(pipefd)) { 51 perror("Can't create pipe"); 52 ksft_exit_fail(); 53 } 54 55 epollfd = epoll_create1(0); 56 if (epollfd < 0) { 57 perror("epoll_create1 failed"); 58 ksft_exit_fail(); 59 } 60 61 memset(&ev, 0xff, sizeof(ev)); 62 ev.events = EPOLLIN | EPOLLOUT; 63 64 if (epoll_ctl(epollfd, EPOLL_CTL_ADD, pipefd[0], &ev)) { 65 perror("epoll_ctl failed"); 66 ksft_exit_fail(); 67 } 68 69 fddup = dup2(pipefd[1], duped_num); 70 if (fddup < 0) { 71 perror("dup2 failed"); 72 ksft_exit_fail(); 73 } 74 75 if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fddup, &ev)) { 76 perror("epoll_ctl failed"); 77 ksft_exit_fail(); 78 } 79 close(fddup); 80 81 pid2 = fork(); 82 if (pid2 < 0) { 83 perror("fork failed"); 84 ksft_exit_fail(); 85 } 86 87 if (!pid2) { 88 int pid2 = getpid(); 89 int ret; 90 91 fd2 = open(kpath, O_RDWR, 0644); 92 if (fd2 < 0) { 93 perror("Can't open file"); 94 ksft_exit_fail(); 95 } 96 97 /* An example of output and arguments */ 98 printf("pid1: %6d pid2: %6d FD: %2ld FILES: %2ld VM: %2ld " 99 "FS: %2ld SIGHAND: %2ld IO: %2ld SYSVSEM: %2ld " 100 "INV: %2ld\n", 101 pid1, pid2, 102 sys_kcmp(pid1, pid2, KCMP_FILE, fd1, fd2), 103 sys_kcmp(pid1, pid2, KCMP_FILES, 0, 0), 104 sys_kcmp(pid1, pid2, KCMP_VM, 0, 0), 105 sys_kcmp(pid1, pid2, KCMP_FS, 0, 0), 106 sys_kcmp(pid1, pid2, KCMP_SIGHAND, 0, 0), 107 sys_kcmp(pid1, pid2, KCMP_IO, 0, 0), 108 sys_kcmp(pid1, pid2, KCMP_SYSVSEM, 0, 0), 109 110 /* This one should fail */ 111 sys_kcmp(pid1, pid2, KCMP_TYPES + 1, 0, 0)); 112 113 /* This one should return same fd */ 114 ret = sys_kcmp(pid1, pid2, KCMP_FILE, fd1, fd1); 115 if (ret) { 116 printf("FAIL: 0 expected but %d returned (%s)\n", 117 ret, strerror(errno)); 118 ksft_inc_fail_cnt(); 119 ret = -1; 120 } else { 121 printf("PASS: 0 returned as expected\n"); 122 ksft_inc_pass_cnt(); 123 } 124 125 /* Compare with self */ 126 ret = sys_kcmp(pid1, pid1, KCMP_VM, 0, 0); 127 if (ret) { 128 printf("FAIL: 0 expected but %d returned (%s)\n", 129 ret, strerror(errno)); 130 ksft_inc_fail_cnt(); 131 ret = -1; 132 } else { 133 printf("PASS: 0 returned as expected\n"); 134 ksft_inc_pass_cnt(); 135 } 136 137 /* Compare epoll target */ 138 epoll_slot = (struct kcmp_epoll_slot) { 139 .efd = epollfd, 140 .tfd = duped_num, 141 .toff = 0, 142 }; 143 ret = sys_kcmp(pid1, pid1, KCMP_EPOLL_TFD, pipefd[1], 144 (unsigned long)(void *)&epoll_slot); 145 if (ret) { 146 printf("FAIL: 0 expected but %d returned (%s)\n", 147 ret, strerror(errno)); 148 ksft_inc_fail_cnt(); 149 ret = -1; 150 } else { 151 printf("PASS: 0 returned as expected\n"); 152 ksft_inc_pass_cnt(); 153 } 154 155 ksft_print_cnts(); 156 157 if (ret) 158 ksft_exit_fail(); 159 else 160 ksft_exit_pass(); 161 } 162 163 waitpid(pid2, &status, P_ALL); 164 165 return ksft_exit_pass(); 166 } 167