ネットワーク・プロトコル#165

探査機フライトソフトウェアのOTA更新 — 「動いているコンピュータの中身」を書き換える

地上のスマートフォンOTA更新と違い、探査機のフライトソフトウェア更新は失敗すれば機体全体が二度と目覚めないリスクを伴う。CFDPで学んだ転送の信頼性の先にある、イメージのハッシュ検証、A/Bパーティションによる安全な書き込み、そしてデッドマンスイッチ的な自動ロールバック機構を数式で理解する。

前提知識: CFDP — ファイル単位で信頼性を保証する宇宙データ転送プロトコルマスメモリとオンボードデータ蓄積 — 可視時間の外で生まれるデータをどう守るか

フライトソフトウェアOTA更新A/Bパーティションデッドマンスイッチソフトウェア検証

この回で学ぶこと

前々回、私たちはCFDPというプロトコルが「ファイル全体が最終的に1バイトも欠けることなく届く」ことをどう保証するかを、選択的再送とNAKのやり取りの数式を通じて学びました。そのとき例として挙げた用途の1つが、探査機に搭載されたフライトソフトウェア(FSW: Flight Software)のアップデートファイルを地上から送り込むという作業でした。

今回はその応用先そのものに焦点を当てます。地上に届いたファイルを開いてみたら中身が壊れていた、というだけなら「ダウンロードし直せばいい」で済みます。しかし探査機のフライトソフトウェア更新は、この牧歌的な話では済みません。フライトソフトウェアとは、探査機の姿勢制御、電源管理、通信、観測機器の制御まで、機体のあらゆる動作を司る中枢のプログラムです。数億kmの彼方で、しかも今まさに動作しているコンピュータの中身を、動かしたまま書き換えるという、地上のシステム運用者が聞いたら震え上がるような作業を、私たちは日常的に(とはいえ細心の注意を払って)行っているのです。

手元のスマートフォンのOTA (Over-The-Air) 更新と比較すると、この違いがはっきりします。スマートフォンの更新に失敗しても、最悪ユーザーは販売店やサポートセンターに持ち込んで修理・初期化してもらえます。物理的にアクセスできるからです。ところが探査機には、打ち上げた瞬間から二度と手を触れることができません。更新に失敗して機体が起動しなくなれば、それは「サポートに問い合わせる」話ではなく、ミッション全体の恒久的な喪失を意味します。この非対称性こそが、探査機のソフトウェア更新プロトコルを、地上の何気ないOTA更新とはまったく異なる、慎重の上にも慎重を重ねた設計にしている理由です。

この回では、CFDPが保証する「ファイルが完全に届く」という土台の上に、さらに次の3つの安全機構がどう積み重なるかを見ていきます。

  1. 届いたソフトウェアイメージが、意図した通りの中身であることを確認する検証(ハッシュ・チェックサム)
  2. 検証が終わるまで、現在動いているソフトウェアには一切手を触れないA/Bパーティション設計
  3. 切り替え後に何か問題があれば自動的に元に戻すロールバック(デッドマンスイッチ)機構

直感的導入: なぜ「上書き」ではダメなのか

もっとも素朴な更新方法を考えてみましょう。地上から新しいソフトウェアイメージを送り、探査機の不揮発性メモリ(フラッシュメモリなど)上の、現在起動に使われている領域にそのまま上書きする。これがもし何のトラブルもなく完了すれば、それで十分です。

問題は「もし何かトラブルが起きたら」という部分です。フラッシュメモリへの書き込みには時間がかかります(データ量にもよりますが、深宇宙リンクの低いアップリンクレートを考えると、転送そのものに数十分〜数時間、書き込み自体にも相応の時間がかかることがあります)。この書き込み処理の真っ最中に、電源系の瞬断、宇宙線による予期しないリセット、バッテリー電圧の急落といった異常が起きたらどうなるでしょうか。

