strcpy_s()は、どのような点で安全なのでしょうか?

[戻る]
秋田の杉の子 2013/05/30(木) 08:27:39
Win7とVS2008です。

strcpy()を使おうとすると安全なstrcpy_s()を使うように奨められます。

そこで、書き直して使ってみます。 しかし、

int _tmain(int argc, _TCHAR* argv[])

{

     char msg[]="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbb";

     char tMsg[9];

     strcpy_s(tMsg, 6, msg);

     cout << "tMsg[]=" << tMsg << endl;

    return 0;

}

を実行すると、OSに途中で強制的に終了させられてしまいます。

ターゲットのサイズを6と指定してあるのだから、

tMsg[]="aaaaa\0";とコピーをして強制終了を避けることもできると

思うのですが、そうはならずダウンします。

strcpy_s()は、どのような点で安全なのでしょうか?

ホウジョウウサギ 2013/05/30(木) 09:44:09
strcpy_s()の機能(処理内容,というか,行われること)自体はstrcpy()と同じであって,

msgの位置〜'\0'までをtMsg以降の場所にコピー することであって,
msg[0]〜msg[5]までの(文字列の一部分)をtMsg以降の場所にコピー するわけではありま
せん.

_s とは,
strcpy( tMsg, msg );
とうっかり書いたら大問題なのに何も無かったように実行されてしまう(=危険!)ところを
実行時エラーを出してくれるという意味で「安全」ということだと思います.

tetrapod 2013/05/30(木) 11:19:54
追加フォローしておくなら
本来 strcpy_s は strcpy をさっくりそのまま置換すればよい、という関数だ。
# 例示してある3引数の strcpy_s は下請け。

ユーザーの書いたソースコード
 char str[N];
 strcpy(str, src); // バッファーオーバーフロー脆弱性を含みうる
があるとき、この strcpy を単純に strcpy_s に置換したコード
 char str[N];
 strcpy_s(str, src); // バッファーオーバーフロー脆弱性がない (即エラー終了)
は「安全」だ、ということ。

「安全」という単語に何を求めているのか?で話は違いそうだが、
Microsoft が strcpy_s を実装した際の方針は、たぶん以下のとおり。
・デバッグ中にバッファオーバーフロー脆弱性を検出する のが第一
・バッファオーバーフロー脆弱性をデバッグしきれずに市場に流出してしまったとき
 攻撃者が悪用しようとしてもプログラムが即時エラー終了する
 =悪用できないのだから安全、のが第二
・不完全な文字列で動作継続ができてしまうと別の脆弱性を引き起こす可能性がある
 =余計なことをせずにエラー終了すべきである
ということ。

部分文字列をコピーしたいのなら最初から strncpy (strncpy_s) を使うべし。

瀬戸っぷ [E-Mail] 2013/05/30(木) 11:24:44
既に回答されていますが…
「バッファサイズ渡しているんだからよろしく処理してくれる」ものではない…というこ
とです。
# というか勝手によろしく処理されても困るでしょう。

http://msdn.microsoft.com/ja-jp/library/td1esda9%28v=vs.80%29.aspx
より…
>strDestination または strSource が null ポインタの場合、またはコピー先文字列が
小さすぎる場合は、「パラメータの検証」に説明されているように、無効なパラメータ
ハンドラが呼び出されます。
例外投げるからプログラマ側で対応してくれ。
ということでしょう。
サイズが足りなかったから動的確保で大きいサイズで取得し直して再試行するなり、エ
ラーとして処理継続しないようにするなりのコードで対処してね♪
って事で。
# で、この例外を処理するコードがなかったから「OSに途中で強制的に終了させられ
て」いるのかと。

規定サイズより小さい範囲でコピーしてほしい。
とかなら別の標準関数もありますしね。

仲澤@失業者 2013/05/30(木) 11:52:18
詳しく解説すると犯罪者を助けてしまいますけど。
セキュリティ強化版「でない」関数で何ができるかというと、
バッファオーバーランなどをうまく利用すると、
スタックの内容を意図した値に書き換えたりできるわけですね。
この様なやり方で関数の戻り値や戻りアドレスを
上手にコントロールすると、悪意のあるコードを
実行できる可能性があるわけですね。

秋田の杉の子 2013/05/30(木) 20:56:58
[[解決]]
ホウジョウウサギさん、tetrapodさん、瀬戸っぷさん、仲澤@失業者さん

全部を理解できたわけではないのですが、ご回答に満足です。

皆様有難う御座いました。



tetrapod さんの回答は、「下請け」の意味が分からないことを除くと説得力がありまし
た。



瀬戸っぷさんの、

>>「バッファサイズ渡しているんだからよろしく処理してくれる」ものではない…とい
うことです。



わかりました。



>># というか勝手によろしく処理されても困るでしょう。



は、私、初心者のせいか、「勝手によろしく処理され」るとありがたいです。

「勝手によろしく処理されても困る」場合については、わかるような気もするのですが、

具体例が今頭に浮かびません。



MSDNの

>>無効なパラメータハンドラが呼び出されます。



って何のことかなーと思っていましたら、例外処理のことなんですね。あとで調べてみま
す。



皆様有難うございました。

tetrapod 2013/05/30(木) 21:31:31
我々末端プログラマが strcpy_s に期待している動作は
・文字列全部を正しくコピーし正常終了する
・バッファオーバーフローを検出して失敗する(異常終了する)
のどちらか。

「文字列の一部分だけコピーして正常終了したかのごとく振舞う」ではない。

もしそんなことをされたら
del *.old という文字列を strcpy_s のコピー元として与えたら、
コピー先では勝手に del * に変化し、そのことを知るすべが無いということになる。
これは明らかにダメ。

rm -fr ~/tmp → rm -fr ~/ とかでも同じだろうし
SELECT * FROM *** WHERE 後略 → SELECT * FROM *** とかでも同じ。

「下請け」の話は俺個人としては好きな内容なんだけどちょっと高度かもしれないので
今この発言では解説しないでおこう。
興味があるなら、いくらでも解説してあげられるので聞いてほしい。

bun 2013/05/31(金) 17:40:49
バッファオーバーランの話はどのみち全世界公開されてるので参考までに。

http://www.ipa.go.jp/security/awareness/vendor/programmingv1/b06.html

古いスレッドには追加発言できません。