2019年4月19日金曜日

samba上で共有中のファイルをVisual Studioで編集すると実行可能になってしまう

sambaで共有中のファイルをうっかり Visual Studio から編集したファイルが、Linux上でlsすると実行可能になっているように見えてしまうケースのお話です。

結論から述べると、原因は保存されたファイルに付与されたACLのマスク値です。

以上です。

以下、駄文です。
祝Visual Studio 2019正式リリース、ということで思い出したのでこの記事を書いたのですが、これは2019以前から同じです。

以下ダラダラと書き綴りますが、その前に要約すると、Visual Studioはファイルを変更したときの保存方法は、実はファイルを保存する毎に新規作成をしてエディタの中身を保存してから、元のファイルを消しています。ファイルの内容の保護のためと思います。
従って、その副作用として、Windowsから見た場合はACL、Linuxから見た場合はパーミッションが、新規作成時のものになります。
平凡なアプリは気にもしてくれませんが、Visual Studioはさすがによくできていて、元のファイルのACLを新しいファイルへ再設定しようとします。
そのため、samba側も頑張って異文化のACLとの共存を図るべく必死に対応しようとするのですが、ここでlsコマンドさんが乱入してきてナンダコレ、というのが以下のあらすじです。

一応触れておきますが、以上の理由から、シェルスクリプトなど、パーミッションが重要なたぐいのファイルに対してはカジュアルにsamba越しにVisual Studioでファイルを編集してはいけません。

では、順次どうなっているのか見ていきたいと思います。
前提としてsambaは4.8.3、設定はほとんどデフォルト、ユーザ認証でホームディレクトリのcreate maskは0644でserver roleはstandaloneです。

さて、まず、Visual Studioでファイルを新規に作成し、sambaで共有しているディレクトリに保存した場合、lsコマンドで見てもごく普通のファイルに見えます。

たとえば、以下のように。
[ayumi@test ~]$ ls -la acltest.txt
-rw-r--r-- 1 ayumi ayumi 4  4月 19 21:55 acltest.txt

ついでにACLも確認しておきます。
[ayumi@test ~]$ getfacl acltest.txt
# file: acltest.txt
# owner: ayumi
# group: ayumi
user::rw-
group::r--
other::r--

どちらもsambaの設定どおりの挙動です。ACLは設定されていません。

さらに次いでに、WindowsからACLを確認してみます。
X:>icacls acltest.txt
acltest.txt S-1-5-21-3384635174-2336484230-2688597162-1001:(R,W)
            S-1-22-2-1000:(R)
            Everyone:(R)

長いSIDはsambaが出鱈目につけたayumiのSID, 短いSIDはグループのSID、EveryoneはotherのSIDですから、getfaclコマンドの結果と完全に一致しています。

さて、続けて同じファイルをVisual Studioから保存してみます。
すると、lsコマンドで見るとこうなります。
[ayumi@test ~]$ ls -la acltest.txt
-rw-rwxr--+ 1 ayumi ayumi 6  4月 19 22:03 acltest.txt*

ファイル名末尾にアスタリスク*がついて、グループにxがついていますからグループayumiに属する人に実行権が与えられているように見えることが確認できます。

ここで、パーミッションリストの末尾にプラス+がついているのでACLが追加されていることも同時にわかります。
getfaclコマンドの結果は以下のようになっています。
[ayumi@test ~]$ getfacl acltest.txt
# file: acltest.txt
# owner: ayumi
# group: ayumi
user::rw-
user:ayumi:rw-
group::r--
group:ayumi:r--
mask::rwx
other::r--

確かに元からのowner:groupに加えて、名指しでayumi:ayumiが追加されています。Windowsから見たらもともとの伝統的ファイルパーミッションはACLにしか見えませんから、それをコピーしただけの事ですが、Linux上ではパーミッションとACLは別々に管理されるため、新しく増えてしまったわけです。
しかし、read,write,executeのフラグはowner,group,otherすべてが644のままです。
実際に、先ほどのテキストが本当に実行可能なのか試してみると・・・

[ayumi@test ~]$ ./acltest.txt
-bash: ./acltest.txt: 許可がありません

と叱られます。

さて、ついでですからwindowsから見るとどうなっているでしょうか。
X:>icacls acltest.txt
acltest.txt S-1-5-21-3384635174-2336484230-2688597162-1001:(R,W)
            S-1-22-2-1000:(R)
            S-1-22-2-1000:(R)
            S-1-5-21-3384635174-2336484230-2688597162-1001:(R,W)
            Everyone:(R)