上書き方式では、起動に使われる領域が「半分は新しいコード、半分は古いコード」という中途半端な状態のまま止まってしまいます。次に電源が入ったとき、探査機のコンピュータはこの支離滅裂なコードを実行しようとして起動に失敗します。地上のPCなら「セーフモードで起動」「リカバリメディアから復旧」といった手段がありますが、探査機にそのような都合のよい手段があらかじめ用意されていなければ、機体は永遠に沈黙します。これを俗に「文鎮化(ブリック化)」と呼びますが、探査機の場合その代償は地上の機器よりもはるかに重いのです。

この「更新中の中断が致命傷になる」という問題を根本から解消するのが、これから見ていく設計です。結論を先取りすると、発想はシンプルです。「今動いているものには絶対に触らず、別の場所に新しいものをそっくり用意してから、検証が終わったときだけ切り替える」。以下、これを段階を追って定式化していきます。

第1段: イメージの完全性と真正性の検証

CFDPのクラス2転送は、EOF PDUに含まれるチェックサム(CRC-32やモジュラーチェックサムなど、CCSDS 727.0-Bで規定される複数の方式から選択可能)によって、「送信側が送ったバイト列と、受信側が受け取ったバイト列が一致している」ことをすでに保証しています。CRCの回で見た通り、これはリンク上の伝送誤りや欠損を検出するための仕組みです。

しかしフライトソフトウェアの更新では、これだけでは足りません。確認したいことは実は2つあり、両者は似ているようで本質的に異なります。

  • 完全性(Integrity): 送信側が意図した通りのバイト列が、1バイトも欠けたり化けたりせずに探査機側の不揮発性メモリに書き込まれたか。
  • 真正性(Authenticity): そのイメージが本当に正規の管制センターから発行された、承認済みのビルドであるか(悪意ある第三者によるコマンドリンクへの侵入や、地上系での取り違えによる誤ったイメージの混入ではないか)。

完全性の確認には、CFDP自身のチェックサムに加えて、探査機側でイメージ全体に対する暗号学的ハッシュ関数 HH を独立に計算し直し、地上が事前に計算しておいた基準値と突き合わせる、という二重チェックがよく行われます。

honboard=H(imagereceived),受理条件:honboard=hrefh_{\text{onboard}} = H(\text{image}_{\text{received}}), \qquad \text{受理条件:}\quad h_{\text{onboard}} = h_{\text{ref}}

ここで HH にSHA-256のような出力長 n=256n=256 ビットのハッシュ関数を使うと、たとえ CRC-32 (n=32n=32)をすり抜けるような特殊なビット誤りパターンがあったとしても、無関係な2つのイメージが同じハッシュ値を持ってしまう確率はおおよそ

P(偶然の一致)2nP(\text{偶然の一致}) \approx 2^{-n}

程度に抑えられます。n=32n=32 のCRC-32では 2322.3×10102^{-32} \approx 2.3 \times 10^{-10}n=256n=256 のSHA-256では 22562^{-256} という、比較にならないほど小さい値になります。CRCが「ランダムな伝送誤りの検出」に最適化された軽量な符号であるのに対し、暗号学的ハッシュ関数は「意図的な改ざんに対しても、同じハッシュ値を持つ別のビット列を作ることが計算量的に極めて困難」という、より強い性質(衝突耐性・原像計算困難性)を持つ点が異なります。フライトソフトウェアの更新のように失敗の代償が甚大な場面では、この強い性質を持つハッシュ関数を使う価値があります。

真正性の確認には、コマンド認証の回で学んだMAC(メッセージ認証コード)の考え方を、イメージ全体に応用します。地上は共有鍵 KK を使って、イメージのハッシュ値に対するタグを計算し、イメージ本体とは別に(あるいはメタデータPDUの一部として)送ります。

T=MACK(href)T = \mathrm{MAC}_K(h_{\text{ref}})

探査機側は受信したイメージから計算した honboardh_{\text{onboard}} と、受信したタグ TT を使って、

受理条件:honboard=href  かつ  T=MACK(href)\text{受理条件:} \quad h_{\text{onboard}} = h_{\text{ref}} \ \ \text{かつ} \ \ T = \mathrm{MAC}_K(h_{\text{ref}})

