cannot execute binary exec format errorの原因と解決策


「cannot execute binary: exec format error」:原因と解決策の徹底解説

はじめに

LinuxやUnix系OSを使用している際に、実行ファイルを起動しようとしたり、シェルスクリプトを実行しようとしたりしたとき、「cannot execute binary: exec format error」というエラーメッセージに遭遇することがあります。このエラーは、ユーザーを困惑させることが少なくありません。なぜなら、ファイルが存在し、権限も正しく設定されているように見えるのに、OSがそのファイルを「実行可能なバイナリ」として認識できない、あるいは実行するための情報が不足していることを示唆しているからです。

このエラーは単一の原因によって引き起こされるものではなく、その性質上、非常に多岐にわたる要因が考えられます。アーキテクチャの不一致、ファイル形式の不整合、ファイル破損、スクリプトの記述問題、さらにはカーネルやファイルシステム、セキュリティ設定に至るまで、様々なレベルで問題が発生する可能性があります。

本記事では、「cannot execute binary: exec format error」が発生する主な原因を詳細に掘り下げ、それぞれの原因に対する具体的な確認方法と解決策を網羅的に解説します。約5000語にわたる詳細な解説を通じて、読者がこのエラーに遭遇した際に、冷静かつ体系的に原因を特定し、解決に至るための知識と実践的なスキルを習得できることを目指します。

エラーメッセージの解釈:「exec format error」とは何か?

「cannot execute binary: exec format error」というエラーメッセージは、文字通り「バイナリを実行できません:実行形式エラー」という意味です。

LinuxやUnix系OSにおいて、プログラムを実行する際には、カーネルのシステムコールであるexecve()(または関連するシステムコール群)が使用されます。このexecve()システムコールは、指定されたファイルをプログラムとして実行しようとします。この際、カーネルは実行しようとしているファイルの内容を読み込み、そのファイルがどのような種類の実行ファイルであるかを識別し、メモリにロードして実行を開始するための様々な準備を行います。

「exec format error」は、この識別や準備の段階で問題が発生したことを示しています。具体的には、カーネルが以下のいずれか、または複数の理由により、指定されたファイルを有効な実行形式(フォーマット)を持つプログラムとして認識できない場合に発生します。

  1. ファイルがそもそも実行可能なバイナリ形式ではない。
  2. ファイルは実行可能なバイナリ形式だが、現在のシステム環境(CPUアーキテクチャ、OSのビット数など)とは互換性がない。
  3. ファイルは実行可能な形式であるはずだが、破損しているか、内容が不完全である。
  4. ファイルはスクリプトだが、実行に必要なインタプリタ情報(シバン行など)に問題がある。
  5. ファイルシステムやカーネルの設定により、そのファイルを実行する仕組みが有効になっていない。
  6. セキュリティ機構によって実行がブロックされている。

このエラーは、ファイルが存在しない場合や、ファイルに対する読み取り権限がない場合に表示される「No such file or directory」や「Permission denied」とは異なります。ファイル自体は存在し、多くの場合、読み取り権限も付与されているにもかかわらず、実行の「形式」に関する問題として報告されるのが特徴です。

主要な原因とその詳細な解説

「exec format error」の主な原因は以下のカテゴリに分類できます。それぞれの原因について、詳細な説明、確認方法、そして具体的な解決策を解説します。

原因1: アーキテクチャの不一致 (Architecture Mismatch)

これは「exec format error」の最も一般的な原因の一つです。コンパイル済みの実行ファイルは、特定のCPUアーキテクチャ(例: x86-64, ARM64, ARMv7など)および特定のビット数(32ビットまたは64ビット)向けにビルドされています。実行しようとしているシステムのCPUアーキテクチャやビット数が、そのバイナリが想定しているものと異なる場合に、このエラーが発生します。

詳細な説明:

  • CPUアーキテクチャ: 現在主流のデスクトップ/サーバー向けCPUはx86-64 (AMD64) です。一方で、Raspberry Piのようなシングルボードコンピューターや多くのモバイルデバイスはARMアーキテクチャを使用しています。古いシステムではx86 (i386) 32ビットアーキテクチャもまだ使われています。バイナリは特定のアーキテクチャの命令セットで記述されているため、異なるアーキテクチャのCPU上では直接実行できません。
  • ビット数: x86の場合、32ビット (i386) と64ビット (x86-64) があります。64ビットOS上で32ビットバイナリを実行することは可能ですが、そのためにはOS側に32ビット互換ライブラリ(例: libc6:i386など)がインストールされている必要があります。逆に、32ビットOS上で64ビットバイナリを実行することは、通常は不可能です。
  • クロスコンパイル: 別のアーキテクチャ向けにコンパイルされたバイナリを、そのターゲットアーキテクチャではないホストシステム上で実行しようとした場合によく発生します。例えば、x86-64のPC上でARM向けにコンパイルされたバイナリを実行しようとする場合などです。

確認方法:

  1. バイナリのアーキテクチャを確認する (file コマンド):
    最も重要なコマンドです。実行しようとしているファイルがどのアーキテクチャ向けにビルドされているかを確認できます。
    bash
    file /path/to/your/executable

    出力例とその解釈:

    • ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l...
      • これは 64ビットのx86-64アーキテクチャ 向けELFバイナリです。
    • ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/l...
      • これは 32ビットのIntel 80386 (x86) アーキテクチャ 向けELFバイナリです。
    • ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/l...
      • これは 64ビットのARM (aarch64) 向けELFバイナリです。
    • ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/l...
      • これは 32ビットのARM 向けELFバイナリです。

    fileコマンドの出力で、「executable」となっているにも関わらず、続くアーキテクチャ情報が実行しているシステムのアーキテクチャと一致しない場合、アーキテクチャの不一致が原因である可能性が高いです。

  2. システムのアーキテクチャを確認する (uname -m, lscpu コマンド):
    現在実行しているシステムのCPUアーキテクチャを確認します。
    bash
    uname -m

    出力例:

    • x86_64: 64ビットのx86-64アーキテクチャです。
    • i686 または i386: 32ビットのx86アーキテクチャです。
    • aarch64: 64ビットのARMアーキテクチャです。
    • armv7l: 32ビットのARMv7アーキテクチャです。

    より詳細なCPU情報は lscpu コマンドで確認できます。
    bash
    lscpu

    ArchitectureCPU op-modes(s) (32-bit, 64-bit) の項目を確認してください。

