84

と がとの安全な代替品として設計されたことを理解してstrlcpyいます。しかし、一部の人々は、自分は安全ではなく、単に別の種類の問題を引き起こすだけだと考えています。strlcatstrncpystrncat

strlcpyまたはstrlcat(つまり、常に文字列を null で終了する関数) を使用してセキュリティ上の問題が発生する可能性がある例を誰かが挙げることができますか?

Ulrich Drepper と James Antill は、これは正しいと述べていますが、例を提供したり、この点を明確にしたりすることはありません。

4

8 に答える 8

116

まず、strlcpyの安全なバージョンとして意図されたことはありませんstrncpy(また、 の安全なバージョンstrncpyとして意図されたことはありませんstrcpy)。この 2 つの機能はまったく無関係です。strncpyは、C 文字列 (つまり、null で終わる文字列) とはまったく関係のない関数です。名前にプレフィックスが含まれているという事実は、str...単なる歴史的な失敗です。の歴史と目的strncpyはよく知られており、十分に文書化されています。これは、Unix ファイル システムの一部の歴史的なバージョンで使用されている、いわゆる「固定幅」文字列 (C 文字列ではなく) を操作するために作成された関数です。今日、一部のプログラマーはその名前に混乱し、strncpy長さが制限された C 文字列のコピー機能 (の「安全な」兄弟) として何らかの形で機能するはずだと思い込んでいます。strcpy)、これは実際には完全にナンセンスであり、悪いプログラミング手法につながります。現在の形式の C 標準ライブラリには、制限された長さの C 文字列をコピーする機能がまったくありません。これがstrlcpy適合する場所です。strlcpy実際には、C 文字列を操作するために作成された真の制限された長さのコピー関数です。strlcpy限られた長さのコピー関数が行うべきすべてのことを正しく行います。残念ながら、それが標準ではないという唯一の批判があります。

第二に、strncat一方で、 は確かに C 文字列で動作し、制限された長さの連結を実行する関数です (実際には の「安全な」兄弟ですstrcat)。この関数を適切に使用するには、プログラマは特別な注意を払う必要があります。この関数が受け入れるサイズ パラメータは、実際には結果を受け取るバッファのサイズではなく、残りの部分 (ターミネータ文字も) のサイズであるからです。暗黙的にカウントされます)。そのサイズをバッファーのサイズに結び付けるために、プログラマーは追加の計算を実行することを覚えておく必要があるため、これは混乱を招く可能性がありますstrncatstrlcatこれらの問題に対処し、インターフェースを変更して、余分な計算が不要になるようにします (少なくとも呼び出しコードでは)。繰り返しますが、これを批判できる唯一の根拠は、関数が標準ではないということです。また、strcatグループの関数は、再スキャンに基づく文字列連結のアイデアそのものの使いやすさが限られているため、プロのコードではあまり見られないものです。

これらの機能がどのようにセキュリティ上の問題を引き起こす可能性があるかについては...単純にできません。C言語自体が「セキュリティの問題を引き起こす」可能性がある以上に、それらがセキュリティの問題を引き起こすことはありません。ご存知のように、かなり長い間、C++ 言語は Java の奇妙なフレーバーに発展する方向に移行しなければならないという強い感情がありました。この感情は C 言語の領域にも波及することがあり、C 言語の機能や C 標準ライブラリの機能に対する無知で強制的な批判が行われることがあります。この場合も、そのようなことを扱っているのではないかと思いますが、事態がそれほど悪くないことを願っています。

于 2010-01-22T04:43:35.793 に答える
32

Ulrich の批判は、プログラムによって検出されない文字列の切り捨てが、誤ったロジックによってセキュリティの問題につながる可能性があるという考えに基づいています。したがって、安全を確保するために、切り捨てをチェックする必要があります。文字列連結に対してこれを行うことは、次の行に沿ってチェックを行うことを意味します。

if (destlen + sourcelen > dest_maxlen)
{
    /* Bug out */
}

これでstrlcat、プログラマーが結果を確認することを覚えていれば、このチェックを効果的に行うことができます。したがって、安全に使用できます。

if (strlcat(dest, source, dest_bufferlen) >= dest_bufferlen)
{
    /* Bug out */
}

ウルリッヒのポイントは、持っdestlensourcelen回る(またはそれらを再計算する、これが効果的に行われる)必要があるため、とにかくstrlcatより効率的なものを使用するだけでよいということです。memcpy

if (destlen + sourcelen > dest_maxlen)
{
    goto error_out;
}
memcpy(dest + destlen, source, sourcelen + 1);
destlen += sourcelen;

