Linuxで Permission denied に遭遇したことがない人はいないだろう。原因の大半は、ファイルやディレクトリに設定された**パーミッション(権限)**が、今実行しようとしている操作を許可していないことにある。この記事では、ls -l の読み方という基礎から、chmod の数字(8進数)が何を意味するのか、chown/chgrp による所有者変更、umask によるデフォルト権限の決まり方、SUID/SGID/sticky bitという特殊権限、そして基本の9ビットでは足りない場合の ACL(POSIX ACL) と capabilities まで、Linuxのパーミッションを一通り体系的に整理する。
1. Linuxのパーミッションとは
Linuxのファイルシステムでは、すべてのファイルとディレクトリに「誰が」「何を」できるかを示すパーミッション情報が付与されている。これを確認する最も基本的なコマンドが ls -l だ。
$ ls -l file.sh
-rwxr-xr-- 1 yuhi-sa staff 220 7 20 09:30 file.sh
先頭の -rwxr-xr-- という10文字が、このファイルの種別とパーミッションを表す文字列である。これを分解すると次のようになる。
図1: -rwxr-xr-- の9ビット分解と8進数(754)への変換

1文字目: ファイルタイプ
最初の1文字はパーミッションではなく、ファイルの種別を表す。代表的なものは次の通り。
| 文字 | 意味 |
|---|---|
- | 通常ファイル |
d | ディレクトリ |
l | シンボリックリンク |
p | 名前付きパイプ(FIFO) |
s | ソケット |
b / c | ブロック/キャラクタデバイス |
2〜10文字目: 3つの権限区分 × rwx
残り9文字は、所有者(owner/user)・所有グループ(group)・その他(other) の3区分について、それぞれ3文字ずつ r(read, 読み取り)・w(write, 書き込み)・x(execute, 実行)の可否を示す。権限がなければ - になる。つまり9ビットの真偽値(ビットマップ)の集合であり、これが「基本パーミッション」あるいは「9ビットパーミッション」と呼ばれるものの正体である。
なぜ「所有者・グループ・その他」の3区分なのか。これは、1人のユーザーに対して個別に権限を割り当てる代わりに、ユーザーを「本人」「特定のグループのメンバー」「それ以外の全員」という3層に分類することで、少ないビット数(3区分 × 3ビット = 9ビット)で実用上十分な権限管理を実現するためだ。より細かい制御が必要な場合の解決策が、7章で扱う ACL である。
先頭の -rwxr-xr-- の例では、所有者は読み書き実行すべて可能(rwx)、グループは読み取りと実行のみ可能(r-x)、その他は読み取りのみ可能(r--)ということになる。
2. chmodの数字(8進数)の意味
パーミッションを変更するコマンドが chmod(change mode)である。chmod には数値モード(8進数)とシンボリックモードの2つの指定方法がある。
数値モード: rwxを4・2・1で足し算する
r・w・x にはそれぞれ 4・2・1 という値が割り当てられており、権限が「ある」ビットの値を合計したものが1桁の8進数になる。3区分あるので、合計3桁の数字でパーミッション全体を表現できる。
| 権限 | 2進数 | 8進数 |
|---|---|---|
--- (なし) | 000 | 0 |
--x (実行のみ) | 001 | 1 |
-w- (書き込みのみ) | 010 | 2 |
-wx | 011 | 3 |
r-- (読み取りのみ) | 100 | 4 |
r-x | 101 | 5 |
rw- | 110 | 6 |
rwx (すべて) | 111 | 7 |
先ほどの -rwxr-xr-- であれば、所有者 rwx=7、グループ r-x=5、その他 r--=4 なので、これは chmod 754 と表現できる。よく使われる組み合わせを一覧にしておく。
| 数値 | 意味 | 典型的な用途 |
|---|---|---|
777 | 全員が読み書き実行可能 | ほぼ非推奨。誰でも改ざん・削除可能になる |
755 | 所有者は読み書き実行、他は読み取り実行 | 実行可能スクリプト、ディレクトリの定番 |
700 | 所有者のみ読み書き実行 | 秘密鍵、個人用スクリプト |
644 | 所有者は読み書き、他は読み取りのみ | 一般的な設定ファイル、HTMLなど |
600 | 所有者のみ読み書き | 秘密鍵、パスワードを含む設定ファイル |
640 | 所有者は読み書き、グループは読み取りのみ | グループ内で共有するログファイルなど |
chmod 755 deploy.sh # 所有者rwx、グループ/その他 r-x
chmod 644 index.html # 所有者rw-、グループ/その他 r--
chmod 600 id_rsa # 所有者rw-のみ、他は一切アクセス不可
シンボリックモード: u/g/o/a と +/-/= で指定する
数値モードは全体を一度に上書きするのに向いているが、「所有者にだけ実行権限を足したい」のように一部だけ変更したい場合はシンボリックモードが便利だ。書式は [対象][操作][権限] で表される。
| 対象 | 意味 |
|---|---|
u | 所有者(user) |
g | グループ(group) |
o | その他(other) |
a | 全員(all、指定省略時の既定と同義) |
| 操作 | 意味 |
|---|---|
+ | 権限を追加する |
- | 権限を削除する |
= | 指定した権限に上書きする(記載のない権限は削除される) |
chmod u+x script.sh # 所有者に実行権限を追加
chmod go-w secret.conf # グループとその他から書き込み権限を削除
chmod a=r public.txt # 全員を読み取りのみに上書き
chmod u=rwx,g=rx,o=r file # 754と同じ意味をシンボリックモードで表現
X(大文字)という特殊な権限文字もある。これは「対象がディレクトリであるか、既にいずれかの区分で実行権限が設定されている場合にのみ」実行権限を付与するもので、chmod -R a+X のようにディレクトリツリー全体へ再帰的に権限を付与する際、通常ファイルまで無条件に実行可能にしてしまう事故を防げる。
-R オプションを付けるとディレクトリ以下を再帰的に変更できるが、後述するSUID/SGIDビットが意図せず付与・削除されるケースがあるため、特殊権限を含むツリーに対する再帰適用は慎重に行う必要がある。
3. 所有者とグループ: chown/chgrp
パーミッションの3区分(所有者・グループ・その他)のうち、「誰が所有者で、どのグループに属するか」を変更するのが chown(change owner)と chgrp(change group)である。
chown yuhi-sa file.txt # 所有者をyuhi-saに変更
chown yuhi-sa:staff file.txt # 所有者とグループを同時に変更
chown :staff file.txt # グループのみ変更(chgrp staff file.txtと同義)
chgrp staff file.txt # グループのみ変更する専用コマンド
chown -R www-data:www-data /var/www/app # ディレクトリ以下を再帰的に変更
所有者・グループの変更には通常root権限(sudo)が必要である。これは、任意のユーザーが他人のファイルの所有権を自由に自分に付け替えられてしまうと、パーミッションによるアクセス制御そのものが意味をなさなくなるためだ。なお、Linuxではこの制限は CAP_CHOWN という capability(7章で解説)によって実現されている。
所有者・グループが3区分制になっている理由は先述の通りだが、実務上は「Webサーバーのプロセスが実行するユーザー(www-data など)をグループに含め、デプロイ担当者は所有者として管理する」といった形で、chownとchmodを組み合わせて権限モデルを設計することが多い。
4. umaskとデフォルトパーミッション
新しくファイルやディレクトリを作成したとき、パーミッションは何もしなくても自動的に決まる。これを制御しているのが umask(user file-creation mode mask)である。
umaskはシェルやプロセスに設定されたマスク値で、ファイル・ディレクトリの「基準パーミッション」から特定のビットを差し引く(オフにする)働きをする。計算式は次の通り。
最終パーミッション = 基準パーミッション & ~umask
基準パーミッションは、通常ファイルが 666(実行ビットは持たない)、ディレクトリが 777(検索のために x が必要)である。デフォルトでよく使われる umask 022 の場合を計算してみる。
$ umask
0022
$ touch newfile.txt && ls -l newfile.txt
-rw-r--r-- 1 yuhi-sa staff 0 7 20 09:30 newfile.txt
$ mkdir newdir && ls -ld newdir
drwxr-xr-x 2 yuhi-sa staff 64 7 20 09:30 newdir
- ファイル:
666 & ~022=666 - 022=644(rw-r--r--) - ディレクトリ:
777 & ~022=777 - 022=755(rwxr-xr-x)
umaskのビットは「グループとその他から書き込み権限を落とす」という意味の 022 を指定していることになる。umaskを変更すればデフォルトの権限を厳しく(あるいは緩く)できる。
umask 077 # 新規ファイルは600、新規ディレクトリは700になる(所有者以外アクセス不可)
umask 002 # グループにも書き込みを許す(共有作業ディレクトリなどで使用)
umaskは現在のシェルセッションにのみ有効なので、恒久的に変更したい場合は ~/.bashrc や /etc/profile などに記述する。サーバーの用途によっては umask 027(その他からの読み取りも遮断)のように、デフォルトから絞る運用も一般的だ。
5. 特殊権限: SUID・SGID・sticky bit
基本の9ビットに加えて、Linuxには特殊権限と呼ばれる3種類のビットがある。数値モードでは4桁目(先頭)に 4(SUID)・2(SGID)・1(sticky bit)を足すことで指定する。
図2: SUID・SGID・sticky bitの効果まとめ

