Bashのソースに実行ビットが必要ないのはなぜですか?


57

Bash sourceを使用すると、実行ビットを設定せずにスクリプトを実行できます。これは文書化されており、予想される動作ですが、実行ビットの使用に反していませんか?

sourceサブシェルは作成されません。


2
chmod8進数で許可( `xを含む)を設定できるという事実は、それがどの時代から来たのかについての手がかりを与えます。それが迅速かつ汚いとして始まった場合、私は驚かないだろう彼女-強打が発明された前の日から、指標を「これはあなたが実行可能なバイナリファイルである」が、私はそれに証拠を持っていない
infixed

9
繰り返しになりますが、SUIDが登場すると、さまざまなカテゴリのユーザーに対するさまざまなレベルの保護がより重要になります。必要に応じて、私のSUIDプログラムを読んでください。しかし、単に読み取るだけで実行すると、SUIDの権限はそれに
付随

@infixed Linuxプログラムローダーは、実行ビットが設定されていない限り、シバンをさえしません。(自分のホーンを少し鳴らすには:こちらを参照してください。)
カイルストランド

実行中のプロセスにコードを注入することによって、バイナリを読み取ることが通常可能であるので、あなたはまた、+ XRを持つことができますが、それは少し奇妙です
ニクラスB.を

@KyleStrand「単に読むだけで実行した場合、SUIDの力はそれに付随していません」という線に沿って何かを想像していましたcp /sbin/suidexecutable /tmp/mycopy; /tmp/mycopy
16年

回答:


36

Bashはインタープリターです。入力を受け入れ、必要な処理を実行します。実行可能ビットに注意する必要はありません。実際、Bashは移植性があり、実行可能ビットの概念を持たないオペレーティングシステムおよびファイルシステムで実行できます。

実行可能ビットが重要なのは、オペレーティングシステムカーネルです。execたとえば、Linuxカーネルは、ファイルシステムがnoexecオプションでマウントされていないことを確認し、プログラムファイルの実行可能ビットを確認し、セキュリティモジュール(SELinuxやAppArmorなど)によって課せられた要件を実施します。

実行可能ビットは、任意の種類の制御であることに注意してください。たとえば、Linux x86-64システムでは、インタープリターとして明示的に呼び出すこと/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2により、実行可能ビットのカーネルの検証をバイパスできます。

cp /bin/ls /tmp/
chmod -x /tmp/ls
/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 /tmp/ls

これはld.so、インタープリターであり、実行するコードがELF形式のマシンコードであることを除いて、BashでBashソースコードをソースすることに多少似ています。


3
ローダーを「バイトコード」の「インタープリター」として使用すると、たまたま実際の実行可能バイナリになります。有難うございます。
カイルストランド

@KyleStrandには、いくつかのレベルの間接化(格納されたプログラムとロードされたプロセスの違い、メモリのマッピング方法、さまざまなスーパーバイザー、VMなど)がありますが、原則としてマシンコードはCPUによって直接実行できます(マイクロコードなし、など)、したがって、マシンコードは解釈されません。ハードウェアはそれをそのまま(ネイティブ言語であると)解釈し、インタープリターは必要ありません。
jfs

2
@JFSebastianはい、ネイティブコードであることがわかっているため、「インタープリター」は引用符で囲まれています。の仕事ld.soは、動的リンクを行うことです。
200_success

@JFSebastian 200_successが言ったこと。また、それが「実際の実行可能バイナリ」の意味であり、「バイトコード」も引用符で囲みます(通常、「バイトコード」は実際にコンパイルされたネイティブ実行可能バイナリコードを指すために使用されないため)。また、素敵なユーザー名。
カイルストランド

@JFSebastian現代のx86のようなCPUは実際には内部的にRISCであり、古いスタイルのCISC命令セットは基本的に対応するRISC命令のマイクロコード実行を駆動し、1つのCISC命令により多くのRISC命令が実行されると考えています。したがって、ある意味では、RISCマシンコードでCPUが行うことを「解釈」と呼ぶことは、技術的な観点から完全に正しいとは言えないにしても、少なくとも有効なメンタルモデルです。AES-NIはおそらく最も極端な例の1つです。AESラウンドごとに1つのCISC命令です。
CVn

57

sourceまたは同等の標準ドット.はスクリプトを実行しませんが、スクリプトファイルからコマンドを読み取り、現在のシェル環境で1行ずつ実行します。

シェルはファイルの内容を読み取るための読み取り許可のみを必要とするため、実行ビットの使用に反対するものはありません。

実行ビットは、スクリプトを実行するときにのみ必要です。ここで、シェルはfork()新しいプロセスを実行し、execve()関数を使用してスクリプトから新しいプロセスイメージを作成します。これは、通常の実行可能ファイルである必要があります。


5
@alexis:私が本当に従うかどうかわかりません。あなたがするならbash < script、あなたは本質的に同じ結果を得るsource script。実行ビットチェックはどのような保護を提供しますか?
目立ったコンパイラ

27
@alexis、それが解釈するスクリプトの許可を確認することは、インタプリタの仕事ではありません。何もないのPython、Rubyのない、ないJava仮想マシンではなく、他のランダムシェル-このません。実行ビットはexecv、インタープリターが実行するかどうかではなく、OS *ファミリーのsyscallsを実行可能ファイルと共に使用できるかどうかを制御します。なぜ規約を破ることで人々を混乱させる(そしてファイル以外のソースからストリームされるコードを評価する能力を破る)のか?
チャールズダフィー

14
@alexis、さらに、実行可能ではないシェルライブラリを持つことには価値のある意味があります。「私はコマンドではなくライブラリです。ソースミー、実行しないでください」と書かれています。それ以外の場合は、ソースのみを目的とするコードの誤用を検出および修正するコードを記述する必要がありますが、+ x権限を持たないことにより、ユーザーがそのような方法でライブラリを誤用できないようにすることができます。
チャールズダフィー

6
@alexis「それは著者による決定でした」含まれていなかった他のすべてのコードが決定であったという意味でのみ。シェルは、ファイルを読み取り用に開き、コマンドを読み取ります。読み取り許可を確認することは期待していません。ファイルを開こうとするだけで、できない場合は失敗します。同様に、これらのチェックはファイルの読み取りには関係ないため、書き込みまたは実行の許可をチェックしません。
ランディオリソン

2
@alexisこれは実際に使用されますが、たとえばpythonのvirtualenvでは、それをアクティブにするスクリプトはソースであり、実行されbin/activateないため、実行可能なビットはありません。スクリプトは、完全にライブラリーまたはそのようなものにすることができます。.shを持っていることも合図かもしれませんが、最小限の./bin/activate. bin/activate
フットガンを持っ

20

nonsetuidおよびnonsetguidファイルの実行可能ビット(残りとは異なります)は、セキュリティメカニズムではありません。読むことができるもの、間接的に実行することができ、Linuxでは、実行できるが直接読むことができないものはすべて間接的に読み取ることができます(non-set(g)uid x-bitの概念に穴を開けるのに十分なはずです)セキュリティ対策)。

それはもっと便利なことです:ビットが設定されている場合、システムに直接実行させてください。そうでない場合は、間接的に行う必要があります(bash the_script;または読み取り禁止の実行可能ファイルのメモリイメージを取得するためのハッキングが必要です)。

インソースとインソース可能の両方を実行する場合は、便利に設定できます。

しかし、どうやら、多くの共有ライブラリの実装者があなたの考えを共有しているため、多くのシステムでは、本質的にシェルのインソース不可能なネイティブライブラリである共有ライブラリを使用可能にするために実行可能にする必要があります。共有ライブラリが実行可能な理由をご覧ください


3
@ Motte001本当にやりたいのであれば、それらの添付ファイルを実行できます。便利です。
PSkocik

2
実行可能ビットはセキュリティ用ではありません。ファイルを所有している場合は自由にchmod実行でき、実行可能にします。プログラムからのデータをソートするためのものであるため、OPの質問は妥当なものです。
アレクシス

1
@ Motte001これは、GUIファイルブラウザ/メールアプリケーションのセキュリティ機能です。名前が「.sh」で終わるファイルをダブルクリックすると、ターミナル(Windowsスタイル)で実行するか、逆に「ダウンロードした添付ファイル」ディレクトリ内のファイルをクリックすると、組み込みのサンドボックスプレビューアプリが起動します。このxビットは、何をすべきかのヒントを読み書きできる余分な場所にすぎません。
IMSoP

3
実行可能ビットが必要な理由の1つは、特にrootが所有するsetuidプログラムを実行することです。それらを自分で確実に実行することはできますが、必要な許可を得るためには、OSを実行する必要があります。他のいくつかのケースでは、本当に便利です。
ワリー

2
「Linuxでは、/ procで実行できるものなら何でも読むことができます」 -まあ、私のストックDebianカーネルはそうではありません:/tmp$ cp /bin/cat ./cat ; chmod a-rw ./cat ; ./cat & cp /proc/$!/exe /tmp/cat2->cp: cannot stat ‘/proc/16260/exe’: Permission denied
ilkkachu

9

それは良い質問です!Unixは実行可能ビットを使用して、プログラムとデータを区別します。新しいプロセスとして実行するためにソーススクリプトがOSに渡されないため、OSは実行ビットを必要としません。ただし、シェルはソーススクリプトをプログラムとして扱い、ソース$PATHするファイルを探します。そのため、シェル自体がソースファイルの実行権限を必要としている可能性があります。しかし、そうではなかった。

質問はずっと前に出されたに違いありません。Bourneシェルの設計は、Bell Labsの住人の間で行われた「修正、対話、議論の長いシーケンス」の結果であり、多くの設計決定がSR Bourneと他の人によって長年にわたって議論されました。残念なことに、私のクイックルックでは、ソース機能に関する議論は見つかりませんでした(私の防御では、Googleで検索するのは難しいです)。私が見つけたのは、「。」コマンドは、Bourne自身によるこのシェルの初期の紹介には登場しませんが、より成熟したバージョン7バージョンには存在します。

権限がない場合、ここに私自身の解釈があります:

  1. .コマンドは、別名source、(のような効果テキスト包含している#include実行スクリプトまたは対話型セッションのソースコードにCプリプロセッサで)。そのため、含まれているファイルは、おそらく「実行」されていません。

  2. Unixの哲学は常に、プログラマーに自分自身を掛けるのに十分なロープを与えることでした。あまりにも多くの手持ちと任意の制限が邪魔になります。ごく最近になって、いくつかのディストリビューションrm -r /が、あなたが求めていることを拒否したようになりました。(このコマンドは、コンピューター上のすべてrm削除する ように指示します。root として試してはいけません!または、さらに良いことに、まったくありません。)ファイルを入手しようとすると、自分が何をしているのかを知っていると仮定するだけです。それはまた、不必要な作業を回避し、当時はサイクルが非常に重要でした。


しかし、@ catが言ったことは絶対に すべきではありません。
TOOGAM

フラグが付けられず、@ TOOGAMが削除されていないことに驚いていますが、/ sを入れました!

そこで、@ catが何を書いたのかはわかりませんが、その答えをさらに子供向けにしたのです。(しかし、さあ、それはすでに文脈から十分に明確でした。)
アレクシス

4

OSに関する限り、シェルスクリプトを含むファイルは単なるデータです。そのようなデータファイルの名前をsourceコマンドに渡すか、コマンドラインでbashシェルの呼び出しに渡すと、OSが認識するのは、データを含むファイルの名前と一致する文字列のみです。

その場合、実行ビットはどのように関連しますか?


3

実行可能ファイルとしては役に立たないが、入手した場合にのみ役立つシェルコマンドのファイルがある場合があるため、この区別は重要です。このファイルの場合、実行ビットをオフにすると、ソースコマンドで明示的に指定されない限りアクセスされなくなります。このようなことの理由は、実行元のシェルに副作用があるためです。具体的な例として、パスを調べて変更するfix_pathというスクリプトがあります。


1

誰かがさらなる研究や説明に興味がある場合に備えて:少し前に実装されたほぼPOSIX準拠のシェルでは、 'exec_program()'および 'builtin_source()'関数の内部動作は非常に模範的です。これらの関数では、それらの違いが正確にわかります。

https://github.com/rsenn/shish/blob/master/src/builtin/builtin_source.c

https://github.com/rsenn/shish/blob/master/src/exec/exec_exec.program.c

基本的に、ソースは、シェルが内部ファイル記述子を一時的にリダイレクトし、そこからシェルスクリプトを解析する(対話モードの端末)ように見えます。ですから、<input_file.txt>>append_to_something.listなどの他のリダイレクトと非常によく似ており、これらはファイルを開いたり閉じたりするだけです。

そのため、実行はexecve()、実行ビットが必須のシステムコールによって処理されます。

ELF / a.outバイナリの実行を許可するいくつかのシステムを見たことを思い出しますが、「/ lib / ld-dynamic-linker.so」を実行し、最初の引数としてバイナリプログラム(execビットなし)を使用します。私はそれがいくつかのDEC AlphaまたはVAXマシンにあったと信じています(SCO Unixだったのでしょうか?)


-2

別の観点:

ソーススクリプトは、基本的にシェルの組み込みとプログラム呼び出しで構成されます。シェルのビルトイン(sourceその中にある)はシェルの一部であり、シェルは最初に実行可能でなければなりません。呼び出されるすべてのプログラム(ELF、シバンを含む別のスクリプトなど)には実行ビットを設定する必要があります。そうしないと実行されません。

実行ビットがないと実行されないため、実行ビットの使用に反しません。検証は、ソーススクリプト全体では発生しません。パーツごとに個別に実行されますが、実行されます。


シェルビルドインは、シェルスクリプトから取得されません。通常、これらはシェル実行可能ファイルの一部です。ksh93、zsh、およびその他のいくつかのシェルでは、シェル拡張機能になります。
fpmurphy

@ fpmurphy1これは「シェル組み込み(...)はシェルの一部です」という文章ではありませんか?
カミルマシオロウスキ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.