unix域套接字权限配置需全流程管控:创建前设umask(077)、bind后chmod 0600、避免/tmp目录、验证systemd socketmode生效条件、检查selinux/apparmor上下文与规则、多进程间优先用scm_rights传递fd。

Socket 文件权限太宽导致非授权访问
Unix 域套接字(AF_UNIX)若创建时未显式设限,系统常默认用 0777 或继承 umask 后仍残留写/执行位,普通用户就能 connect() 甚至发送恶意数据。这不是“可能被利用”,而是只要文件路径可猜(比如 /run/myapp.sock),攻击者调用 nc -U /run/myapp.sock 就能试连。
- 创建 socket 前务必调用
umask(077),再用bind();别依赖进程启动时的默认 umask - 绑定后立即调用
chmod("/run/myapp.sock", 0600)—— 某些 libc 实现中bind()不尊重 umask,必须显式修正 - 避免把 socket 放在
/tmp或/var/tmp:这些目录通常带 sticky bit,但文件自身权限若为0666,其他用户仍可 connect(Linux 不校验 socket 文件的读写位,只看是否存在)
systemd 服务中 Socket 单元权限配置失效
很多人以为在 .socket 单元里写 SocketMode=0600 就万事大吉,但实际生效需同时满足三个条件:socket 文件由 systemd 自己创建(即没被应用提前 touch)、ListenStream= 指向抽象名或绝对路径、且服务未启用 RuntimeDirectoryPreserve=yes。
- 检查是否启用了
RuntimeDirectory=:如果用了,systemd 会先创建目录(如/run/myapp),但 socket 文件仍由你的程序创建 —— 此时SocketMode完全不生效 - 用
ls -l /run/myapp.sock验证权限,别只信单元文件里的配置 - 若必须由应用创建 socket,就在
.service的ExecStartPre=里加一句rm -f /run/myapp.sock,确保 systemd 不跳过创建流程
SELinux 或 AppArmor 下 socket 访问被静默拒绝
权限看似正确(0600),connect() 却返回 EACCES 而非 ECONNREFUSED,大概率是 MAC 策略拦截。这时候 strace -e trace=connect,sendto 会显示系统调用直接失败,日志里却没报错 —— 因为 socket 文件节点没被正确标记上下文。
- 用
ls -Z /run/myapp.sock查看 SELinux 上下文,正常应为system_u:object_r:myservice_var_run_t:s0类型;若是unconfined_u:object_r:var_run_t:s0,策略就放行不了 - 在 SELinux 策略中为 socket 添加类型规则:
allow myservice_t myservice_var_run_t:sock_file { create bind write } - AppArmor 用户注意:
unix (bind, listen, connect) type=stream规则必须显式包含 socket 文件路径,通配符如/run/myapp/*.sock在部分内核版本中不匹配 Unix 域 socket
多进程共享 socket 时权限继承混乱
主进程以 root 启动、drop privileges 后 fork 子进程,子进程尝试 connect() 到本机 socket 时失败,常见原因是 socket 文件所有者仍是 root,而子进程 uid 已降权,但 socket 权限又没放开 —— 这不是 bug,是设计使然。
- 不要让子进程去连父进程的监听 socket;改用
SCM_RIGHTS通过sendmsg()传递已打开的 socket fd,这是最安全的进程间通信方式 - 若必须用文件路径,主进程应在 drop privileges 前,用
chown()把 socket 文件属主改为目标 uid/gid(例如chown 1001:1001 /run/myapp.sock) - 避免使用
SOCK_CLOEXEC外的 socket 标志:某些旧版 glibc 在 fork 后未关闭的 socket fd 可能被子进程误用,造成权限绕过
真正难的不是设 0600,而是确认整个生命周期里——从 systemd 创建、到进程 bind、再到 SELinux 标记、最后到子进程访问——每个环节都没被默认行为悄悄覆盖。漏掉任意一环,审计报告里那个“高危”就不会消失。










