Skip to content

Linux Kernel Landlock 安全模块详细分析 ​

目录 ​

  1. Landlock 概述
  2. 核心数据结构
  3. 规则集管理
  4. 文件系统访问控制
  5. 网络访问控制
  6. 作用域限制
  7. 层级限制与继承模型
  8. 系统调用接口
  9. LSM Hooks 架构
  10. 审计日志

1. Landlock 概述 ​

1.1 什么是 Landlock ​

Landlock 是 Linux 内核中的一个 用户空间安全模块 (Userspace Security Module),提供基于 沙箱 (Sandbox) 的访问控制机制。它允许非特权进程自愿限制自己对系统资源的访问能力。

关键特性:

  • 无特权沙箱: 不需要 CAP_SYS_ADMIN 即可创建基本限制
  • 层级化策略: 支持最多 16 层规则叠加 (LANDLOCK_MAX_NUM_LAYERS)
  • 基于路径: 通过文件系统路径而非 inode 来定义规则
  • 不可绕过: 一旦应用,限制无法被移除(只能叠加新层)

1.2 架构图 ​

┌─────────────────────────────────────────────────────────────────┐
│                      User Space                                  │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────────────────┐ │
│  │landlock_create│  │landlock_add │  │landlock_restrict_self  │ │
│  │  _ruleset() │  │   _rule()   │  │                         │ │
│  └──────┬──────┘  └──────┬──────┘  └────────────┬────────────┘ │
└─────────┼────────────────┼─────────────────────┼───────────────┘
          │                │                     │
          ▼                ▼                     ▼
┌─────────────────────────────────────────────────────────────────┐
│                     System Calls                                  │
│  ┌─────────────────────────────────────────────────────────────┐│
│  │  sys_landlock_create_ruleset()                              ││
│  │  sys_landlock_add_rule()                                    ││
│  │  sys_landlock_restrict_self()                               ││
│  └─────────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────────┘
          │
          ▼
┌─────────────────────────────────────────────────────────────────┐
│                   Landlock LSM Core                              │
│  ┌────────────────┐  ┌────────────────┐  ┌─────────────────┐  │
│  │   ruleset.c    │  │     fs.c       │  │     net.c      │  │
│  │  - 创建规则集  │  │ - 文件系统hooks│  │ - 网络hooks    │  │
│  │  - 添加规则   │  │ - 路径检查     │  │ - 端口检查     │  │
│  │  - 合并规则集 │  │ - inode管理    │  │               │  │
│  └───────┬────────┘  └───────┬────────┘  └────────┬────────┘  │
│          │                   │                    │            │
│  ┌───────▼───────────────────▼────────────────────▼──────────┐ │
│  │                    access.h / ruleset.h                   │ │
│  │              (核心数据结构和辅助函数)                       │ │
│  └───────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
          │
          ▼
┌─────────────────────────────────────────────────────────────────┐
│                    Kernel LSM Framework                          │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐             │
│  │ inode hooks │  │  file hooks │  │ sock hooks  │             │
│  │ path hooks  │  │  sb hooks   │  │ cred hooks  │             │
│  └─────────────┘  └─────────────┘  └─────────────┘             │
└─────────────────────────────────────────────────────────────────┘

1.3 访问权限类型 ​

文件系统访问权限 (定义于 include/uapi/linux/landlock.h:319-336):

c
#define LANDLOCK_ACCESS_FS_EXECUTE         (1ULL << 0)  // 执行文件
#define LANDLOCK_ACCESS_FS_WRITE_FILE       (1ULL << 1)  // 写文件
#define LANDLOCK_ACCESS_FS_READ_FILE        (1ULL << 2)  // 读文件
#define LANDLOCK_ACCESS_FS_READ_DIR         (1ULL << 3)  // 读目录
#define LANDLOCK_ACCESS_FS_REMOVE_DIR       (1ULL << 4)  // 删除目录
#define LANDLOCK_ACCESS_FS_REMOVE_FILE      (1ULL << 5)  // 删除文件
#define LANDLOCK_ACCESS_FS_MAKE_CHAR        (1ULL << 6)  // 创建字符设备
#define LANDLOCK_ACCESS_FS_MAKE_DIR         (1ULL << 7)  // 创建目录
#define LANDLOCK_ACCESS_FS_MAKE_REG         (1ULL << 8)  // 创建普通文件
#define LANDLOCK_ACCESS_FS_MAKE_SOCK        (1ULL << 9)  // 创建套接字
#define LANDLOCK_ACCESS_FS_MAKE_FIFO        (1ULL << 10) // 创建命名管道
#define LANDLOCK_ACCESS_FS_MAKE_BLOCK      (1ULL << 11) // 创建块设备
#define LANDLOCK_ACCESS_FS_MAKE_SYM        (1ULL << 12) // 创建符号链接
#define LANDLOCK_ACCESS_FS_REFER            (1ULL << 13) // 重命名/链接(跨目录)
#define LANDLOCK_ACCESS_FS_TRUNCATE         (1ULL << 14) // 截断文件
#define LANDLOCK_ACCESS_FS_IOCTL_DEV        (1ULL << 15) // 设备IOCTL

