Libseccomp: バグ:src /db.cの手直しによって壊れたA2処理

作成日 2018年02月26日  ·  18コメント  ·  ソース: seccomp/libseccomp

提案されたバイナリツリーのパフォーマンスの改善をテストするために、read()とそのバッファサイズ引数(A2)の非現実的なルールセットを作成しました。 しかし、src / db.cリワークコミット(ce3dda9a1)がA2処理を中断したようです-少なくともこのテストケースでは。

db rework commitの前に、次のような読み取り( read(devzero_fd, buf, 8000) )は-10返しました。 このコミットの後、 -5返すようになりました。

ばかげたread()ルールを生成するために使用したCコードは次のとおりです。

        /* read */
        for (i = 5; i <= 12; i++) {
                rc = seccomp_rule_add(ctx, SCMP_ACT_ERRNO(i), SCMP_SYS(read), 1,
                        SCMP_A2(SCMP_CMP_GT, 4 << i));
                if (rc < 0) {
                        fprintf(stdout, "%s:%d Failed to add read rule %d : rc = %d\n",
                                __FUNCTION__, __LINE__, i, rc);
                        goto error;
                }   
        }   
        rc = seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 1,
                SCMP_A2(SCMP_CMP_LE, 64));
        if (rc < 0) {
                fprintf(stdout, "%s:%d Failed to add read allow rule : rc = %d\n",
                        __FUNCTION__, __LINE__, rc);
                goto error;
        } 

そして、これがそれが生成したPFCです:

  # filter for syscall "read" (0) [priority: 65525]
  if ($syscall == 0)
    if ($a2.hi32 >= 0)
      if ($a2.lo32 > 64)
      else
        action ALLOW;
      if ($a2.lo32 > 16384)
        action ERRNO(12);
      if ($a2.lo32 > 8192)
        action ERRNO(11);
      if ($a2.lo32 > 4096)
        action ERRNO(10);
      if ($a2.lo32 > 2048)
        action ERRNO(9);
      if ($a2.lo32 > 1024)
        action ERRNO(8);
      if ($a2.lo32 > 512)
        action ERRNO(7);
      if ($a2.lo32 > 256)
        action ERRNO(6);
      if ($a2.lo32 > 128)
        action ERRNO(5);
    else
      action ALLOW;
  # default action
  action ERRNO(34);
bug priorithigh

全てのコメント18件

ちなみに、私は根がそれを引き起こすのを助けるために私ができることをします

scmp_bpf_disasmを使用して、最新のlibseccompがジャンプを誤った順序で配置しています

 0014: 0x25 0x11 0x00 0x00000080   jgt 128  true:0032 false:0015
 0015: 0x25 0x0f 0x00 0x00000100   jgt 256  true:0031 false:0016
 0016: 0x25 0x0d 0x00 0x00000200   jgt 512  true:0030 false:0017
 0017: 0x25 0x0b 0x00 0x00000400   jgt 1024 true:0029 false:0018
 0018: 0x25 0x09 0x00 0x00000800   jgt 2048 true:0028 false:0019
 0019: 0x25 0x07 0x00 0x00001000   jgt 4096 true:0027 false:0020
 0020: 0x25 0x05 0x00 0x00002000   jgt 8192 true:0026 false:0021
 0021: 0x25 0x03 0x00 0x00004000   jgt 16384 true:0025 false:0022
 0022: 0x25 0x01 0x00 0x00000040   jgt 64   true:0024 false:0023
 0023: 0x06 0x00 0x00 0x7fff0000   ret ALLOW

