Il y a une question similaire qui traite du scénario de «wrapping», où vous souhaitez remplacer par exemple cd
une commande qui appelle la fonction intégrée cd
.
Cependant, à la lumière de shellshock et al et sachant que bash importe des fonctions de l'environnement, j'ai fait quelques tests et je ne peux pas trouver un moyen d'appeler le builtin en toute sécurité à cd
partir de mon script.
Considère ceci
cd() { echo "muahaha"; }
export -f cd
Tous les scripts appelés dans cet environnement à l'aide de cd
se briser (considérer les effets de quelque chose comme cd dir && rm -rf .
).
Il existe des commandes pour vérifier le type d'une commande (appelée commodément type
) et des commandes pour exécuter la version intégrée plutôt qu'une fonction ( builtin
et command
). Mais, voilà, ceux-ci peuvent également être remplacés à l'aide de fonctions
builtin() { "$@"; }
command() { "$@"; }
type() { echo "$1 is a shell builtin"; }
Donnera ce qui suit:
$ type cd
cd is a shell builtin
$ cd x
muahaha
$ builtin cd x
muahaha
$ command cd x
muahaha
Existe-t-il un moyen de forcer en toute sécurité bash à utiliser la commande intégrée, ou au moins détecter qu'une commande n'est pas une commande intégrée, sans effacer tout l'environnement?
Je me rends compte que si quelqu'un contrôle votre environnement, vous êtes probablement foutu de toute façon, mais au moins pour les alias, vous avez la possibilité de ne pas appeler l'alias en insérant un \
avant.
env
commande avant, comme ceci:env -i <SCRIPT.sh>
env
n'est pas redéfini en tant que fonction également. C'est terrifiant. J'ai d'abord pensé que les caractères spéciaux aideraient - appeler avec un chemin complet qui inclut/
, utiliser.
pour source, et ainsi de suite. Mais ceux-ci peuvent également être utilisés pour les noms de fonction! Vous pouvez redéfinir n'importe quelle fonction que vous souhaitez, mais il est difficile de revenir à l'appel de la commande d'origine.#/bin/sh
s'il ne s'agit pas d'un shell interactif par défaut.Réponses:
Olivier D est presque correct, mais vous devez vous mettre
POSIXLY_CORRECT=1
avant de courirunset
. POSIX a une notion de Special Built-ins , et bash la prend en charge .unset
est un tel intégré. RechercherSPECIAL_BUILTIN
dansbuiltins/*.c
la source de bash pour une liste, il comprendset
,unset
,export
,eval
etsource
.Le voleur
unset
a été retiré de l'environnement, si vous enlevezcommand
,type
,builtin
alors vous devriez être en mesure de procéder, maisunset POSIXLY_CORRECT
si vous comptez sur le comportement non-POSIX ou fonctionnalités avancées de bash.Cela ne concerne pas les alias, vous devez donc utiliser
\unset
pour être sûr que cela fonctionne dans le shell interactif (ou toujours, si le casexpand_aliases
est en vigueur).Pour les paranoïaques, cela devrait tout arranger, je pense:
(
while
,do
,done
Et[[
sont des mots réservés et ne précautions ont pas besoin.) Notez que nous utilisonsunset -f
pour être sûr de fonctions non définies, bien que les variables et les fonctions partagent le même espace , il est possible pour que les deux existent simultanément (grâce à Etan Reisner) auquel cas Unset-ing deux fois ferait aussi l'affaire. Vous pouvez marquer une fonction en lecture seule, bash ne vous empêche pas de désactiver une fonction en lecture seule jusqu'à bash-4.2 inclus, bash-4.3 vous en empêche, mais il honore toujours les commandes spéciales lorsquePOSIXLY_CORRECT
est défini.Une lecture seule
POSIXLY_CORRECT
n'est pas un vrai problème, ce n'est pas un booléen ou un indicateur sa présence active le mode POSIX, donc s'il existe en lecture seule, vous pouvez compter sur les fonctionnalités POSIX, même si la valeur est vide ou 0. Vous aurez simplement besoin de fonctions problématiques non définies d'une manière différente de celle ci-dessus, peut-être avec un copier-coller:(et ignorez toutes les erreurs) ou engagez-vous dans d'autres scripts .
Autres notes:
function
est un mot réservé, il peut être aliasé mais pas remplacé par une fonction. (L'aliasingfunction
est légèrement gênant car il\function
n'est pas acceptable comme moyen de le contourner)[[
,]]
sont des mots réservés, ils peuvent être aliasés (qui seront ignorés) mais pas remplacés par une fonction (bien que les fonctions puissent être ainsi nommées)((
n'est pas un nom valide pour une fonction, ni un aliasla source
unset
et al d'être écrasé.-f
argument,unset
n'est-ce pas? Sinon, si une variable et une fonction nommées de la même manière qu'une fonction intégrée sont définiesunset
, la variable à désélectionner sera sélectionnée en premier. Cela échoue également si l'une des fonctions d'obscurcissement est définie,readonly
n'est-ce pas? (Bien que cela soit détectable et puisse être une erreur fatale.) Cela manque également la fonction[
intégrée, semble-t-il.\unset -f unset
cela ait du sens, étant donné que cela se fera dans la boucle de lecture. Siunset
est une fonction que vous\unset
y résoudriez normalement au lieu de la fonction intégrée, mais vous pouvez l'utiliser en\unset
toute sécurité tant que le mode POSIX est en vigueur. Explicitement appeler\unset -f
sur[
,.
et:
peut - être une bonne idée cependant, que vos exclut regex eux. J'ajouterais également-f
à\unset
dans la boucle, et ferais\unset POSIXLY_CORRECT
après la boucle, au lieu d'avant.\unalias -a
(après\unset -f unalias
) permet également de renoncer en toute sécurité à l'échappement lors des commandes suivantes.[[ ${POSIXLY_CORRECT?non-POSIX mode shell is untrusted}x ]]
cela provoquera la fermeture d' un script non interactif avec l'erreur indiquée si la variable n'est pas définie, ou continuera si elle est définie (vide ou n'importe quelle valeur).\unset
" ... Il convient de noter que la citation de tout caractère fonctionnerait pour éviter l'expansion d'alias, pas seulement le premier.un"se"t
fonctionnerait tout aussi bien, mais moins lisible. "Le premier mot de chaque commande simple, s'il n'est pas cité, est vérifié pour voir s'il a un alias." - Bash RefOui ça. Si vous exécutez un script dans un environnement inconnu, toutes sortes de choses peuvent mal se passer, en commençant par
LD_PRELOAD
faire en sorte que le processus shell exécute du code arbitraire avant même de lire votre script. Tenter de se protéger contre un environnement hostile depuis l'intérieur du script est futile.Sudo a assaini l'environnement en supprimant tout ce qui ressemble à une définition de fonction bash depuis plus d'une décennie. Depuis Shellshock , d'autres environnements qui exécutent des scripts shell dans un environnement non entièrement fiable ont emboîté le pas.
Vous ne pouvez pas exécuter un script en toute sécurité dans un environnement qui a été défini par une entité non approuvée. S'inquiéter des définitions de fonction n'est donc pas productif. Assainissez votre environnement et, ce faisant, les variables que bash interpréterait comme des définitions de fonction.
la source
/bin/cat
un chroot pourrait appeler n'importe quoi.) La désinfection de l'environnement vous donne un sensPATH
(en supposant que vous le faites correctement bien sûr). Je ne vois toujours pas votre point.Vous pouvez utiliser
unset -f
pour supprimer les fonctions intégrées, la commande et le type.la source
unset() { true; }
s'occupe de ça.