网络访问权限 (landlock.h:354-357):

c
#define LANDLOCK_ACCESS_NET_BIND_TCP        (1ULL << 0)  // 绑定TCP端口
#define LANDLOCK_ACCESS_NET_CONNECT_TCP     (1ULL << 1)  // 连接TCP端口

作用域标志 (landlock.h:379-382):

c
#define LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET (1ULL << 0)  // 抽象Unix域套接字
#define LANDLOCK_SCOPE_SIGNAL               (1ULL << 1)  // 信号

2. 核心数据结构 ​

2.1 landlock_object - 底层对象管理 ​

文件: security/landlock/object.h:29-77

c
struct landlock_object {
    refcount_t usage;              // 引用计数
    spinlock_t lock;                // 保护并发访问
    void *underobj;                 // 底层内核对象(如inode)
    union {
        struct rcu_head rcu_free;  // RCU释放
        const struct landlock_object_underops *underops;  // 底层对象操作
    };
};

关键设计:

  • 使用引用计数管理生命周期
  • RCU (Read-Copy-Update) 支持无锁读取
  • underops->release() 释放底层对象 (如 inode)

2.2 landlock_ruleset - 规则集结构 ​

文件: security/landlock/ruleset.h:113-190

c
struct landlock_ruleset {
    // 红黑树根节点 - inode 类型规则
    struct rb_root root_inode;

#if IS_ENABLED(CONFIG_INET)
    // 红黑树根节点 - 网络端口类型规则
    struct rb_root root_net_port;
#endif

    // 层级结构 - 支持域继承和ptrace保护
    struct landlock_hierarchy *hierarchy;

    union {
        struct work_struct work_free;  // 延迟释放工作
        struct {
            struct mutex lock;         // 保护规则集修改
            refcount_t usage;          // 引用计数
            u32 num_rules;             // 规则数量
            u32 num_layers;            // 层级数量
            // 灵活数组成员 - 每层的访问掩码
            struct access_masks access_masks[];
        };
    };
};

2.3 landlock_rule - 单条规则 ​

文件: security/landlock/ruleset.h:86-111

c
struct landlock_rule {
    struct rb_node node;           // 红黑树节点
    union landlock_key key;        // 规则关键字(object或data)
    u32 num_layers;                // 层数
    // 灵活数组 - 每层允许的访问权限
    struct landlock_layer layers[] __counted_by(num_layers);
};

struct landlock_layer {
    u16 level;                     // 层级位置(从1开始)
    access_mask_t access;          // 允许的访问权限位域
};

union landlock_key {
    struct landlock_object *object; // inode对象指针
    uintptr_t data;                 // 原始数据(如TCP端口)
};

2.4 landlock_cred_security - 凭证安全 blob ​

文件: security/landlock/cred.h:32-53

c
struct landlock_cred_security {
    struct landlock_ruleset *domain;  // 不可变规则集
#ifdef CONFIG_AUDIT
    u16 domain_exec;                  // 执行时域层位掩码
    u8 log_subdomains_off : 1;        // 子域日志开关
#endif
} __packed;

2.5 landlock_hierarchy - 层级继承 ​

文件: security/landlock/domain.h:73-118

c
struct landlock_hierarchy {
    struct landlock_hierarchy *parent;  // 父节点
    refcount_t usage;                   // 引用计数
#ifdef CONFIG_AUDIT
    enum landlock_log_status log_status;
    atomic64_t num_denials;             // 拒绝计数
    u64 id;                             // 域ID
    const struct landlock_details *details;
    u32 log_same_exec : 1;
    u32 log_new_exec : 1;
#endif
};

3. 规则集管理 ​

3.1 创建规则集 - landlock_create_ruleset() ​

文件: security/landlock/ruleset.c:56-76

c
struct landlock_ruleset *
landlock_create_ruleset(const access_mask_t fs_access_mask,
                      const access_mask_t net_access_mask,
                      const access_mask_t scope_mask)
{
    struct landlock_ruleset *new_ruleset;

    // 空规则集检查
    if (!fs_access_mask && !net_access_mask && !scope_mask)
        return ERR_PTR(-ENOMSG);

    // 创建单层规则集
    new_ruleset = create_ruleset(1);
    if (IS_ERR(new_ruleset))
        return new_ruleset;

    // 设置各类型访问掩码
    if (fs_access_mask)
        landlock_add_fs_access_mask(new_ruleset, fs_access_mask, 0);
    if (net_access_mask)
        landlock_add_net_access_mask(new_ruleset, net_access_mask, 0);
    if (scope_mask)
        landlock_add_scope_mask(new_ruleset, scope_mask, 0);

    return new_ruleset;
}

