本文地址:https://www.ebpf.top/post/bpf-74-xattr-kfunc-dispute

对峙:Alexei 留在 fs/,Paul 要进 security/

先说结论:截至北京时间 2026 年 10 月 23 日 18:17,「[GIT PULL] BPF changes for 7.4」线程已从最初 3 封扩到 6 封:Alexei 的合并请求、Paul 的反对、Alexei 的逐条回应,随后又有 Paul 的再答、Alexei 请 Linus 裁决,以及 VFS 维护者 Christian Brauner 的表态(偏把代码留在 fs/)。Linus Torvalds 仍未在线程里回复,主线也还没有合入 bpf-next-7.4。

发稿后补注(不改写上文截稿判断):北京时间 2026 年 10 月 24 日 07:08,相关改动已合入 bpf-next-7.4(55fbedcec622)。此处只记录合入事实,不从合并行为另行推断裁决含义。

分歧的对象是一个 kfunc:bpf_inode_init_xattr(),它让 BPF LSM 程序在 inode 创建时写入安全标签。两边争的不是它该不该存在,而是它该放在 fs/bpf_fs_kfuncs.c 还是 security/ 下,也就是由谁来评审、由谁来维护。几个关键数字:它会是 fs/bpf_fs_kfuncs.c 里的第 7 个 xattr kfunc;补丁从 4 月 v1 到 7 月 v6 走了六个版本、三个月;9 月起它已在 linux-next。

下面我们按时间顺序,一个回合一个回合地看。文中时间均为北京时间,引用以 lore 原文为准。

1. 开场:合并请求发出 25 分钟后,LSM 维护者回信反对【10 月 22 日】

10 月 22 日 05:01,Alexei 向 Linus 发出 BPF 7.4 合并请求(tag bpf-next-7.4,570 个文件改动)。在 “Other features and fixes” 一栏里,有这样一行:

Alexei Starovoitov:

Let BPF LSM set xattrs at inode creation with bpf_inode_init_xattr()

让 BPF LSM 通过 bpf_inode_init_xattr() 在 inode 创建时设置 xattr

署名 David Windsor 和 Daniel Borkmann。

05:26,LSM 维护者 Paul Moore 回信,并把 linux-security-module 列表加进抄送:

Paul Moore:

I need to object to the BPF LSM kfunc added in commit ff0d1c0915d1

我需要对 commit ff0d1c0915d1 加入的这个 BPF LSM kfunc 提出反对。

06:45,Alexei 回复,开头直接写给 Linus,随后逐段引用 Paul 的话作答,并把 Christian Brauner、David Windsor、KP Singh、Matt Bobrowski 加进抄送。

一个合并请求里出现子系统维护者之间的公开分歧,并不常见。要看懂这场往返,得先弄清这个 kfunc 到底做什么。

2. 背景:bpf_inode_init_xattr() 让 BPF LSM 在建 inode 时写标签

SELinux、Smack 这类 LSM 把安全标签存在扩展属性(xattr)里。补丁说明把问题讲得很清楚:如果 inode 在 xattr 写好之前就已可访问,它会短暂处于无标签状态,基于标签做决策的 LSM 就可能出错。内核里现成的 LSM 都在 inode_init_security 钩子里设置 xattr,这个钩子在 inode 可访问之前执行。

BPF LSM 程序以前做不到这一点。原因有二:钩子用输出参数 xattr_count 返回数量,BPF 程序写不了它;现有的 bpf_set_dentry_xattr() 需要 dentry,而 dentry 要等 inode 可访问之后才有。

新 kfunc 的做法是:接过钩子自己的 xattrs 和 xattr_count 参数,替程序调用 lsm_get_xattr_slot() 领一个槽位,填入名字和值,最后由 LSM 框架里的 security_inode_init_security() 统一交给文件系统写入。补丁的改动统计如下(引自上面的补丁邮件):