の両方が成り立って初めて、このイメージを「起動に使ってよい正規のソフトウェア」として受理します。前者だけでは「転送は正しく完了した(が、そもそも間違った、あるいは偽造されたイメージが送られてきていたかもしれない)」ことしか確認できず、後者を組み合わせて初めて「送られてきた中身自体が、鍵を知っている正規の送信元によって承認されたものである」ことまで確認できる、という点が、単なる転送の完全性チェックとの決定的な違いです。

第2段: A/Bパーティション — 「動いている領域には触れない」設計

検証の仕組みが整っても、まだ「いつ・どこに書き込むか」という問題が残っています。ここで登場するのが、不揮発性メモリを2つの独立した領域(パーティション、あるいはバンクと呼びます)に分割しておく設計です。片方を アクティブバンク(現在起動に使われている領域)、もう片方を スタンバイバンク(待機領域) とします。

更新手順は次のようになります。

  1. 新しいソフトウェアイメージを、現在動作中のアクティブバンクには一切触れず、スタンバイバンクにCFDPクラス2で転送・書き込む。
  2. 書き込みが終わったら、前節のハッシュ検証・MAC検証をスタンバイバンクの内容に対して行う。
  3. 検証に合格した場合のみ、「次回起動時にどちらのバンクから立ち上がるか」を指し示すブートセレクタ(小さなフラグ、多くの場合、書き込みが単純で壊れにくい保護された領域や冗長化されたレジスタに置かれます)を、スタンバイバンク側に書き換える。
  4. 探査機を(あるいは次の定期リセットのタイミングで)再起動し、新しいバンクから立ち上がらせる。

この設計のありがたみを、確率の言葉で定量化してみましょう。探査機に予期しないリセットや電源異常が、時間あたり一定の確率で独立に発生するポアソン過程(発生率 λ\lambda、単位は例えば「1時間あたりの回数」)に従うとします。ソフトウェアの書き込みに要する時間を TwriteT_{\text{write}} とすると、この書き込み時間内に少なくとも1回の異常が発生する確率は、

P(write中の異常発生)=1eλTwriteP(\text{write中の異常発生}) = 1 - e^{-\lambda T_{\text{write}}}

上書き方式では、この異常がアクティブバンク(=起動に使われている当のコード)そのものを破壊している最中に起きるため、異常が発生すればほぼ確実に機体が起動不能になります。

P(ブリック化上書き方式)P(write中の異常発生)=1eλTwriteP(\text{ブリック化} \mid \text{上書き方式}) \approx P(\text{write中の異常発生}) = 1 - e^{-\lambda T_{\text{write}}}

一方、A/Bパーティション方式では、TwriteT_{\text{write}} の間ずっと動き続けているのはアクティブバンク(旧ソフトウェア、無傷のまま)であり、書き込み中の異常はスタンバイバンクの内容を壊すだけです。壊れたスタンバイバンクは次のハッシュ検証で単に不合格となり、ブートセレクタは書き換えられず、探査機は何事もなかったかのようにアクティブバンク(旧ソフトウェア)から起動し続けます。ブリック化が起こり得るのは、ブートセレクタというごく小さな、単純で保護されたデータ構造そのものが壊れるという、はるかに稀な事象が重なった場合に限られます。

P(ブリック化A/B方式)P(write中の異常発生)×pselectorP(\text{ブリック化} \mid \text{A/B方式}) \approx P(\text{write中の異常発生}) \times p_{\text{selector}}

ここで pselectorp_{\text{selector}} はブートセレクタ自体が破損する条件付き確率で、冗長化・保護されたごく小さな記憶領域であることから pselector1p_{\text{selector}} \ll 1 です。したがってリスクの比は、

P(ブリック化A/B方式)P(ブリック化上書き方式)pselector1\frac{P(\text{ブリック化} \mid \text{A/B方式})}{P(\text{ブリック化} \mid \text{上書き方式})} \approx p_{\text{selector}} \ll 1