create_ruleset() 内部实现 (ruleset.c:31-54):

c
static struct landlock_ruleset *create_ruleset(const u32 num_layers)
{
    struct landlock_ruleset *new_ruleset;

    // 使用灵活数组分配 - access_masks[num_layers]
    new_ruleset = kzalloc_flex(*new_ruleset, access_masks, num_layers,
                               GFP_KERNEL_ACCOUNT);
    if (!new_ruleset)
        return ERR_PTR(-ENOMEM);

    refcount_set(&new_ruleset->usage, 1);
    mutex_init(&new_ruleset->lock);
    new_ruleset->root_inode = RB_ROOT;

#if IS_ENABLED(CONFIG_INET)
    new_ruleset->root_net_port = RB_ROOT;
#endif

    new_ruleset->num_layers = num_layers;
    // hierarchy = NULL, num_rules = 0, access_masks[] = 0
    return new_ruleset;
}

3.2 插入规则 - landlock_insert_rule() ​

文件: security/landlock/ruleset.c:304-316

c
int landlock_insert_rule(struct landlock_ruleset *const ruleset,
                        const struct landlock_id id,
                        const access_mask_t access)
{
    struct landlock_layer layers[] = { {
        .access = access,
        .level = 0,  // level=0 表示扩展规则集
    } };

    build_check_layer();
    return insert_rule(ruleset, id, &layers, ARRAY_SIZE(layers));
}

insert_rule() - 红黑树插入 (ruleset.c:205-286):

c
static int insert_rule(struct landlock_ruleset *const ruleset,
                      const struct landlock_id id,
                      const struct landlock_layer (*const layers)[],
                      const size_t num_layers)
{
    struct rb_node **walker_node;
    struct rb_node *parent_node = NULL;
    struct landlock_rule *new_rule;
    struct rb_root *root;

    root = get_root(ruleset, id.type);
    if (IS_ERR(root))
        return PTR_ERR(root);

    walker_node = &root->rb_node;
    while (*walker_node) {
        struct landlock_rule *const this =
            rb_entry(*walker_node, struct landlock_rule, node);

        // 比较关键字 - 按data值排序
        if (this->key.data != id.key.data) {
            parent_node = *walker_node;
            if (this->key.data < id.key.data)
                walker_node = &((*walker_node)->rb_right);
            else
                walker_node = &((*walker_node)->rb_left);
            continue;
        }

        // 找到匹配规则 - level=0 表示扩展访问权限
        if ((*layers)[0].level == 0) {
            this->layers[0].access |= (*layers)[0].access;
            return 0;
        }

        // 层级合并 - 取交集
        new_rule = create_rule(id, &this->layers, this->num_layers,
                               &(*layers)[0]);
        rb_replace_node(&this->node, &new_rule->node, root);
        free_rule(this, id.type);
        return 0;
    }

    // 没有匹配规则 - 创建新规则
    new_rule = create_rule(id, layers, num_layers, NULL);
    rb_link_node(&new_rule->node, parent_node, walker_node);
    rb_insert_color(&new_rule->node, root);
    ruleset->num_rules++;
    return 0;
}

3.3 合并规则集 - landlock_merge_ruleset() ​

文件: security/landlock/ruleset.c:536-583

c
struct landlock_ruleset *
landlock_merge_ruleset(struct landlock_ruleset *const parent,
                      struct landlock_ruleset *const ruleset)
{
    struct landlock_ruleset *new_dom = create_ruleset(num_layers);
    // ...
    // 1. 继承父规则集
    err = inherit_ruleset(parent, new_dom);

    // 2. 合并新规则集
    err = merge_ruleset(new_dom, ruleset);

    // 3. 初始化层级日志
    err = landlock_init_hierarchy_log(new_dom->hierarchy);

    return new_dom;
}

inherit_ruleset() - 复制父规则 (ruleset.c:435-479):

c
static int inherit_ruleset(struct landlock_ruleset *parent,
                           struct landlock_ruleset *child)
{
    // 复制inode树
    err = inherit_tree(parent, child, LANDLOCK_KEY_INODE);

#if IS_ENABLED(CONFIG_INET)
    // 复制网络端口树
    err = inherit_tree(parent, child, LANDLOCK_KEY_NET_PORT);
#endif

    // 复制父层掩码
    memcpy(child->access_masks, parent->access_masks, ...);

    // 设置父子关系
    child->hierarchy->parent = parent->hierarchy;
    return 0;
}

3.4 层级掩码操作 ​

landlock_unmask_layers() (ruleset.c:628-658):

