ulimit -i 仅限制待处理信号数量,而非信号量;信号量由内核参数(如kernel.sem)或程序调用控制,待处理信号指已发送未处理的信号,超出ulimit -i值将被丢弃。

ulimit -i 不能限制信号量,只能限制待处理信号数量。这是常见误解的源头——“信号量”(semaphore)和“待处理信号”(pending signal)在Linux中是完全不同的概念。
先分清两个关键概念
• 信号量:用于进程/线程间同步的IPC机制(如 System V 或 POSIX sem),ulimit 完全不管理 它;需靠程序内调用 semget、sem_init 等控制,或通过内核参数(如 kernel.sem)限制系统级总量。
• 待处理信号(pending signals):已发送但尚未被目标进程接收或处理的信号(如大量 kill -USR1 持续发给一个忙于计算、无暇调用 sigwait 的进程)。ulimit -i 限制的就是这个数量。
ulimit -i 的真实作用与设置方法
它限制单个进程可挂起的未决信号数,默认值通常为 255112(取决于系统配置)。超出该数后,新信号会被丢弃(对实时信号则可能返回 EAGAIN)。防范信号流攻击(如 flood 式发送 SIGUSR1/SIGRTMIN)时,可主动压低该值:
- 查看当前限制:
ulimit -i - 临时设为 1024:
ulimit -i 1024 - 设硬限制(需 root):
ulimit -Hi 1024 - 验证是否生效:
kill -USR1 $PID循环发送,配合cat /proc/$PID/status | grep SigQ观察队列长度是否卡在 1024
真正需要防护信号量滥用?得换思路
如果目标是防 System V 信号量耗尽(如恶意进程反复 semget 创建信号量集),ulimit -i 完全无效。应改用:
- 调整内核参数:
echo "kernel.sem = 250 32000 32 128" | sudo tee -a /etc/sysctl.conf && sudo sysctl -p(四个数字分别对应:SEMMSL, SEMMNS, SEMOPM, SEMMNI) - 限制用户 IPC 资源:
echo "* hard msgqueue 8192" | sudo tee -a /etc/security/limits.conf(POSIX 消息队列常与信号量共用资源池) - 禁用非必要 IPC:
sudo sysctl -w kernel.msgmax=0(慎用,影响依赖消息队列的服务)
实战建议:组合加固更有效
仅靠 ulimit -i 防御有限。推荐搭配以下措施:
- 对关键服务用户(如
www-data)在/etc/security/limits.conf中固定-i值,避免被子进程继承宽松限制 - 用
systemd启动的服务,直接在[Service]段加LimitSIGPENDING=1024(比 ulimit 更精准,且自动生效) - 监控异常信号行为:
auditctl -a always,exit -F arch=b64 -S kill,tkill,tgkill记录高频信号发送源











