Libseccomp: RFE: extend SCMP_FLTATR_API_SYSRAWRC support to the notification API

Created on 13 Nov 2020  ·  5Comments  ·  Source: seccomp/libseccomp

The implementation of seccomp_notify_receive() just uses:

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

Regardless of the error in errno, it returns -ECANCELED.

When debugging with strace, I found out that the ioctl returned EINTR because of the signal SIGURG:

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)

The signal SIGURL is generated by the Golang runtime, see details in https://go-review.googlesource.com/c/go/+/232862/
According to that report, the syscall should just be reissued when getting EINTR.
Ideally libseccomp should take care of that, so it it transparent for users.

As a workaround, I tried to reissue the syscall by calling seccomp_notify_receive() in my program, and to do the same in seccomp_notify_respond() because it has the same pattern:

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

But sometimes I get the return value errno = ENOENT:

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

libseccomp does not allow me to distinguish between ENOENT (the target process has been interrupted just before calling SECCOMP_IOCTL_NOTIF_SEND) and EINTR (the seccomp agent was interrupted by the SIGURG signal).

Additionally, I cannot read errno from Golang, so I cannot have a workaround.

enhancement prioritmedium

Most helpful comment

But the new functions ... are using _rc_filter() and not _rc_filter_sys() ...

Ah ... sorry about that. Actually, it goes deeper than the API level, look in "system.c" and you'll see that the libseccomp system level calls don't propogate those up to the API level functions. Looking at the manpages, it appears we don't make any claims about SCMP_FLTATR_API_SYSRAWRC for the notification API (see seccomp_load(3) for a counter example).

I'll go ahead and reopen this as a RFE since we don't currently make any claims about this working.

@drakenclimber I think this is v2.6.x (possibly v2.5.2) material as I don't want to slow the v2.5.1 release. If you think otherwise let me know.

All 5 comments

Hi @alban.

Look at SCMP_FLTATR_API_SYSRAWRC in the seccomp_attr_set(3) manpage:

A flag to specify if libseccomp should pass system error codes back to the caller instead of the default -ECANCELED. Defaults to off (value == 0).

We force -ECANCELED in this case to ensure a stable return code promise in the libseccomp API across different kernel/libc versions. We offer the SCMP_FLTATR_API_SYSRAWRC for callers that still wish to see the actual kernel/libc return code, just be warned that we do not guarantee a stable return code if you enable that attribute.

I'm going to close this issue as NOTABUG, but feel free to continue to discuss this here if you have additional questions. We can reopen if it looks like there is a real problem that needs to be addressed.

Hi @pcmoore, thanks for the quick reply.

We offer the SCMP_FLTATR_API_SYSRAWRC for callers that still wish to see the actual kernel/libc return code

But the new functions

  • seccomp_notify_receive
  • seccomp_notify_respond
  • seccomp_notify_id_valid

are using _rc_filter() and not _rc_filter_sys(), so SCMP_FLTATR_API_SYSRAWRC should not have an effect, if I am not mistaken.

But the new functions ... are using _rc_filter() and not _rc_filter_sys() ...

Ah ... sorry about that. Actually, it goes deeper than the API level, look in "system.c" and you'll see that the libseccomp system level calls don't propogate those up to the API level functions. Looking at the manpages, it appears we don't make any claims about SCMP_FLTATR_API_SYSRAWRC for the notification API (see seccomp_load(3) for a counter example).

I'll go ahead and reopen this as a RFE since we don't currently make any claims about this working.

@drakenclimber I think this is v2.6.x (possibly v2.5.2) material as I don't want to slow the v2.5.1 release. If you think otherwise let me know.

Thanks!

For the record, I fount the workaround in the Golang side to be able distinguish ENOENT and EINTR, with this code pattern:

-   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
    }

With this, it seems to work fine with libseccomp-2.5.0,

Was this page helpful?
0 / 5 - 0 ratings