となり、A/Bパーティション方式は上書き方式に比べて、更新中の異常に起因するブリック化のリスクを桁違いに下げていることが分かります。これが「動いている領域には触れず、まっさらな別領域に新しいものを用意してから切り替える」という設計が、探査機のソフトウェア更新において半ば常識的な作法になっている数理的な理由です。

第3段: ロールバック機構 — デッドマンスイッチとしてのタイムアウト

ハッシュ検証に合格し、A/Bの切り替えを終えても、まだ安心はできません。ハッシュ検証は「送られてきたビット列が意図した通りである」ことしか確認しておらず、「そのソフトウェアが実際に探査機上で正しく機能する」ことまでは保証していないからです。地上のテストベッドでどれだけ検証していても、実機特有の環境(放射線環境、実際のセンサ・アクチュエータとの相互作用、長時間運用での予期しない状態遷移)で初めて表面化する不具合はゼロにはできません。

そこで新しいソフトウェアに切り替えた直後は、いきなり「本採用」にはせず、一定の**お試し期間(トライアル期間)**を設け、その間に地上からの正常性確認が得られなければ自動的に元のバンクへ戻す、という仕組みを組み込みます。これは考え方として、一定時間内に人間からの応答(ハートビート)がなければ危険な動作を自動的に停止する「デッドマンスイッチ」と同じ発想です。

具体的な手順は次のようになります。

  1. 新バンクへの切り替え・再起動後、探査機は一定のトライアル状態に入り、ロールバックタイマーを起動する。同時にブートセレクタは「まだ確定していない(暫定)」状態のままにしておく。
  2. 地上局は新しいソフトウェアで生成されたテレメトリを受信し、機体の健全性(電源電圧、姿勢、温度、通信品質など)を解析する。
  3. 問題がなければ、地上は認証済みのコマンドで「コミット(確定)」を送り、探査機はブートセレクタを恒久的に新バンクに確定させ、ロールバックタイマーを解除する。
  4. 何らかの理由でコミットコマンドがタイムアウト時間 TrollbackT_{\text{rollback}} 以内に届かなければ、探査機は自律的にブートセレクタを旧バンクへ戻し、次回リセット時に(あるいは即座に)旧ソフトウェアへ復帰する。

このタイムアウト TrollbackT_{\text{rollback}} の設計が、深宇宙ミッション特有の難しさを持っています。地上が新バンクの健全性を確認してコミットコマンドを送り返すまでには、最低でも次の時間がかかります。

Tmin_response=TRTLT+Tanalyze+TDSN_waitT_{\text{min\_response}} = T_{\text{RTLT}} + T_{\text{analyze}} + T_{\text{DSN\_wait}}

ここで TRTLTT_{\text{RTLT}} は往復光行時間(CFDPの回で見た通り、火星で約8〜48分、木星ではさらに長時間)、TanalyzeT_{\text{analyze}} はテレメトリを受信してから運用チームが健全性を判断するまでの解析時間、TDSN_waitT_{\text{DSN\_wait}} は(マスメモリの回で見た可視時間の制約と同様に)地上局アンテナのスケジュールが空くまでの待ち時間です。TrollbackT_{\text{rollback}} をこれより短く設定してしまうと、実際には新ソフトウェアは正常なのに、単に地上の応答が物理的にまだ届いていないだけで自動ロールバックが発動してしまう「誤ロールバック」が起き、正当な更新が台無しになります。したがって設計上は、十分な安全マージン TmarginT_{\text{margin}} を上乗せして、

Trollback>TRTLT+Tanalyze+TDSN_wait+TmarginT_{\text{rollback}} > T_{\text{RTLT}} + T_{\text{analyze}} + T_{\text{DSN\_wait}} + T_{\text{margin}}

を満たすように選びます。一方で TrollbackT_{\text{rollback}} を必要以上に長く取りすぎると、万一新ソフトウェアに深刻な不具合があった場合に、探査機が不安定な状態のまま長時間さらされ続けるリスクが増すため、単純に「長ければ長いほど安全」というわけでもありません。実務上は、想定されるミッションフェーズでの最悪ケースのRTLTとDSNスケジュール制約を洗い出した上で、この不等式を満たすギリギリまで TrollbackT_{\text{rollback}} を切り詰める、という設計になります。

