20年前のバグ報告
春の推理2024参加作品
ちょっと専門的な内容ですが、なろう読者には通じる人はいるのではと思い書いてみました。
ただ、あまり詳細に仕掛けを書くと、難解になりすぎるので、多少加減しています。雰囲気だけ味わっていただければ幸いです。
その日、Kシステム社の、通信システム4課のグループメールに不審なメールが届いた。
「A百貨店のPOSシステムには致命的なバクがある。リミットは2024年5月。至急調査されたし」
送り先は見るからに捨てアドレスだ。イタズラだと思いたい反面、実際に4課はA百貨店のシステムを担当しているので無視も出来ない。
差出人は内部の人間か、もしくは退職者の可能性もある。
「もう20年以上年保守しているシステムだ。関わった人間なんて山ほどいるよ。それにグループアドレスなんて社員であれば分かるだろ。そうなると犯人は、とても絞り切れるもんじゃない」
井田課長が言う。
彼は、一応上に報告した後『適切な方針を決めて対応するように』との、有難い指示を拝命していた。
「犯人探しは諦めましょう。仮に社員全員と退職者全員捕まえて面談したところで、話すことがありません。『お前か?』『違います』で話が終わります。無駄な工数ですよ」
4課のエース格である新井が、プログラマらしい見解を言った。
「そりゃそうだな。じゃあ、どうする?」
井田の言を受けて新井は席を立ち、ホワイトボードの前に立った。
「案1は何もしないこと。イタズラと断定することですね」
新井は板書しながら話す。
「それは無いな。多分、そう報告したら『イタズラと断定する根拠を示せ』と言われるだろう」
即座に井田が反応した。
「案2は警察に任せる」
「それも無いな。これだけじゃ世に溢れる迷惑メールと区別が出来ない。それに内容も親切に『バグがある』と言われているだけで、なんの脅迫もされていない。まぁ、形だけ届けて終わりにする手もあるはあるが・・・」
「上が納得しない?」
「ああ」
井田は缶コーヒーをグビリと飲んで、腕を組み、椅子の背もたれにもたれて大きく背伸びをした。
「じゃあ、案3は調査するしかないですね」
新井がそう言うと、ミーティングに参加している4課のメンバーはゲンナリとした顔をした。
20年以上も使われているプログラムは、もはや誰も全容が分からない。
何世代にも渡り、様々な担当者が変更を加えているので構造が複雑怪奇なのだ。
プログラムを読んで『風が吹く』処理だと思って動かしてみたら、実際は『桶屋が儲かる』処理だったなんてことが往々にしてある。
更に別の所では、桶屋が儲かれば宇宙戦争が勃発するような処理が動いていたりするから、もう手に負えない。
また、今ではあまり使われなくなったC言語という言語でプログラムが書かれているのも厄介だ。
この言語はコンピュータの細部にまで命令できる分、部分的にプログラムを読んでも意図が非常に分かりにくい。
人間で例えるなら、『歩け』とか『脚を上げろ』という命令ではなく『右大腿四頭筋を収縮させろ』というような命令でプログラムが構成されているのだ。
C言語は20年前は主流だったのだが、もっと簡易で安全な言語が増えた今は主流ではなく、精通したエンジニアも減ってきている。
「どうやって調査するよ・・・」
井田はため息をつく。
「そもそも課長は、バグがあると思いますか?」
新井が聞いた。
「まぁ人が作ったシステムだからな。。何かしらのバグがあることは考えられるが、随分枯れたシステムだ。もう致命的なものはそうそう無いだろうとは思うが。。」
井田の意見に、会議人参加したメンバー全員が頷く。
「ならば、上が納得する理由を作る目的で調査すればいいんじゃないですか?」
そう言って、新井はいくつか調査方針を板書した。
①「2024」「5」「may」等の文字列でソースコードを検索して怪しい箇所が無いか見直す
②「date」「year」等の日付処理の関数名になりそうな文字列で検索して怪しい箇所が無いか見直す
③テスト環境の日付を変えて2024年5月にし、主要な処理を行ってみる
「ざっくりですが、これぐらいやれば『調べたけど問題ありません』と言えるかと。それでダメと言われたら、言った人から具体的な指示を貰いましょう」
「それしかないか・・・」
井田は頷くつつも、何かを考えながらホワイトボードの文字を見た。
「『怪しい箇所』はどうする?なんとなく眺めるってわけにも行かないだろ」
「『メモリ破壊をしてないか?』の調査でいいんじゃなですか。C言語のプログラムの『致命的なバグ』ならば」
新井がその質問は想定済みとばかりに答えた。
C言語は、今時の言語なら制限が掛かって出来ないことが出来てしまう。人で例えるなら脳の重要な記憶まで簡単に書き換えてしまうことが出来るのだ。『小学生の頃の記憶を消せ』とか『自転車の乗り方を忘れろ』なんてことまで出来てしまう。
こういう、壊してはいけない記憶を壊してしまうことを『メモリ破壊』と呼んでいる。
「そうだな。。。それでいこう」
井田は決断を下した。
そして、調査の担当者を決め、調査方針を誰でも出来るように更に詳細なポイントを決めて会議は解散し、実働に入った。
作業は3日を呈して行われた。
井田の予想通り、結局、ソースコードの確認でも実機の調査でも問題は発覚しなかった。
調査が終了し、本件が一旦クローズとなった翌日。
新井は社長室に呼ばれていた。
社長室は意外に簡素な部屋で、社長用のデスクとPC、打ち合わせ用のモニタとホワイトボード、後は本棚ぐらいしかなかった。
「メール報告ありがとうございます」
田中社長が言った。
そして、自身のPCの画面を大型モニタに映す。そこには新井が出したメールが表示されている。
ーーーーーーーーーーーーーーー
田中社長
お疲れ様です。
ご懸念のA社POSシステムの件、現行システムでは顕著化しませんので、ご安心ください。
概要は添付資料にまとめてあります。
必要であれば詳しく説明に伺います。
通信システム4課 新井
ーーーーーーーーーーーーーーー
「詳細はどこまで分かっていますか?」
社長が聞いた。新井は一瞬質問の意図を考えてから口を開いた。
「まず、現象ですが、問題の処理が働いた場合、2024年5月10日にA百貨店で商品を購入すると、レシート末尾にこれが表示されます」
そう言って新井は、現象を再現させて出力したレシートを提示した。
そこには、次のように書かれていた。
ーーーーーーーーーー
Kシステムはブラック企業
詳しくはこちらまで!
http://xxx.xxx.xxx
ーーーーーーーーーー
新井は続けて説明する。
「本来キャンペーン内容を表示する部分ですが、そこに巧妙に割り込むようなプログラムが忍ばせてありました。しかし、現在はインボイス制度対応を機にレシート出力処理を作り替えてるので、問題の処理があるプログラムそのものが使われなくなっています」
新井は社長の様子を見ながら、あえて感情を入れずに淡々と話した。
社長はアゴに手を当てて、二度三度頷き、『そうか、インボイスか・・』と呟いた。
「しかし、どうやって分かったんですか?井田君の報告には、これは載っていなかった。あなたも井田君のチームで、調査方針もあなたの提案と聞いていますが」
問題無しと確信して安堵したのか、社長の質問は興味のそれになっていた。
「課長に提案したのは『バグを調査する』観点ですから。でも、これはバグじゃない。『誰かがバレないように仕組んだプログラム』です。むしろバグを見つけるより簡単でしたよ」
「ほう」
社長は前のめりになる。
「わが社の開発環境でバレないようにするにはどうするか?と考えればヒントはいくらでもあります」
「例えば?」
「ウチの品質保証部門は、テスト環境では徹底的に品質検査をします。だから、そもそもテスト環境では起きないように仕込むでしょう」
「なるほど」
「それに、20年以上前とはいえ、既に開発環境はwindows2000ですよね。本件の調査でやった文字列検索なんて、誰でも手軽に出来ました。だから検索で簡単に発覚するような処理にするワケがない」
新井の説明に社長は一々大きく頷く。
「テスト環境で発覚せず、プログラムを見てもパッとは分からないのであれば、通信データの中身かな?と当たりをつけました。そうしたら見つけました。特定の条件下でサーバーから送る通信データを故意に間違えたように作っている部分を」
新井はニヤリと笑ってホワイトボードに文章を書いた。
毎週木曜は○○デー!
詳しくはこちらまで!
「元々はこんな文章が書かれている文字列の領域に、部分的に別の文字列を上書きしてありました。だから、プログラムだけ見ても気付きにくい。文字列コピー処理なんて担当者以外まともに読みませんからね。そして元々プログラムにある文字列を使って切り貼りしているので、修正プログラムをチェックインする時に差分を取っても怪しいテキストは出てこない」
新井は、あえて普通なら経営者にしないような、専門的な話をした。社長が現場上がりというのは周知のことではあるが、別の意図もある。
「2024年5月という日付自体には深い意味は無いのでしょう。通信データに含まれるキャンペーン開始日を『自然に間違う為』に適当なデータをコピーした結果かと。意味が無いものほど調査では見つけにくいものです」
新井はそこまで説明すると、言葉を切って社長の反応を待った。
「素晴らしい」
社長が言った。
「本当に素晴らしい。優秀なエンジニアはプログラムのロジックだけでなく、人の心理まで分析するものなんですね。さて・・・」
そこで社長は一旦、言葉を切った。
「このプログラムの作成者は分かりましたか?」
社長はじっと新井の目を見た。
「証拠はありません」
新井はまず即答する。そして続けた。
「当時は担当者や変更歴の管理が杜撰だったようで、作成者を特定する情報は残っていませんでした。ただ、プログラムの書き方というのはクセが出ますから、なんとなくは分かりますけどね。。」
新井は、あえて濁した。
社長は軽く笑って『ふむ』と頷いた。
「井田君や4課のメンバーに謝った方がいいかな?」
社長が言った。
「その必要は無いと思います。証拠も無いですし、そもそも彼らは、たいした苦労はしてません。むしろプログラムの内部構造を勉強し直すいい機会になったんじゃないですかね?時々こういうのやったら社員教育にいいかもしれませんよ」
新井はさらりと言い放つ。
「君にそう言われたら何も言えないな・・」
社長は苦笑いをするしかなかった。
「それに、私は面白かったです。噂に聞いてた昔の様子も垣間見れましたし」
「ああ」
社長は遠い目をした。
「当時は本当にブラックだった。。ストレス発散にイタズラしたくなるぐらいにね。まさか、あのシステムが20年以上現役で、自分が社長やるなんて、思ってもいなかったな」
社長は、椅子の背もたれに大きくもたれかかった。
それを見て、新井は今日一番伝えたかったことを言った。
「おかげ様で、今は随分働きやすい会社になってますよ」
お読みいただき、ありがとうございます。
--------ここからは分かる人だけ--------
一応、仕掛けや背景はこんな感じで考えていました。
・本番機のホスト名かIPアドレスを取ってきて環境のエラーチェックをするような処理にトリガーを忍ばせる
・キャンペーンデータは実施日と表示内容をまとめたレコードになっており、複数レコードがまとめてサーバーから各端末に送られる。送られたレコードデータは端末にストックされ、実施日を端末側で判定してレシートに内容が表示される。
・そのレコード作成処理が、無駄に凝ったデータ構造になっており非常に難解だった。それを利用して(誰も詳しく読みたくない処理だから)レコードの末に問題のレコードを追加する処理を忍ばせた
・現象が発生するのは端末だが、端末側のプログラムには何も悪い処理は無いので端末のプログラムを調べても問題は出てこない
・日付はソース中はこんな感じで書きつつ、rec_ptrはIDでは無く日付を指している。(IDは日付にコピーして機能する物から適当に選んだだけ)
/*IDセット*/
memcpy(rec_ptr, ID, ID_SIZE)
・本番環境機で問題の日付にならない限り現象が発生しないので、プログラムを詳細に読めないと発覚しにくい
・当時の品質保証部はプログラム知識は少なく、ひたすら実機確認をする方針だった。その(プログラム知識の無い)部署にいつもバグを指摘され、怒られているので「お前らにこれは見つけられないだろ!」という反感の意味もあった
・ブラック企業の『ブラック』部分は商品名の『ブラックコーヒー』等から切り貼りした
箇条書きで書いても分かりづらいですね・・・なので私の文章力ではとうてい小説に落とし込めずに断念しました。。。