c
bool landlock_unmask_layers(const struct landlock_rule *rule,
                           struct layer_access_masks *masks)
{
    // 清除规则授予的访问权限
    for (size_t i = 0; i < rule->num_layers; i++) {
        const struct landlock_layer *layer = &rule->layers[i];
        masks->access[layer->level - 1] &= ~layer->access;
    }

    // 检查是否所有层级都满足
    for (size_t i = 0; i < ARRAY_SIZE(masks->access); i++) {
        if (masks->access[i])
            return false;  // 还有未满足的权限
    }
    return true;  // 所有权限都已满足
}

4. 文件系统访问控制 ​

4.1 FS Hooks 初始化 ​

文件: security/landlock/fs.c:1823-1855

c
static struct security_hook_list landlock_hooks[] __ro_after_init = {
    LSM_HOOK_INIT(inode_free_security_rcu, hook_inode_free_security_rcu),

    LSM_HOOK_INIT(sb_delete, hook_sb_delete),
    LSM_HOOK_INIT(sb_mount, hook_sb_mount),
    LSM_HOOK_INIT(move_mount, hook_move_mount),
    LSM_HOOK_INIT(sb_umount, hook_sb_umount),
    LSM_HOOK_INIT(sb_remount, hook_sb_remount),
    LSM_HOOK_INIT(sb_pivotroot, hook_sb_pivotroot),

    LSM_HOOK_INIT(path_link, hook_path_link),
    LSM_HOOK_INIT(path_rename, hook_path_rename),
    LSM_HOOK_INIT(path_mkdir, hook_path_mkdir),
    LSM_HOOK_INIT(path_mknod, hook_path_mknod),
    LSM_HOOK_INIT(path_symlink, hook_path_symlink),
    LSM_HOOK_INIT(path_unlink, hook_path_unlink),
    LSM_HOOK_INIT(path_rmdir, hook_path_rmdir),
    LSM_HOOK_INIT(path_truncate, hook_path_truncate),

    LSM_HOOK_INIT(file_alloc_security, hook_file_alloc_security),
    LSM_HOOK_INIT(file_open, hook_file_open),
    LSM_HOOK_INIT(file_truncate, hook_file_truncate),
    LSM_HOOK_INIT(file_ioctl, hook_file_ioctl),
    LSM_HOOK_INIT(file_ioctl_compat, hook_file_ioctl_compat),
    LSM_HOOK_INIT(file_set_fowner, hook_file_set_fowner),
    LSM_HOOK_INIT(file_free_security, hook_file_free_security),
};

__init void landlock_add_fs_hooks(void)
{
    security_add_hooks(landlock_hooks, ARRAY_SIZE(landlock_hooks),
                       &landlock_lsmid);
}

4.2 文件打开检查 - hook_file_open() ​

文件: security/landlock/fs.c:1614-1680

c
static int hook_file_open(struct file *const file)
{
    access_mask_t open_access_request, full_access_request, allowed_access;
    const struct landlock_cred_security *subject =
        landlock_get_applicable_subject(file->f_cred, any_fs, NULL);

    // 获取打开文件所需的访问权限
    open_access_request = get_required_file_open_access(file);

    // 预取额外权限用于后续操作
    optional_access = LANDLOCK_ACCESS_FS_TRUNCATE;
    if (is_device(file))
        optional_access |= LANDLOCK_ACCESS_FS_IOCTL_DEV;

    full_access_request = open_access_request | optional_access;

    // 检查路径访问权限
    if (is_access_to_paths_allowed(...)) {
        allowed_access = full_access_request;
    } else {
        // 计算实际允许的访问权限
        allowed_access = full_access_request;
        for (size_t i = 0; i < ARRAY_SIZE(layer_masks.access); i++)
            allowed_access &= ~layer_masks.access[i];
    }

    // 记录在文件结构中供后续使用
    landlock_file(file)->allowed_access = allowed_access;

    if (access_mask_subset(open_access_request, allowed_access))
        return 0;

    // 权限不足 - 记录拒绝
    return -EACCES;
}

4.3 路径访问检查 - is_access_to_paths_allowed() ​

文件: security/landlock/fs.c:741-944

这是 Landlock 文件系统检查的核心函数,实现了 多层安全 (MLS) 检查:

c
static bool is_access_to_paths_allowed(
    const struct landlock_ruleset *domain,
    const struct path *path,
    access_mask_t access_request_parent1,
    struct layer_access_masks *layer_masks_parent1,
    ...
    access_mask_t access_request_parent2,
    struct layer_access_masks *layer_masks_parent2,
    ...)
{
    // 遍历路径从叶节点到根
    while (true) {
        const struct landlock_rule *rule;

        // 查找当前dentry的规则
        rule = find_rule(domain, walker_path.dentry);

        // 检查每层是否满足访问请求
        allowed_parent1 = landlock_unmask_layers(rule, layer_masks_parent1);
        allowed_parent2 = landlock_unmask_layers(rule, layer_masks_parent2);

        if (allowed_parent1 && allowed_parent2)
            break;  // 所有层都满足,允许访问

        // 向上遍历到父目录
        if (walker_path.dentry == walker_path.mnt->mnt_root) {
            if (follow_up(&walker_path)) {
                goto jump_up;
            } else {
                break;  // 到达真实根目录
            }
        }
        // ...
    }

    return allowed_parent1 && allowed_parent2;
}

