Armadilloフォーラム

eMMC からのブートに固定するための設定に関して

yorikasa

2024年5月17日 17時22分

お世話になっております。

現在、セキュリティの観点からArmadillo-IoT A6EにてSDカードによるブートが無効化できないか確認しております。
※設定変更後、SDカードによるイメージの書き直し等も出来なくなる点については許容する前提です。

フォーラムや他機種のマニュアル等を確認したところ、下記のマニュアルにて「10.15.4.2. eMMC からのブートに固定」という内容がございました。
A6Eで利用しているCPUも「NXP Semiconductors i.MX6ULL」のため、同様にfuseを利用することでブートを限定できるのではないかと想像しているのですが合っていますでしょうか?

https://armadillo.atmark-techno.com/files/downloads/armadillo-640/docum…

もし、認識があっている場合「10.15.4.2. eMMC からのブートに固定」の手順をそのままArmadillo-IoT A6Eで実施しても問題ないでしょうか?

ご教示の程よろしくお願いいたします。

コメント

at_dominique.m…

2024年5月17日 18時32分

yorikasaさん

お世話になっています、
マルティネです。

> 現在、セキュリティの観点からArmadillo-IoT A6EにてSDカードによるブートが無効化できないか確認しております。
> ※設定変更後、SDカードによるイメージの書き直し等も出来なくなる点については許容する前提です。

(ご存知だと思われますが、fuse を焼くと元に戻れないので、fuse の値を間違った場合は全く起動できなくなる恐れもあります)

> フォーラムや他機種のマニュアル等を確認したところ、下記のマニュアルにて「10.15.4.2. eMMC からのブートに固定」という内容がございました。
> A6Eで利用しているCPUも「NXP Semiconductors i.MX6ULL」のため、同様にfuseを利用することでブートを限定できるのではないかと想像しているのですが合っていますでしょうか?
>
> https://armadillo.atmark-techno.com/files/downloads/armadillo-640/docum…

はい、同じ i.MX6ULL ですので、fuse の設定は同じです。
Armadillo IoT ゲートウェイ A6E のマニュアルに説明が書いておらず申し訳ございません。

> もし、認識があっている場合「10.15.4.2. eMMC からのブートに固定」の手順をそのままArmadillo-IoT A6Eで実施しても問題ないでしょうか?

はい、書込み方法は同じです:
起動する時にシリアルでキー入力か、SW1 を押して u-boot の => プロンプトに入ってから「fuse prog」コマンドを利用できます。

(同じだと分かっていても、ただいま以下のコマンドで SD ブートをできなくなったことを確認しました)

=> fuse prog -y 0 5 0x4060 0x10
Programming bank 0 word 0x00000005 to 0x00004060...
Programming bank 0 word 0x00000006 to 0x00000010...

よろしくお願いします

マルティネさん

お世話になっております。

> はい、同じ i.MX6ULL ですので、fuse の設定は同じです。
> Armadillo IoT ゲートウェイ A6E のマニュアルに説明が書いておらず申し訳ございません。

ご回答ありがとうございました。
合っているとのことで安心いたしました。

もし、マニュアルのアップデートのタイミングがございましたら、マージを行っていただけると幸いです。

> > もし、認識があっている場合「10.15.4.2. eMMC からのブートに固定」の手順をそのままArmadillo-IoT A6Eで実施しても問題ないでしょうか?
>
> はい、書込み方法は同じです:
> 起動する時にシリアルでキー入力か、SW1 を押して u-boot の => プロンプトに入ってから「fuse prog」コマンドを利用できます。
>
> (同じだと分かっていても、ただいま以下のコマンドで SD ブートをできなくなったことを確認しました)
>

> => fuse prog -y 0 5 0x4060 0x10
> Programming bank 0 word 0x00000005 to 0x00004060...
> Programming bank 0 word 0x00000006 to 0x00000010...
> 

実際にお試しいただいた内容についてもありがとうございます。
私の方でも確認させていただきます。

マルティネさん

度々申し訳ございません。
下記に関して1点追加で質問をさせてください。