なお、この時計に基づくタイムアウトだけでは救えないケースもあります。新ソフトウェアがあまりにも壊れていて、そもそもタイマーを動かすところまで正常に起動できない(いわゆるクラッシュループ)場合です。この対策として、多くのミッションはソフトウェアそのものとは独立に動くハードウェアウォッチドッグと起動カウンタを併用します。起動を試みるたびにカウンタ cc をインクリメントし、正常起動を示す確認フラグが一定時間内にクリアされないまま再起動が続くと、cc が閾値 cmaxc_{\max} に達した時点でハードウェアレベルで強制的に旧バンクへフォールバックします。各起動試行が(バグの影響で)正常に立ち上がる確率を pbootp_{\text{boot}} とすると、cmaxc_{\max} 回連続で失敗し続けてしまう確率は、

P(全試行失敗)=(1pboot)cmaxP(\text{全試行失敗}) = (1 - p_{\text{boot}})^{c_{\max}}

で与えられます。たとえば深刻なバグにより pboot=0.5p_{\text{boot}} = 0.5(2回に1回しか正常に立ち上がらない)という劣悪な状況でも、cmax=5c_{\max}=5 回まで粘る設計にしておけば P(全試行失敗)=0.55=0.03125P(\text{全試行失敗}) = 0.5^5 = 0.03125 まで下がり、ほとんどの場合はいずれかの起動試行が成功して地上と通信できる状態に持ち込めます。このように、「時計ベースの地上確認タイムアウト」と「ソフトウェアの実行自体に依存しないハードウェアの起動カウンタ」を二重に備えることで、正常に起動すらできないという最悪のケースにも備えるのが、実務上の定石です。

実務での使われ方

フライトソフトウェアのOTA更新は、決して理論だけの話ではなく、実際のミッションで繰り返し実施されてきた運用作業です。

Voyager 1の2024年のリモートパッチ。 2023年末、太陽系外縁を航行中のVoyager 1のFDS (Flight Data System) から送られてくるテレメトリが解読不能な状態に陥りました。JPLのエンジニアチームは、片道約22.5光時間という気の遠くなるような通信遅延と、当時の設計者がすでに引退して久しい半世紀近く前のアーキテクチャという二重の困難の中、破損したメモリ領域を特定し、影響を受けたコードを別のメモリ番地へ再配置するパッチを作成しました。パッチを実機にいきなり適用するのではなく、まず一部だけを慎重に送って反応を確認し、段階的に検証を重ねながら適用するという、まさに本回で述べた「一度に全部を賭けない」慎重な手順が取られたことが報じられています。

火星探査ローバーのフライトソフトウェア更新。 Curiosityは着陸後も複数回の大規模なフライトソフトウェア更新を受けており、たとえば2016年の更新では、鋭利な岩によるホイール損傷を軽減するための自律的なトラクション制御アルゴリズムが新たに組み込まれました。こうした更新は、地上に置かれた実機と同一構成のテストベッド(エンジニアリングモデル)で数ヶ月単位の回帰試験を重ねたのち、初めて実機へのアップリンクが承認されるという、極めて段階的なプロセスを経ています。

Ingenuity火星ヘリコプターの更新。 火星の飛行実証機Ingenuityは、Perseveranceローバーを中継局として複数回のフライトソフトウェア更新を受けました。2021年には、飛行中の航法アルゴリズムに起因する不具合を受けて、着陸誤差を検知した際の安全な処置(緊急着陸)ロジックを追加する更新が行われています。

フライトソフトウェア基盤への組み込み。 CFDPの回で触れたNASA/JPLの飛行ソフトウェア基盤 core Flight System (cFS) は、CFDPアプリケーションに加えて、イメージの検証・A/B的なイメージ管理をサポートするブートローダ層とのインタフェースを備えており、ミッションごとに安全な更新の仕組みを一から設計し直す必要がないよう部品化が進められています。ハッシュ検証のアルゴリズムとしては、計算資源の制約から軽量なCRC系チェックサムと組み合わせつつ、真正性の確認にはSHA-2系のハッシュとHMACやCMACなどの共有鍵ベースの認証コード(コマンド認証の回参照)が使われることが一般的で、計算資源に余裕のある比較的新しいミッションでは公開鍵ベースの署名検証を採用する例も増えています。