確かに、同じユーザとグループがリストに追加されているという奇妙な状態ではありますが、ReadとWriteしか付与されておらず、実行権はありません。getfaclの結果と同様で、矛盾はありません。

しかし、lsコマンドで見ると、確かに実行権が付いているようにしか見えません。
オイ、maskがrwxじゃねえか!!!とお叱りの向きもございましょう。
しかし、このmaskはorではなくてandのために使用されます。
つまり、ユーザーがいっくらchmod 0777としても、maskが0600だった場合は、実際には0600として動作しますよ、というように、です。

実際にmaskをreadだけにしてみます。
[ayumi@test ~]$ setfacl -m mask:r acltest.txt

すると、それぞれ以下のように見えます。
[ayumi@test ~]$ ls -l acltest.txt
-rw-r--r--+ 1 ayumi ayumi 34  4月 19 22:08 acltest.txt
[ayumi@test ~]$ getfacl acltest.txt
# file: acltest.txt
# owner: ayumi
# group: ayumi
user::rw-
user:ayumi:rw-                  #effective:r--
group::r--
group:ayumi:r--
mask::r--
other::r--

lsで見ると実行権は消えても相変わらずwrite権限を持っているように見えますが、getfaclコマンドの結果では
#effective:r--
とあります。これは「設定ではrw-だけど実際の効果はr--だよ」ということを示しています。
ここから実際のACLリストに追加されたユーザはすべてread権限しかないことがわかります。

windowsから見ると次のように見えます。
X:>icacls acltest.txt
acltest.txt S-1-5-21-3384635174-2336484230-2688597162-1001:(R,W)
            S-1-22-2-1000:(R)
            S-1-22-2-1000:(R)
            S-1-5-21-3384635174-2336484230-2688597162-1001:(R)
            Everyone:(R)

getfaclの結果と矛盾していません。

結局、ACLが付与されたファイルの場合はlsコマンドは普段と表示方法を変更しているのですが、manページにも記載がなく、大変迷惑な話です。
centos7のgitは古いからかもしれませんが、実際にgitコマンドでもcommit時のパーミッションの記録時に騙されたりしちゃったりして実害もあります。

そこで、じゃあ、マスク値をsamba側でコントロールできないのかという疑問が出てきますが、マニュアルを読む限りどこにもありませんでした。
そりゃそうですよね、最初っからマスクを下手に最小限にしたら、誰にもアクセスできないファイルが簡単にできてしまいます。

ではVisual StudioでACLを追加させない方法があるのか、または編集内容の保存方法を変える方法があるのか、という疑問が出てきますが、設定全般を見る限りはないようです。
まあ、繰り返しになりますが、もともとのVisual Studioが編集結果をファイルに保存する際は常に
  1. 元のファイルをテンポラリな名前に変更し、
  2. 新規に元のファイル名でファイルを作成し、
  3. 新規に作ったファイルにエディタ上の中身を保存し、
  4. ACLを新規ファイルに再設定し、
  5. 元のファイルを削除する
という保存方法のため、Visual Studioの挙動も、保存中にファイルが壊れた、なんてことがないようにする配慮ですからごもっともとしか言いようがありません。

lsコマンドにもlsコマンドなりの理由があって、+がついてたらACLが設定されてるよ、ACLに設定されてる情報をなるべく伝えたいよという(でもACLの中身とかattrとかはlsは詳しいことは見せないよ、というちょっと意地悪でもある)善意からのものですので、これもまた責めるのはかわいそうです。

それぞれの言い分が鋭く対立した結果、こうなってしまったわけですが、結局、どこかで誰かに妥協してもらわないと実際に使っている側が困ってしまいます。

仕方がないので、smb.confの以下のパラメータを順次ひとつづつ"No"にして再起動(reloadだと効果が出ないものもありますので)をしたらどうなるかを試した結果をまとめました。

実行順パラメタ既定値結果
1map archiveYes変化なし
2map hiddenNo変化なし
3map read onlyyes変化なし
4map systemNo変化なし
5store dos attributes記載なし変化なし
6acl map full controlYes変化なし
7acl allow execute alwaysNo変化なし
8acl check permissionsYes変化なし
9acl group controlNo変化なし
10nt acl supportYes効果あり

※既定値はtestparm -vコマンドで表示したときのものです。map read onlyの既定値が小文字なのも原文ママです。
変化なしの意味はlsでの見え方です。効果ありの意味はACLそのものが付与されていないことを意味しています。

この表からお分かりの通り、結局、ACLの取り扱いそのものを停止しないとダメでした!わはは

だから何だって?

以上、お読みいただいてありがとうございました。

0 件のコメント:

コメントを投稿