web-dev-qa-db-ja.com

valgrindの下で実行するとsetrlimitが失敗し、操作は許可されません

何か不足している可能性がありますが、ない場合がありますが、valgrindの下で実行すると、setrlimit関数が一貫して失敗します

int main()
{
        const struct rlimit file_limits = { .rlim_cur = 65536, .rlim_max = 65536 };
        if ( setrlimit( RLIMIT_NOFILE, &file_limits ) )
        {
                printf(" Failed  %d", errno );
                perror(" More " );
        }
        else
        {
                printf(" Success ");
        }
        printf("\n");
        return 0;
}

ここにサンプルの実行があります

通常の実行

sh-4.2# ulimit -H -n
800000
sh-4.2# ulimit -S -n
500000
sh-4.2# ./rlimit
 Success
sh-4.2#

valgrindの下

sh-4.2#
sh-4.2# valgrind ./rlimit
==28974== Memcheck, a memory error detector
==28974== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==28974== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==28974== Command: ./rlimit
==28974==
 More : Operation not permitted
 Failed  1
==28974==
==28974== HEAP SUMMARY:
==28974==     in use at exit: 0 bytes in 0 blocks
==28974==   total heap usage: 1 allocs, 1 frees, 568 bytes allocated
==28974==
==28974== All heap blocks were freed -- no leaks are possible
==28974==
==28974== For counts of detected and suppressed errors, rerun with: -v
==28974== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
sh-4.2#

これに関するヒントがあればすばらしいでしょう。 注:これはCentOSリリース7.4(最終)にあります。

編集#1

最小限の作業コードで:

int main()
{
        const struct rlimit file_limits = { .rlim_cur = 65536, .rlim_max = 65536 };
        setrlimit( RLIMIT_NOFILE, &file_limits ) ;
        perror(" wrong ?? " );
        printf("\n");
        return 0;
}

対応する出力:

[root@localhost kk]# valgrind ./rlimit
==29179== Memcheck, a memory error detector
==29179== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==29179== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==29179== Command: ./rlimit
==29179==
 wrong ?? : Operation not permitted

==29179==
==29179== HEAP SUMMARY:
==29179==     in use at exit: 0 bytes in 0 blocks
==29179==   total heap usage: 1 allocs, 1 frees, 568 bytes allocated
==29179==
==29179== All heap blocks were freed -- no leaks are possible
==29179==
==29179== For counts of detected and suppressed errors, rerun with: -v
==29179== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
[root@localhost kk]# ./rlimit
 wrong ?? : Success

これ間違い?? :操作は許可されていませんが私を狂わせています:(

#2を編集

だからいくつかの提案に基づいて、私は既存の制限を取得してそれに何か問題があるかどうかを確認しようとしましたが、私の理解を超えた動作が判明しました

int main()
{
        const struct rlimit file_limits = { .rlim_cur = 65536, .rlim_max = 65536 };
        struct rlimit limit;
        getrlimit(RLIMIT_NOFILE,&limit);
        printf("%d \n",limit.rlim_max);

        setrlimit( RLIMIT_NOFILE, &file_limits ) ;
        perror(" wrong ?? " );
        printf("\n");

        getrlimit(RLIMIT_NOFILE,&limit);
        printf("%d \n",limit.rlim_max);
        return 0;
}

最初の実行、制限は65590に設定され、実行可能ファイルは制限を65536に変更できます。

[root@localhost kk]# ulimit -n
65590
[root@localhost kk]# ./rlimit
65590
 wrong ?? : Success

65536
[root@localhost kk]#

valgrindの下での2回目の実行

[root@localhost kk]# ulimit -n
65590
[root@localhost kk]# valgrind ./rlimit
==17595== Memcheck, a memory error detector
==17595== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==17595== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==17595== Command: ./rlimit
==17595==
65578
 wrong ?? : Operation not permitted

65578
==17595==
==17595== HEAP SUMMARY:
==17595==     in use at exit: 0 bytes in 0 blocks
==17595==   total heap usage: 1 allocs, 1 frees, 568 bytes allocated
==17595==
==17595== All heap blocks were freed -- no leaks are possible
==17595==
==17595== For counts of detected and suppressed errors, rerun with: -v
==17595== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
[root@localhost kk]#

私はおそらくvalgrindがその使用のためにいくつかのファイル記述子を予約しているかもしれないと言う傾向があります ここでの議論に基づいて この場合それを12としましょうか?したがって、制限を65578に設定しますか?これは、プログラムが65536を予約しようとしているものを超えています。

従うべき他の提案?

14
u__

Valgrindは、fd 0 .. hard_limitの許容範囲のうち、独自の目的のために範囲の最後、つまり範囲hard_limit-11 .. hard_limitでfdのセットを予約し、hard_limit-12である新しいハード制限をシミュレートします。

次に、ゲストアプリケーションがこの(シミュレートされた)ハード制限を変更することを禁止します。以下は、setrlimitシミュレーションを処理するコードです。

 if (((struct vki_rlimit *)(Addr)ARG2)->rlim_cur > VG_(fd_hard_limit) ||
      ((struct vki_rlimit *)(Addr)ARG2)->rlim_max != VG_(fd_hard_limit)) {
     SET_STATUS_Failure( VKI_EPERM );
  }

ご覧のように、指定されたrlim_maxがシミュレートされたVG_(fd_hard_limit)と異なる場合、valgrindはsetrlimitを失敗させます。受け入れられると、valgrindはシミュレートされたソフトリミットを変更します。

上記のコードがハードの下限を受け入れず、シミュレートしたVG_(fd_hard_limit)に設定する理由を理解できません。これは、このVG_(fd_hard_limit)がvalgrindによって使用され、valgrind予約済みfdsとゲストfdsの違いを見つけるためだと思います。

問題を回避するには、制限を取得し、ハード制限の変更はvalgrind setrlimitシミュレーションによって拒否されるため、ハード制限より下のソフト制限のみを変更する必要があります。

3
phd

これはValgrindの制限の1つ、つまりValgrindで実行した場合のハードリミットのsetrlimitの制限のようです。参照 リリース2.1.2のニュース

  • 現在の予約領域に加えて、ファイル記述子のエミュレートされたソフト制限を実装します。これは、ハード制限として効果的に機能します。 setrlimitシステムコールは、エミュレートされた制限を可能な限り最適に更新するようになりました。ハード制限はまったく移動できず、変更しようとするとEPERMが返されます。これにより、valgrindが予約領域から記述子を割り当てようとしたときに、アサーションを引き起こすソフト制限の削減が停止します。 (これは実際にはバグ#83998からのものです)。

このValgrindの制限に当てはまるのはあなただけではないことに注意してください。たとえば github issue を参照してください。

0
ks1322