演習問題

  1. 探査機に搭載されたフラッシュメモリへの異常発生率が λ=0.02\lambda = 0.02 回/時間(ポアソン過程)、新イメージの書き込みに要する時間が Twrite=3T_{\text{write}} = 3 時間であるとします。上書き方式を採用した場合の、書き込み中に異常が発生する確率 P(write中の異常発生)P(\text{write中の異常発生}) を計算してください。またブートセレクタの破損確率が pselector=104p_{\text{selector}} = 10^{-4} であるA/Bパーティション方式の場合の P(ブリック化)P(\text{ブリック化}) と比較し、リスクがおよそ何桁縮小するか述べてください。
  2. CRC-32によるチェックサムと、SHA-256による暗号学的ハッシュのそれぞれについて、無関係な2つのソフトウェアイメージが偶然同じ値を持ってしまう確率のオーダーを求め、なぜフライトソフトウェアの完全性確認には後者(あるいはそれに準じる強度のハッシュ関数)がより望ましいのかを説明してください。
  3. 木星探査機との往復光行時間が最大 TRTLT=100T_{\text{RTLT}} = 100 分、地上での健全性解析に Tanalyze=60T_{\text{analyze}} = 60 分、DSNのスケジュール待ちを最悪 TDSN_wait=4T_{\text{DSN\_wait}} = 4 時間と見積もるとき、安全マージン Tmargin=2T_{\text{margin}} = 2 時間を加えた場合に、ロールバックタイムアウト TrollbackT_{\text{rollback}} として最低限確保すべき時間を計算してください。
  4. 「ハッシュ検証(完全性・真正性の確認)」「A/Bパーティション(書き込み中の安全性)」「デッドマンスイッチ的ロールバック(機能面の安全性)」という3つの安全機構は、それぞれ異なる種類の故障モードに対応しています。もしこのうち1つだけしか採用できないとしたら、あなたならどれを優先しますか。それぞれの機構が守れない・守れる故障モードの違いを踏まえて、理由とともに論じてください。

まとめと次回予告

探査機のフライトソフトウェア更新は、CFDPが保証する「ファイルが完全に届く」という土台の上に、さらに3層の安全機構を積み重ねた、深宇宙運用の中でもとりわけ慎重さが求められる作業です。届いたイメージが意図した中身と一致し、かつ正規の送信元から来たものであることをハッシュとMACで確認し(検証)、動作中の領域には一切手を触れずに別領域へ新イメージを用意してから切り替え(A/Bパーティション)、切り替え後も一定期間は地上の確認が得られなければ自動的に元へ戻す(デッドマンスイッチ的ロールバック)。この3層構造のどれか1つが欠けても、探査機を恒久的に失いかねないリスクが残る、というのがこの回の核心でした。

次回は少し話題を変えて、探査機が地上とやり取りするテレメトリや科学データ、そして今回扱ったソフトウェアイメージのようなデータを、どのようなバイト列の形式で表現し構造化しているのかという、宇宙データ用のシリアライゼーション形式に軽く触れます。

参考文献

  • CCSDS 727.0-B, CCSDS File Delivery Protocol (CFDP)
  • CCSDS 355.0-B, Space Data Link Security Protocol, Blue Book
  • NIST FIPS 180-4, Secure Hash Standard (SHS)
  • NIST FIPS 198-1, The Keyed-Hash Message Authentication Code (HMAC)
  • NASA JPL News, NASA’s Voyager 1 Resumes Sending Engineering Updates to Earth, 2024
  • NASA-HDBK-2203, NASA Software Engineering Handbook
  • J. H. Yuen (ed.), Deep Space Telecommunications Systems Engineering, JPL Publication 82-76