SUID (Set User ID, +4000)
SUIDが設定された実行ファイルは、実行したユーザーではなく、ファイルの所有者の権限で動作する。典型例が passwd コマンドだ。
$ ls -l /usr/bin/passwd
-rwsr-xr-x 1 root root 68208 ... /usr/bin/passwd
所有者の実行ビットの位置が x ではなく s になっている点に注目してほしい。passwd はユーザーが自分のパスワードを変更するためのコマンドだが、パスワードの実体は一般ユーザーには書き込み権限のない /etc/shadow に格納されている。SUIDによって passwd が実行中だけroot権限で動作するため、一般ユーザーでも自分の分だけパスワードを更新できる、という仕組みになっている。
SUIDは強力な分、リスクも大きい。root所有でSUIDが付いたスクリプトやバイナリに脆弱性があると、一般ユーザーがroot権限を奪取する足がかりになりうる。find / -perm -4000 のようなコマンドでSUID付きファイルを定期的に棚卸しするのはセキュリティ運用の基本だ。なお、ディレクトリに対してSUIDを立てても、Linuxでは通常意味を持たない。
SGID (Set Group ID, +2000)
SGIDは対象がファイルかディレクトリかで挙動が変わる。
- ファイルの場合: SUIDと同様に、実行したユーザーの所属グループではなく、ファイルのグループの権限で動作する。
- ディレクトリの場合: そのディレクトリ配下に新しく作成されるファイル・サブディレクトリの所有グループが、作成者本人のプライマリグループではなく親ディレクトリと同じグループに自動的に引き継がれる。
後者はチーム共有ディレクトリの構築で頻繁に使われる。
sudo chmod 2775 /srv/shared
sudo chown :teamdev /srv/shared
こうしておけば、teamdev グループの誰がファイルを作成しても、そのファイルは自動的に teamdev グループ所有になり、グループメンバー全員が編集できる状態を保てる。SGIDなしでは、作成者ごとに異なるプライマリグループが付与されてしまい、権限がバラつく問題が起きやすい。
Sticky Bit (+1000)
sticky bitは主にディレクトリに対して使う。これが設定されたディレクトリでは、ファイルの削除・リネームができるのは、そのファイルの所有者(またはディレクトリの所有者、root)に限られる。ディレクトリ自体への書き込み権限があっても、他人が作成したファイルは削除できない。
最も身近な例が /tmp である。
$ ls -ld /tmp
drwxrwxrwt 10 root root 4096 ... /tmp
その他区分の実行ビットの位置が x ではなく t になっている。/tmp は全ユーザーが読み書きできる(rwxrwxrwx)が、sticky bitがなければ、あるユーザーが作った一時ファイルを別の悪意あるユーザーが勝手に削除・置き換えできてしまう。sticky bitはこれを防ぎ、「共有の書き込み場所だが、他人のファイルには触れない」という状態を実現している。ファイルに対するsticky bitは、歴史的にはスワップ上にプログラムを常駐させる目的で使われていたが、現代のLinuxではファイルに対する効果は実質的に無効化されている。
表示上の大文字 S / T
ls -l の出力で特殊権限ビットが小文字(s, t)ではなく大文字(S, T)で表示されることがある。これは、特殊権限は立っているが、対応する実行ビット(x)が立っていないという矛盾した状態を示す。例えば rwSr--r-- は「SUIDは設定されているが、所有者に実行権限がない」状態で、実質的にSUIDは機能しない。設定ミスの兆候として覚えておくとよい。
6. ディレクトリのパーミッションの意味
ディレクトリの r・w・x は、ファイルの場合と意味が異なるため誤解されやすい。まとめると次の通りだ。
| ビット | ディレクトリでの意味 |
|---|---|
r | ディレクトリ内のファイル名の一覧を取得できる(ls が実行できる) |
w | ディレクトリ内でファイルの作成・削除・リネームができる |
x | ディレクトリを通過できる(cd やパス経由でのファイルアクセスに必要) |
特に誤解されやすいのが次の2点だ。
w(書き込み権限)は「ファイルの中身」ではなく「ディレクトリ内の一覧」に対する操作を許可する。あるファイルの中身を編集できるかどうかは、そのファイル自身のパーミッションで決まる。逆に言えば、ファイル自体が600で自分以外書き込み不可でも、そのファイルが置かれているディレクトリに書き込み権限があれば、他人がそのファイルを削除できてしまう。これが sticky bit が必要になる理由でもある。x(実行権限)がないディレクトリは、中のファイル名を知っていてもアクセスできない。xは「通過権」であり、cd dirnameの実行やcat dirname/file.txtのようなパス越しのアクセスに必須である。rだけあってxがないディレクトリは、lsでファイル名の一覧は見えるが、個々のファイルの中身へはアクセスできないという奇妙な状態になる。
$ mkdir noexec && touch noexec/secret.txt
$ chmod 644 noexec # rwなのにxがない
$ ls noexec
secret.txt # 一覧は見える(rがあるので)
$ cat noexec/secret.txt
cat: noexec/secret.txt: Permission denied # 通過できないので中身は読めない
パスを辿ってファイルにアクセスするには、そのパス上のすべてのディレクトリに x 権限が必要である。深い階層のファイルで Permission denied が出た場合、対象ファイル自身だけでなく、途中のディレクトリの権限も確認する必要がある。
7. ACLとcapabilities: 9ビットで足りないとき
所有者・グループ・その他の3区分9ビットは強力だが、「特定の1人にだけ追加で権限を与えたい」「複数のグループに異なる権限を与えたい」といった細かい要求には対応できない。この限界を超えるのが POSIX ACL(Access Control List) である。
getfacl / setfacl
ACLを使うには acl パッケージ(多くのディストリビューションで標準または容易にインストール可能)が必要で、対象のファイルシステムがACLをサポートしている必要がある(ext4・XFSなどは標準対応)。
# 現在のACLを確認する
$ getfacl report.csv
# file: report.csv
# owner: yuhi-sa
# group: staff
user::rw-
group::r--
other::r--
# ユーザーalice個人に読み書き権限を追加で付与する
$ setfacl -m u:alice:rw report.csv
# グループdevには読み取りのみ追加で付与する
$ setfacl -m g:dev:r report.csv
# 付与したACLを確認する(末尾に+が付くのがACL設定済みの目印)
$ ls -l report.csv
-rw-rw-r--+ 1 yuhi-sa staff 1024 ... report.csv
$ getfacl report.csv
user::rw-
user:alice:rw-
group::r--
group:dev:r--
mask::rw-
other::r--
ls -l のパーミッション文字列の末尾に付く + が、そのファイルに通常の9ビットに加えてACLが設定されていることを示すサインである。
ACLエントリには user(特定ユーザー)・group(特定グループ)・mask・other の種別がある。ここで重要なのが mask エントリの役割だ。maskは、user(所有者以外)・group(グループオブジェクト以外)・特定グループに対するACLエントリが実際に許可できる権限の上限として働く。つまり、個別のACLエントリで rw を許可していても、maskが r だけなら実効権限は r に絞られる。chmod でグループパーミッションを変更すると、多くの実装ではmaskエントリの値が書き換わる点にも注意したい。
ACLの削除は次のように行う。
setfacl -x u:alice report.csv # aliceのエントリだけ削除
setfacl -b report.csv # ACLをすべて削除(基本の9ビットのみに戻す)
capabilities: root全権限を分割する
SUIDのところで触れた通り、「一部の操作だけroot権限が必要だが、プログラム全体をroot権限で動かすのはリスクが大きい」という問題は根強く存在する。この問題への現代的な解として、Linux 2.2以降では伝統的なroot権限を capabilities という単位に分割し、必要なものだけを個別に付与できるようになっている。
代表的なcapabilityには次のようなものがある。
| capability | 意味 |
|---|---|
CAP_NET_BIND_SERVICE | 1024番未満のポートへのbindを許可(従来はroot専用) |
CAP_NET_ADMIN | ネットワークインターフェース設定、ルーティングテーブル変更などを許可 |
CAP_CHOWN | 任意のファイルの所有者変更を許可 |
CAP_DAC_OVERRIDE | 通常のパーミッションチェックをバイパス |
CAP_SYS_ADMIN | マウント操作や名前空間管理など、広範な管理操作をまとめて許可(過剰権限になりやすく多用は非推奨) |
例えば、Webサーバーを80番ポートで動かすためだけにroot権限でプロセス全体を起動するのではなく、次のように必要なcapabilityだけをバイナリに付与できる。
# CAP_NET_BIND_SERVICEだけを付与し、root権限なしで80番ポートをbindできるようにする
sudo setcap 'cap_net_bind_service=+ep' /usr/bin/myserver
# 付与されているcapabilityを確認する
getcap /usr/bin/myserver
SUIDが「root権限を丸ごと渡す」オール・オア・ナッシングの仕組みであるのに対し、capabilitiesは「必要な権限だけを渡す」最小権限の原則を実現できる。root所有・SUID付きのバイナリを見つけたら、capabilitiesで代替できないか検討するのが、現代的なLinuxセキュリティ運用のセオリーである。
8. 実務チートシート & トラブルシュート
早見表
# 権限確認
ls -l file # ファイルの権限を確認
ls -ld dir # ディレクトリ自体の権限を確認(中身ではなく)
stat file # より詳細な情報(数値モードも表示)
# 権限変更
chmod 644 file
chmod -R 755 dir # 再帰的に変更(特殊権限には要注意)
chmod u+x script.sh
# 所有者変更
chown user:group file
chown -R user:group dir
# デフォルト権限
umask # 現在のumaskを確認
umask 022 # umaskを設定
# 特殊権限
chmod u+s file # SUID
chmod g+s dir # SGID
chmod +t dir # sticky bit
find / -perm -4000 2>/dev/null # SUID付きファイルの棚卸し
# ACL
getfacl file
setfacl -m u:username:rwx file
setfacl -b file
Permission denied の切り分け手順
Permission denied に遭遇したら、次の順序で確認すると原因を特定しやすい。
- 対象ファイル自体の権限を見る:
ls -l fileで、自分が所有者/グループ/その他のどの区分に該当するかを確認する。idコマンドで自分の所属グループも確認しておく。 - パス上のすべてのディレクトリの
x権限を見る: 6章で述べた通り、パスの途中にxのないディレクトリが1つでもあれば、その先へは到達できない。namei -l /path/to/fileを使うと、パス上の各階層の権限を一覧表示できて便利。 - ACLの有無を確認する:
ls -lの末尾に+が付いていれば、9ビットだけでなくACLも見る必要がある。getfacl fileで実効権限を確認する。 - SELinux/AppArmorなど強制アクセス制御(MAC)の可能性を疑う: 通常のパーミッション(DAC)がすべて許可していても、SELinuxやAppArmorのポリシーで拒否されているケースがある。
dmesgや/var/log/audit/audit.logにAVC denied のログがないか確認する。 - マウントオプションを疑う: ファイルシステムが
noexecやro(読み取り専用)でマウントされていないかmount | grep <マウントポイント>で確認する。
まとめ
Linuxのパーミッションは、ls -l の先頭に現れる10文字の記号列に集約されている。基本は所有者・グループ・その他の3区分 × rwxの9ビットで、chmod の数値モードはこれをr=4/w=2/x=1の合計として8進数1桁に変換したものにすぎない。所有者・グループは chown/chgrp で変更し、新規作成時のデフォルト権限は umask が制御する。基本の9ビットで足りない場面では、SUID/SGID/sticky bitという特殊権限、あるいはユーザー単位・グループ単位で権限を追加できるACL、root権限を分割するcapabilitiesという選択肢がある。Permission denied に遭遇したら、対象ファイル自身だけでなく、パス上のディレクトリ、ACL、MACまで含めて順に切り分けていくのが近道だ。
よくある質問(FAQ)
Q. chmod 777が危険な理由は?
A. 777 は所有者・グループ・その他すべてに読み書き実行の全権限を与える設定であり、システム上の誰でも(場合によってはネットワーク越しの他プロセスでも)そのファイルを自由に書き換え・削除・実行できてしまう。Webアプリケーションのファイルなどに設定すると、脆弱性を突かれた際に任意のコードを書き込まれるリスクに直結する。「動かないから777にする」は原因調査を放棄した対症療法であり、本来必要な権限区分(所有者・特定グループ)だけに絞り込むのが正しい対処である。
Q. 755と644はどう使い分ける?
A. 755(rwxr-xr-x)は所有者に加えてグループ・その他にも実行権限を与えるため、実行可能なスクリプトやプログラム、および中をcdで通過する必要があるディレクトリに使う。644(rw-r--r--)は実行権限を含まないため、設定ファイル・HTML・画像・ログなど「読めればよいが実行はしない」通常ファイルに使う。ディレクトリに644を設定するとxがないため中へcdできず、通常ファイルに755を設定すると不要な実行権限が付与されてしまう点に注意する。
Q. ディレクトリにxがないとどうなる?
A. 6章で述べた通り、x(実行権限)はディレクトリの「通過権」である。xがないディレクトリは、rがあればlsでファイル名の一覧までは見えるが、cdで中に入ることも、パス経由で中のファイルにアクセスすることもできなくなる。深い階層のファイルにアクセスできない場合、対象ファイルだけでなく、途中の各ディレクトリにxがあるかをnamei -lなどで確認する必要がある。
Q. chmodとchownの違いは?
A. chmod(change mode)は「誰が・何をできるか」という権限の内容(rwxのビット、SUID/SGID/sticky bit)を変更するコマンドである。一方 chown(change owner)は「誰が所有者/グループか」という権限を判定する主体を変更するコマンドである(グループのみの変更にはchgrpも使える)。両者は独立しており、たとえば「所有者をrootに変更(chown)した上で、所有者だけが書き込める設定(chmod 700)にする」のように組み合わせて使うのが一般的である。
関連書籍
コマンドライン操作とパーミッションを含むLinuxの基礎を体系的に学びたい読者には、定番入門書の最新版を挙げておく。
他の分野の定番書は エンジニアにおすすめの技術書10選 にまとめている。
参考文献
- chmod(1) - Linux manual page
- chmod(2) - Linux manual page
- umask(2) - Linux manual page
- acl(5) - Linux manual page
- capabilities(7) - Linux manual page
同シリーズでは、 ユーザー・グループの管理方法 や、パスワードなしでログインできる SSH公開鍵認証の設定方法 も解説しているので、あわせて参照してほしい。