fs/bpf_fs_kfuncs.c         | 99 ++++++++++++++++++++++++++++++++++++++
include/linux/bpf_lsm.h    | 11 ++++-
kernel/bpf/bpf_lsm.c       | 22 ++++++++-
kernel/bpf/bpf_lsm_proto.c | 15 ++++++
security/bpf/hooks.c       |  1 +

BPF LSM 在 inode 创建时写 xattr 的调用流程

这条链路本身没有争议。争议在于:这段代码横跨 VFS 和 LSM 两个子系统,它算谁的?

3. 第一回合:kfunc 从 v1 起就放在 fs/,两位维护者先后给出条件【4 月 27 日—7 月 1 日】

David Windsor 在 4 月 27 日发出 v1,当时的名字还是 bpf_init_inode_xattr,代码就放在 fs/bpf_fs_kfuncs.c。之后 5 月 4 日 v2、6 月 19 日 v3、7 月 1 日凌晨 v4 陆续发出。

6 月 25 日,VFS 维护者 Christian Brauner 在 v3 讨论中回复,前半段支持放在 VFS,后半段把决定权交了出去:

Christian Brauner:

all VFS related bpf kfuncs should continue living there it’s a bpf specific helper so it’s the bpf maintainer’s call

所有与 VFS 相关的 bpf kfunc 应继续放在那里。 这是 bpf 专用的辅助函数,所以由 bpf 维护者决定。

7 月 1 日,Paul 在 v4 讨论中回复。他明确:lsm_get_xattr_slot() 和 BPF_LSM_INODE_INIT_XATTRS 不应在 security/ 之外使用;同时给出附条件让步(“As I said previously”):若执意放在 VFS 的 kfunc 文件里,LSM 部分需抽成 LSM 函数。他给出了草图 security_lsmxattr_add(),并表示可替 David 写补丁。

到这里,看起来双方有了一个折中方案,不过这是 Paul 附了条件的让步。

4. 第二回合:看过 v5 后 Paul 改变看法,讨论进入僵局【8 月 1 日】

David 在 7 月 8 日的 v5 和 7 月 31 日的 v6 里照这个方向做了,v6 涉及 security/security.c、SELinux、Smack、EVM 多处,也抄送了 LSM 列表。

但看过 v5 后,Paul 的看法变了。8 月 1 日凌晨(美东时间 7 月 31 日),他在 v6 讨论里说明原因:LSM 部分抽出来以后,这个函数的性质反而更清楚——只能在 BPF LSM 回调里调用,除去 BPF 指针样板,做的只是回调一个 LSM 辅助函数;因此他改变了看法。同一线程的另一封回复里,他把话说到了底:

Paul Moore:

this puts us at a stalemate and David will need to find another approach for his work.

这让我们陷入僵局,David 需要为他的工作另找办法。

从 v1 到 v6,正好三个月。补丁的功能没人反对,位置问题却没谈拢。

5. 第三回合:Daniel 接手新系列,9 月进入 linux-next【9 月 10 日—24 日】

9 月 10 日,Paul 在一个与本补丁无关的 BPF LSM 系列下发问:BPF 这边是否仍反对在 security/bpf_lsm_kfuncs.c 里放 kfunc,并提出维护需归 LSM 框架(类比 bpf_fs_funcs.c 归 VFS)。9 月 12 日,Alexei 在同一线程回复:

Alexei Starovoitov:

There is will be no kfuncs under security/. Period.

security/ 下不会有 kfunc,就这样。

9 月 15 日,Daniel Borkmann 发出新的 bpf-next 系列,第 4 个补丁就是 David 的 bpf_inode_init_xattr()(Daniel 标为 Co-developed-by),kfunc 仍在 fs/bpf_fs_kfuncs.c,抄送里有 Brauner、KP、Matt,没有 LSM 列表。9 月 24 日凌晨,Daniel 在 Paul 的又一封回信下回复,认为现在的位置完全合理,并表示若有技术意见或 bug 乐意处理。据 Alexei 在 GIT PULL 线程里的说法,这个系列 9 月起就在 linux-next 中,此后没有人报告技术问题或 bug。

