Libseccomp: RFE:将 SCMP_FLTATR_API_SYSRAWRC 支持扩展到通知 API

创建于 2020-11-13  ·  5评论  ·  资料来源: seccomp/libseccomp

seccomp_notify_receive()的实现只是使用:

        if (ioctl(fd, SECCOMP_IOCTL_NOTIF_RECV, req) < 0)
                return -ECANCELED;

无论errno中的错误如何,它都会返回-ECANCELED

使用 strace 调试时,我发现 ioctl 由于信号 SIGURG 而返回 EINTR:

1448850 ioctl(7, SECCOMP_IOCTL_NOTIF_RECV <unfinished ...>
1448230 getpid()                        = 1448217
1448230 tgkill(1448217, 1448850, SIGURG) = 0
1448850 <... ioctl resumed>, 0x7fc65d49ecd0) = -1 EINTR (Interrupted system call)

信号 SIGURL 由 Golang 运行时生成,详见https://go-review.googlesource.com/c/go/+/232862/
根据该报告,系统调用应该在获得 EINTR 时重新发出。
理想情况下,libseccomp 应该处理好这一点,因此它对用户来说是透明的。

作为一种解决方法,我尝试通过在我的程序中调用 seccomp_notify_receive() 来重新发出系统调用,并在seccomp_notify_respond()中执行相同的操作,因为它具有相同的模式:

        if (ioctl(fd, SECCOMP_IOCTL_NOTIF_SEND, resp) < 0)
                return -ECANCELED;

但有时我会得到返回值 errno = ENOENT:

1497880 ioctl(12, SECCOMP_IOCTL_NOTIF_SEND, 0x7f718fd28e10) = -1 ENOENT (No such file or directory)

libseccomp 不允许我区分 ENOENT(目标进程在调用SECCOMP_IOCTL_NOTIF_SEND之前已被中断)和 EINTR(seccomp 代理被 SIGURG 信号中断)。

此外,我无法从 Golang 读取errno ,因此我无法找到解决方法。

enhancement prioritmedium

最有用的评论

但是新功能......正在使用 _rc_filter() 而不是 _rc_filter_sys() ...

啊……对不起。 实际上,它比 API 级别更深入,查看“system.c”,您会发现 libseccomp 系统级别调用不会将它们传播到 API 级别函数。 查看手册页,我们似乎没有为通知 API 提出任何关于SCMP_FLTATR_API_SYSRAWRC的声明(参见seccomp_load(3)的反例)。

我将继续作为 RFE 重新打开它,因为我们目前没有对此工作提出任何声明。

@drakenclimber我认为这是 v2.6.x(可能是 v2.5.2)材料,因为我不想放慢 v2.5.1 的发布速度。 如果您不这么认为,请告诉我。

所有5条评论

嗨@alban。

查看seccomp_attr_set(3)联机帮助页中的SCMP_FLTATR_API_SYSRAWRC

用于指定 libseccomp 是否应将系统错误代码而不是默认的 -ECANCELED 传递回调用者的标志。 默认为关闭(值 == 0)。

在这种情况下,我们强制-ECANCELED以确保 libseccomp API 中跨不同内核/libc 版本的稳定返回码承诺。 我们为仍希望看到实际内核/libc 返回代码的调用者提供SCMP_FLTATR_API_SYSRAWRC ,但请注意,如果您启用该属性,我们不保证稳定的返回代码。

我将以 NOTABUG 的身份结束此问题,但如果您还有其他问题,请随时在此处继续讨论。 如果看起来确实存在需要解决的问题,我们可以重新开放。

@pcmoore ,感谢您的快速回复。

我们为仍希望查看实际内核/libc 返回码的调用者提供 SCMP_FLTATR_API_SYSRAWRC

但是新功能

  • seccomp_notify_receive
  • seccomp_notify_respond
  • seccomp_notify_id_valid

正在使用_rc_filter()而不是_rc_filter_sys() ,所以如果我没记错的话, SCMP_FLTATR_API_SYSRAWRC应该没有效果。

但是新功能......正在使用 _rc_filter() 而不是 _rc_filter_sys() ...

啊……对不起。 实际上,它比 API 级别更深入,查看“system.c”,您会发现 libseccomp 系统级别调用不会将它们传播到 API 级别函数。 查看手册页,我们似乎没有为通知 API 提出任何关于SCMP_FLTATR_API_SYSRAWRC的声明(参见seccomp_load(3)的反例)。

我将继续作为 RFE 重新打开它,因为我们目前没有对此工作提出任何声明。

@drakenclimber我认为这是 v2.6.x(可能是 v2.5.2)材料,因为我不想放慢 v2.5.1 的发布速度。 如果您不这么认为,请告诉我。

谢谢!

作为记录,我在 Golang 方面找到了能够区分 ENOENT 和 EINTR 的解决方法,使用以下代码模式:

-   if retCode := C.seccomp_notify_respond(C.int(fd), resp); retCode != 0 {
-       return errRc(retCode)
+   for {
+       retCode, errno := C.seccomp_notify_respond(C.int(fd), resp)
+       if errno == syscall.EINTR {
+           continue
+       }
+       if errno == syscall.ENOENT {
+           return errno
+       }
+       if retCode != 0 {
+           return errRc(retCode)
+       }
+       break
    }

有了这个,它似乎与 libseccomp-2.5.0 一起工作正常,

此页面是否有帮助?
0 / 5 - 0 等级