> はい、書込み方法は同じです:
> 起動する時にシリアルでキー入力か、SW1 を押して u-boot の => プロンプトに入ってから「fuse prog」コマンドを利用できます。
>
> (同じだと分かっていても、ただいま以下のコマンドで SD ブートをできなくなったことを確認しました)
>

> => fuse prog -y 0 5 0x4060 0x10
> Programming bank 0 word 0x00000005 to 0x00004060...
> Programming bank 0 word 0x00000006 to 0x00000010...
> 

こちらの設定をプロンプトからの実施ではなく、工場出荷状態のArmadilloのキッティング(出来ればSWUpdate)でeMMCブートに固定にしたいのですが、
その場合取扱説明書(v2.9.0)の「6.27.1. ブートローダーをビルドする」を参考にブートローダーカスタマイズすることで実現可能でしょうか?

どうぞよろしくお願いいたします。

at_dominique.m…

2024年5月22日 8時23分

yorikasaさん

マルティネです。

> こちらの設定をプロンプトからの実施ではなく、工場出荷状態のArmadilloのキッティング(出来ればSWUpdate)でeMMCブートに固定にしたいのですが、
> その場合取扱説明書(v2.9.0)の「6.27.1. ブートローダーをビルドする」を参考にブートローダーカスタマイズすることで実現可能でしょうか?

fuse は linux で書き込み不可能になっていないので、残念ながら swupdate だけでは設定できませんが、u-boot の boot script で対応できますのでブートローダーをビルドしなくていいです。

以下のスクリプトは Armadillo IoT G4のセキュアブートのための物なので、いくつかの調整が必要ですが、少し見直せば使えるはずです:

    local first_fuse srk_fuse_prog
    srk_fuse_prog="fuse prog -y 6 0 ...."
    first_fuse="${srk_fuse_prog#fuse prog -y 6 0 }"
    first_fuse="${first_fuse%% *}"
    cat > mnt/boot/boot.txt <<EOF
# two phase boots:
# first boot programs fuses and reset,
# second boot just boots normally
# ... and abort if an unexpected value comes up, installer won't work...
 
# uboot cannot compare memory to a given value, we need to write value
# in another address to use cmp...
# 30350580 is the shadow register for the first srk hash word
mw \${fdt_addr} 0
if cmp.l \${fdt_addr} 30350580 1; then
    echo "Programming secureboot fuses"
    $srk_fuse_prog
    fuse prog -y 1 3 0x2000000
    reset
fi
mw \${fdt_addr} $first_fuse
if cmp.l \${fdt_addr} 30350580 1; then
    run loadimage && run mmcboot
    echo "boot failed, falling back to prompt"
    exit
fi
echo "fuse value does not match expected value, falling back to prompt"
EOF
 
    mkbootscr mnt/boot/boot.txt mnt/boot/boot.scr \
        || error "Could not generate boot script for secureboot"

修正するべきところ:
- fuse prog -y の行を間違わないように
- iMX.6ULL の bank 0 word 5 (0x4060 を書いてる物)の shadow register は 21bc450 なので、固定のアドレスはそれにして first_fuse の値は 0x4060 になります
- (このスクリプトは armadillo で実行する想定ですが、swupdate を使う場合はあらかじめ一つの armadillo で mkbootscr を実行して、boot.scr ファイルだけを配信すればいいかと)

その boot.scr を使えば、fuse が設定された場合は普通に起動するだけなので、swupdate で /boot/boot.scr を設置して放置してもいいですし、そのまた次のアップデートで削除してもいいです(現場で使用する場合は prompt に入らないようにする必要があるかもしれませんが)

何か問題か疑問に思う点があれば聞いてください。

マルティネさん

> > こちらの設定をプロンプトからの実施ではなく、工場出荷状態のArmadilloのキッティング(出来ればSWUpdate)でeMMCブートに固定にしたいのですが、
> > その場合取扱説明書(v2.9.0)の「6.27.1. ブートローダーをビルドする」を参考にブートローダーカスタマイズすることで実現可能でしょうか?
>
> fuse は linux で書き込み不可能になっていないので、残念ながら swupdate だけでは設定できませんが、u-boot の boot script で対応できますのでブートローダーをビルドしなくていいです。