bpf_inode_init_xattr() 从 v1 到 GIT PULL 的时间线

于是到了 10 月 22 日,同一个问题被摆到了 Linus 面前。

6. 第四回合:GIT PULL 里的正面交锋,双方各有四点

Paul 的反对和 Alexei 的回应大致可以一一对应。我们把两边按相同的顺序摆出来。

6.1 Paul Moore:这是 LSM kfunc,应进 security/

  • 它名为 inode/xattr,实为 LSM kfunc。 “despite its name, is a LSM kfunc”(尽管名字如此,它是一个 LSM kfunc。)他认为它应放在 security/bpf_lsm_kfuncs.c。
  • 它不调用 VFS API,调用的是 LSM 内部 API。 流程是:BPF LSM 程序调用它 → 分配 xattr 名/值缓冲区 → 加入 LSM 框架管理的列表 → 由 security_inode_init_security() 汇总写入 inode。
  • 放在 fs/ 没有充分的技术理由。

Paul Moore:

There is no good technical reason why this kfunc is located outside the security/ directory

没有充分的技术理由把这个 kfunc 放在 security/ 目录之外

他列举 BPF kfunc 已分布在 drivers、VFS、io_uring、cgroups、scheduler、mm、networking 等目录,唯独 security/ 没有,因此认为这一决定"largely (solely?)"(主要甚至完全)出于一项"petulant policy"(赌气式的政策),并附上了 Alexei 9 月那封邮件的链接。

  • 支持功能,不接受绕开评审。 他说支持 David 的工作,7.4 的 LSM 合并请求里也有方便 BPF LSM 的改动,同时写明:

Paul Moore:

I can’t support the BPF maintainers actively circumventing review/oversight from LSM developers

我不能支持 BPF 维护者主动绕开 LSM 开发者的评审与监督

他的要求是把 kfunc 和相关代码挪进 security/bpf_lsm_kfuncs.c。

6.2 Alexei Starovoitov:它是第 7 个 xattr kfunc,应留在 fs/

  • 那个文件并不存在。 “there is no such file”(没有这个文件。)他说实际诉求是新建这个文件并交给 LSM 树维护,引的正是 Paul 9 月那句"维护需要归 LSM 框架"。
  • fs/ 下已有 6 个同类 kfunc。 bpf_{get,set,remove}_dentry_xattr()、bpf_get_file_xattr()、bpf_cgroup_read_xattr()、bpf_sock_read_xattr(),“bpf_inode_init_xattr() is the 7th”(这是第 7 个)。前缀并不统一:bpf_cgroup_read_xattr / bpf_sock_read_xattr 只接受 user.*;bpf_get_file_xattr / bpf_get_dentry_xattr 支持 user.* 与 security.bpf.*;设置、删除及新 inode 初始化(含本争议的 bpf_inode_init_xattr)才是检查 security.bpf. 的那一侧。Alexei 把新 kfunc 与既有 xattr 接口并列,是在说同属 fs/bpf_fs_kfuncs.c 这一族,不能据此理解为六个函数都用同一前缀。他引用了 Brauner 6 月的前半句(见下)。
  • 所谓 LSM 内部 API 只有三行。 他贴出 include/linux/lsm_hooks.h 里 static inline 的 lsm_get_xattr_slot():
1
2
3
4
/* 引自 Alexei 回信中贴出的 lsm_get_xattr_slot() 函数体 */
	if (unlikely(!xattrs))
		return NULL;
	return &xattrs[(*xattr_count)++];

并说 security_inode_init_security() 的 kdoc 要求 LSM 调用它,selinux、smack、evm 都这么做,“BPF LSM is one more LSM”(BPF LSM 只是又一个 LSM)。这个系列在 security/ 下只改了 security/bpf/hooks.c 一行。

  • 时间顺序不支持"赌气"的说法。 kfunc 从 4 月 v1 就在 fs/,Paul 引用的邮件是 9 月的。他复述了 7 月 1 日到 8 月 1 日的经过,结论是:

Alexei Starovoitov:

Six versions in three months, stuck on the name of the file. That’s why I don’t want bpf kfuncs under security/.

三个月六个版本,卡在文件名上。这就是我不想让 bpf kfunc 进 security/ 的原因。

关于评审,他说 v3–v6 都发到了 LSM 列表,最后这个系列没有抄送,

Alexei Starovoitov:

It should have been. Fair point. Will cc next time.

本该抄送。这一点说得对,下次会抄送。

Paul Moore 与 Alexei Starovoitov 的四点论据对照

还有两处原文细节值得读者自己对照。其一,Alexei 引用 Brauner 时只引了「VFS 相关的放 VFS」;Brauner 原邮件后半句是:

Christian Brauner:

Anything that’s just bpf infra specific can go to security/bpf/kfuncs.c instead

只与 bpf 基础设施相关的东西可以改放 security/bpf/kfuncs.c

其二,Paul 所说的"petulant policy"指向的邮件,确实是 Alexei 本人 9 月写的那句"security/ 下不会有 kfunc"。

7. 第五回合:Paul 再答、Alexei 请 Linus 裁决、Christian 表态偏 fs/【10 月 22 日 09:26—19:04】

上午的三封邮件之后,同一天又来了三封。

7.1 Paul:不只是抄送名单,还有是否正视其他子系统的意见【09:26】

09:26,Paul 再回一封。他重申:这个 kfunc「isn’t really a VFS kfunc」(并不真是 VFS kfunc),它填充的是 LSM 管理的缓冲区,调用的是 LSM 私有 API。对 Alexei 复述的 7–8 月经过,他强调自己一直在和 David 互动,并写明:

Paul Moore:

It’s about actually being open to feedback and working with other subsystems to arrive at a solution that everyone can accept, even if they do so begrudgingly.

关键在于是否真正开放地接受反馈,并与其他子系统一起找到一个即便有人不情愿、也能接受的方案。

他还认为,若坚持在其他子系统反对下推进,应在发给 Linus 的合并请求里写清楚,由 Linus 仲裁;并提到此前 Hornet LSM 讨论作对照(那次最终没有把 PR 推到 Linus)。这段是立场陈述,读者可顺着链接看原文脉络,不必把类比当成已定论。

7.2 Alexei:列 fs/bpf_fs_kfuncs.c 的来历,并把球交给 Linus【11:18】

11:18,Alexei 再回,把 fs/bpf_fs_kfuncs.c 的形成史写了一遍:2023 年底 Song 把 bpf_get_file_xattr() 加在 kernel/trace/bpf_trace.c;2024 年 3 月 Christian 要求「这类定义必须放在 fs/」;同年 7 月 Matt 建起 fs/bpf_fs_kfuncs.c 并得到 Christian 的 ack;此后 Song、Christian 本人贡献的 xattr kfunc 都进了这个文件;David 的 v1 从一开始就放在旁边。他接着写:

Alexei Starovoitov:

It cannot be in fs/ and in security/ at the same time. it’s your call. If you think the kfunc should move I’ll send a follow up. there is no need to hold the pull request for that

它不能同时既在 fs/ 又在 security/。 由你来定。若你认为该挪,我会再发一版跟进。 不必为此卡住整份合并请求

并以 “imo xattrs are VFS territory”(在我看来 xattr 属于 VFS 领地)收束。

7.3 Christian:夹在中间,但给出「更像文件系统契约」的判断【19:04】

19:04,被多次点名的 VFS 维护者 Christian Brauner 回信。开头自嘲「I love how I always end up in the middle of this somehow」(我总是不知怎么就夹在中间),并写明想尽量两边都听进去。