プレリワーク

 0014: 0x25 0x01 0x00 0x00000040   jgt 64   true:0016 false:0015
 0015: 0x06 0x00 0x00 0x7fff0000   ret ALLOW
 0016: 0x25 0x0f 0x00 0x00004000   jgt 16384 true:0032 false:0017
 0017: 0x25 0x0d 0x00 0x00002000   jgt 8192 true:0031 false:0018
 0018: 0x25 0x0b 0x00 0x00001000   jgt 4096 true:0030 false:0019
 0019: 0x25 0x09 0x00 0x00000800   jgt 2048 true:0029 false:0020
 0020: 0x25 0x07 0x00 0x00000400   jgt 1024 true:0028 false:0021
 0021: 0x25 0x05 0x00 0x00000200   jgt 512  true:0027 false:0022
 0022: 0x25 0x03 0x00 0x00000100   jgt 256  true:0026 false:0023
 0023: 0x25 0x01 0x00 0x00000080   jgt 128  true:0025 false:0024
 0024: 0x06 0x00 0x00 0x00050022   ret ERRNO(34)

面白い。 したがって、PFCは「正しい」ように見えますが、生成されたBPFは...後方です。 奇数。 特に、コミットによってBPF生成コードが変更されなかったことを考えると。

どういうわけか優先度の値がめちゃくちゃになっているのかな?

あいまいさでごめんなさい。 PFC(リワーク変更後)も間違った順序になっています。 上に投稿したPFCは、db.cのリワーク前の順序です。

これが現在HEADによって生成されているPFCです

  # filter for syscall "read" (0) [priority: 65525]
  if ($syscall == 0)
    if ($a2.hi32 >= 0)
      if ($a2.lo32 > 128)
        action ERRNO(5);
      if ($a2.lo32 > 256)
        action ERRNO(6);
      if ($a2.lo32 > 512)
        action ERRNO(7);
      if ($a2.lo32 > 1024)
        action ERRNO(8);
      if ($a2.lo32 > 2048)
        action ERRNO(9);
      if ($a2.lo32 > 4096)
        action ERRNO(10);
      if ($a2.lo32 > 8192)
        action ERRNO(11);
      if ($a2.lo32 > 16384)
        action ERRNO(12);
      if ($a2.lo32 > 64) 
      else
        action ALLOW;
    else
      action ALLOW;
  # default action
  action ERRNO(34);

さて、それはもう少し理にかなっています。 問題は間違いなくdbレイヤーのどこかにあります。

それが正確に後方にあるのは少しおかしいです。

問題を見つけました。 チェーン引数管理では、大規模なdb.cのリワーク後に、lvl_nxtとlvl_prvの動作が入れ替わりました。 _db_tree_add()にいくつかの小さな変更を加えると、以前のlibseccompの動作と一致するようになりました。

これが修正されたブランチです
https://github.com/drakenclimber/libseccomp/tree/issues/112

変更をクリーンアップし、テストを1つか2つ追加して、コードカバレッジが十分であることを確認します。

私は今朝、おそらくあなたが上記を投稿する直前時間を見つけ、これを少し調べることにしました。 修正は少し異なりますが、ほぼ同じ結論に達したようです。 これが私の現在の修正ですが、あなたと同じように、追加の作業/クリーンアップが必要です。

今、どちらのアプローチが好きかわかりません。これについて少し考える必要があります。

うーん...私は嘘をつきません。 現時点では、どちらの修正にも夢中ではありません。

私のは単純なものですが、_db_tree_prune()を完全に無視しました。これは、要点で述べたように、おそらく同様の問題があります。

gt()マクロを作り直してlt()マクロとeq()マクロを利用するというあなたのアイデアが好きですが、それらは扱いにくくなっています-特にlt()。 lt()をインライン関数に変換しない理由はありますか?
編集-私はあなたが要点で同様のコメントをしたことに気づきました。

私は古いlibseccompとHEADに対してgdbを実行し、lvl_prvとlvl_nxtの動作は変更されましたが、それは私たち以外の誰も見るべきではない内部変数であるため、おそらくそれは大したことではありません。

やっぱりこのとりとめのないことだと思います…わかりません。 私は同意します、私はそれについて考える必要があります;)

うーん...私は嘘をつきません。 現時点では、どちらの修正にも夢中ではありません。

このようなツリーレベルの並べ替えには微妙なバグがあるのではないかと心配しています、以前のコミットによってレベルこれは微妙なバグの1つです。