こちらについてありがとうございました。
boot scriptで可能とのこと承知致しました。

> 修正するべきところ:
> - fuse prog -y の行を間違わないように
> - iMX.6ULL の bank 0 word 5 (0x4060 を書いてる物)の shadow register は 21bc450 なので、固定のアドレスはそれにして first_fuse の値は 0x4060 になります
> - (このスクリプトは armadillo で実行する想定ですが、swupdate を使う場合はあらかじめ一つの armadillo で mkbootscr を実行して、boot.scr ファイルだけを配信すればいいかと)
>
> その boot.scr を使えば、fuse が設定された場合は普通に起動するだけなので、swupdate で /boot/boot.scr を設置して放置してもいいですし、そのまた次のアップデートで削除してもいいです(現場で使用する場合は prompt に入らないようにする必要があるかもしれませんが)
>
> 何か問題か疑問に思う点があれば聞いてください。

boot.scrを作成し確認してみます。
ありがとうございました。

マルティネさん

期間が開いてしまって申し訳ありませんが、boot.scrに関して何点か質問させてください。

質問1:

boot.scrを用意した場合、既存のboot処理を実行後、追加したboot.scrの処理が実行されるのでしょうか?
追加したboot.scrの内容で上書きされてしまうのか教えていただけると幸いです。

質問2:

質問1の質問の回答にもよるのかと思うのですが、「fuse prog -y 0 5 0x4060 0x10」のみboot.txtに記載するだと正常に変更できないでしょうか?

質問3:

教えていただいた内容でスクリプトの内容を変更すると下記になるのかなと思うのですが、fdt_addrはどこで定義される内容なのでしょうか?
first_fuseの内容なのですが、セキュアブートに関する内容と想像しているため、利用箇所は削除しております。

# uboot cannot compare memory to a given value, we need to write value
# in another address to use cmp...
# 021bc450 is the shadow register for the first srk hash word
mw \${fdt_addr} 0
if cmp.l \${fdt_addr} 021bc450 1; then
    echo "SD Boot Disable "
    fuse prog -y 0 5 0x4060 0x10
    reset
fi
echo "fuse value does not match expected value, falling back to prompt"

質問4:boot.txt作成後は下記のコマンドでboot.scrを作成できる認識あっておりますでしょうか?

armadillo:~# mkbootscr /tmp/boot.txt

mkbootscrに関する参考URL

* https://github.com/atmark-techno/armadillo-x2-rtos-demo
* https://armadillo.atmark-techno.com/forum/armadillo/20243

at_dominique.m…

2024年6月28日 8時43分

yorikasaさん

マルティネです。

> boot.scrを用意した場合、既存のboot処理を実行後、追加したboot.scrの処理が実行されるのでしょうか?
> 追加したboot.scrの内容で上書きされてしまうのか教えていただけると幸いです。

boot.scr がある場合に普段の boot 処理が実行されません。
詳細は「bootcmd」の環境変数を確認できます(改行はこちらが追加しました):

bootcmd=
  mmc dev ${mmcdev};
  sleep 0.5;
  if mmc rescan; then
    run update_encrypted_boot;
    if run loadbootscript; then
      run bootscript;
    else
      run loadimage && run mmcboot;
    fi;
    run rollback;
  fi;

なので、boot.scr の最後に「run loadimage && run mmcboot」を追加すれば、スクリプト無しと同じ動作になります。
(loadbootscript 等の「run」する関数も printenv/fw_printenv で表示すると内容を確認できます)

> 質問2:
>
> 質問1の質問の回答にもよるのかと思うのですが、「fuse prog -y 0 5 0x4060 0x10」のみboot.txtに記載するだと正常に変更できないでしょうか?

そうですね、二つ目の起動以降にエラーメッセージが表示されると思いますがそれでも起動できます(上記の行も入れれば)