他描述这个 kfunc 实际做的事:检查 security.bpf. 名字空间与长度上限、拷贝值、填好 struct xattr,再由文件系统的 ->initxattrs() 在创建 inode 的过程中写入。LSM 相关部分主要是 lsm_get_xattr_slot() 这个取出数组下一槽的 static inline。系列里碰到的 ocfs2 问题——回调之后仍握着 name 指针——是文件系统契约,并已与 ocfs2 维护者理清;Christian 写:

Christian Brauner:

This is a decent hint where this code belongs imho.

在我看来,这很好地提示了代码该落在哪里。

对 CONFIG_BPF_LSM 门控,他说那是历史原因,binfmt_misc 的 BPF 程序也在用这个文件,门控本身说明不了归属。原则句是:

Christian Brauner:

The lsm framework doesn’t own code in other subsystems because it calls an lsm helper. The same way the vfs doesn’t own the lsms simply because the majority of them live on vfs objects.

LSM 框架不会因为调用了某个 LSM 辅助函数,就拥有其他子系统里的代码;同理,VFS 也不会只因为多数 LSM 挂在 VFS 对象上,就拥有那些 LSM。

他也承认担忧:BPF LSM 让人写出从不出现在 LSM 邮件列表上的策略,kfunc 又是搭积木的接口——「对我来说这是好事,因为能把一批代码移出内核」,但「万一暴露出真正会烧房子的东西呢」。他没有替 Linus 下判决,但技术判断明显更靠近「留在 fs/」。

8. 现状:截至北京时间 18:17,6 封邮件后 Linus 仍未表态,PR 未合并

截至北京时间 2026 年 10 月 23 日 18:17(curl -A lei/curl 拉取线程 t.mbox.gz):

  • 线程里现有 6 封邮件(相对 v2 截点的 3 封,新增 Paul 再答、Alexei 再答、Christian 表态)。Linus 没有出现在 From 行里。线程总览可核对。
  • BPF PR 尚未合并。 主线 git log 检索仍看不到 bpf-next-7.4 合入记录。
  • 没有人要求撤下功能。 Paul 要的是挪到 security/;Alexei 表示若 Linus 要求挪可以跟进补丁,但不必因此卡住整份 PR;Christian 的技术判断偏 fs/。

同一周与评审边界相关的 xdp link_create 插曲仍如 v2 所述:Jakub Kicinski 要求改核心网络代码前先拿到网络维护者 ack,Alexei 回复“Fair point. Will wait for an ack next time.",该系列不在 7.4 合并请求提交列表里。

Linus 会直接合并、要求挪文件,还是先让双方再谈,截至这一刻仍没有公开依据去判断。状态以 lore 为准。

9. 总结:位置之争未收场,VFS 维护者给出了方向性意见

回头看这三个多月,双方在几件事上其实一致:功能有用;BPF LSM 需要在 inode 创建时原子写标签;lsm_get_xattr_slot() 是 LSM 写 xattr 的标准入口。

分歧仍集中在两处。一是代码位置:按 xattr 家族归类,它是 fs/bpf_fs_kfuncs.c 的第 7 个;按调用关系归类,它只在 BPF LSM 回调里跑,并调用 LSM 辅助函数。二是评审归属:留在 fs/,还是新建 security/ 下的 kfunc 文件交给 LSM 树。

10 月 22 日晚 Christian 的回信没有结束争论,但把「文件系统契约 / initxattrs」这一侧的技术理由写清楚了,也明确说 LSM 辅助调用不等于 LSM 拥有该文件。最终决定权仍在 Linus。截至发稿他还没有表态,后续我们会持续关注。本人水平有限,如有错误欢迎批评指正。

裁决:待 Linus 拍板

延伸阅读

若还想顺着读,可看这几篇:

  1. Linux 7.3 BPF新特性:binfmt_misc 可编程、arena 指针直通 kfunc、验证器"说人话”
  2. 一文全面了解 LSM BPF (含实战,强烈建议收藏)
  3. Linus 强势拍板合入: BPF 赋能调度器终成正果