EACCES(Permission denied)
Permission denied(EACCES)が出たら、パーミッション・所有者・特権ポート・SELinuxのどれが原因かを切り分け、最小権限のまま安全に直す逆引き手順が身につく。
- EACCESはカーネルが権限チェックで拒否した合図。ファイルのモード/所有者だけでなく、1024未満ポートへのbind、SELinux/AppArmor、実行ビット無しなど原因は複数ある。
- 診断は ls -l と id で主体と対象の権限を突き合わせ、それでも説明がつかなければ dmesg/ausearch で LSM(SELinux/AppArmor)の拒否を疑う順で切り分ける。
- 解決は最小権限が原則。chmod/chownで直せる場合も root常用やchmod 777は避け、特権ポートはsetcapのCAP_NET_BIND_SERVICEで、SELinuxはaudit2allowでポリシーを絞る。
一言でいうと(このエラーが何を意味するか)
EACCES は「Permission denied」に対応する POSIX のエラー番号(多くの Linux で errno 13)で、カーネルがアクセス制御チェックの結果として操作を拒否したことを意味します。ファイルが存在しないわけでも壊れているわけでもなく、いま実行している主体(プロセスの実効 UID/GID とケーパビリティ)に、その対象へその操作を行う権限が無い、という判定です。
重要なのは、EACCES は単一の原因を指さないことです。カーネルの権限判定は複数の層を順に通り、どこか1つでも拒否すれば EACCES(またはポートで EACCES、所有権操作で EPERM)が返ります。層は大きく分けて、(1) 従来型の所有者・グループ・その他のパーミッションビット(DAC)、(2) ケーパビリティ(1024 未満ポートへの bind など特権操作)、(3) SELinux や AppArmor などの LSM(MAC)です。DAC で許可されても MAC で拒否されれば EACCES になります。
ENOENT(No such file or directory)は対象そのものが無い場合。EPERM(Operation not permitted)は「そもそも特権が要る操作」を非特権で行った場合(chown、bind の一部、mount など)で、EACCES が「DAC のパーミッション不足」寄りなのに対し EPERM は「ケーパビリティ不足」寄りです。ただしポート bind のように EACCES を返す特権操作もあり、両者は文脈で読み分けます。
横にスクロール
よくある原因(複数を具体的に、頻度順)
- ファイルのパーミッションビット不足(最頻): 読みたいのに r が、書きたいのに w が、実行したいのに x が無い。ディレクトリの x(実行ビット)は「通過(探索)」権限で、これが無いと配下のファイルを名前で開けません。ディレクトリの r は「一覧」権限で別物です。
- 所有者・グループの不一致: モードは十分でも、対象の所有者が別ユーザーで、自分は「その他(other)」の権限しか得られていない。
www-dataが作ったファイルを別ユーザーで開くなど。 - 実行ビットが無い/スクリプトを直接起動:
./script.shに x が無い、あるいは x はあってもシェバン(#!/usr/bin/env bashなど)の指すインタプリタが不正。 - 1024 未満(特権)ポートへの bind: 非 root で 80/443 に listen しようとすると bind(2) が EACCES。ケーパビリティ CAP_NET_BIND_SERVICE が無いため。
- SELinux/AppArmor(MAC)による拒否: DAC 上は問題ないのに、ラベルやプロファイルで拒否される。Nginx が非標準ドキュメントルートを読めない、コンテナがホストのボリュームに書けない等が典型。
- マウントオプション:
noexecでマウントされた領域上のバイナリ実行、ro領域への書き込み。 - 上位ディレクトリの探索権限欠如: 目的のファイル自体は 644 でも、途中のディレクトリに x が無ければ到達できない。
cat /a/b/c.txt が EACCES のとき、c.txt のモードだけ見ても解決しないことがあります。パスを構成する /a と /a/b の各ディレクトリに実行(探索)ビットが必要で、途中の1つでも x が欠けると配下に到達できません。切り分けでは対象ファイルだけでなく親ディレクトリ群の権限も確認します。
診断の手順(切り分け方・見るべきログ/コマンド)
まず「誰が(主体)」「何に(対象)」「何をして(操作)」拒否されたかを確定します。strace で失敗したシステムコールと errno を特定するのが最短です。
# どのシステムコールがEACCESで落ちたかを特定
strace -f -e trace=openat,execve,bind ./myapp
# 出力例: openat(AT_FDCWD, "/etc/app/secret", O_RDONLY) = -1 EACCES (Permission denied)
次に主体と対象を突き合わせます。
id # 実効UID/GID・所属グループを確認
ls -l /etc/app/secret # 対象の所有者・グループ・モードを確認
namei -l /etc/app/secret # パス上の各ディレクトリの権限を上から順に表示
DAC で説明がつく(モード・所有者・グループのいずれかが不足)なら、そこが原因です。DAC 上は通るはずなのに EACCES なら、MAC を疑います。
getenforce # SELinuxがEnforcingか確認
sudo ausearch -m avc -ts recent # 直近のSELinux拒否(AVC denied)を検索
sudo dmesg | grep -i -e denied -e apparmor # AppArmorの拒否メッセージ
特権ポートの疑いには、プロセスのケーパビリティやバイナリのファイルケーパビリティを確認します。
getcap /usr/bin/myserver # バイナリに付与されたケーパビリティ
grep Cap /proc/$(pgrep myserver)/status # 稼働プロセスの実効ケーパビリティ
| 症状 | 確認コマンド | 疑うべき原因 |
|---|---|---|
| ファイルを開けない | ls -l / namei -l / id | モード・所有者・親ディレクトリの探索権限 |
| 80/443にbindできない | getcap / id | 特権ポート(CAP_NET_BIND_SERVICE不足) |
| DACは通るのに拒否 | getenforce / ausearch -m avc | SELinuxラベル不一致 |
| 実行できない | ls -l / file / mount | 実行ビット無し・シェバン不正・noexec |
SELinux の拒否は ausearch -m avc -ts recent | audit2allow -w で「なぜ拒否したか」を平易に読めます。audit2allow -M mymodule はそのまま許可する最小ポリシーモジュールを生成しますが、鵜呑みで適用せず、まずは正しいラベル付け(restorecon)や真偽値(setsebool)で直せないかを先に検討します。
解決と予防(対処と再発防止)
原因の層に応じて対処します。共通原則は最小権限で、chmod 777 や root 常用は EACCES を消す代わりに攻撃面を広げるため避けます。
- パーミッション・所有者: 必要な最小ビットだけ付ける。ファイルは通常
644、ディレクトリと実行ファイルは755。所有者を正すならchown。
chmod 640 /etc/app/secret # 所有者rw・グループr、その他は無権限
chown appuser:appgroup /etc/app/secret
chmod +x ./deploy.sh # 実行ビットを付与(スクリプト起動時のEACCES)
- 特権ポート: root で起動して権限降格する代わりに、バイナリにケーパビリティを与えるか、リバースプロキシ経由にする。
# rootでなくても80/443にbind可能にする(最小特権)
sudo setcap 'cap_net_bind_service=+ep' /usr/bin/myserver
- SELinux/AppArmor: 拒否を無効化(
setenforce 0)で握りつぶさない。正しいラベルを回復するか、必要な真偽値を立てる。
restorecon -Rv /var/www/site # 既定のラベルを回復
setsebool -P httpd_read_user_content on # 必要な操作だけ真偽値で許可
chmod 777、SELinux の Permissive 化、常時 sudo は、確かに EACCES を止めますが、権限境界そのものを壊します。とくに Web に露出するプロセスでこれをやると、1つの脆弱性が任意ファイルの読み書きに直結します。恒久対処は必ず「必要な主体に、必要な対象への、必要な操作だけ」を許す形にします。
再発防止(root でない権限設計): サービスは専用の非特権ユーザーで動かし、特権が要る操作だけをケーパビリティで局所的に付与します。特権ポートは setcap かプロキシで解決し、書き込みが要るパスだけを所有者・グループで限定します。SELinux/AppArmor は無効化せず、必要な許可を最小ポリシーとして明示的に足します。この設計なら、万一プロセスが乗っ取られても被害範囲がその権限内に閉じます。
- EACCESはerrno 13。ENOENT(対象なし)・EPERM(特権操作を非特権で)との違いを説明できること
- ディレクトリの x は「探索(通過)」、r は「一覧」。パス上の全ディレクトリに x が要る
- 1024未満ポートへのbindが非rootで失敗する理由はCAP_NET_BIND_SERVICE不足。setcapで最小付与
- SELinux拒否は ausearch -m avc → audit2allow で読む。setenforce 0 は解決でなく回避
- 恒久対処は最小権限。chmod 777・root常用・Permissive化は権限境界を壊すアンチパターン
権限判定の前提となる所有者・パーミッション・プロセス特権のモデルはOSを、SELinux/AppArmor や最小権限の考え方はセキュリティを、特権ポートやリバースプロキシ構成の背景はネットワークを参照してください。
エラー辞典の記事ガイド
EACCES(Permission denied)を実務で読む
TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。
解決すること
Linux
比較で見る軸
難易度: advanced / カテゴリ: エラー辞典 / タグ数: 6
導入後に効く点
診断は ls -l と id で主体と対象の権限を突き合わせ、それでも説明がつかなければ dmesg/ausearch で LSM(SELinux/AppArmor)の拒否を疑う順で切り分ける。
先に潰すリスク
用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。
- 難易度
- advanced
- カテゴリ
- エラー辞典
- タグ数
- 6
判断チェックリスト
- 自社の用途が「Linux / パーミッション」に近いか確認する。
- 強みである「EACCESはカーネルが権限チェックで拒否した合図。ファイルのモード/所有者だけでなく、1024未満ポートへのbind、SELinux/AppArmor、実行ビット無しなど原因は複数ある。」が本当に評価軸になるか確認する。
- 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
- 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
- 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
- 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。