以前提供した例ではセキュアブートの設定でしたが、fuse を書き込んだ直後では適用されてないので、セキュアブートの設定の場合は一度書き込んだ後に再起動しないといけません。
(セキュアブートを有効する際に暗号化用の鍵が変わりますので、セキュアブート有効状態で書込みを行わないと、書込みが終わったあとに鍵が更新されて普通に起動できなくなります)
そのため、「fuse が未設定でしたら書き込む、設定されている場合は起動する」の少しややっこしい実装になっていますが、SD ブート無効化の場合は直後の起動と関係ないのですぐに起動してもいいです。

> 質問3:
>
> 教えていただいた内容でスクリプトの内容を変更すると下記になるのかなと思うのですが、fdt_addrはどこで定義される内容なのでしょうか?
> first_fuseの内容なのですが、セキュアブートに関する内容と想像しているため、利用箇所は削除しております。

このスクリプトでは、fuse の値が記載されてあるメモリアドレスを 0 と書込み予定の値に比較したいですが、u-boot の if コマンドでアドレスの内容と値を直接に比較できるコマンドはなさそうでしたので「どこでもいいから使えるアドレス」に値を書いて cmp コマンドで比較していました。
${fdt_addr} は起動の際に使いますが、起動に入る前でしたら書込みも可能なのでそれを使ってました。

> 質問4:boot.txt作成後は下記のコマンドでboot.scrを作成できる認識あっておりますでしょうか?

ドキュメンテーションが不足していて申し訳ございません。
はい、ただ txt ファイルに実行して、結果のファイルを /boot/boot.scr に書けばいいです。
boot.scr をあらかじめ生成してもいいですし、boot.txt として転送して armadillo で mkbootscr を実行してもいいです。

mkbootscr は text ファイルを u-boot が「source」で理解できる形式に変更しているだけです(mkbootscr --help に書いてある u-boot のソースにある mkimage コマンドと同じです)
u-boot の source コマンドについては u-boot のソースコードを確認できますが、使う分としては boot.txt に記載されてる内容が実行されるだけです。

よろしくお願いします。

マルティネさん

お世話になっております。
ご回答ありがとうございました。

追加で何点か教えていただけると幸いです。

> boot.scr がある場合に普段の boot 処理が実行されません。

こちら、boot.scrファイルが無ければ普段のboot処理が実施される認識で合っておりますでしょうか?
何度もSDBootを無効化するための設定処理を行う必要はないと考えており、
以下の1.及び2.の操作後、Armadilloを起動した際に普段のboot処理に戻るのを期待しています。

1. SDBoot無効化を行うためのboot.scrをSWUpdateでArmadilloに配置後再起動
2. SDBootの無効化は完了しているはずなので再度SWUpdateでboot.scrを削除

> このスクリプトでは、fuse の値が記載されてあるメモリアドレスを 0 と書込み予定の値に比較したいですが、u-boot の if コマンドでアドレスの内容と値を直接に比較できるコマンドはなさそうでしたので「どこでもいいから使えるアドレス」に値を書いて cmp コマンドで比較していました。

fw_printenvでfdt_addrの内容も確認できました。
SDBoot無効化に関しては、再度書き込みが行われても影響は無いと考えており、
事前にfdt_addrを利用した比較は不要かと思っているのですがいかがでしょうか?

よろしくお願いいたします。

at_dominique.m…

2024年6月28日 13時35分

yorikasaさん

> > boot.scr がある場合に普段の boot 処理が実行されません。
>
> こちら、boot.scrファイルが無ければ普段のboot処理が実施される認識で合っておりますでしょうか?

はい、集荷状態や初期化の際などに boot.scr がないので、普段のboot処理に入ります。

> 何度もSDBootを無効化するための設定処理を行う必要はないと考えており、
> 以下の1.及び2.の操作後、Armadilloを起動した際に普段のboot処理に戻るのを期待しています。
>
> 1. SDBoot無効化を行うためのboot.scrをSWUpdateでArmadilloに配置後再起動
> 2. SDBootの無効化は完了しているはずなので再度SWUpdateでboot.scrを削除