解決策:

  • 適切なアーキテクチャ用のバイナリを入手/コンパイルする:
    これが最も根本的な解決策です。実行したいプログラムを提供している場所(公式ウェブサイト、リポジトリ、コンパイル元のソースコードなど)から、現在使用しているシステムのアーキテクチャおよびビット数に合ったバージョンのバイナリを入手してください。
    もしソースコードがある場合は、現在のシステム上で再コンパイルしてください。

  • 64ビットOS上で32ビットバイナリを実行する場合(互換ライブラリのインストール):
    多くの64ビットLinuxディストリビューションは、32ビットバイナリを実行するための互換機能を持っていますが、必要な32ビット版ライブラリがデフォルトでインストールされていない場合があります。この場合、必要なライブラリパッケージをインストールすることで解決できます。
    パッケージ名はディストリビューションによって異なります。

    • Debian/Ubuntu系:
      bash
      sudo dpkg --add-architecture i386 # 32bitアーキテクチャを追加
      sudo apt update
      sudo apt install libc6:i386 libncurses5:i386 libstdc++6:i386 # 必要な32bitライブラリ例

      実行しようとしているバイナリが依存する具体的なライブラリは、ldd /path/to/your/32bit/executable コマンドで確認できます。「not found」となっている32ビット版ライブラリをインストールする必要があります。
    • RHEL/CentOS/Fedora系:
      bash
      sudo yum install glibc.i686 libstdc++.i686 # 必要な32bitライブラリ例

      または dnf を使用します。
      bash
      sudo dnf install glibc.i686 libstdc++.i686
    • Arch Linux系:
      multilib リポジトリを有効にし、必要な32ビットライブラリをインストールします。
      /etc/pacman.conf を編集し、[multilib] セクションのコメントアウトを解除します。
      bash
      [multilib]
      Include = /etc/pacman.d/mirrorlist

      その後、データベースを更新し、必要なライブラリをインストールします。
      bash
      sudo pacman -Sy
      sudo pacman -S lib32-glibc lib32-gcc-libs # 必要な32bitライブラリ例
  • 適切な実行環境を使用する:
    クロスコンパイルされたバイナリや、現在のシステムとは異なるアーキテクチャ向けのバイナリを実行する必要がある場合は、そのバイナリが想定するアーキテクチャのシステムを用意する必要があります。これは、仮想マシン(VirtualBox, VMwareなど)、コンテナ(Dockerなど)、または別の物理マシンを使用することで実現できます。
    特定のアーキテクチャをエミュレートするツール(例: qemu-user)を使用する方法もありますが、パフォーマンスが低下することがあります。

原因2: ファイル形式の不一致または破損 (File Format Mismatch or Corruption)

Linux/Unixにおける標準的な実行可能ファイル形式はELF (Executable and Linkable Format) です。もし実行しようとしているファイルがELF形式ではない場合、またはELF形式であっても内容が破損している場合、OSはそれを実行可能なプログラムとして正しくロードできません。

詳細な説明:

  • 非ELF形式のファイル:
    • WindowsのPE (Portable Executable) ファイル: .exe, .dll などの拡張子を持つファイル。これらはWindows専用の形式であり、Linux上で直接実行することはできません。
    • macOSのMach-Oファイル: macOSの実行可能ファイル形式。Linux上では直接実行できません。
    • 単なるデータファイル: テキストファイル、画像ファイル、アーカイブファイルなどを誤って実行しようとした場合。
  • ファイル破損:
    • ダウンロード中にファイルが不完全になった、またはエラーが発生した。
    • ファイルをコピーする際にエラーが発生した。
    • ファイルが保存されているストレージメディアに物理的な問題がある。
    • ファイル自体がウイルスやマルウェアによって改変/破損された。
  • スクリプトファイルをバイナリとして扱おうとした:
    シェルスクリプトやPythonスクリプトなどのテキストファイルを実行しようとした際に、システムがそれをバイナリファイルとして誤って解釈しようとする場合があります(例えば、シバン行がない、または不適切である場合など)。

確認方法:

  1. ファイルのタイプを確認する (file コマンド):
    file コマンドは、ファイルの内容を分析してそのタイプを特定します。実行形式かどうか、どのような形式か、破損している可能性があるかなどを判断するのに役立ちます。
    bash
    file /path/to/your/file

    出力例とその解釈:

    • /path/to/your/file: ELF 64-bit LSB executable, x86-64, ...
      • これは期待通りのLinux実行可能なELFバイナリです。もしこれでexec format errorが出るなら、アーキテクチャの不一致、ファイル破損、または他の高度な問題が考えられます。
    • /path/to/your/file: PE32+ executable (console) x86-64, for MS Windows
      • これはWindowsのPE形式です。Linux上では直接実行できません。
    • /path/to/your/file: Mach-O 64-bit executable x86_64
      • これはmacOSのMach-O形式です。Linux上では直接実行できません。
    • /path/to/your/file: ASCII text または /path/to/your/file: Bourne-Again shell script, ASCII text, with CRLF line terminators
      • これはテキストファイルまたはスクリプトファイルです。バイナリではありません。スクリプトの場合は、スクリプトとして実行する必要があります(後述の原因4参照)。with CRLF line terminators はWindows形式の改行コードを示しており、Linuxで問題を引き起こす可能性があります。
    • /path/to/your/file: data
      • これは file コマンドがその形式を特定できなかったことを示します。バイナリである可能性も、単なるデータである可能性もあり、破損していることも考えられます。
  2. ファイルのサイズやソースを確認する:
    ダウンロードしたファイルの場合、ダウンロード元で示されているファイルサイズとローカルのファイルサイズが一致するか確認します。また、信頼できるソースからダウンロードしたか確認します。

  3. ファイルのハッシュ値を確認する:
    提供元がファイルのハッシュ値(MD5, SHA256など)を公開している場合、ダウンロードしたファイルのハッシュ値を計算して一致するか確認します。一致しない場合は、ファイルが破損しているか改ざんされています。
    bash
    sha256sum /path/to/your/file