4.4 inode 对象管理 ​

get_inode_object() (fs.c:254-308):

c
static struct landlock_object *get_inode_object(struct inode *inode)
{
    struct landlock_object *object, *new_object;
    struct landlock_inode_security *inode_sec = landlock_inode(inode);

    rcu_read_lock();
retry:
    object = rcu_dereference(inode_sec->object);
    if (object) {
        if (likely(refcount_inc_not_zero(&object->usage))) {
            rcu_read_unlock();
            return object;
        }
        // 竞争 - 等待release_inode()完成
        spin_lock(&object->lock);
        spin_unlock(&object->lock);
        goto retry;
    }
    rcu_read_unlock();

    // 创建新对象
    new_object = landlock_create_object(&landlock_fs_underops, inode);
    if (IS_ERR(new_object))
        return new_object;

    spin_lock(&inode->i_lock);
    if (unlikely(rcu_access_pointer(inode_sec->object))) {
        spin_unlock(&inode->i_lock);
        kfree(new_object);
        goto retry;
    }

    ihold(inode);
    rcu_assign_pointer(inode_sec->object, new_object);
    spin_unlock(&inode->i_lock);
    return new_object;
}

release_inode() (fs.c:55-92):

c
static void release_inode(struct landlock_object *object)
{
    struct inode *inode = object->underobj;

    object->underobj = NULL;

    sb = inode->i_sb;
    atomic_long_inc(&landlock_superblock(sb)->inode_refs);

    rcu_assign_pointer(landlock_inode(inode)->object, NULL);

    iput(inode);  // 释放inode引用

    if (atomic_long_dec_and_test(&landlock_superblock(sb)->inode_refs))
        wake_up_var(...);  // 唤醒等待者
}

4.5 挂载拓扑变更检测 ​

文件: security/landlock/fs.c:1420-1504

Landlock 禁止沙箱进程修改文件系统拓扑:

c
static int hook_sb_mount(const char *dev_name, const struct path *path,
                        const char *type, unsigned long flags, void *data)
{
    const struct landlock_cred_security *subject =
        landlock_get_applicable_subject(current_cred(), any_fs, &handle_layer);

    if (!subject)
        return 0;

    log_fs_change_topology_path(subject, handle_layer, path);
    return -EPERM;  // 永远拒绝
}

受保护的挂载操作:

  • hook_sb_mount() - 挂载文件系统
  • hook_move_mount() - 移动挂载点
  • hook_sb_umount() - 卸载文件系统
  • hook_sb_remount() - 重新挂载
  • hook_sb_pivotroot() - pivot_root

5. 网络访问控制 ​

5.1 网络 Hooks ​

文件: security/landlock/net.c:241-250

c
static struct security_hook_list landlock_hooks[] __ro_after_init = {
    LSM_HOOK_INIT(socket_bind, hook_socket_bind),
    LSM_HOOK_INIT(socket_connect, hook_socket_connect),
};

__init void landlock_add_net_hooks(void)
{
    security_add_hooks(landlock_hooks, ARRAY_SIZE(landlock_hooks),
                       &landlock_lsmid);
}

5.2 端口规则检查 - current_check_access_socket() ​

文件: security/landlock/net.c:44-210

c
static int current_check_access_socket(struct socket *sock,
                                     struct sockaddr *address,
                                     int addrlen,
                                     access_mask_t access_request)
{
    __be16 port;
    struct layer_access_masks layer_masks = {};
    struct landlock_id id = {
        .type = LANDLOCK_KEY_NET_PORT,
    };

    // 从地址提取端口
    switch (address->sa_family) {
    case AF_INET: {
        const struct sockaddr_in *addr4 = (struct sockaddr_in *)address;
        port = addr4->sin_port;
        // 审计信息...
        break;
    }
#if IS_ENABLED(CONFIG_IPV6)
    case AF_INET6: {
        const struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)address;
        port = addr6->sin6_port;
        break;
    }
#endif
    default:
        return 0;
    }

    id.key.data = (__force uintptr_t)port;

    // 查找规则
    rule = landlock_find_rule(subject->domain, id);
    access_request = landlock_init_layer_masks(...);

    if (landlock_unmask_layers(rule, &layer_masks))
        return 0;  // 允许

    // 记录拒绝
    landlock_log_denial(subject, &request);
    return -EACCES;
}

5.3 添加网络规则 - landlock_append_net_rule() ​

文件: security/landlock/net.c:22-42

