iOS7.0.6で修正された「最悪のセキュリティバグ」はありがちなコーディングミスで発生していた 172
お手本のようなコーディングミス 部門より
Appleが先日公開したiOS 7.0.6では、「過去最悪のセキュリティバグ」が修正されているという(アプリオ)。
SSL/TLSの不適切な扱いにより、データが暗号化されない場合があり、これにより通信内容が盗聴されるおそれがあるようだ。
現在利用中の環境にこのバグがあるかどうかは、gotofail.comというサイトで確認できる模様。
興味深いのが、このバグの要因とされているコードだ。SSLで使われる暗号鍵の検証を行うコードにバグがあったとのことなのだが、その途中で以下のように「goto」文が続いているミスがあったという(ImperialViolet - Apple's SSL/TLS bug)。
static OSStatus
SSLVerifySignedServerKeyExchange(SSLContext *ctx, bool isRsa, SSLBuffer signedParams,
uint8_t *signature, UInt16 signatureLen)
{
OSStatus err;
...
if ((err = SSLHashSHA1.update(&hashCtx, &serverRandom)) != 0)
goto fail;
if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
goto fail;
goto fail;
if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0)
goto fail;
...
fail:
SSLFreeBuffer(&signedHashes);
SSLFreeBuffer(&hashCtx);
return err;
}
コード全文は修正後のコードを見てほしいが、このように「goto fail;」が2行続いたことで途中の検証作業が飛ばされてしまい、その結果本来エラーとなるケースでエラーにならない、という問題が発生している模様。
格好つけずに括弧つけろよ (スコア:5, おもしろおかしい)
処理が1行だからといって、if文で格好つけるのはやめましょう。
Re:格好つけずに括弧つけろよ (スコア:2)
lisp神の守護を受けていればこんな事にはならなかった
C/C++はBSD/オールマン・スタイルで書いてます
Re:格好つけずに括弧つけろよ (スコア:1)
Python教徒がアップを始めました
Re:格好つけずに括弧つけろよ (スコア:1)
意図と違ったコードになってることには気づきやすい!はず!
# ちょっとだけ必死
Re:格好つけずに括弧つけろよ (スコア:2)
もしかして:括弧 というより、『gotoなしで else if連鎖にすると』の間違い? コード例的に。
Re:格好つけずに括弧つけろよ (スコア:1)
条件式の後に単文を実行する場合はブレースを付けないコーディング規約なのかも知れません。
私はかつて、最初にプログラマとして勤めた職場が「ブレース省略禁止」で叩き込まれたこともあり、ブレース省略の利点がさっぱりわからない(こういうバグを生む)のですが、なぜか「単文ではブレース省略」とする規約は見たことがあります。
Re:格好つけずに括弧つけろよ (スコア:2)
不要なコードは書くな主義かな。
ソースコードのサイズを制限したいとか
#そういう時代もあったんです
あるいはK&Rスタイルに沿っているつもりとか。
単文にはそもそも中括弧は不要だからでしょう。
つまり「省略」じゃない。
Syntax Sugarの一種で水増しだといわれても仕方がない面があるから。
IFの実行部は必ずブロックにしろ、単文は使うなってのは30年以上前から言われてますけどね。
Re:格好つけずに括弧つけろよ (スコア:2)
> 以下のプログラムのPOINT2は絶対に実行されない。
それは誰でもわかってるだろ。
#2550906のプログラムと違うだろう。
Re:格好つけずに括弧つけろよ (スコア:1)
> 戻り値がboolだから条件判断を省略するとか
いやむしろそれは正しい気がする。
逆に条件句で整数が入るケースが気色悪い。
if(1) みたいな。
Re:格好つけずに括弧つけろよ (スコア:2)
K&Rから入ったせいか(i != 0)を(i)と書かないと冗長に見えて落ち着かないんです。
Re:格好つけずに括弧つけろよ (スコア:1)
↑は多用するけど、
↑はあまり好きじゃないです。
他人が書いてるのは見て見ぬふりをするけど、自分で書くときは前者のスタイルで書きます。
Re:格好つけずに括弧つけろよ (スコア:1)
私なら何を判定しているのか自分以外(未来の自分含む)の人にもすぐ理解してもらうために省略せず後者の書き方をします。
テストしてねーの? (スコア:3, すばらしい洞察)
OSのクセにこれぐらいのバグも検出できないぐらいテスト項目が粗い、ということがわかった。
他の機能も危なそうだな。
Re: (スコア:0)
検証コードを書いた人も実行してないっぽいですね。
/* FIXME: can this line be removed? */
あるあるすぎる。
これぐらいで「過去最悪」とは片腹痛い (スコア:2)
証券会社は不適切なワンクリックで破産したりする
https://www.google.co.jp/search?q= [google.co.jp]誤発注
ジェイコムのより桁が2つ違う
https://www.google.co.jp/search?q= [google.co.jp]俺はバグでこんなすごい被害を出したぞ
も怖い
Re: (スコア:0)
過去最悪かどうかはわからないが、近年で見ると最悪レベルだと思う。
つまり、ネットバンクやSNSなんかをSSLで使ってる人は多いと思うが、iOS/Macを使っている人の場合は、MITM攻撃で情報を盗み見できる状態にあったってことだ。
iPhone/iPad/Macはローカルだけで使ってください、という話になるよ。
これを最悪といわずに、なんという。
だからAppleにしては珍しく、前倒しして早めに修正パッチをリリースしたわけで。
Re:これぐらいで「過去最悪」とは片腹痛い (スコア:1)
私は apple製品を使う人間は
馬鹿か自殺志願者
と思っています。
あそこは何ひとつテストしませんからね。
そもそもテストどころか動作すらしないものえを発売するところですし。(動作しないんだからテストもできるわけがない)
http://internet.watch.impress.co.jp/cda/news/2007/09/28/17017.html [impress.co.jp]
大事な事なので二度書きました (スコア:2)
しっかり下まで落とせるわけだ。
修正後のコード (スコア:2)
>>コード全文は修正後のコードを見てほしいが
これって件の問題が修正されたものなの?
全く、これだからgotoは (スコア:1)
#本名ぶっぱなのでAC
ヨシ、さっそく営業だ! (スコア:1)
静的コード解析ツールを扱っている営業マンがApple本社に集まってきたりして。
このパターンだと確実にツールに指摘されるところだが、Appleほどの会社がまだ使っていないのかなぁ?
コピペしてるうちにgotoの行が増えちゃった (スコア:1)
多分コピペが原因だろうね。
経験上コピペがバグの原因になる可能性は高いから(俺も含めて)みんな気をつけよう!
コピペしたら中身の修正漏れはないか、余計に(または少なく)行をコピってないか
そもそもコピペをせずに関数化するかを慎重に確認しないとね(俺が…)。
unreachable codeの警告は無視されたのか (スコア:0)
警告を無視しちゃいかんという教訓を得たと。
こんな感じに、if分を一行にまとめてしまえば、こんな不具合出なかった気がします。
if ((err = SSLHashSHA1.update(&hashCtx, &serverRandom)) != 0) goto fail;
if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0) goto fail;
if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0) goto fail;
一行が長くなるのを嫌ったのかな?
Re:unreachable codeの警告は無視されたのか (スコア:3, すばらしい洞察)
一行にまとめるコーディングは嫌いですし、職業プログラマーはあまり使うべきではないとも思っています。
なので対処はif分の処理が1行でも必ず括弧で括る事です。
Re:unreachable codeの警告は無視されたのか (スコア:1)
そうですね。
どっちにしろ2行以上あれば必ず括弧が必要な訳だし、if文書いたら脊髄反射で{}を書いてしまうくらいでちょうどいいです。
Re:unreachable codeの警告は無視されたのか (スコア:1)
スタイルの問題ではないでしょこれは。
こういう重要な箇所くらいテストで100%のカバレッジを確保しろよと。
どーでもいいとこに心血注ぐ必要はないけどさ。
Re:unreachable codeの警告は無視されたのか (スコア:1)
unreachable codeの検出は、停止性問題と同じなんで、goto文みたいな自由度の高い構文ではうまく動かないんじゃないのかね。
それ以前にgccもclangもgotoの警告はやる気ないから
Re: (スコア:0)
#define ErrorCheck(f) do { if ((err = f) != 0) goto fail; } while (0)
ErrorCheck(SSLHashSHA1.update(&hashCtx, &serverRandom));
ErrorCheck(SSLHashSHA1.update(&hashCtx, &signedParams));
ErrorCheck(SSLHashSHA1.final(&hashCtx, &hashOut));
ってやりたくなるんだけど、ダメ?
Re:unreachable codeの警告は無視されたのか (スコア:3)
マクロをdo-while(0)で囲むワケ
http://d.hatena.ne.jp/ryochack/20111022/1319252481 [hatena.ne.jp]
Re:unreachable codeの警告は無視されたのか (スコア:1)
マクロ関数を普通の関数のように最後に ; を付けて適切に展開されるようにするため。
do while (0) なしだと
if ()
ErrorCheck(...);
else
ErrorCheck(...);
が
if ()
{ ... };
else
{ ... };
となり、 if の終わりの {} の後の ; が空文となるので、 else の行で文法エラーとなる。
do while (0) ありだと
if ()
ErrorCheck(...);
else
ErrorCheck(...);
が
if ()
do { ... } while (0);
else
do { ... } while (0);
と、 if と else が適切に対応する形になるよう展開される。
Re:unreachable codeの警告は無視されたのか (スコア:3, 参考になる)
それは潜在的に危険なコードです。
ErrorCheck()を使う側で、以下ようなコードを書くと、
この見た目と違って、実際のマクロ展開は(改行と字下げを付けると)、
となり、「処理B」が「条件A」のelse部でなく、「(err = ...) != 0」のelse部にくっついてしまいます。
else節は最も近いif文にくっつくという構文規則になっているので、 マクロにelse節無しの剥き出しのif文を埋め込むのは危険なのです。
do〜while(0)で囲めば、このような副作用が無くなるので、より安全なマクロ定義となります。
関数ポインタ (スコア:1)
"."が使われている場合でも、C++のメンバ関数ではなく
構造体のメンバに関数ポインタがあり、それを呼び出しているだけの可能性もあるので
呼び出し側だけではC++noコードだとは判断が付きません。
その構造体の定義は見つける前にGive upしましたが、関数ポインタをメンバに持つ似たような構造体定義は同じディレクトリの
sslTypes.h [apple.com]の下の方にもあります。
Re:unreachable codeの警告は無視されたのか (スコア:4, おもしろおかしい)
今回はかっこつけてないから発生したバグですよ。
failに行くのにエラーにならない!? (スコア:0)
goto fail;で、全部エラーに飛ぶように見えるんだけど、違うの。
goto successじゃないよね?
Re:failに行くのにエラーにならない!? (スコア:1)
> goto fail;で、全部エラーに飛ぶように見えるんだけど、違うの。
goto fail なんだけど err になにも入ってないで帰るんでしょ。
うまく考えて書いたんだろうけど、読みにくい人がいるんでデバッグに向いてないし、バグを生む。
Re:failに行くのにエラーにならない!? (スコア:1)
実はfailじゃなくてfainal、そう、実はfinalのTypoだったんだよ!(ねーよ
Re:failに行くのにエラーにならない!? (スコア:1)
無駄な値で初期化せず、
(もしロジックに誤りがあった場合に)コンパイラに未初期化変数の使用の警告をさせることを望みたいですねえ。
そういう意味では別ツリーのコーディング規約で括弧を付けろ、よりもコンパイラにunreachable codeの検出をして欲しかった。
人間が頑張ったって限界があるし。
必ずfailへ行くのに? (スコア:0)
エラーにならんの?
どういうこと?
Re: (スコア:0)
とよく読み直したらerrが0になっててそれをそのまま返してるからか。
Re:goto文 (スコア:2)
某、try{} catch{}的に使うのは 結構多用してますが、なんだかなあ、という気にはなりますよねえ。
goto considerd harmful論争? (スコア:2)
強力すぎる(ブロックの中に飛んだり)
制御フローをぶっちするのでわかりにくく間違いの元
ということで使うな論があった。
Cの制御文の貧弱さゆえに使わざるを得ない、もしくは使ったほうがいい場合にのみ使えということになった。
#continue文もなあ、対応間違いとかあるし
Re:gotoを久しぶりに見た (スコア:1)
久しぶりだからはしゃいでいるんでしょうねえ。賑わってて何よりです。ふだんはgotoを禁則事項とされている人が大多数なんじゃないかと。
Re:gotoを久しぶりに見た (スコア:1)
「構造化プログラミングではgoto禁止」の原理主義にはまり込む流れ
step1 とりあえずgoto禁止
step2 後始末は一箇所にまとめたい
step3 変数の使用と後始末の場所が離れてるのがイヤ
step4 break って、結局gotoだよなと気づき、goto禁止主義と撤回
結局、gotoを使う方がシンプルで読みやすいって結論になる。
使って言いgotoと使ったらダメなgotoをコーディングルールで縛るのが難しいのが欠点かなぁ。
#step3のテクニックで、try~catchっぽくするマクロを見た覚えがあるんですが、今探したら見つけられなかった…
確か、do while(0) と switch とで二重にくるんで、break →switch脱出、continue→do while 脱出と、二種類の似非gotoを使い分けてた覚えがある。
Re:gotoを久しぶりに見た (スコア:2)
こんな感じですかね。
#switch (0) { default: xxxx } って構文初めて見た
Re:gotoを久しぶりに見た (スコア:2)
あらダメだ、THROWマクロにbreakは使えない
Re:gotoを久しぶりに見た (スコア:2)
Re:gotoを久しぶりに見た (スコア:2)
よく見られた書き方ですね。
IDEないから正常処理をわかりやすくとか、
#上から下一直線
修正忘れがあるから同じ処理を別々に書くなを重視しエラー処理をまとめるとこういうスタイルになる。
別コメにあったけどfinally無いからこうせざるを得ない。
Re:goto 使う派 (スコア:2)
本来なら例外を使うべきところを、効率が求められるOS内コードなので goto で代用した、と考えると納得がいく気がします。
例外機能のありがたみがわかる事例 (スコア:1)
.cみたいなのでこのコードはC++ではなくCなのではないかと思います。
そうすると例外機能がないので。
自分で確認はしてないですが、コメントに「同じディレクトリに.cppのファイル」があるという話なようですね。
とすればプロジェクトは(恐らく)C++ も使える環境なんだろうと思うので
何故このコードがCでないといけないのか不思議には思いますが…。
C++である場合、例外の実装ではオーバーヘッドは主に投げる時に発生し、
投げない時には極力発生しないように工夫されているという話なので
チェックが失敗したときに少し遅くなる程度はそれほど問題にならない気もしなくはないです。
(失敗した場合、それよりうしろのチェックの処理時間はなくなるわけだし。)
参考: 「C++オブジェクトモデル―内部メカニズムの詳細 」 [amazon.co.jp](S.B. リップマン 著)の7.2節
Re:例外機能のありがたみがわかる事例 (スコア:1)
その後、ディレクトリを眺めましたが殆どが.cと.hであり、.cppはごく少数にとどまるので、
どうやら基本的にCで書かれ、C++からも呼び出せるようになっているということなのかなと思います。
#検索できないので詳細を追うのは諦めました。