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
,因此我无法找到解决方法。
嗨@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
但是新功能
正在使用_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 一起工作正常,
最有用的评论
啊……对不起。 实际上,它比 API 级别更深入,查看“system.c”,您会发现 libseccomp 系统级别调用不会将它们传播到 API 级别函数。 查看手册页,我们似乎没有为通知 API 提出任何关于
SCMP_FLTATR_API_SYSRAWRC
的声明(参见seccomp_load(3)
的反例)。我将继续作为 RFE 重新打开它,因为我们目前没有对此工作提出任何声明。
@drakenclimber我认为这是 v2.6.x(可能是 v2.5.2)材料,因为我不想放慢 v2.5.1 的发布速度。 如果您不这么认为,请告诉我。