いずれにせよ、私はレベルに必要な順序を理解したいと思います。最初に「最大」、最後に「最大」ですか? それを理解したら、テスト/修正を進めることができます。 以前の2.xリリースとの互換性以外の理由がなければ、答えは最初に「最大」だと思いますが、現時点では確かにそれを言うことはできません。

私のは単純なものですが、_db_tree_prune()を完全に無視しました。これは、要点で述べたように、おそらく同様の問題があります。

どちらも基本的に同じことを原則として実行します。いくつかの条件を追加し、db_chain_lt(x、y)マクロをクリーンアップすることで、もう少し進んでいます。

gt()マクロを作り直してlt()マクロとeq()マクロを利用するというあなたのアイデアが好きですが、それらは扱いにくくなっています-特にlt()。 lt()をインライン関数に変換しない理由はありますか?

主に歴史的な理由。 彼らはもっと単純なマクロとして生活を始めましたが、おそらく関数であるべきだと私が思うところまでかなり成長しました。 それらが本当にヘッダーファイルにある必要があるかどうかを評価することも良いと思います。それらはsrc / db.cによってのみ使用されると思います。

私は古いlibseccompとHEADに対してgdbを実行し、lvl_prvとlvl_nxtの動作は変更されましたが、それは私たち以外の誰も見るべきではない内部変数であるため、おそらくそれは大したことではありません。

ええ、それは内部の状態/ツリーです、私はそれについてあまり心配していません。 重要なのは、生成されたフィルターの正確さです。

やっぱりこのとりとめのないことだと思います…わかりません。 私は同意します、私はそれについて考える必要があります;)

ふふ。 これを1日か2日与えて、再グループ化しましょう:)今のところ、これはリリースされたバージョンには影響しません。マスターブランチにのみあるので、問題を解決するための時間があります。

現在、これはリリースされたバージョンには影響しません。マスターブランチにのみ存在するため、問題を解決するための時間があります。

いいですね。 計画を立てる間、いくつかのテストを行います

現在のseccompA2の処理を評価するプログラムを作成しました。 プログラム全体はここから入手できます。

https://gist.github.com/drakenclimber/3c6b45ecd973ee495281ef225fa5e54a