c
int landlock_append_net_rule(struct landlock_ruleset *ruleset,
                            u16 port, access_mask_t access_rights)
{
    const struct landlock_id id = {
        .key.data = (__force uintptr_t)htons(port),
        .type = LANDLOCK_KEY_NET_PORT,
    };

    // 转换为绝对访问权限
    access_rights |= LANDLOCK_MASK_ACCESS_NET &
                     ~landlock_get_net_access_mask(ruleset, 0);

    mutex_lock(&ruleset->lock);
    err = landlock_insert_rule(ruleset, id, access_rights);
    mutex_unlock(&ruleset->lock);

    return err;
}

6. 作用域限制 ​

6.1 作用域标志 ​

文件: security/landlock/task.c

Landlock 支持两种作用域限制:

  1. LANDLOCK_SCOPE_ABSTRACT_UNIX_SOCKET - 限制访问抽象Unix域套接字
  2. LANDLOCK_SCOPE_SIGNAL - 限制发送信号

6.2 作用域检查 - domain_is_scoped() ​

文件: security/landlock/task.c:169-233

c
static bool domain_is_scoped(const struct landlock_ruleset *client,
                            const struct landlock_ruleset *server,
                            access_mask_t scope)
{
    int client_layer, server_layer;
    const struct landlock_hierarchy *client_walker, *server_walker;

    client_layer = client->num_layers - 1;
    client_walker = client->hierarchy;

    server_layer = server ? (server->num_layers - 1) : -1;
    server_walker = server ? server->hierarchy : NULL;

    // 遍历客户端的层级
    for (; client_layer > server_layer; client_layer--) {
        if (landlock_get_scope_mask(client, client_layer) & scope)
            return true;  // 客户端在作用域内
        client_walker = client_walker->parent;
    }

    // 遍历到相同层级
    for (; server_layer > client_layer; server_layer--)
        server_walker = server_walker->parent;

    for (; client_layer >= 0; client_layer--) {
        if (landlock_get_scope_mask(client, client_layer) & scope) {
            // 客户端和服务器在同一层级
            return server_walker != client_walker;
        }
        client_walker = client_walker->parent;
        server_walker = server_walker->parent;
    }
    return false;
}

6.3 信号限制 - hook_task_kill() ​

文件: security/landlock/task.c:338-388

c
static int hook_task_kill(struct task_struct *p,
                         struct kernel_siginfo *info, int sig,
                         const struct cred *cred)
{
    const struct landlock_cred_security *subject;
    bool is_scoped;

    // 同线程组内始终允许
    if (same_thread_group(p, current))
        return 0;

    subject = landlock_get_applicable_subject(cred, signal_scope, ...);

    is_scoped = domain_is_scoped(subject->domain,
                                  landlock_get_task_domain(p),
                                  LANDLOCK_SCOPE_SIGNAL);

    if (!is_scoped)
        return 0;

    landlock_log_denial(subject, &request);
    return -EPERM;
}

6.4 Unix 域套接字限制 ​

hook_unix_stream_connect() (task.c:265-295):

c
static int hook_unix_stream_connect(struct sock *sock, struct sock *other,
                                   struct sock *newsk)
{
    if (!is_abstract_socket(other))
        return 0;

    if (!sock_is_scoped(other, subject->domain))
        return 0;

    return -EPERM;
}

7. 层级限制与继承模型 ​

7.1 层级架构图 ​

                    ┌─────────────────────────────────────────┐
                    │          Domain (层叠规则集)             │
                    │  ┌─────────────────────────────────────┐ │
                    │  │ Layer N (最新层)                    │ │
                    │  │  - access_masks[N]                 │ │
                    │  │  - 规则: /a/b -> rw                │ │
                    │  └─────────────────────────────────────┘ │
                    │  ┌─────────────────────────────────────┐ │
                    │  │ Layer N-1                           │ │
                    │  │  - access_masks[N-1]               │ │
                    │  │  - 规则: /a -> rwx                 │ │
                    │  └─────────────────────────────────────┘ │
                    │              ...                       │
                    │  ┌─────────────────────────────────────┐ │
                    │  │ Layer 0 (最初层)                     │ │
                    │  │  - access_masks[0]                  │ │
                    │  │  - 规则: / -> rx                    │ │
                    │  └─────────────────────────────────────┘ │
                    └─────────────────────────────────────────┘
                                    │
                                    │ inherit_ruleset()
                                    ▼
                    ┌─────────────────────────────────────────┐
                    │          Child Domain                   │
                    │  (继承所有父层 + 新增层)                 │
                    │  - num_layers = parent.num_layers + 1   │
                    │  - hierarchy.parent = parent.hierarchy   │
                    └─────────────────────────────────────────┘

7.2 访问检查语义 ​

关键规则: 对于每一层(per-layer),必须至少有一条规则授予请求的访问权限。

