You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用RLIMIT_NPROC阻止二进制程序创建新进程失败,如何修复?

如何禁止Python启动的二进制程序创建新进程

问题分析

你尝试通过RLIMIT_NPROC限制子进程创建新进程但未达预期,核心原因如下:

  • RLIMIT_NPROC是用户级资源限制,管控的是当前用户能拥有的总进程数,而非单个进程可创建的子进程数量。
  • 当你在preexec_fn中设置RLIMIT_NPROC=(1,1)时,子进程a.out本身已计入用户进程总数,而系统中通常还存在Python主进程、Shell进程等其他进程,此时用户总进程数早已超过1,fork调用不会触发限制。
  • 普通用户默认无法将RLIMIT_NPROC的硬限制降低到系统默认值以下,即便强行设置,也无法实现单个进程的子进程创建限制。

解决方案

要实现单个进程级别的禁止创建新进程,推荐使用Linux内核的seccomp机制,它可以精确过滤进程的系统调用,直接阻断fork/clone/vfork这些用于创建新进程的调用。

方法1:使用Python seccomp库(推荐)

首先安装依赖:

sudo apt install python3-seccomp  # Debian/Ubuntu
# 或通过pip安装
pip install python-seccomp

修改foo.py代码:

import subprocess
import resource
import seccomp

def restrict_process():
    # 可选:设置RLIMIT_NPROC作为双重保障
    resource.setrlimit(resource.RLIMIT_NPROC, (1, 1))
    # 创建seccomp过滤规则,默认允许所有系统调用
    ctx = seccomp.SyscallFilter(seccomp.ActivationFilter.ALLOW)
    # 禁止创建新进程的核心系统调用
    ctx.add_rule(seccomp.KILL_PROCESS, "fork")
    ctx.add_rule(seccomp.KILL_PROCESS, "clone")
    ctx.add_rule(seccomp.KILL_PROCESS, "vfork")
    # 将规则加载到内核生效
    ctx.load()

if __name__ == '__main__':
    proc = subprocess.Popen(['./a.out'], preexec_fn=restrict_process)
    proc.wait()
    print(f"子进程退出码: {proc.returncode}")

方法2:直接调用C库(无需额外依赖)

如果无法安装seccomp库,可通过ctypes直接调用系统接口:

import subprocess
import resource
import ctypes
from ctypes import cdll, c_int, c_ulong, POINTER

libc = cdll.LoadLibrary('libc.so.6')

# 定义prctl和seccomp相关常量
PR_SET_NO_NEW_PRIVS = 38
PR_SET_SECCOMP = 22
SECCOMP_MODE_FILTER = 2
SECCOMP_RET_KILL_PROCESS = 0x80000000 | 0x00000009
SECCOMP_RET_ALLOW = 0x7fff0000 | 0

# 定义seccomp_data结构体(对应内核系统调用数据结构)
class seccomp_data(ctypes.Structure):
    _fields_ = [
        ("nr", c_int),
        ("arch", c_ulong),
        ("instruction_pointer", c_ulong),
        ("args", c_ulong * 6)
    ]

# 定义系统调用过滤回调函数
def seccomp_filter(ctx, data):
    data_ptr = ctypes.cast(data, POINTER(seccomp_data))
    syscall_nr = data_ptr.contents.nr
    # 禁止x86_64架构下的fork(57), clone(56), vfork(58)系统调用
    if syscall_nr in [56, 57, 58]:
        return SECCOMP_RET_KILL_PROCESS
    return SECCOMP_RET_ALLOW

# 将Python回调转换为C可调用类型
SECCompFilterFunc = ctypes.CFUNCTYPE(c_int, c_ulong, POINTER(seccomp_data))
filter_func = SECCompFilterFunc(seccomp_filter)

def restrict_process():
    # 禁止子进程提升权限绕过限制
    libc.prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)
    # 加载seccomp过滤规则
    libc.prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, filter_func)
    # 可选:设置RLIMIT_NPROC作为双重保障
    resource.setrlimit(resource.RLIMIT_NPROC, (1, 1))

if __name__ == '__main__':
    proc = subprocess.Popen(['./a.out'], preexec_fn=restrict_process)
    proc.wait()
    print(f"子进程退出码: {proc.returncode}")

效果验证

运行修改后的foo.py,a.out在调用fork时会被内核直接终止,退出码通常为-31(对应SIGSYS信号),符合你预期的“禁止创建新进程”的效果。

内容的提问来源于stack exchange,提问作者Joey

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 21:30:58