一言で言えば、大なり記号は「最後に作成された」「最初に処理された」順序で生成されます。

  • >ルールが昇順で作成されるフィルターの場合、例:
    seccomp_rule_add(ctx, action1, syscall, 1, SCMP(SCMP_CMP_GT, 10)
    seccomp_rule_add(ctx, action2, syscall, 1, SCMP(SCMP_CMP_GT, 20)
    seccomp_rule_add(ctx, action3, syscall, 1, SCMP(SCMP_CMP_GT. 30)
    その場合、フィルターは一貫した方法で動作します。
if (A2 > 30)
    do action3
if (A2 > 20)
    do action2
if (A2 > 10)
    do action1
  • >ルールが降順で作成されるフィルターの場合。
    seccomp_rule_add(ctx, action3, syscall, 1, SCMP(SCMP_CMP_GT, 30)
    seccomp_rule_add(ctx, action2, syscall, 1, SCMP(SCMP_CMP_GT, 20)
    seccomp_rule_add(ctx, action1, syscall, 1, SCMP(SCMP_CMP_GT. 10)
    次に、フィルターが作成されますが、動作がおかしくなります。 デッドコードが生成されます。 最後の2つのifステートメントに到達できません
if (A2 > 10)
    do action1
if (A2 > 20)
    do action2
if (A2 > 30)
    do action1
  • 複数の< A2操作を含むフィルターは、現在seccompでは許可されていません。 上記の>フィルターと同等の<=を作成する方法がわからなかったため、これは奇妙に思えます。
tom<strong i="43">@OracleDesktop</strong> $ ./a2test 3
Failed to add rule
        action = 0x5000e op = 0x3 datum = 18000 rc = -17
Mode 3 (LE descending) test failed.  rc = -17
tom<strong i="46">@OracleDesktop</strong> $ ./a2test 4
Failed to add rule
        action = 0x50006 op = 0x3 datum = 250 rc = -17
Mode 4 (LE ascending) test failed.  rc = -17

src/db.c奥深くelse ifロジックが、 <失敗を引き起こしていると推測しています。 変更/修正する価値があるかどうかはわかりません。

このコードの一部を自動テストに変換して、現在の動作をキャプチャできるようにします。

書かれているように、ここでの要点は、先週追加した自動テストに失敗しました。 掘り下げて、その理由を理解しようと思います。

 batch name: 43-sim-a2_order
 test mode:  c
 test type:  bpf-sim
Test 43-sim-a2_order%%001-00001 result:   SUCCESS
Test 43-sim-a2_order%%002-00001 result:   SUCCESS
Test 43-sim-a2_order%%003-00001 result:   SUCCESS
Test 43-sim-a2_order%%004-00001 result:   SUCCESS
Test 43-sim-a2_order%%005-00001 result:   SUCCESS
Test 43-sim-a2_order%%006-00001 result:   SUCCESS
Test 43-sim-a2_order%%007-00001 result:   SUCCESS
Test 43-sim-a2_order%%008-00001 result:   FAILURE bpf_sim resulted in ERRNO(5)
Test 43-sim-a2_order%%009-00001 result:   FAILURE bpf_sim resulted in ERRNO(5)
Test 43-sim-a2_order%%010-00001 result:   FAILURE bpf_sim resulted in ERRNO(5)
Test 43-sim-a2_order%%011-00001 result:   FAILURE bpf_sim resulted in ERRNO(5)
Test 43-sim-a2_order%%012-00001 result:   FAILURE bpf_sim resulted in ERRNO(5)
Test 43-sim-a2_order%%013-00001 result:   FAILURE bpf_sim resulted in ERRNO(5)
Test 43-sim-a2_order%%014-00001 result:   FAILURE bpf_sim resulted in ERRNO(5)
Test 43-sim-a2_order%%015-00001 result:   FAILURE bpf_sim resulted in ERRNO(5)
Test 43-sim-a2_order%%016-00001 result:   FAILURE bpf_sim resulted in ERRNO(5)
Test 43-sim-a2_order%%017-00001 result:   FAILURE bpf_sim resulted in ERRNO(5)
Test 43-sim-a2_order%%018-00001 result:   FAILURE bpf_sim resulted in ERRNO(5)
Test 43-sim-a2_order%%019-00001 result:   FAILURE bpf_sim resulted in ERRNO(5)
Test 43-sim-a2_order%%020-00001 result:   FAILURE bpf_sim resulted in ERRNO(5)

私の悪い-私は要点を誤用しました。 テストに合格しています。 ふぅ:)

ハ! :)

私はちょうど間違って覚えていた考え出しので、私はそれに対してテストを実行したと思ったが、私はその時にたくさんので遊んでいました。 これを引き続き見てくれてありがとう、私はまだSELinuxと監査に少し行き詰まっていますが、カーネルは現在-rc5にあるので、マージの前に新しいコードに休憩を入れるとすぐに落ち着くと思います窓 ...

心配ない。 それは間違いなくより高い優先順位です。

私はあなたの要点をさまざまな非現実的なテストにかけてきました。 私はそれを壊すことができませんでしたが、私は今のところ_db_tree_prune()の断片を行使しているだけです。 変更に慣れてきましたが、もう少し時間をかけたいと思います。

私は_db_tree_prune()コードを突いて突っ込みましたが、それを破ることはできませんでした。 テスト08-sim-subtree_checksは、prune()内のほとんどのコードパスをテストするのに非常に役立ちます。

あなたの要点からの変更は行ってもいいと思います。

プルリクエスト#115を送信しました。 私はこれが転がる準備ができていると思います

これで解決するはずなので、終了します(上記の履歴を参照)。

このページは役に立ちましたか?
0 / 5 - 0 評価