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を使用してデバッグしているときに、シグナルSIGURGが原因でioctlが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を取得するときにsyscallを再発行する必要があります。
理想的には、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_sys()ではなく_rc_filter()を使用しています...

あぁ…ごめんなさい。 実際には、APIレベルよりも深く、「system.c」を調べてください。libseccompシステムレベルの呼び出しは、APIレベルの関数までそれらを伝播しないことがわかります。 マンページを見ると、通知APIのSCMP_FLTATR_API_SYSRAWRCについては何も主張していないようです(反例についてはseccomp_load(3)を参照してください)。

現在、この動作については何も主張していないので、先に進んでこれをRFEとして再開します。

@drakenclimber v2.5.1のリリースを遅くしたくないので、これはv2.6.x(おそらくv2.5.2)の素材だと思います。 そうでなければ私に知らせてください。

全てのコメント5件

こんにちは@alban。

seccomp_attr_set(3)のマンページでSCMP_FLTATR_API_SYSRAWRCを見てください。

libseccompがデフォルトの-ECANCELEDの代わりにシステムエラーコードを呼び出し元に返すかどうかを指定するフラグ。 デフォルトはオフです(値== 0)。

この場合、異なるカーネル/ libcバージョン間でlibseccompAPIの安定したリターンコードの約束を確実にするために、 -ECANCELEDを強制します。 実際のkernel / libcリターンコードを見たい発信者にはSCMP_FLTATR_API_SYSRAWRCを提供しますが、その属性を有効にした場合、安定したリターンコードは保証されないことに注意してください。

この問題はNOTABUGとして締めくくりますが、さらに質問がある場合は、ここで引き続き議論してください。 対処する必要のある実際の問題があると思われる場合は、再開できます。

こんにちは@pcmoore 、迅速な返信をありがとう。

実際のカーネル/ libcリターンコードを引き続き確認したい発信者向けに、SCMP_FLTATR_API_SYSRAWRCを提供しています。

しかし、新しい機能

  • seccomp_notify_receive
  • seccomp_notify_respond
  • seccomp_notify_id_valid

_rc_filter_sys() _rc_filter()を使用しているので、私が間違っていなければ、 SCMP_FLTATR_API_SYSRAWRCは効果がないはずです。

しかし、新しい関数は... _rc_filter_sys()ではなく_rc_filter()を使用しています...

あぁ…ごめんなさい。 実際には、APIレベルよりも深く、「system.c」を調べてください。libseccompシステムレベルの呼び出しは、APIレベルの関数までそれらを伝播しないことがわかります。 マンページを見ると、通知APIのSCMP_FLTATR_API_SYSRAWRCについては何も主張していないようです(反例についてはseccomp_load(3)を参照してください)。

現在、この動作については何も主張していないので、先に進んでこれをRFEとして再開します。

@drakenclimber v2.5.1のリリースを遅くしたくないので、これはv2.6.x(おそらくv2.5.2)の素材だと思います。 そうでなければ私に知らせてください。

ありがとう!

記録のために、私は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 評価