新審査基準、PIE Binary とは

どうやら、この2、3ヶ月の間に、Appleの審査基準にまた新しい項目が追加されたようです。 古いアプリを修正してリリースする方は注意してくださいね。 (最近新規プロジェクトを作成してビルドをした方はたぶん大丈夫だと思います。デフォルトの設定ではPIE Binaryになっているはずです。)

2013/9/11追記:今日発表になったiPhone 5sのA7チップは、いままでのiPhoneで採用されていた32bitではなく64bitです。64bitのiOSでは、non PIE binaryはサポートされないという情報がAppleからでているので、iPhone 5sで動作させたい場合にはPIE Binary対応が必要です。

Reject with Non-PIE Binary

今年の5月頃からApp Storeで下記のような理由でRejectされるアプリが出てきました。 *1 *2

Non-PIE Binary - The executable 'abc.app' is not a Position Independent Executable. Please ensure that your build settings are configured to create PIE executables. Once the required corrections have been made, go to the Version Details page and click "Ready to Upload Binary." Continue through the submission process until the app status is "Waiting for Upload." You can then deliver the corrected binary.

このrejectに対応するためのAppleの公式情報がでています。 Building a Position Independent Executable

上記ページによると、もし審査で「Non-PIE Binary」でrejectされたら、下記のビルド設定を直して再ビルドしてほしい、ということです。 (1) iOSアプリの場合には、Target OSをiOS4.3以降に、Macアプリの場合には OS X 10.7以降に設定。 (2) ビルド設定の「Generate Position-Dependent Code」をNOに設定。 (3) ビルド設定の「Don't Create Position Independent Executables」をNOに設定。

PIEとは

では、そもそも Position Independent Executable (PIE)とはなんでしょう。 日本語で言うと「位置独立コード」となり、メモリ空間のどこにロードされても実行可能なアプリということです。 *3 当初はメモリ空間に複数のプロセスを同時に走らせるために使われだした手法ですが、iOSで導入されているのはそのためではありません。

セキュリティ脆弱性をふせぐためのOSの手法として、アドレス空間配置のランダム化 (ASLR:Address space layout randomization)という仕組みがあります。 *4 プロセスがロードされるメモリ空間をランダム化することによって、悪意のあるプロセスがメモリー空間上の他のプロセスのメモリーを読んだり書きかえたりなどの攻撃を防ぐためのセキュリティ対策の施策です。 iOSアプリでPIEが必須になっているのはこのASLRのためです。

iOSでは4.3からASLR/PIEに対応していますが、今まではApp Storeの審査で必須とはされていませんでした。 Appleが今になってPIEに対するチェックを始めた理由については、iOS7.0で導入された新multitask対応が関係しているのでは、との見方もあります。 *5 (上記のTechnical Q&Aの日付が2013/05/23なので、おそらく今年のWWDCの少し前くらいから審査基準に加えられたものと思われます。)

審査基準にPIE対応を義務づけても、更新されない古いアプリでPIE非対応のものがApp Storeには残ってしまい、すべてのアプリをPIE対応にすることはできません。 ただ、iOS7の新マルチタスクに対応するためには、今回ビルドし直して審査を受ける必要があるので、PIE非対応アプリは当然新マルチタスクには非対応ということになり、ユーザーのiPhoneで他のアプリと同時実行されることはありません。 結論として、どのアプリもメモリ空間の脆弱性には堅牢になる、ということですね。(理論的には。)

実行ファイルがPIEかどうか確認する

ビルド設定を確認すれば、PIE対応でビルドされるかどうかはわかりますが、実際にビルドしたモジュールからPIE対応されているかどうかを確認する方法もあります。

ターミナルをひらいて、otoolにhvオプションを加えて、下記のように実行してみてください。

$ otool -hv ABC.app/ABC

最新のXcode4.6.2で、デフォルトのままビルドしたPIE対応バイナリ(ABC.ipaとします)をotoolにかけると、こういう結果がでます。

$ otool -hv ABC.app/ABC
ABC.app/ABC (architecture armv7):
Mach header
      magic cputype cpusubtype  caps    filetype ncmds sizeofcmds      flags
   MH_MAGIC     ARM         V7  0x00     EXECUTE    47       5184   NOUNDEFS DYLDLINK TWOLEVEL PIE
ABC.app/ABC (architecture armv7s):
Mach header
      magic cputype cpusubtype  caps    filetype ncmds sizeofcmds      flags
   MH_MAGIC     ARM        V7S  0x00     EXECUTE    47       5184   NOUNDEFS DYLDLINK TWOLEVEL PIE

「architecture armv7」と「architecture armv7s」の二つの結果がでていますが、これはarmv7/armv7sの二つのArchitectureへ対応しているということです。 どちらの行にも、最後に「PIE」という文字が表示されていますが、これが PIE対応です。

それに対して古いアプリ(XYZ.ipaとします)の場合、おそらく多くは次のような表示になると思います。

$ otool -hv XYZ.app/XYZ 
XYZ.app/XYZ (architecture armv6):
Mach header
      magic cputype cpusubtype  caps    filetype ncmds sizeofcmds      flags
   MH_MAGIC     ARM         V6  0x00     EXECUTE    21       2572   NOUNDEFS DYLDLINK TWOLEVEL
XYZ.app/XYZ (architecture armv7):
Mach header
      magic cputype cpusubtype  caps    filetype ncmds sizeofcmds      flags
   MH_MAGIC     ARM         V7  0x00     EXECUTE    21       2572   NOUNDEFS DYLDLINK TWOLEVEL

上のABC.ipaアプリでは行の最後に「PIE」表示がありましたが、こちらにはありません。PIE非対応ということになります。 (「architecture armv6」と「architecture armv7」についてはarmv6/armv7の二つのArchitectureへ対応しているということです。architectureについては、これもまたそのときのデフォルトのビルド設定によるので一概にはいえませんが、確か4.3以前はarmv6/armv7がデフォルトだったはず。)

この方法ならリリース済みのアプリがPIE対応かどうかも確認できるので、気になる方は自分のipaの中身をチェックしてみてください。

otoolについて

otoolがインストールされているかどうかは、ターミナルで「which otool」をいれて確認してみてください。

$ which otool
/usr/bin/otool

インストールされている場合には上記のようにインストールパスが表示されますが、されていない場合には反応がありません。 その場合には、XcodeのPreferenceメニューから、「Download」画面にいき、「Command Line Tools」を選択してインストールしてください。

結論

とりあえず、現時点ではPIE対応アプリにしないとApp Storeの審査自体が通らないので、必然的に Target iOSは4.3以上にしなくては App Storeから配布することはできません。 iPhone5対応の件でも感じたんですが、たとえ機能アップデートを行なわないアプリでも年に一回くらいは最新のiOS状況にあわせてビルドしないと駄目ですね。 当然といえば当然かもしれませんが、開発を外注している会社にとってメンテナンス費用の負担はつらいかもしれません。 作りっぱなしというのは、Apple的にも容認されないということなので、アプリを作るときにはそのあたりも考慮しないといけないかなと思います。

それにしても、「Generate Position-Dependent Code」と「Don't Create Position Independent Executables」はわかりにくい。 意味が同じなんだからどっちかにあわせてほしいですよね。

参考情報

下記の情報を参考にさせていただきました。