kcmp(2) System Calls Manual kcmp(2) kcmp - , LIBRARY Standard C library (libc, -lc) #include /* KCMP_* */ #include /* SYS_* */ #include int syscall(SYS_kcmp, pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2); Note: glibc provides no wrapper for kcmp(), necessitating the use of syscall(2). kcmp() , pid1 pid2 , , .. kcmp() ptrace PTRACE_MODE_READ_REALCREDS pid1 pid2; ptrace(2). type . : KCMP_FILE , idx1 pid1 ( open(2)) idx2 pid2. , , dup(2) ( ) fork(2), ( unix(7)). KCMP_FILES , . idx1 idx2 . CLONE_FILES clone(2). KCMP_FS , (. . , ). idx1 idx2 . CLONE_FS clone(2). KCMP_IO , -. idx1 idx2 . CLONE_IO clone(2). KCMP_SIGHAND , . idx1 idx2 . CLONE_SIGHAND clone(2). KCMP_SYSVSEM , System V. idx1 idx2 . CLONE_SYSVSEM clone(2). KCMP_VM , . idx1 idx2 . CLONE_VM clone(2). KCMP_EPOLL_TFD ( Linux 4.13) , idx1 pid1 epoll(7), idx2 pid2. idx2 , . : struct kcmp_epoll_slot { __u32 efd; __u32 tfd; __u64 toff; }; efd epoll, epoll_create(2), tfd , toff , . , . , kcmp() (false positives), , . SIGSTOP ( signal(7)). kcmp() ( , ). . , v1 v2 -- : 0 v1 v2; , . 1 v1 v2. 2 v1 v2. 3 v1 v2, . -1, errno . kcmp() , . , . EBADF type KCMP_FILE fd1 fd2 . EFAULT epoll, idx2, . EINVAL type . ENOENT epoll(7). EPERM . CAP_SYS_PTRACE, . ptrace, CONFIG_SECURITY_YAMA, /proc/sys/kernel/yama/ptrace_scope 2, kcmp() ; ptrace(2). ESRCH pid1 pid2 . Linux. Linux 3.5. Before Linux 5.12, this system call is available only if the kernel is configured with CONFIG_CHECKPOINT_RESTORE, since the original purpose of the system call was for the checkpoint/restore in user space (CRIU) feature. (The alternative to this system call would have been to expose suitable process information via the proc(5) filesystem; this was deemed to be unsuitable for security reasons.) Since Linux 5.12, this system call is also available if the kernel is configured with CONFIG_KCMP. clone(2). kcmp() , . , . : $ ./a.out Parent PID is 1144 Parent opened file on FD 3 PID of child of fork() is 1145 Compare duplicate FDs from different processes: kcmp(1145, 1144, KCMP_FILE, 3, 3) ==> same Child opened file on FD 4 Compare FDs from distinct open()s in same process: kcmp(1145, 1145, KCMP_FILE, 3, 4) ==> different Child duplicated FD 3 to create FD 5 Compare duplicated FDs in same process: kcmp(1145, 1145, KCMP_FILE, 3, 5) ==> same #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include static int kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2) { return syscall(SYS_kcmp, pid1, pid2, type, idx1, idx2); } static void test_kcmp(char *msg, pid_t pid1, pid_t pid2, int fd_a, int fd_b) { printf("\t%s\n", msg); printf("\t\tkcmp(%jd, %jd, KCMP_FILE, %d, %d) ==> %s\n", (intmax_t) pid1, (intmax_t) pid2, fd_a, fd_b, (kcmp(pid1, pid2, KCMP_FILE, fd_a, fd_b) == 0) ? "same" : "different"); } int main(void) { int fd1, fd2, fd3; static const char pathname[] = "/tmp/kcmp.test"; fd1 = open(pathname, O_CREAT | O_RDWR, 0600); if (fd1 == -1) err(EXIT_FAILURE, "open"); printf("Parent PID is %jd\n", (intmax_t) getpid()); printf("Parent opened file on FD %d\n\n", fd1); switch (fork()) { case -1: err(EXIT_FAILURE, "fork"); case 0: printf("PID of child of fork() is %jd\n", (intmax_t) getpid()); test_kcmp("Compare duplicate FDs from different processes:", getpid(), getppid(), fd1, fd1); fd2 = open(pathname, O_CREAT | O_RDWR, 0600); if (fd2 == -1) err(EXIT_FAILURE, "open"); printf("Child opened file on FD %d\n", fd2); test_kcmp("Compare FDs from distinct open()s in same process:", getpid(), getpid(), fd1, fd2); fd3 = dup(fd1); if (fd3 == -1) err(EXIT_FAILURE, "dup"); printf("Child duplicated FD %d to create FD %d\n", fd1, fd3); test_kcmp("Compare duplicated FDs in same process:", getpid(), getpid(), fd1, fd3); break; default: wait(NULL); } exit(EXIT_SUCCESS); } . clone(2), unshare(2) Alex Nik , Azamat Hackimov , Yuri Kozlov ; GNU 3 , . . , , . Linux man-pages 6.06 31 2023 . kcmp(2)