Linuxでディレクトリの権限を変更した後、ls -l に次のような表示が出たことはありませんか?
-????????? ? ? ? ? ? ca.crt.pem
-????????? ? ? ? ? ? node.key.pem
ファイル名は表示されているのに、権限や所有者などが ? になっています。ファイルが壊れたのでしょうか?
原因の一つは、親ディレクトリに実行権限(x)がないことです。 ディレクトリにおける x はプログラムの「実行」ではなく、名前を指定して中の項目を探索する権限を意味します。
この記事では、UbuntuなどのLinux環境で安全に試せる一時ディレクトリを使い、r と x の違いを確かめます。
ディレクトリにも「実行権限」がある理由
ls -ld でディレクトリ自体の権限を確認すると、例えば次のように表示されます。
drwxr-xr-x
先頭の d はディレクトリを表します。続く rwx は、通常のファイルとディレクトリでは意味が少し異なります。
| 権限 | 通常のファイル | ディレクトリ |
|---|---|---|
r(read) |
ファイルの内容を読む | 中に登録されている名前を列挙する |
w(write) |
ファイルの内容を書き換える | 項目の作成・削除・名前変更を行う(通常は x も必要) |
x(execute/search) |
プログラムとして実行する | 名前を指定して中の項目を探索する |
ディレクトリの x は 探索権限(search permission) です。例えば dir/file.txt を開くには、dir に x が必要になります。
ここで重要なのは、「ファイル名の一覧を取得できる」ことと「そのファイルへアクセスできる」ことは別という点です。
一時ディレクトリで再現する
既存のディレクトリ、特にSSH鍵や証明書を置いている場所では試さないでください。アクセスできなくなり、アプリケーションの動作にも影響します。
以下は一般ユーザーのシェルで実行します。sudo や root は使用しません。rootには通常の権限検査を迂回できる特権があるため、実験結果が変わります。
まず、実験用ファイルを作ります。
workdir=$(mktemp -d)
mkdir "$workdir/demo"
printf 'hello\n' > "$workdir/demo/message.txt"
mktemp -d は他のファイルと衝突しにくい一時ディレクトリを作成します。以降のコマンドは workdir 変数を保持している同じシェルで実行してください。
1. chmod 600:名前は見えても詳細が見えない
chmod 600 "$workdir/demo"
ls -ld "$workdir/demo"
ディレクトリ自身の権限は次のようになります。
drw-------
所有者には r と w があり、x はありません。
まず、名前だけ表示します。
ls -1 "$workdir/demo"
message.txt
r があるため、名前の列挙は可能です。
続いて、詳細情報を取得します。
ls -l "$workdir/demo"
GNU coreutils の ls では、環境やバージョンによって文言は異なりますが、次のように表示されます。
ls: cannot access '.../demo/message.txt': Permission denied
total 0
-????????? ? ? ? ? ? message.txt
ls はディレクトリから名前を列挙できても、その名前を使って対象ファイルの属性を調べる段階で探索権限を要求されます。そのため、取得できない項目が ? と表示されるのです。これは破損を示す表示ではありません。
ファイルを直接読むこともできません。
cat "$workdir/demo/message.txt"
cat: .../demo/message.txt: Permission denied
ls -ld "$workdir/demo" は成功するのに、ls -l "$workdir/demo" では失敗する点にも注目してください。前者はディレクトリ自身の情報を親ディレクトリ経由で調べます。後者はディレクトリの中の各項目の情報を調べます。
2. chmod 100:一覧は見えないが、名前を知っていれば読める
今度は、所有者に x だけを与えます。
chmod 100 "$workdir/demo"
ls -1 "$workdir/demo"
ls: cannot open directory '.../demo': Permission denied
r がないので、名前の一覧は取得できません。
ところが、あらかじめ message.txt というファイル名を知っていれば、次の操作は成功します。
cat "$workdir/demo/message.txt"
hello
ディレクトリを探索でき、さらにファイル自身にも読み取り権限があるためです。
つまり、ディレクトリの r を外しただけでは、中のファイルを秘密にできるとは限りません。
※ この実験では、対象ファイルは実行ユーザーが所有し、読み取り権限がある状態です。ファイル自身の権限やアクセス制御が別途拒否していれば、読むことはできません。
3. chmod 700:所有者が一覧・探索・変更できる
最後に、所有者の rwx を戻します。
chmod 700 "$workdir/demo"
ls -l "$workdir/demo"
cat "$workdir/demo/message.txt"
今度はファイル情報の取得も、内容の読み取りも可能です。
ll で . や .. まで ????????? になるのはなぜ?
Ubuntuなどでは、ll が ls -alF のエイリアスとして設定されていることがあります(type ll で確認できます)。
-a は .(現在のディレクトリ)と ..(親ディレクトリ)も表示対象にします。したがって、x のないディレクトリで ll すると、それらの項目についても属性取得に失敗し、????????? や Permission denied が表示されることがあります。
表示されるエラーメッセージの順序や文言は ls のバージョンによって異なりますが、原因は同じです。
よくある疑問:ディレクトリを 644 にしてはいけない?
通常のファイルには 644(rw-r--r--)がよく使われます。しかし、ディレクトリを 644(drw-r--r--)にすると、所有者にも x がなくなるため、中のファイルを名前で探索できなくなります。
ディレクトリの設定は、用途に応じて選びます。
| 例 | 所有者 | グループ・その他 | 用途の目安 |
|---|---|---|---|
700 |
rwx |
権限なし | 秘密鍵などを収める非公開ディレクトリ |
755 |
rwx |
r-x |
他ユーザーにも閲覧・探索を許すディレクトリ |
711 |
rwx |
--x |
一覧は見せず、名前を知る項目の探索を許すディレクトリ |
※ ディレクトリの権限だけで中のファイルの読み取りを許可するわけではありません。また、ACL、MAC、スティッキービットなどがアクセスを制限する場合があります。
別の注意点として、chmod -R 755 は通常のファイルにも実行権限を付けてしまいます。用途を確認せずに再帰的な権限変更を行わないでください。
後片付け
実験で作成した一時ディレクトリだけを削除します。
chmod 700 "$workdir/demo"
rm -r -- "$workdir"
変数を設定したシェル以外では実行しないでください。workdir が正しい実験用パスを指していることを確認してから削除します。
まとめ
ls -l の ????????? は、ファイル名を列挙できても、そのファイルの属性を調べられない場合に現れる表示です。その代表例が、ディレクトリの探索権限 x の不足です。
-
r:ディレクトリ内の名前を列挙する権限 -
x:名前を指定して中の項目を探索する権限 -
w:中の項目を変更する権限(通常はxも必要)
Permission denied が出たときは、対象ファイルだけでなく、途中の親ディレクトリにも x があるか確認してみてください。