解決策:

  • 適切な形式のファイルを使用する:
    • WindowsやmacOSの実行ファイルの場合は、Linux互換の代替プログラムを探すか、互換レイヤー(Wine)を使用するか、仮想マシン上でWindows/macOSを起動して実行することを検討してください。
    • スクリプトファイルの場合は、後述の「原因4: スクリプトのシバン行またはインタプリタの問題」を参照し、スクリプトとして正しく実行するための設定を確認してください。
  • ファイルを再ダウンロードまたは再構築する:
    ファイルが破損している可能性がある場合は、再度ダウンロードするか、ソースコードから再コンパイルするなどして、ファイルを新しく入手してください。可能であれば、異なるミラーサイトやダウンロード方法(例: wget, curl の代わりにブラウザ、FTPの代わりにHTTPなど)を試してみてください。
  • ファイルの整合性を確認する:
    提供されている場合は、ハッシュ値を確認します。
  • ストレージの問題を診断する:
    ディスクやSSDに問題がある可能性がある場合は、ファイルシステムチェック(fsck コマンドなど)や、ディスク診断ツールを使用することを検討します。

原因3: ファイル権限の問題 (File Permission Issues)

Linux/Unixでは、ファイルを実行するためにはそのファイルに実行権限(execute permission)が付与されている必要があります。この権限が付与されていない場合、システムはファイルを読み取ることはできても、プログラムとして実行することはできません。

詳細な説明:

  • 実行権限 ‘x’: ls -l コマンドの出力で、所有者、グループ、その他のユーザーに対して ‘x’(実行)の文字が表示されている必要があります。例えば -rwxr-xr-x は、所有者には読み取り/書き込み/実行、グループとその他のユーザーには読み取り/実行権限があることを示します。
  • ファイルシステムのマウントオプション ‘noexec’: ファイルシステムが noexec オプション付きでマウントされている場合、そのファイルシステム上のどのファイルも実行できなくなります。これは、/tmp ディレクトリなどがセキュリティ上の理由でよくこのオプション付きでマウントされるケースがあります。
  • スクリプトファイルの場合: バイナリファイルだけでなく、シェルスクリプトや他のスクリプトファイルも、直接 ./script.sh のように実行するには実行権限が必要です。ただし、bash script.sh のようにインタプリタを明示して実行する場合は、スクリプトファイル自体には実行権限は必須ではなく、読み取り権限があれば実行できます。しかし、エラーメッセージが「exec format error」である場合、多くは ./script.sh のように直接実行しようとしていて、かつ権限またはシバン行に問題があるケースが考えられます。

確認方法:

  1. ファイルの権限を確認する (ls -l コマンド):
    bash
    ls -l /path/to/your/file

    出力の最初の10文字を確認します。例えば、-rw-r--r-- のように ‘x’ が一つも含まれていない場合、実行権限がありません。

  2. ファイルシステムのマウントオプションを確認する (mount コマンド):
    ファイルが存在するファイルシステムが noexec オプション付きでマウントされているか確認します。
    bash
    mount

    出力の中から、該当するファイルシステムの行を探し、括弧内のオプションに noexec が含まれていないか確認します。

解決策:

  • 実行権限を付与する (chmod コマンド):
    ファイルに実行権限が付与されていない場合は、chmod コマンドを使用して権限を追加します。所有者のみに実行権限を付与する場合:
    bash
    chmod u+x /path/to/your/file

    すべてのユーザーに実行権限を付与する場合:
    bash
    chmod +x /path/to/your/file

    実行権限を付与した後、再度 ls -l で確認し、権限が追加されていることを確認してください。

  • ファイルシステムのマウントオプションを変更する:
    ファイルシステムが noexec でマウントされている場合は、そのオプションを削除して再マウントする必要があります。これは通常、システムの設定ファイルである /etc/fstab を編集して行います。

    1. /etc/fstab をテキストエディタで開きます(要root権限)。
    2. 該当するファイルシステムの行を見つけ、オプションリストから noexec を削除し、代わりに exec を追加または確認します。
    3. 変更を保存します。
    4. ファイルシステムを再マウントします。
      bash
      sudo mount -o remount,exec /path/to/mount_point

      またはシステムを再起動します。
      注意: システムパーティション(ルート / など)やセキュリティ上重要なパーティション(/tmp など)のマウントオプションを変更する場合は、システム全体のセキュリティや安定性に影響を与える可能性があるため、十分注意して行ってください。

原因4: スクリプトのシバン行またはインタプリタの問題 (Shebang or Interpreter Issues in Scripts)

シェルスクリプト、Pythonスクリプト、Perlスクリプトなどのインタプリタ型言語で書かれたファイルを実行可能にするには、ファイルの先頭行に「シバン行 (shebang line)」を記述するのが一般的です。このシバン行は #! で始まり、そのスクリプトを実行するためのインタプリタへのパスを指定します(例: #!/bin/bash, #!/usr/bin/python3)。