(上記のコードでdest_maxlenは、 は格納できる文字列の最大長で、バッファ destのサイズよりも 1 小さい値です。は のフルサイズです)。destdest_bufferlendest buffer

于 2010-01-22T04:54:30.887 に答える
20

人々が「strcpy()は危険です。strncpy()代わりに使用してください」(またはstrcat()などについての同様のステートメントですが、ここでは焦点として使用strcpy()します) と言うとき、チェックインに境界がないことを意味しstrcpy()ます。したがって、文字列が長すぎるとバッファ オーバーランが発生します。それらは正しいです。このような場合に使用strncpy()すると、バッファ オーバーランを防ぐことができます。

strncpy()これは本当にバグを修正するものではないと感じています。優れたプログラマーであれば簡単に回避できる問題を解決するものです。

C プログラマーは、文字列をコピーする前にコピー先のサイズを知っておく必要があります。strncpy()それはとの最後のパラメータの仮定でもありstrlcpy()ます: それらにそのサイズを指定します。文字列をコピーする前に、ソースのサイズを知ることもできます。次に、宛先が十分に大きくない場合は、を呼び出さないstrcpy()でください。バッファを再割り当てするか、別のことをしてください。

なぜ私は好きではないのstrncpy()ですか?

  • strncpy()ほとんどの場合、これは悪い解決策です。文字列は予告なしに切り捨てられます。何らかの関数に決定させるのではなく、自分でこれを理解してから、実行したい一連のアクションを実行するための追加のコードを記述したいと思います。私は何をすべきかについて。
  • strncpy()非常に非効率的です。宛先バッファのすべてのバイトに書き込みます。'\0'目的地の最後に何千もの必要はありません。
  • '\0'宛先が十分に大きくない場合、終了は書き込まれません。したがって、とにかく自分で行う必要があります。これを行うことの複雑さは、面倒なことには値しません。

では、 に行きstrlcpy()ます。からの変更により改善されstrncpy()ていますが、 の特定の動作がstrl*それらの存在を正当化するかどうかはわかりません。目的のサイズを知る必要があります。strncpy()宛先のすべてのバイトに必ずしも書き込むとは限らないため、より効率的です。しかし、次のようにすることで解決できる問題を解決します*((char *)mempcpy(dst, src, n)) = 0;

たとえば、文字列の一部ではなく完全な文字列が書き込まれると予想される場合など、バグが発生する可能性があると彼ら (および私) が言っていることは、セキュリティの問題につながる可能性がstrlcpy()あると言っているとは思いません。strlcat()

ここでの主な問題は、コピーするバイト数は? プログラマーはこれを知っている必要があり、彼が知らない場合、strncpy()またはstrlcpy()彼を救わない場合。

strlcpy()strlcat()ISO C でも POSIX でもなく、標準ではありません。したがって、移植可能なプログラムでそれらを使用することは不可能です。実際、 にstrlcat()は 2 つの異なるバリアントがあります。Solaris の実装は、長さ 0 を含むエッジ ケースに対して他の実装とは異なります。

于 2010-01-22T04:54:11.573 に答える
12

ウルリッヒ達は、それが誤った安心感を与えると考えていると思います。誤って文字列を切り詰めると、コードの他の部分にセキュリティ上の影響が及ぶ可能性があります (たとえば、ファイル システム パスが切り捨てられた場合、プログラムは目的のファイルに対して操作を実行していない可能性があります)。

于 2010-01-22T05:50:52.017 に答える
7

strl 関数の使用に関連する 2 つの「問題」があります。

  1. 切り捨てを避けるために、戻り値をチェックする必要があります。

c1x 標準の草稿作成者と Drepper は、プログラマーが戻り値をチェックしないと主張しています。_TRUNCATEDrepper は、どうにかして長さを知り、memcpy を使用し、文字列関数を完全に回避する必要があると述べています。標準化委員会は、フラグで特に明記されていない限り、安全な strcpy は切り捨て時にゼロ以外を返す必要があると主張しています。アイデアは、人々が if(strncpy_s(...)) を使用する可能性が高いということです。

  1. 文字列以外には使用できません。

一部の人々は、偽のデータが供給された場合でも文字列関数がクラッシュすることはないと考えています。これは、通常の状態では segfault になる strlen などの標準関数に影響します。新しい標準には、そのような機能が多数含まれます。もちろん、チェックにはパフォーマンスのペナルティがあります。

提案された標準関数の利点は、 strl関数でどれだけのデータを逃したかを知ることができることです。

于 2010-01-22T04:55:15.597 に答える
6
于 2016-06-26T05:27:13.013 に答える