CONFIG_KCMP 是 Linux 内核 5.12+ 新增的独立开关,用于启用 kcmp () 系统调用,核心作用是让用户态安全地比对两个进程是否共享内核资源(FD、内存、信号等),典型用于容器 / CRIU 热迁移、调试与安全审计。下面从配置、系统调用、源码、应用场景、依赖与默认配置几方面详细说明。
一、配置项基本信息(Kconfig)
路径:init/Kconfig
config KCMP
bool "Enable kcmp() system call"
depends on EXPERT
help
Enable the kernel resource comparison system call. It provides
user-space with the ability to compare two processes to see if
they share a common resource, such as a file descriptor or even
virtual memory space.
If unsure, say N.
- 类型:
bool(y/n,不可编译为模块) - 依赖:
CONFIG_EXPERT=y(需开启专家模式才可见) - 引入版本:Linux 5.12(此前 kcmp () 仅随
CONFIG_CHECKPOINT_RESTORE启用) - 主流发行版默认:
y(如 Ubuntu、CentOS、Debian),极简内核默认n
二、kcmp () 系统调用详解
1. 函数原型
#include <linux/kcmp.h>
// 无 glibc 封装,需用 syscall 直接调用
int syscall(SYS_kcmp, pid_t pid1, pid_t pid2, int type,
unsigned long idx1, unsigned long idx2);
- 功能:比较
pid1与pid2的指定资源是否指向同一内核对象 - 权限:需对两个进程有
PTRACE_MODE_READ_REALCREDS权限(类似 ptrace 读权限)
2. 比对类型(type 参数)
表格
| 类型 | 作用 |
|---|---|
KCMP_FILE |
比较 idx1(pid1 的 FD)与 idx2(pid2 的 FD)是否指向同一打开文件 |
KCMP_VM |
比较两进程是否共享虚拟内存(如 clone (CLONE_VM) 创建的线程) |
KCMP_FILES |
比较两进程是否共享文件描述符表(如 clone (CLONE_FILES)) |
KCMP_FS |
比较两进程是否共享文件系统信息(根目录、umask 等) |
KCMP_SIGHAND |
比较两进程是否共享信号处理表 |
KCMP_IO |
比较两进程是否共享 I/O 上下文 |
KCMP_SYSVSEM |
比较两进程是否共享 System V 信号量 |
3. 返回值
0:两个资源完全相同(指向同一内核对象)1:资源类型相同但对象不同2:资源类型不同- 负数:错误(如
-ESRCH:进程不存在;-EPERM:权限不足)
三、核心源码流程(5.12+)
1. 系统调用注册(kernel/syscall.c)
// 5.12+ 独立注册,不再依赖 CHECKPOINT_RESTORE
SYSCALL_DEFINE6(kcmp, pid_t, pid1, pid_t, pid2, int, type,
unsigned long, idx1, unsigned long, idx2)
{
// 权限检查:对 pid1/pid2 执行 ptrace 读权限校验
if (!ptrace_may_access(pid1, PTRACE_MODE_READ_REALCREDS) ||
!ptrace_may_access(pid2, PTRACE_MODE_READ_REALCREDS))
return -EPERM;
// 根据 type 分发到不同资源比对函数
switch (type) {
case KCMP_FILE: return kcmp_file(pid1, pid2, idx1, idx2);
case KCMP_VM: return kcmp_vm(pid1, pid2);
// ... 其他类型处理
default: return -EINVAL;
}
}
2. 示例:kcmp_file 比对逻辑
static int kcmp_file(pid_t pid1, pid_t pid2, unsigned long fd1, unsigned long fd2)
{
struct file *f1, *f2;
struct task_struct *p1, *p2;
// 获取进程结构体
p1 = find_task_by_vpid(pid1);
p2 = find_task_by_vpid(pid2);
if (!p1 || !p2) return -ESRCH;
// 从 FD 表中取出 file 对象
f1 = fget(p1, fd1);
f2 = fget(p2, fd2);
if (!f1 || !f2) return -EBADF;
// 比较 file 对象地址(同一内核对象则地址相同)
int res = (f1 == f2) ? 0 : 1;
fput(f1);
fput(f2);
return res;
}
- 核心:通过内核对象地址比对判断资源是否共享,安全高效,无需暴露敏感 proc 信息
四、关键应用场景
-
CRIU(Checkpoint/Restore In Userspace)
- 容器 / 进程热迁移:迁移前比对进程资源共享关系,确保快照一致性
- 依赖:
CONFIG_KCMP=y或CONFIG_CHECKPOINT_RESTORE=y
-
容器运行时(Docker/containerd)
- 验证容器内进程是否共享命名空间 / 资源(如判断是否为同一容器的线程)
-
调试与排障
- 排查进程间 FD 泄漏:快速定位两个进程是否持有同一文件 / 套接字
- 示例:
kcmp(1234, 5678, KCMP_FILE, 3, 3)检查 1234 的 FD3 与 5678 的 FD3 是否相同
-
安全审计
- 监控进程资源共享异常(如恶意进程共享敏感 FD)
五、依赖与关联配置
- 强依赖:
CONFIG_EXPERT=y(Kconfig 依赖) - 历史关联:5.12 前,
kcmp()仅由CONFIG_CHECKPOINT_RESTORE启用;5.12+ 独立为CONFIG_KCMP,同时保留与CHECKPOINT_RESTORE的兼容 - 无模块选项:
bool类型,只能内置(y)或关闭(n)
六、开启 / 关闭的影响
开启(CONFIG_KCMP=y)
- 优点:支持 CRIU、容器调试、资源比对工具;主流发行版默认开启,兼容性好
- 缺点:内核代码微小增加(约 1KB),无性能损耗
关闭(CONFIG_KCMP=n)
- 优点:极小节省内核内存(可忽略)
- 缺点:
kcmp()系统调用不可用;CRIU 热迁移、部分容器工具失效;网络 / 进程排障工具受限
七、总结
CONFIG_KCMP是 5.12+ 独立启用kcmp()的开关,用于安全比对进程间内核资源共享关系- 核心价值:替代不安全的 proc 解析,为容器、热迁移、调试提供高效安全的资源比对能力
- 生产环境建议:保持默认
y,避免容器 / CRIU 功能失效;极简内核可关闭,但需评估工具兼容性