再び swupdate をインストールしてもいいですし、
/etc/local.d/remove_bootscr.sh で 「persist_file -d /boot/boot.scr /etc/local.d/remove_bootscr.sh」のようなコマンドで起動した後に自動的に削除させるのもいいですね。

> > このスクリプトでは、fuse の値が記載されてあるメモリアドレスを 0 と書込み予定の値に比較したいですが、u-boot の if コマンドでアドレスの内容と値を直接に比較できるコマンドはなさそうでしたので「どこでもいいから使えるアドレス」に値を書いて cmp コマンドで比較していました。
>
> fw_printenvでfdt_addrの内容も確認できました。
> SDBoot無効化に関しては、再度書き込みが行われても影響は無いと考えており、
> 事前にfdt_addrを利用した比較は不要かと思っているのですがいかがでしょうか?

はい、起動モードの設定に関しては特に再起動しなくてもいいですので、fuse prog の後に起動してもいいと思いますので、「ゼロの場合に fuse prog して再起動」の手間は不要だと思います。

ただし、fuse は一度焼けば変更できない物なので、私でしたらありえないと思いつつ 0 / 期待どおりの値 / 別の値のチェックを行うと思います。
すでにどこかで設定されている等の事例がないので、そのまま信用しても問題ないと思いますが、万が一あれば早めに分かった方が対応しやすいので確認して損はないと思っています(私が心配性なだけかもしれません)

ちなみに、その確認は u-boot で行わなくても実は linux からもその値を読めますので、swupdate の swdesc_script で以下のようなコードでもいいかもしれません。スクリプトを失敗させるとアップデートが失敗します。

case "$(xxd -p -l 2 -s 20 < /sys/bus/nvmem/devices/imx-ocotp0/nvmem)" in
0000) : ok;;
6040) : already set;;
*) echo "Invalid fuse value" >&2; exit 1;;
esac

(実は、Armadillo Base OS のツールで sd ブート不可能の設定をチェックできる実装を開発しているところですので、数ヶ月を待っていただければこういうチェックは楽になりますが、すぐに実装したい場合はこまめにアドレスと値を自分で調べるしかないです)

よろしくお願いします。

マルティネさん

お世話になっております。
ご回答ありがとうございました。

> > SDBoot無効化に関しては、再度書き込みが行われても影響は無いと考えており、
> > 事前にfdt_addrを利用した比較は不要かと思っているのですがいかがでしょうか?
>
> はい、起動モードの設定に関しては特に再起動しなくてもいいですので、fuse prog の後に起動してもいいと思いますので、「ゼロの場合に fuse prog して再起動」の手間は不要だと思います。
>
> ただし、fuse は一度焼けば変更できない物なので、私でしたらありえないと思いつつ 0 / 期待どおりの値 / 別の値のチェックを行うと思います。
> すでにどこかで設定されている等の事例がないので、そのまま信用しても問題ないと思いますが、万が一あれば早めに分かった方が対応しやすいので確認して損はないと思っています(私が心配性なだけかもしれません)

コメントいただきありがとうございます。
工場出荷状態(未設定で届くはず)という考えだったので、最初から変更されている可能性もあるというのは盲点でした。
念のためチェック処理は入れておこうかと思います。

> ちなみに、その確認は u-boot で行わなくても実は linux からもその値を読めますので、swupdate の swdesc_script で以下のようなコードでもいいかもしれません。スクリプトを失敗させるとアップデートが失敗します。
>

> case "$(xxd -p -l 2 -s 20 < /sys/bus/nvmem/devices/imx-ocotp0/nvmem)" in
> 0000) : ok;;
> 6040) : already set;;
> *) echo "Invalid fuse value" >&2; exit 1;;
> esac
> 

swdesc_scriptで実施する方法もあるのですね。
ブートスクリプトで比較を実施するか検討したく思います。

> (実は、Armadillo Base OS のツールで sd ブート不可能の設定をチェックできる実装を開発しているところですので、数ヶ月を待っていただければこういうチェックは楽になりますが、すぐに実装したい場合はこまめにアドレスと値を自分で調べるしかないです)
実装について、心待ちにしております。