Pourquoi la source de Bash n'a-t-elle pas besoin du bit d'exécution?

57

Avec Bash, sourceil est possible d'exécuter un script sans définir un bit d'exécution. Ceci est documenté et le comportement attendu, mais n'est-ce pas contre l'utilisation d'un bit d'exécution?

Je sais que sourcecela ne crée pas de sous-shell.

Motte001
la source
2
Le fait que chmodvous puissiez définir des autorisations (y compris `x) avec un nombre octal donne une idée de son époque. Je ne serais pas surpris si cela commençait par un indicateur rapide et sale "il s'agit d'un fichier binaire que vous pouvez exécuter", à partir des jours précédant son invention, mais je n'ai aucune preuve de cela
infixé le
9
Là encore, lorsque le SUID entre en jeu, différents niveaux de protection pour différentes catégories d'utilisateurs deviennent plus importants. Allez-y et lisez mon programme SUID si vous voulez. Mais si vous l'exécutez simplement en le lisant, les pouvoirs du SUID ne l'accompagneront pas
infixé le
@infixed Le chargeur de programme Linux ne regardera même pas le shebang si le bit d'exécution n'est pas défini. (Pour me vanter un peu: voir ici .)
Kyle Strand
Vous pouvez aussi avoir + xr, mais c'est un peu bizarre car il est généralement possible de lire le binaire en injectant du code dans le processus en cours
Niklas B.
@KyleStrand par "si vous l'exécutez simplement en le lisant, les pouvoirs du SUID ne l'accompagnent pas" J'envisageais quelque chose commecp /sbin/suidexecutable /tmp/mycopy; /tmp/mycopy
infixée le

Réponses:

36

Bash est un interprète. il accepte les entrées et fait ce qu'il veut. Il n'est pas nécessaire de tenir compte du bit exécutable. En fait, Bash est portable et peut fonctionner sur des systèmes d'exploitation et des systèmes de fichiers dépourvus de tout concept de bit exécutable.

Ce qui importe dans l’exécutable, c’est le noyau du système d’exploitation. Lorsque le noyau Linux effectue exec, par exemple, qu'il vérifie que le système de fichiers n'est pas monté avec une noexecoption, il vérifie le bit exécutable du fichier programme et applique toutes les exigences imposées par les modules de sécurité (tels que SELinux ou AppArmor).

Notez que le bit exécutable est un type de contrôle plutôt discrétionnaire. Sur un système Linux x86-64, par exemple, vous pouvez ignorer la vérification du bit exécutable par le noyau en appelant explicitement en /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2tant qu'interpréteur :

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

Cela ressemble un peu à la recherche du code source Bash dans Bash, à l'exception de ld.sol'interpréteur et du code qu'il exécute est un code machine au format ELF.

200_success
la source
3
Utiliser le chargeur en tant qu '"interpréteur" de "bytecode" qui s'avère être un vrai binaire exécutable ... génial. Merci pour ça.
Kyle Strand
@KyleStrand il peut y avoir plusieurs niveaux d'indirection (différence entre le programme enregistré et le processus chargé et la configuration de la mémoire, différents superviseurs, machines virtuelles, etc.), mais en principe, le code machine peut être exécuté directement par la CPU (pas de microcode, etc.) . etc) et donc le code machine n’est pas interprété: le matériel le comprend tel quel - c’est la langue maternelle - aucun interprète n’est nécessaire.
jfs
2
@JFSebastian Oui, nous savons que c'est du code natif, donc "interprète" est entre guillemets. Le travail de ld.soest de faire des liens dynamiques.
200_success
@JFSebastian Ce que 200_success a dit. En outre, c'est ce que je voulais dire par "binaire exécutable réel" et par "guillemets" entre guillemets (puisque AFAIK, "octetcode" n'est généralement pas utilisé pour faire référence au code binaire exécutable natif compilé). En outre, un nom d'utilisateur agréable.
Kyle Strand
@JFSebastian Je pense que les processeurs modernes de type x86 sont en réalité des RISC internes, le jeu d'instructions ancien de CISC guidant essentiellement l'exécution en microcode des instructions RISC correspondantes, une instruction CISC pouvant provoquer l'exécution de nombreuses instructions RISC. En un sens, appeler ce que la CPU fait avec le code machine RISC "interpréter" est, si ce n’est pas tout à fait correct du point de vue technique, alors au moins un modèle mental valide. AES-NI est probablement l'un des exemples les plus extrêmes: une instruction CISC par tour AES!
un CVn
57

sourceou l'équivalent , mais la norme dot. ne pas exécuter le script, mais lisez les commandes à partir du fichier de script, puis les exécuter, ligne par ligne, dans un environnement shell actuel.

Il n'y a rien contre l'utilisation du bit d'exécution, car le shell ne doit lire l' autorisation de lire le contenu du fichier.

Le bit d'exécution n'est requis que lorsque vous exécutez le script. Ici, le shell procédera à un fork()nouveau processus, puis utilisera execve()function pour créer une nouvelle image de processus à partir du script, qui doit être un fichier exécutable standard.

cuonglm
la source
5
@ alexis: Je ne suis pas sûre de vraiment suivre. Si vous le faites bash < script, vous obtenez essentiellement le même résultat que source script. Quelle protection une vérification de bit d'exécution fournit-elle?
Remarquable Compiler
27
@ alexis, ce n'est pas un travail d'interprète de vérifier les permissions des scripts qu'il interprète. Rien ne fait cela - pas Python, pas Ruby, pas la machine virtuelle Java, pas d'autres shells aléatoires. Le bit d'exécution contrôle si la execvfamille de systèmes d'appels OS * peut être utilisée avec un exécutable et non si un interprète l'exécutera. Pourquoi confondre les gens (et rompre la capacité d'évaluer le code transmis à partir de sources non-fichiers) en rompant les conventions?
Charles Duffy
14
@ alexis, ... de plus, il y a une signification intéressante à avoir une bibliothèque shell qui ne soit pas exécutable: "Je suis une bibliothèque, pas une commande - source moi, ne m'exécute pas". Sinon, vous devrez écrire du code pour détecter et corriger les utilisations abusives de code destiné uniquement à être importé. Cependant, en ne disposant pas de l'autorisation + x, vous pouvez vous assurer que les utilisateurs ne peuvent pas (n'abuser) d'utiliser de manière incorrecte une bibliothèque.
Charles Duffy
6
@ alexis "c’était une décision des auteurs", c’est seulement dans le sens où tout autre morceau de code possible qui n’était pas inclus était une décision. Le shell ouvre le fichier en lecture, pour en lire les commandes. Je ne m'attendrais pas à ce qu'il vérifie la permission de lecture, il essaie simplement d'ouvrir le fichier et échoue s'il ne le peut pas. De même, il ne vérifie pas l'autorisation d'écriture ou d'exécution, car ces vérifications ne sont pas pertinentes pour la lecture du fichier.
Randy Orrison
2
@alexis Ceci est utilisé dans la pratique bien que, par exemple avec virtualenv de python, le script pour l'activer soit destiné à être recherché, et non exécuté, et bin/activaten'a donc pas de bit exécutable. Les scripts peuvent être totalement des bibliothèques ou d'autres choses comme ça. J'imagine qu'avoir .sh pourrait également être un signal, mais il est bon d'avoir un minimum de pistolets à pied: c'est bien qu'il ne soit pas possible de courir ./bin/activatepar accident au lieu de. bin/activate
daboross
20

Le bit exécutable (contrairement au reste) sur les fichiers non-setuid et non-setguid n'est pas vraiment un mécanisme de sécurité. Tout ce que vous pouvez lire peut être exécuté indirectement, et Linux vous permettra de lire indirectement tout ce que vous pouvez exécuter, mais pas directement (cela devrait suffire à percer un trou dans le concept de non-set (g) uid x-bit étant un mesure de sécurité).

C’est plus une question de commodité: laissez le système l’exécuter pour moi directement si le bit est défini, sinon je dois le faire indirectement ( bash the_script;ou un peu de piratage informatique pour obtenir l’image mémoire d’un exécutable sans autorisation de lecture ).

Vous pouvez le configurer pour plus de commodité si vous avez l’intention d’intégrer le code source et d’exécuter votre code source unique.

Apparemment, cependant, de nombreux développeurs de bibliothèques partagées partagent votre pensée et par conséquent, de nombreux systèmes exigent que les bibliothèques partagées, qui sont essentiellement l'équivalent natif des commandes à sous shell, soient marquées comme exécutables pour pouvoir être utilisées. Voir Pourquoi les bibliothèques partagées sont-elles exécutables? .

PSkocik
la source
3
@ Motte001 Ils peuvent exécuter ces pièces jointes s'ils le souhaitent vraiment. C'est une commodité.
PSkocik
2
Le bit exécutable n’est pas destiné à la sécurité: si je possède un fichier, je suis libre de chmodle créer et de le rendre exécutable. C'est pour trier les données des programmes, la question du PO est donc raisonnable.
Alexis
1
@ Motte001 Il s’agit plutôt d’une fonctionnalité de sécurité du navigateur de fichiers graphique / de l’application de messagerie. Elle peut facilement décider que le fait de double-cliquer sur un fichier dont le nom se termine par ".sh" soit exécuté dans un terminal (style Windows) ou inversement. cliquer sur un fichier du répertoire "Pièces jointes téléchargées" invoquera une application de prévisualisation en bac à sable intégrée. Le xbit est juste un endroit supplémentaire où il peut lire / écrire un soupçon de quoi faire.
IMSoP
3
Une des raisons pour lesquelles nous avons besoin du bit exécutable est d’exécuter les programmes setuid, en particulier ceux appartenant à root. Bien que vous puissiez certainement les exécuter vous-même, vous avez besoin du système d'exploitation pour les exécuter afin qu'ils disposent des autorisations nécessaires. Dans d'autres cas, c'est simplement une commodité.
Waleed Khan
2
"Linux vous permettra de lire tout ce que vous pouvez exécuter via / proc" - Eh bien, mon noyau Debian d'origine ne permet pas: /tmp$ cp /bin/cat ./cat ; chmod a-rw ./cat ; ./cat & cp /proc/$!/exe /tmp/cat2->cp: cannot stat ‘/proc/16260/exe’: Permission denied
ilkkachu le
9

C'est une bonne question! Unix utilise le bit exécutable pour distinguer les programmes des données. Le système d'exploitation n'a pas besoin du bit d'exécution, puisqu'un script source n'est pas transmis au système d'exploitation pour exécution en tant que nouveau processus. Mais le shell considère un script source comme un programme et recherchera $PATHle fichier que vous souhaitez créer. Ainsi, le shell lui-même aurait pu nécessiter une autorisation d'exécution pour les fichiers sourcés; mais ça n'a pas été le cas.

La question doit avoir été posée il y a longtemps. La conception du shell Bourne est le résultat d' une "longue séquence de modifications, dialogues, discussions" entre les habitants des Bell Labs, et de nombreuses décisions de conception ont été discutées par SR Bourne et d'autres au fil des ans. Malheureusement, mon rapide coup d'oeil n'a trouvé aucune discussion sur la fonctionnalité source (pour ma défense, il est difficile de chercher sur Google). Ce que j'ai trouvé, c'est que le "." La commande n'apparaît pas dans cette première introduction au shell par Bourne lui-même, mais elle est présente dans la version plus mature de la version 7 .

En l'absence d'autorité, voici ma propre interprétation:

  1. La .commande, à savoir source, est en fait une inclusion textuelle (comme #includedans le préprocesseur C) dans le code source du script en cours d'exécution ou de la session interactive. En tant que tel, le fichier inclus n'est sans doute pas "exécuté".

  2. La philosophie Unix a toujours été de donner aux programmeurs assez de corde pour se pendre. Trop de restrictions manuelles et arbitraires font obstacle. Ce n’est que récemment que certaines distributions effectuées rm -r /refusent de faire ce que vous demandez. (Cette commande dit rmde tout supprimer sur votre ordinateur. N'essayez pas en tant que root! Ou mieux encore, pas du tout.) Alors, peut-être que Bourne est al. vient de décider que lorsque vous essayez de créer un fichier, vous êtes censé savoir ce que vous faites. Cela évite également des travaux inutiles et les cycles comptaient beaucoup à l'époque.

alexis
la source
Mais il ne faut absolument pas faire ce que @cat a dit.
TOOGAM
Je suis surpris qu'il n'ait pas été signalé et supprimé @TOOGAM mais j'ai mis dans le / s!
Chat
Là, je ne sais pas ce que @cat avait écrit mais j'ai corrigé la réponse encore plus. (Mais allez, c'était assez clair du contexte.)
alexis
4

En ce qui concerne le système d'exploitation, un fichier contenant un script shell est simplement une donnée. Si vous transmettez le nom d'un tel fichier de données à la sourcecommande ou le transmettez sur la ligne de commande à un appel du shell bash, tout ce que le système d'exploitation voit est une chaîne qui coïncide avec le nom d'un fichier contenant des données.

Quelle serait la pertinence du bit d'exécution dans ce cas?

Stephen M. Webb
la source
3

La distinction est importante car vous pouvez avoir un fichier de commandes shell qui n’est pas utile comme exécutable, mais seulement lorsqu’il est généré. Pour ce fichier, vous pouvez désactiver le bit d’exécution et il ne sera jamais utilisé à moins d’être explicitement utilisé dans une commande source. La raison d'une telle chose est d'avoir des effets secondaires sur la coquille à partir de laquelle il est exécuté. Pour un exemple spécifique, j'ai un script appelé fix_path qui examine et modifie le chemin.

CARTE
la source
1

Juste au cas où quelqu'un serait intéressé par d'autres études et / ou précisions: Dans un shell conforme à POSIX et implémenté il y a quelque temps, le fonctionnement interne des fonctions 'exec_program ()' et 'builtin_source ()' est très exemplaire. Dans ces fonctions, vous voyez exactement quelle est la différence entre elles:

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

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

en gros, le sourcing peut être vu comme le shell redirigeant temporairement son descripteur de fichier interne où il analyse le script du shell depuis (le terminal en mode interactif). il est donc très similaire aux autres redirections telles que <input_file.txtet >>append_to_something.listet celles-ci doivent simplement ouvrir et fermer des fichiers.

l'exécution est donc gérée par l' execve()appel système pour lequel le bit d'exécution est obligatoire.

Je me souviens d’avoir vu certains systèmes autorisant l’exécution de fichiers binaires ELF / a.out, mais en exécutant le "/lib/ld-dynamic-linker.so" et avec le programme binaire (sans le bit d’exécution) comme premier argument. Je crois que c’était sur certaines machines DEC Alpha ou VAX (est-ce que c’était SCO Unix?)

rsenn
la source
-2

Un autre point de vue:

Le script sourced consiste essentiellement en des commandes intégrées au shell et des appels de programme. Shell intégré (avec sourceparmi eux) sont des parties du shell et le shell doit être exécutable en premier lieu. Chaque programme appelé (ELF, un autre script avec shebang, peu importe) doit avoir un bit d’exécution défini, sinon il ne fonctionnera pas.

Donc, ce n’est pas contre l’utilisation d’un bit d’exécution, car rien ne sera exécuté sans bit d’exécution. La validation ne se produit pas pour le script source dans son ensemble; il est exécuté pour chaque partie séparément, mais c'est le cas.

Kamil Maciorowski
la source
Les buildins du shell ne proviennent pas d'un script shell. Généralement, ils font partie de l'exécutable du shell. Dans ksh93, zsh et quelques autres shell, ils peuvent être des extensions de shell.
fpmurphy
@ fpmurphy1 N'est-ce pas ma phrase "shell builtins (...) sont des parties de la coque"?
Kamil Maciorowski