「exec format error」がスクリプトファイルで発生する場合、以下の問題が考えられます。

詳細な説明:

  • シバン行が間違っている、または存在しない: システムはシバン行を見て、どのプログラムでスクリプトを実行すればよいかを判断します。シバン行がない場合、システムはそれをバイナリとして実行しようとして失敗することがあります。また、シバン行に書かれたパスが間違っている(例: /bin/bash ではなく /usr/bin/bash であるべきなど)場合も問題になります。
  • 指定されたインタプリタが存在しない: シバン行に指定されたインタプリタ(例: /usr/bin/python3)がシステムにインストールされていない、または指定されたパスに存在しない場合。
  • インタプリタ自体に問題がある: シバン行で指定されたインタプリタプログラム自体が、アーキテクチャの不一致や権限の問題などで実行できない場合。
  • Windows形式の改行コード: Windows環境で作成・編集されたスクリプトファイルは、行末にCRLF (\r\n) という改行コードを使用します。LinuxはLF (\n) を使用します。シバン行を含むファイルの先頭にCR (\r) があると、システムがシバン行を正しく解釈できず、エラーとなることがあります。例えば #!/bin/bash\r と認識されてしまい、/bin/bash\r という名前のインタプリタを探しに行ってしまいます。

確認方法:

  1. シバン行を確認する (head コマンド):
    ファイルの最初の数行(特に1行目)を確認します。
    bash
    head -n 1 /path/to/your/script.sh

    シバン行 (#!...) が正しく記述されているか確認します。パスが絶対パスであるか確認します。
  2. ファイルのタイプを確認する (file コマンド):
    file コマンドの出力で、ファイルがスクリプトとして認識されているか、改行コードに問題がないかを確認します。
    bash
    file /path/to/your/script.sh

    出力例: /path/to/your/script.sh: Bourne-Again shell script, ASCII text, with CRLF line terminators のように CRLF line terminators が表示されていないか確認します。
  3. インタプリタの存在とパスを確認する (which コマンド):
    シバン行に指定されているインタプリタがシステムに存在するか、またそのパスが正しいか確認します。例えばシバン行が #!/usr/bin/python3 なら:
    bash
    which python3

    出力されるパスがシバン行と一致するか、またコマンドが見つかるか確認します。
  4. インタプリタ自体の実行可能性を確認する:
    which で確認したインタプリタのパスに対し、file コマンドを実行して、そのインタプリタバイナリ自体に問題がないか確認します(アーキテクチャ不一致など)。

解決策:

  • 正しいシバン行を記述する:
    スクリプトファイルの1行目に、適切なインタプリタへの絶対パスを含むシバン行を正確に記述します。
    例:

    • Bashスクリプト: #!/bin/bash
    • Pythonスクリプト: #!/usr/bin/env python3 (または #!/usr/bin/python3 など、which python3 の出力で確認)
    • Perlスクリプト: #!/usr/bin/perl
      #!/usr/bin/env <interpreter_name> の形式は、インタプリタが /usr/bin 以外の場所にインストールされている場合でも、システムのPATH環境変数を使ってインタプリタを見つけてくれるため、よりポータブルです。
  • 必要なインタプリタをインストールする:
    シバン行で指定されたインタプリタがシステムにインストールされていない場合は、パッケージマネージャーを使ってインストールします(例: sudo apt install python3, sudo yum install perl)。
  • 改行コードを変換する:
    Windows形式のCRLF改行コードが原因の場合は、LFのみに変換します。dos2unix コマンドが便利です。
    bash
    sudo apt install dos2unix # Debian/Ubuntu系の場合
    sudo yum install dos2unix # RHEL/CentOS/Fedora系の場合
    dos2unix /path/to/your/script.sh

    dos2unix コマンドが使えない場合は、sed コマンドでも変換できます。
    bash
    sed -i 's/\r//' /path/to/your/script.sh
  • インタプリタを明示して実行する:
    シバン行の問題や権限の問題を回避するために、スクリプトをインタプリタを明示して実行することもできます。
    bash
    bash /path/to/your/script.sh
    python3 /path/to/your/script.py

    この方法の場合、スクリプトファイル自体に実行権限は不要です(読み取り権限は必要)。エラーメッセージが「exec format error」ではなくなった場合は、原因はスクリプトのシバン行または権限設定にあった可能性が高いです。

原因5: カーネルまたはファイルシステムの問題 (Kernel or Filesystem Issues)

より低レベルな部分、つまりOSの心臓部であるカーネルや、ファイルが格納されているファイルシステム自体に問題がある場合も、「exec format error」が発生することがあります。

詳細な説明:

  • バイナリフォーマットローダーの問題 (binfmt_misc): Linuxカーネルは、様々な実行可能ファイル形式(ELFだけでなく、Java .class ファイル、Pythonスクリプトなどを直接実行可能にするための設定など)を処理するための仕組み binfmt_misc を持っています。この設定が壊れている、または特定のフォーマット(特にELF)を処理するためのモジュールがロードされていない場合、正しく実行形式を認識できなくなることがあります。
  • ファイルシステムドライバーの問題: ファイルシステムの種類(ext4, XFS, NFS, FUSEなど)によっては、特定の状況下で実行に関連する問題が発生する可能性があります。特にネットワークファイルシステム (NFS) やFUSEベースのファイルシステムでは、設定や安定性によって問題が生じやすい場合があります。
  • ファイルシステムの破損: ファイルシステム自体が破損している場合、ファイルの内容が正しく読み取れず、実行形式として認識できないことがあります。
  • カーネルの不具合: 稀ですが、カーネルのバグによって特定の実行形式が正しく処理されない可能性もゼロではありません。

確認方法:

  1. カーネルログを確認する (dmesg):
    システム起動時やプログラム実行時にカーネルレベルで発生したエラーメッセージが記録されています。エラー発生直後に dmesg コマンドを実行し、関連するログ(execve, binfmt などを含むメッセージ)がないか確認します。
    bash
    dmesg | tail
    dmesg | grep -i exec
    dmesg | grep -i binfmt
  2. binfmt_misc の設定を確認する:
    /proc/sys/fs/binfmt_misc ディレクトリには、現在カーネルが認識しているバイナリフォーマットローダーの設定が表示されます。
    bash
    ls /proc/sys/fs/binfmt_misc/
    cat /proc/sys/fs/binfmt_misc/register # 現在登録されているハンドラー
    cat /proc/sys/fs/binfmt_misc/elf # ELFハンドラーが有効か確認

    elf ファイルの内容が enabled になっているか確認します。
  3. ファイルシステムをチェックする (fsck):
    問題のファイルが存在するファイルシステムに対し、整合性チェックを実行します。これは通常、ファイルシステムをアンマウントした状態で行う必要があります。
    bash
    # 例: /dev/sda1 の場合 (アンマウントが必要)
    sudo umount /dev/sda1
    sudo fsck /dev/sda1

    注意: ルートファイルシステム (/) の fsck は、システム起動時のリカバリモードなどで行うのが一般的です。稼働中のシステムパーティションに対して安易に fsck を実行しないでください。
  4. ファイルシステムの種類を確認する (mount または /etc/fstab):
    mount コマンドの出力や /etc/fstab ファイルで、該当ファイルシステムの種類(ext4, xfs, nfs, fuseなど)を確認します。特定のファイルシステムでの既知の問題がないか検索することができます。

解決策:

  • binfmt_misc 設定を確認・修正する:
    通常、ELFフォーマットのハンドリングはデフォルトで有効になっています。もし elf の状態が disabled になっていたり、ファイル自体が存在しない場合は、binfmt_misc サービスや関連カーネルモジュールに問題がある可能性があります。システムサービス (systemctl status systemd-binfmt.service) を確認したり、必要であればカーネルモジュールをロードしたりします(通常は自動)。非常に稀なケースであり、一般的なユーザーが手動で修正することは少ないです。
  • ファイルシステムの問題を修復する:
    fsck でファイルシステムの破損が見つかった場合は、修復を試みます。重要なデータは事前にバックアップしておきましょう。
  • 別のファイルシステムにコピーして実行してみる:
    ファイルシステム自体の問題(権限、属性、特殊なマウントオプションなど)を切り分けるために、問題のファイルを別の標準的なファイルシステム(例: /tmp ディレクトリや別のパーティションのext4ファイルシステム)にコピーし、そこで実行してみます。もしコピー先で実行できる場合、元のファイルシステムに問題がある可能性が高いです。
  • カーネルのアップデートまたはダウングレード:
    もしカーネルの不具合が疑われる場合は、カーネルを最新バージョンにアップデートするか、問題が発生しなかった以前のバージョンにダウングレードすることを検討します。これは上級者向けの操作であり、システムにリスクを伴う可能性があります。

原因6: SELinux/AppArmorなどのセキュリティ機構 (SELinux/AppArmor or Other Security Mechanisms)

SELinux (Security-Enhanced Linux) や AppArmor のような強制アクセス制御 (MAC) セキュリティフレームワークは、システム上のプログラムが実行できる操作を細かく制限できます。これらのポリシーによって、特定のプログラムの実行自体がブロックされている場合、「exec format error」と表示されることがあります。

詳細な説明:

  • セキュリティポリシーによるブロック: SELinuxやAppArmorは、プログラムの種類や実行コンテキストに基づいて、ファイルへのアクセス、ネットワーク通信、他のプログラムの起動などを制限します。厳格なポリシーが設定されている場合、新しくインストールしたプログラムや、通常とは異なる場所にあるプログラムの実行がポリシー違反とみなされ、ブロックされることがあります。
  • 監査ログへの記録: セキュリティ機構によってブロックされた操作は、通常、システムやセキュリティ関連のログファイル(特に監査ログ)に記録されます。

確認方法:

  1. SELinuxの状態を確認する:
    bash
    getenforce

    出力が Enforcing の場合、SELinuxが有効かつ強制モードで動作しています。Permissive は警告のみ、Disabled は無効です。
    より詳細なステータスは sestatus で確認できます。
  2. AppArmorの状態を確認する:
    AppArmorがインストールされ有効な場合、以下のコマンドで状態を確認できます。
    bash
    sudo aa-status
  3. 監査ログを確認する:
    SELinuxによる拒否は、監査ログに記録されます。ログファイルの場所はディストリビューションによって異なりますが、一般的には /var/log/audit/audit.log です。
    bash
    sudo tail /var/log/audit/audit.log
    sudo grep AVC /var/log/audit/audit.log # SELinuxのアクセス拒否ログを検索

    AppArmorのログは、syslogやカーネルログ (dmesg) に出力されることが多いです。
    bash
    dmesg | grep -i apparmor

解決策:

  • セキュリティポリシーを調整する:
    これが推奨される方法ですが、複雑な操作が必要です。SELinuxの場合は、監査ログのAVCメッセージを解析し、audit2allow のようなツールを使ってポリシーモジュールを生成・ロードすることで、特定の操作を許可することができます。AppArmorの場合は、プロファイルを編集または再学習 (aa-genprof, aa-complain など) します。これらの操作は、セキュリティの専門知識を必要とします。
  • 一時的にPermissiveモードにする(トラブルシューティング目的):
    原因がSELinux/AppArmorにあるかを切り分けるために、一時的にポリシーを強制しないPermissiveモードに変更することができます。

    • SELinux: sudo setenforce Permissive
    • AppArmor: sudo aa-complain /path/to/your/executable または sudo service apparmor reload (プロファイルをコンプレインモードに変更後)
      この状態で再度プログラムを実行してみて、エラーが発生しなくなった場合、原因はセキュリティポリシーにあった可能性が高いです。ただし、Permissiveモードはセキュリティレベルを低下させるため、原因特定後は速やかにEnforcingモードに戻し、適切なポリシー調整を行うべきです。 本番環境では、原則として無効化や恒久的なPermissiveモードの使用は推奨されません。
  • セキュリティ機構を無効化する(非推奨):
    トラブルシューティングの最終手段として、SELinuxやAppArmor自体を完全に無効化することも可能ですが、これはシステムのセキュリティを著しく低下させるため、本番環境では絶対に行わないでください。 無効化は通常、起動設定(カーネルパラメータや/etc/sysconfig/selinuxなどの設定ファイル)を変更して行い、システム再起動が必要です。

原因7: ライブラリの依存関係または動的リンカーの問題 (Library Dependencies or Dynamic Linker Issues)

実行ファイルが他の共有ライブラリに依存している場合、それらのライブラリが見つからない、または互換性のないバージョンである場合に実行エラーが発生します。通常、この種のエラーは「No such file or directory (for library)」や「symbol lookup error」などのメッセージで報告されることが多いですが、特定の状況、特に32ビットバイナリを64ビット環境で実行しようとして32ビットライブラリが不足しているようなケースでは、「exec format error」と関連して発生することもあります。

詳細な説明:

  • 不足している共有ライブラリ: 実行ファイルがロードされる際に、そのファイルが必要とする .so などの共有ライブラリがシステム上の標準的なパスに見つからない。
  • ライブラリのバージョン不一致: 見つかったライブラリが、実行ファイルがビルドされた際に想定されていたバージョンと異なるため、必要な関数やシンボルが見つからない。
  • 動的リンカーの問題: 実行ファイルをロードし、必要なライブラリを見つけてリンクする役割を担う動的リンカー (/lib/ld-linux.so.X/lib64/ld-linux-x86-64.so.X など) 自体に問題がある場合。

確認方法:

  1. 依存ライブラリを確認する (ldd コマンド):
    実行ファイルが依存している共有ライブラリのリストを確認します。
    bash
    ldd /path/to/your/executable

    出力で「not found」となっているライブラリがないか確認します。32ビットバイナリの場合は、32ビット版のライブラリへの依存が表示されます。
    bash
    ldd /path/to/your/32bit/executable # 32bitバイナリの場合

    ldd 自体が「not a dynamic executable」や類似のエラーを出す場合、そのファイルはスタティックリンクされているか、実行可能なELF形式ではない可能性があります(原因2)。
  2. 実行トレースを確認する (strace コマンド):
    プログラムが実行される際にカーネルが実行するシステムコールをトレースします。ファイルのオープン、ライブラリのロードなどの詳細な過程を確認でき、問題箇所を特定するのに役立ちます。
    bash
    strace /path/to/your/executable

    出力で、ファイルオープン(openat, open)が失敗している箇所や、execve コール自体の詳細を確認します。エラーコード (ENOEXEC など) が表示されることがあります。

解決策:

  • 不足しているライブラリをインストールする:
    ldd の出力で「not found」となっているライブラリを、パッケージマネージャーを使ってインストールします。32ビットバイナリの場合は、対応する32ビット版ライブラリパッケージを探してインストールします(原因1の解決策参照)。
    どのパッケージに特定のライブラリファイルが含まれているかは、ディストリビューションの検索機能(例: Debian/Ubuntuの apt-file search <library_file_name>、RHEL/CentOSの yum provides <library_file_name> または dnf provides <library_file_name>)で調べられます。
  • 環境変数 LD_LIBRARY_PATH を設定する:
    特定のディレクトリにあるライブラリを使用させたい場合は、LD_LIBRARY_PATH 環境変数にそのディレクトリのパスを設定して実行します。これは開発環境やテストなどで一時的に使用する方法であり、システム全体に設定することは推奨されません。
    bash
    export LD_LIBRARY_PATH=/path/to/your/libraries:$LD_LIBRARY_PATH
    /path/to/your/executable
  • Rpath/Runpath の確認:
    実行ファイル自体に特定のライブラリパス情報(Rpath/Runpath)が埋め込まれている場合があります。これは objdump -x /path/to/your/executable | grep RPATH で確認できます。もしそこに古いパスや存在しないパスが指定されている場合、問題の原因となることがあります。解決には通常、ソースからの再コンパイルが必要です。
  • 動的リンカーの確認:
    ldd の出力で、動的リンカー自体のパスが表示されます(例: /lib64/ld-linux-x86-64.so.2)。このファイルが破損しているか、誤ったバージョンになっている場合は、システムの基本的なライブラリ(glibcなど)に問題がある可能性が高く、システムパッケージの再インストールやシステムの復旧が必要になる場合があります。

トラブルシューティングの手順

「cannot execute binary: exec format error」に遭遇した場合、以下の手順で体系的に原因を特定し、解決策を試すことをお勧めします。

  1. エラーメッセージを正確に確認する:
    表示されたエラーメッセージを正確に把握します。「exec format error」以外の付随情報(ファイル名、追加のエラーコードなど)がないか確認します。
  2. ファイルの存在と読み取り権限を確認する:
    まず基本として、実行しようとしているファイルが指定されたパスに存在するか、そしてそのファイルに対する読み取り権限が実行ユーザーにあるかを確認します。
    bash
    ls -l /path/to/your/file

    ファイルが存在しない、または読み取り権限がない場合は、それぞれ「No such file or directory」や「Permission denied」エラーになるはずですが、稀に別のエラーとして現れることもあります。
  3. file コマンドでファイルタイプとアーキテクチャを確認する (最も重要):
    bash
    file /path/to/your/file

    この出力は、ファイルがどのような種類のファイルであり、どのようなアーキテクチャ向けにビルドされているかを示す最も重要な手がかりです。

    • ELF executable: バイナリ形式。アーキテクチャ (x86-64, ARM, Intel 80386 など) を確認します。
    • script: スクリプト形式。シバン行や改行コードに問題がないか確認します(手順5へ)。
    • PE, Mach-O: WindowsまたはmacOSの形式。Linuxでは直接実行できません(原因2)。
    • data, ASCII text など: 実行ファイルとして認識されていない。目的のファイルか、破損していないか確認します(原因2)。
  4. システムアーキテクチャと比較する:
    手順3で確認したバイナリのアーキテクチャと、現在のシステムアーキテクチャを比較します。
    bash
    uname -m

    アーキテクチャやビット数が異なる場合は、原因1の解決策(適切なバイナリの入手、互換ライブラリのインストールなど)を試します。
  5. ファイル権限を確認し、必要なら実行権限を付与する:
    bash
    ls -l /path/to/your/file

    実行権限 (‘x’) がない場合は、chmod +x /path/to/your/file で付与します(原因3)。
    もしファイルシステムが noexec でマウントされていないかも確認します(mount コマンド、原因3)。
  6. スクリプトの場合はシバン行とインタプリタを確認する:
    file コマンドでスクリプトと判断された場合、以下の点を確認します(原因4)。

    • head -n 1 /path/to/your/script でシバン行をチェック。
    • シバン行のインタプリタパスを which で確認。
    • file コマンド出力に CRLF line terminators がないか確認。
      シバン行の修正、インタプリタのインストール、改行コードの変換を行います。
  7. ldd で依存ライブラリを確認する:
    file コマンドでELFバイナリと判断されたが実行できない場合、必要な共有ライブラリが不足していないか確認します(特に32ビットバイナリの場合)。
    bash
    ldd /path/to/your/executable

    「not found」があれば、対応するライブラリパッケージをインストールします(原因7)。
  8. strace で実行トレースを確認する:
    上記の手順で原因が特定できない場合、strace でプログラムの実行をトレースし、システムコールレベルでのエラーを確認します。
    bash
    strace /path/to/your/file

    execve() システムコールの呼び出しや、その後のファイルオープン、メモリマッピングなどでエラー(特に ENOEXEC)が発生していないか詳細にログを調べます。
  9. カーネルログ (dmesg) やシステムログを確認する:
    カーネルやシステムレベルでのエラーが発生している可能性があるため、ログを確認します。特にエラー発生直後のログが重要です(原因5, 6)。
    bash
    dmesg | tail
    sudo journalctl -xe # systemd環境の場合
  10. SELinux/AppArmor の状態を確認する:
    セキュリティ機構が有効になっている場合、一時的にPermissiveモードにして実行できるか確認します(原因6)。原因特定後はポリシーの調整を行います。
    bash
    getenforce # SELinux
    sudo aa-status # AppArmor

    一時的に変更: sudo setenforce Permissive または sudo aa-complain /path/to/your/file
  11. ファイルのソースやファイルシステムを確認する:
    ダウンロードしたファイルの場合は、ダウンロード元や方法を変えて再入手してみます。ファイルがネットワークファイルシステム(NFSなど)上にある場合は、ローカルにコピーして実行できるか確認します(原因2, 5)。ファイルシステムの破損も考慮します(原因5)。

これらの手順を順に実行することで、ほとんどの「exec format error」の原因を特定し、適切な解決策を見つけることができるはずです。

特定のシナリオとケーススタディ

Dockerコンテナ内でのエラー

Dockerコンテナは、ホストOSとは独立した環境を提供しますが、内部で使用されるベースイメージは特定のOSやアーキテクチャに基づいています。コンテナ内で「exec format error」が発生する場合、以下の原因が考えられます。

  • ホストとコンテナのアーキテクチャ不一致: 例えば、x86-64ホスト上でARMベースのコンテナイメージを実行しようとする、またはその逆の場合。QEMUなどのエミュレーターが使用されますが、互換性の問題が生じることがあります。
  • コンテナイメージ内のアーキテクチャ不一致: コンテナイメージ自体が、異なるアーキテクチャ向けのバイナリを含んでいる場合。
  • ベースイメージと追加バイナリのアーキテクチャ不一致: x86-64のベースイメージに、誤って32ビットのx86バイナリやARMバイナリを追加した場合。
  • コンテナ内の必要なライブラリ不足: 特に32ビットバイナリを64ビットコンテナ内で実行する場合など、互換ライブラリがイメージに含まれていない場合。
  • Scratchイメージや最小限イメージ使用時の問題: 極端に小さなコンテナイメージ(Alpine Linuxなど)では、基本的なライブラリやシェル(Bashなど)、インタプリタがデフォルトで含まれていない場合があります。
  • ボリュームマウントされたファイルの権限や形式: ホストからコンテナにボリュームとしてマウントされた実行ファイルが、コンテナ内のファイルシステムで実行可能になっていない、またはホスト側の属性を引きずっている場合。

解決策:

  • コンテナイメージのアーキテクチャを確認する: docker inspect <image_name> コマンドの出力で Architecture を確認します。ホストと一致しない場合は、適切なアーキテクチャのイメージを選択するか、マルチアーキテクチャイメージを構築/使用します。
  • Dockerfile を確認する: バイナリのコピー元や、インストールしているパッケージを確認し、ターゲットアーキテクチャに合ったものを選んでいるか確認します。32ビットバイナリを含める場合は、Dockerfile 内で dpkg --add-architecture i386yum install *.i686 など、32ビット互換パッケージのインストールを含める必要があります。
  • 必要なパッケージ(ライブラリ、インタプリタ)をインストールする: 最小限のイメージを使用している場合は、apk add, apt-get install, yum install などで必要なランタイム(libc、インタプリタなど)を追加します。
  • ボリュームマウントのオプションを確認する: Docker Compose の volumes 設定などで、実行権限が正しく設定されているか確認します。

クロスコンパイル環境でのエラー

あるアーキテクチャのシステム(ホスト)で、別のアーキテクチャ(ターゲット)向けのバイナリをコンパイルすることをクロスコンパイルといいます。この環境で、誤ってターゲット向けのバイナリをホスト上で実行しようとすると、「exec format error」が発生します。

詳細な説明:

  • ターゲットバイナリの誤実行: ビルドプロセスで生成されたターゲット向けの実行ファイルやテストバイナリを、ターゲット環境ではなく開発用のホスト環境で直接実行しようとした。

解決策:

  • ターゲット環境で実行する: クロスコンパイルされたバイナリは、そのターゲットアーキテクチャのシステム(物理デバイス、仮想マシン、エミュレーター、コンテナなど)で実行する必要があります。
  • エミュレーターを使用する: ホスト上でターゲットアーキテクチャのバイナリを実行するために、QEMU User Emulation のようなツールを使用することができます。例えば、qemu-aarch64 /path/to/arm64/executable のように実行します。これを binfmt_misc と組み合わせて、透過的に実行できるように設定することも可能です。
  • ホスト上で実行可能なツール(ビルドツールなど)とターゲットバイナリを区別する: クロスコンパイル環境では、ホスト上で実行されるコンパイラやビルドツールと、ターゲット向けに生成される成果物(バイナリ)を明確に区別し、誤ってターゲットバイナリをホスト上で実行しないように注意が必要です。

ネットワークファイルシステム (NFS) 上でのエラー

NFSのようなネットワークファイルシステム上で実行ファイルを実行しようとした際に、エラーが発生する場合があります。

詳細な説明:

  • NFSマウントオプション: NFSクライアント側で noexec オプション付きでマウントされている場合、そのボリューム上のファイルは実行できません(原因3と同様)。
  • ファイル属性の不整合: クライアントとサーバー間でファイル属性(権限など)が正しく同期されない、または解釈が異なる場合。
  • ネットワークの問題やNFSサーバーの不安定性: ファイル内容の読み取りが途中で中断されたり、不正なデータが返されたりすることで、カーネルが実行形式を正しく認識できなくなる。
  • User ID/Group ID (UID/GID) マッピングの問題: NFSv4などではUID/GIDマッピングが行われますが、設定ミスがあるとファイルの所有者や権限が正しく認識されない場合があります。

解決策:

  • クライアント側のNFSマウントオプションを確認する: /etc/fstabmount コマンドの出力で、該当するNFSマウントに noexec オプションが付いていないか確認します。付いている場合は exec に変更して再マウントします(原因3と同様)。
  • ローカルにコピーして実行してみる: 問題のファイルをNFSボリュームからローカルのファイルシステムにコピーし、そこで実行できるか確認します。もしローカルでは実行できる場合、NFSのマウント設定やネットワーク、サーバー側の問題が原因である可能性が高いです。
  • NFSサーバーとクライアントの設定を確認する: エクスポートオプション(no_root_squash, all_squash など)、バージョン、UID/GIDマッピング設定などを確認します。
  • ネットワークの安定性を確認する: ネットワーク遅延やパケットロスが問題を引き起こしていないか確認します。

まとめ

「cannot execute binary: exec format error」は、Linux/Unix環境でプログラム実行時によく遭遇するエラーですが、その原因は単一ではなく、ファイルそのものの属性、実行環境、権限、さらに低レベルなカーネルやファイルシステム、セキュリティ機構に至るまで、多岐にわたります。

本記事で解説した主な原因は以下の通りです。

  1. アーキテクチャの不一致: バイナリが想定するCPUやビット数が、実行システムのそれと異なる。
  2. ファイル形式の不一致または破損: LinuxのELF形式ではないファイル(Windows PE, macOS Mach-Oなど)を実行しようとした、またはファイルが破損している。
  3. ファイル権限の問題: 実行ファイルに実行権限がない、またはファイルシステムが noexec でマウントされている。
  4. スクリプトのシバン行またはインタプリタの問題: スクリプトファイルのシバン行が不正、インタプリタが存在しない、または改行コードがWindows形式。
  5. カーネルまたはファイルシステムの問題: バイナリフォーマットローダーの設定、ファイルシステムドライバーの問題、ファイルシステムの破損など。
  6. SELinux/AppArmorなどのセキュリティ機構: セキュリティポリシーによって実行がブロックされている。
  7. ライブラリの依存関係または動的リンカーの問題: 必要な共有ライブラリが見つからない(特に32ビット環境関連)。

これらの原因を特定するための最も重要な最初のステップは、file コマンドを使用して対象ファイルのタイプとアーキテクチャを確認することです。続くステップとして、ls -l で権限を確認し、必要に応じて ldd で依存ライブラリ、head でスクリプトのシバン行、mount でファイルシステムオプション、dmesg や監査ログでシステムレベルのエラー、strace で実行トレースを詳細に調査します。

体系的なトラブルシューティングの手順を踏むことで、原因を絞り込み、適切な解決策(適切なバイナリの入手、権限の変更、ライブラリのインストール、スクリプトの修正、ファイルシステムの修復、セキュリティポリシーの調整など)を適用することができます。

このエラーは、OSがどのように実行ファイルを認識し、ロードするかの仕組みを理解する良い機会でもあります。本記事が、「exec format error」に遭遇した際の冷静な対処と問題解決の一助となれば幸いです。


コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

上部へスクロール