请求: 对 /a/b/c 的读文件权限

Layer 2: /a/b 有 read 规则 ✓
Layer 1: /a 有 read 规则 ✓
Layer 0: / 有 read 规则 ✓

结果: 允许 (每层都满足)

7.3 Ptrace 保护 ​

文件: security/landlock/task.c:63-70

c
static int domain_ptrace(const struct landlock_ruleset *parent,
                        const struct landlock_ruleset *child)
{
    // 检查父域是否是子域的祖先
    if (domain_scope_le(parent, child))
        return 0;  // 允许 - parent是child的祖先

    return -EPERM;  // 拒绝
}

domain_scope_le() (task.c:41-61):

c
static bool domain_scope_le(const struct landlock_ruleset *parent,
                           const struct landlock_ruleset *child)
{
    const struct landlock_hierarchy *walker;

    if (!parent)
        return true;  // 非沙箱进程可以追踪

    if (!child)
        return false;

    // 遍历子域的层级链
    for (walker = child->hierarchy; walker; walker = walker->parent) {
        if (walker == parent->hierarchy)
            return true;  // parent是child的祖先
    }
    return false;
}

8. 系统调用接口 ​

8.1 landlock_create_ruleset() ​

文件: security/landlock/syscalls.c:198-260

c
SYSCALL_DEFINE3(landlock_create_ruleset,
               const struct landlock_ruleset_attr __user *, attr,
               const size_t, size, const __u32, flags)
{
    struct landlock_ruleset_attr ruleset_attr;
    struct landlock_ruleset *ruleset;

    if (!is_initialized())
        return -EOPNOTSUPP;

    // 获取ABI版本
    if (flags == LANDLOCK_CREATE_RULESET_VERSION)
        return landlock_abi_version;

    // 获取errata
    if (flags == LANDLOCK_CREATE_RULESET_ERRATA)
        return landlock_errata;

    // 复制用户空间结构
    err = copy_min_struct_from_user(&ruleset_attr, sizeof(ruleset_attr), ...);
    if (err)
        return err;

    // 验证访问权限掩码
    if ((ruleset_attr.handled_access_fs | LANDLOCK_MASK_ACCESS_FS) !=
        LANDLOCK_MASK_ACCESS_FS)
        return -EINVAL;

    // 创建规则集
    ruleset = landlock_create_ruleset(ruleset_attr.handled_access_fs,
                                      ruleset_attr.handled_access_net,
                                      ruleset_attr.scoped);

    // 创建匿名FD
    ruleset_fd = anon_inode_getfd("[landlock-ruleset]", &ruleset_fops,
                                  ruleset, O_RDWR | O_CLOEXEC);
    return ruleset_fd;
}

8.2 landlock_add_rule() ​

文件: security/landlock/syscalls.c:421-447

c
SYSCALL_DEFINE4(landlock_add_rule, const int, ruleset_fd,
               const enum landlock_rule_type, rule_type,
               const void __user *const, rule_attr, const __u32, flags)
{
    ruleset = get_ruleset_from_fd(ruleset_fd, FMODE_CAN_WRITE);
    if (IS_ERR(ruleset))
        return PTR_ERR(ruleset);

    switch (rule_type) {
    case LANDLOCK_RULE_PATH_BENEATH:
        return add_rule_path_beneath(ruleset, rule_attr);
    case LANDLOCK_RULE_NET_PORT:
        return add_rule_net_port(ruleset, rule_attr);
    default:
        return -EINVAL;
    }
}

8.3 landlock_restrict_self() ​

文件: security/landlock/syscalls.c:482-583

c
SYSCALL_DEFINE2(landlock_restrict_self, const int, ruleset_fd, const __u32, flags)
{
    // 权限检查
    if (!task_no_new_privs(current) &&
        !ns_capable_noaudit(current_user_ns(), CAP_SYS_ADMIN))
        return -EPERM;

    // 获取规则集
    ruleset = get_ruleset_from_fd(ruleset_fd, FMODE_CAN_READ);

    // 准备新凭证
    new_cred = prepare_creds();
    new_llcred = landlock_cred(new_cred);

    // 合并规则集
    new_dom = landlock_merge_ruleset(new_llcred->domain, ruleset);

    // 更新凭证
    new_llcred->domain = new_dom;

    // 线程同步(如果需要)
    if (flags & LANDLOCK_RESTRICT_SELF_TSYNC) {
        err = landlock_restrict_sibling_threads(current_cred(), new_cred);
        if (err) {
            abort_creds(new_cred);
            return err;
        }
    }

    return commit_creds(new_cred);
}

9. LSM Hooks 架构 ​

9.1 Hook 注册 ​

文件: security/landlock/setup.c

c
extern struct lsm_blob_sizes landlock_blob_sizes;
extern const struct lsm_id landlock_lsmid;

9.2 Blob 大小 ​

