能否通过Unix套接字使用SCM_RIGHTS传输降权限文件描述符?
基于SCM_RIGHTS实现降权限文件描述符传输的方案说明
核心结论
原生SCM_RIGHTS机制本身不支持在传输过程中直接修改待传文件描述符的访问权限,但通过标准系统调用的组合,可以完全实现你描述的「发送端保留高权限、接收端获得低权限访问能力」的典型场景。
原生SCM_RIGHTS的固有特性
- Unix域套接字的
SCM_RIGHTS控制消息,本质是跨进程传递已打开文件的struct file内核对象引用,而非传递文件路径 - 默认流程下,接收进程拿到的新文件描述符,与发送进程用来发送的原文件描述符共享同一个
struct file实例,会原封不动继承原fd的全部访问标记(读写权限、非阻塞、追加模式等) - 传输流程本身没有内置参数可以让发送方在发消息时指定「把这个fd以只读权限发出去」,直接传递原始的RW权限fd时,接收方会获得完全一致的读写能力,无法实现权限裁剪。
匹配场景的通用实现路径
不需要特殊内核修改,靠标准接口就能覆盖你提到的全流程需求,实现逻辑如下:
- 发送端保留高权限fd:进程P1以
O_RDWR权限打开目标文件x,得到初始的读写权限fd(记为fd_rw),P1全程保留这个fd的所有权,随时可以执行读写、偏移调整等操作 - 发送端预生成独立的低权限fd:P1通过procfs接口创建指向同一文件的只读独立fd——执行
open("/proc/self/fd/fd_rw", O_RDONLY | O_NOFOLLOW | O_CLOEXEC),得到的新fd(记为fd_ro)拥有独立的struct file上下文,访问模式被严格限制为只读,与原fd_rw的状态完全独立,不会互相干扰内核会自动对这个环节做权限校验:只要P1本身对原文件拥有合法访问权限,生成的只读fd就可以正常工作,且两个fd指向同一个底层文件inode,写入内容对所有访问该inode的上下文全局可见
- 通过SCM_RIGHTS传输低权限fd:P1将生成的
fd_ro通过Unix套接字的控制消息发送给进程P2,因为传递的本身就是独立的只读权限fd,P2接收后拿到的fd仅具备只读访问能力,尝试执行写入操作时会被内核以权限错误拦截 - 权限隔离效果验证:
- P2使用接收的fd可以正常执行文件读取操作
- P1持有的
fd_rw依然可以正常向文件写入内容,整个过程不受P2侧fd权限的影响 - 两个fd的文件偏移位置相互独立,操作不会产生串扰
进阶的内核态实现方案
如果不想引入procfs的额外调用开销,可以通过自定义Linux安全模块(LSM)在SCM_RIGHTS的传输链路中挂载钩子:当内核为接收进程构造对应的接收端fd时,根据发送方传入的自定义标记,主动裁剪新file对象的写权限位。这种方案不需要发送端额外打开procfs路径,但是属于非通用的内核扩展能力,不属于POSIX标准覆盖的功能范围。
注意事项
- 常见操作误区:直接把原始的RW权限fd通过SCM_RIGHTS发送是无法实现权限裁剪的,这种场景下接收方拿到的fd会和发送方原fd共享同一个file对象,拥有完全一致的读写权限
- 通过procfs生成的独立fd不会自动继承原fd的文件锁、追加模式等特殊标记,如果需要对齐这些属性,需要在生成新fd时通过对应的系统调用(如
fcntl)手动设置。
内容的提问来源于stack exchange,提问作者Andrei Pangratie
相关产品推荐
相关产品推荐

