| .\" Copyright (C) 2012, Cyrill Gorcunov <gorcunov@openvz.org> |
| .\" and Copyright (C) 2012, 2016, Michael Kerrisk <mtk.manpages@gmail.com> |
| .\" |
| .\" %%%LICENSE_START(VERBATIM) |
| .\" Permission is granted to make and distribute verbatim copies of this |
| .\" manual provided the copyright notice and this permission notice are |
| .\" preserved on all copies. |
| .\" |
| .\" Permission is granted to copy and distribute modified versions of |
| .\" this manual under the conditions for verbatim copying, provided that |
| .\" the entire resulting derived work is distributed under the terms of |
| .\" a permission notice identical to this one. |
| .\" |
| .\" Since the Linux kernel and libraries are constantly changing, this |
| .\" manual page may be incorrect or out-of-date. The author(s) assume |
| .\" no responsibility for errors or omissions, or for damages resulting |
| .\" from the use of the information contained herein. The author(s) may |
| .\" not have taken the same level of care in the production of this |
| .\" manual, which is licensed free of charge, as they might when working |
| .\" professionally. |
| .\" |
| .\" Formatted or processed versions of this manual, if unaccompanied by |
| .\" the source, must acknowledge the copyright and authors of this work. |
| .\" %%%LICENSE_END |
| .\" |
| .\" Kernel commit d97b46a64674a267bc41c9e16132ee2a98c3347d |
| .\" |
| .TH KCMP 2 2021-03-22 "Linux" "Linux Programmer's Manual" |
| .SH NAME |
| kcmp \- compare two processes to determine if they share a kernel resource |
| .SH SYNOPSIS |
| .nf |
| .B #include <linux/kcmp.h> |
| .PP |
| .BI "int kcmp(pid_t " pid1 ", pid_t " pid2 ", int " type , |
| .BI " unsigned long " idx1 ", unsigned long " idx2 ); |
| .fi |
| .PP |
| .IR Note : |
| There is no glibc wrapper for this system call; see NOTES. |
| .SH DESCRIPTION |
| The |
| .BR kcmp () |
| system call can be used to check whether the two processes identified by |
| .I pid1 |
| and |
| .I pid2 |
| share a kernel resource such as virtual memory, file descriptors, |
| and so on. |
| .PP |
| Permission to employ |
| .BR kcmp () |
| is governed by ptrace access mode |
| .B PTRACE_MODE_READ_REALCREDS |
| checks against both |
| .I pid1 |
| and |
| .IR pid2 ; |
| see |
| .BR ptrace (2). |
| .PP |
| The |
| .I type |
| argument specifies which resource is to be compared in the two processes. |
| It has one of the following values: |
| .TP |
| .BR KCMP_FILE |
| Check whether a file descriptor |
| .I idx1 |
| in the process |
| .I pid1 |
| refers to the same open file description (see |
| .BR open (2)) |
| as file descriptor |
| .I idx2 |
| in the process |
| .IR pid2 . |
| The existence of two file descriptors that refer to the same |
| open file description can occur as a result of |
| .BR dup (2) |
| (and similar) |
| .BR fork (2), |
| or passing file descriptors via a domain socket (see |
| .BR unix (7)). |
| .TP |
| .BR KCMP_FILES |
| Check whether the processes share the same set of open file descriptors. |
| The arguments |
| .I idx1 |
| and |
| .I idx2 |
| are ignored. |
| See the discussion of the |
| .BR CLONE_FILES |
| flag in |
| .BR clone (2). |
| .TP |
| .BR KCMP_FS |
| Check whether the processes share the same filesystem information |
| (i.e., file mode creation mask, working directory, and filesystem root). |
| The arguments |
| .I idx1 |
| and |
| .I idx2 |
| are ignored. |
| See the discussion of the |
| .BR CLONE_FS |
| flag in |
| .BR clone (2). |
| .TP |
| .BR KCMP_IO |
| Check whether the processes share I/O context. |
| The arguments |
| .I idx1 |
| and |
| .I idx2 |
| are ignored. |
| See the discussion of the |
| .BR CLONE_IO |
| flag in |
| .BR clone (2). |
| .TP |
| .BR KCMP_SIGHAND |
| Check whether the processes share the same table of signal dispositions. |
| The arguments |
| .I idx1 |
| and |
| .I idx2 |
| are ignored. |
| See the discussion of the |
| .BR CLONE_SIGHAND |
| flag in |
| .BR clone (2). |
| .TP |
| .BR KCMP_SYSVSEM |
| Check whether the processes share the same |
| list of System\ V semaphore undo operations. |
| The arguments |
| .I idx1 |
| and |
| .I idx2 |
| are ignored. |
| See the discussion of the |
| .BR CLONE_SYSVSEM |
| flag in |
| .BR clone (2). |
| .TP |
| .BR KCMP_VM |
| Check whether the processes share the same address space. |
| The arguments |
| .I idx1 |
| and |
| .I idx2 |
| are ignored. |
| See the discussion of the |
| .BR CLONE_VM |
| flag in |
| .BR clone (2). |
| .TP |
| .BR KCMP_EPOLL_TFD " (since Linux 4.13)" |
| .\" commit 0791e3644e5ef21646fe565b9061788d05ec71d4 |
| Check whether the file descriptor |
| .I idx1 |
| of the process |
| .I pid1 |
| is present in the |
| .BR epoll (7) |
| instance described by |
| .I idx2 |
| of the process |
| .IR pid2 . |
| The argument |
| .I idx2 |
| is a pointer to a structure where the target file is described. |
| This structure has the form: |
| .PP |
| .in +4n |
| .EX |
| struct kcmp_epoll_slot { |
| __u32 efd; |
| __u32 tfd; |
| __u64 toff; |
| }; |
| .EE |
| .in |
| .PP |
| Within this structure, |
| .I efd |
| is an epoll file descriptor returned from |
| .BR epoll_create (2), |
| .I tfd |
| is a target file descriptor number, and |
| .I toff |
| is a target file offset counted from zero. |
| Several different targets may be registered with |
| the same file descriptor number and setting a specific |
| offset helps to investigate each of them. |
| .PP |
| Note the |
| .BR kcmp () |
| is not protected against false positives which may occur if |
| the processes are currently running. |
| One should stop the processes by sending |
| .BR SIGSTOP |
| (see |
| .BR signal (7)) |
| prior to inspection with this system call to obtain meaningful results. |
| .SH RETURN VALUE |
| The return value of a successful call to |
| .BR kcmp () |
| is simply the result of arithmetic comparison |
| of kernel pointers (when the kernel compares resources, it uses their |
| memory addresses). |
| .PP |
| The easiest way to explain is to consider an example. |
| Suppose that |
| .I v1 |
| and |
| .I v2 |
| are the addresses of appropriate resources, then the return value |
| is one of the following: |
| .RS 4 |
| .IP 0 4 |
| .I v1 |
| is equal to |
| .IR v2 ; |
| in other words, the two processes share the resource. |
| .IP 1 |
| .I v1 |
| is less than |
| .IR v2 . |
| .IP 2 |
| .I v1 |
| is greater than |
| .IR v2 . |
| .IP 3 |
| .I v1 |
| is not equal to |
| .IR v2 , |
| but ordering information is unavailable. |
| .RE |
| .PP |
| On error, \-1 is returned, and |
| .I errno |
| is set to indicate the error. |
| .PP |
| .BR kcmp () |
| was designed to return values suitable for sorting. |
| This is particularly handy if one needs to compare |
| a large number of file descriptors. |
| .SH ERRORS |
| .TP |
| .B EBADF |
| .I type |
| is |
| .B KCMP_FILE |
| and |
| .I fd1 |
| or |
| .I fd2 |
| is not an open file descriptor. |
| .TP |
| .B EFAULT |
| The epoll slot addressed by |
| .I idx2 |
| is outside of the user's address space. |
| .TP |
| .B EINVAL |
| .I type |
| is invalid. |
| .TP |
| .B ENOENT |
| The target file is not present in |
| .BR epoll (7) |
| instance. |
| .TP |
| .B EPERM |
| Insufficient permission to inspect process resources. |
| The |
| .B CAP_SYS_PTRACE |
| capability is required to inspect processes that you do not own. |
| Other ptrace limitations may also apply, such as |
| .BR CONFIG_SECURITY_YAMA , |
| which, when |
| .I /proc/sys/kernel/yama/ptrace_scope |
| is 2, limits |
| .BR kcmp () |
| to child processes; |
| see |
| .BR ptrace (2). |
| .TP |
| .B ESRCH |
| Process |
| .I pid1 |
| or |
| .I pid2 |
| does not exist. |
| .SH VERSIONS |
| The |
| .BR kcmp () |
| system call first appeared in Linux 3.5. |
| .SH CONFORMING TO |
| .BR kcmp () |
| is Linux-specific and should not be used in programs intended to be portable. |
| .SH NOTES |
| Glibc does not provide a wrapper for this system call; call it using |
| .BR syscall (2). |
| .PP |
| Before Linux 5.12, |
| this system call is available only if the kernel is configured with |
| .BR CONFIG_CHECKPOINT_RESTORE , |
| since the original pupose 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 |
| .BR proc (5) |
| filesystem; this was deemed to be unsuitable for security reasons.) |
| Since Linux 5.12, this system call is made available unconditionally. |
| .PP |
| See |
| .BR clone (2) |
| for some background information on the shared resources |
| referred to on this page. |
| .SH EXAMPLES |
| The program below uses |
| .BR kcmp () |
| to test whether pairs of file descriptors refer to |
| the same open file description. |
| The program tests different cases for the file descriptor pairs, |
| as described in the program output. |
| An example run of the program is as follows: |
| .PP |
| .in +4n |
| .EX |
| $ \fB./a.out\fP |
| 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 |
| .EE |
| .in |
| .SS Program source |
| \& |
| .EX |
| #define _GNU_SOURCE |
| #include <sys/syscall.h> |
| #include <sys/wait.h> |
| #include <sys/stat.h> |
| #include <stdint.h> |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <unistd.h> |
| #include <fcntl.h> |
| #include <linux/kcmp.h> |
| |
| #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \e |
| } while (0) |
| |
| 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("\et%s\en", msg); |
| printf("\et\etkcmp(%jd, %jd, KCMP_FILE, %d, %d) ==> %s\en", |
| (intmax_t) pid1, (intmax_t) pid2, fd_a, fd_b, |
| (kcmp(pid1, pid2, KCMP_FILE, fd_a, fd_b) == 0) ? |
| "same" : "different"); |
| } |
| |
| int |
| main(int argc, char *argv[]) |
| { |
| int fd1, fd2, fd3; |
| char pathname[] = "/tmp/kcmp.test"; |
| |
| fd1 = open(pathname, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); |
| if (fd1 == \-1) |
| errExit("open"); |
| |
| printf("Parent PID is %jd\en", (intmax_t) getpid()); |
| printf("Parent opened file on FD %d\en\en", fd1); |
| |
| switch (fork()) { |
| case \-1: |
| errExit("fork"); |
| |
| case 0: |
| printf("PID of child of fork() is %jd\en", (intmax_t) getpid()); |
| |
| test_kcmp("Compare duplicate FDs from different processes:", |
| getpid(), getppid(), fd1, fd1); |
| |
| fd2 = open(pathname, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); |
| if (fd2 == \-1) |
| errExit("open"); |
| printf("Child opened file on FD %d\en", fd2); |
| |
| test_kcmp("Compare FDs from distinct open()s in same process:", |
| getpid(), getpid(), fd1, fd2); |
| |
| fd3 = dup(fd1); |
| if (fd3 == \-1) |
| errExit("dup"); |
| printf("Child duplicated FD %d to create FD %d\en", fd1, fd3); |
| |
| test_kcmp("Compare duplicated FDs in same process:", |
| getpid(), getpid(), fd1, fd3); |
| break; |
| |
| default: |
| wait(NULL); |
| } |
| |
| exit(EXIT_SUCCESS); |
| } |
| .EE |
| .SH SEE ALSO |
| .BR clone (2), |
| .BR unshare (2) |