在 security/landlock/ 初始化时设置:

c
landlock_blob_sizes.lbs_cred = sizeof(struct landlock_cred_security);
landlock_blob_sizes.lbs_file = sizeof(struct landlock_file_security);
landlock_blob_sizes.lbs_inode = sizeof(struct landlock_inode_security);
landlock_blob_sizes.lbs_superblock = sizeof(struct landlock_superblock_security);

9.3 Hook 调用流程 ​

应用进程
    │
    ▼
sys_landlock_restrict_self()
    │
    ▼
commit_creds()  ─────────────────────────────────────┐
    │                                                │
    ▼                                                │
landlock_cred(new_cred)->domain = new_dom            │
    │                                                │
    ▼                                                │
进程执行系统调用                                      │
    │                                                │
    ▼                                                │
VFS 调用                                              │
    │                                                │
    ▼                                                │
Landlock LSM Hook (如 hook_file_open)                │
    │                                                │
    ├── landlock_get_applicable_subject()            │
    │     │                                         │
    │     └── 检查 domain 是否处理请求的访问权限     │
    │                                                │
    ├── is_access_to_paths_allowed()                │
    │     │                                         │
    │     ├── 从路径向下到根遍历                     │
    │     ├── 对每层检查规则                         │
    │     └── landlock_unmask_layers()              │
    │                                                │
    └── 返回 0 (允许) 或 -EACCES (拒绝)              │
                                                   │
                           ┌────────────────────────┘
                           │
                           ▼
                      hook_file_free_security()
                      清理资源

10. 审计日志 ​

10.1 拒绝日志 - landlock_log_denial() ​

文件: security/landlock/audit.c (假设存在)

10.2 日志配置 ​

域层级日志状态:

c
enum landlock_log_status {
    LANDLOCK_LOG_PENDING = 0,
    LANDLOCK_LOG_RECORDED,
    LANDLOCK_LOG_DISABLED,
};

日志标志:

c
#define LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF   (1U << 0)
#define LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON     (1U << 1)
#define LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF  (1U << 2)

11. 关键限制 ​

11.1 系统限制 ​

文件: security/landlock/limits.h

c
#define LANDLOCK_MAX_NUM_LAYERS     16      // 最大层级数
#define LANDLOCK_MAX_NUM_RULES     U32_MAX // 最大规则数

// 访问权限数量
#define LANDLOCK_NUM_ACCESS_FS      __const_hweight64(LANDLOCK_MASK_ACCESS_FS)
#define LANDLOCK_NUM_ACCESS_NET    __const_hweight64(LANDLOCK_MASK_ACCESS_NET)
#define LANDLOCK_NUM_SCOPE         __const_hweight64(LANDLOCK_MASK_SCOPE)

11.2 ABI 版本 ​

当前版本: landlock_abi_version = 8 (syscalls.c:167)


12. 总结 ​

12.1 核心设计原则 ​

  1. 层级化安全: 每层必须独立满足访问请求
  2. 基于路径: 通过文件系统路径而非 inode 绑定规则
  3. 不可绕过: 限制一旦应用,无法移除
  4. 最小权限: 默认拒绝所有未明确允许的访问
  5. 无特权沙箱: 基本限制不需要 CAP_SYS_ADMIN

12.2 数据流 ​

用户空间                    内核空间
   │                           │
   ├── landlock_create_ruleset() ──→ 创建规则集结构
   │                                 (分配 landlock_ruleset)
   │
   ├── landlock_add_rule() ──────→ 插入规则到规则集
   │                                 (添加到红黑树)
   │
   └── landlock_restrict_self() ─→ 合并规则集到域
                                     (创建新 domain)
                                         │
                                         ▼
                              ┌──────────────────────┐
                              │   凭证更新           │
                              │ landlock_cred()->    │
                              │ domain = new_domain  │
                              └──────────────────────┘
                                         │
                                         ▼
                              ┌──────────────────────┐
                              │   访问检查           │
                              │ hook_file_open()    │
                              │ is_access_to_paths  │
                              │ _allowed()          │
                              └──────────────────────┘

附录: 文件清单 ​

文件描述
security/landlock/ruleset.c规则集管理核心实现
security/landlock/ruleset.h规则集数据结构定义
security/landlock/fs.c文件系统 LSM hooks
security/landlock/fs.h文件系统数据结构
security/landlock/net.c网络 LSM hooks
security/landlock/task.cPtrace 和作用域 hooks
security/landlock/cred.c/h凭证管理
security/landlock/object.c/h对象生命周期管理
security/landlock/domain.c/h域和层级管理
security/landlock/access.h访问权限定义
security/landlock/limits.h系统限制常量
security/landlock/syscalls.c系统调用实现
security/landlock/setup.c/hLSM 初始化
include/uapi/linux/landlock.h用户空间 API

基于 VitePress 构建