qual shell irá sudo usar para executar um script shell sem a linha shebang

7

Meu ambiente é o Ubuntu 12.04 LTS, e a versão sudo é 1.8.3p1.

Primeiro, faço login como usuário normal:

$ whoami
fin

$ cat /etc/passwd | grep -i "root\|fin"
root:x:0:0:root:/root:/bin/bash
fin:x:1000:1000:This is a normal user:/home/fin:/bin/bash

$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4 Mar 30  2012 /bin/sh -> dash

$ ls -l /bin/bash
-rwxr-xr-x 1 root root 920788 Apr  3  2012 /bin/bash

$ echo $SHELL
/bin/bash

$ ps | grep "$$" | awk '{ print $4 }'
bash

$ ls -l ./test.sh
-rwxr-xr-x 1 fin fin 37 Sep 27 16:46 test.sh

$ cat ./test.sh
ps | grep "$$" | awk '{ print $4 }'

$ ./test.sh
bash

$ sudo ./test.sh
sh

Suponho que a última saída também deva ser bash porque /etc/passwd mostra que a raiz usa bash , estou faltando algum ponto sobre sudo ?

    
por layka 27.09.2013 / 11:02

3 respostas

12

Ele usa _PATH_BSHELL como execvp() , que no Linux é definido como /bin/sh in /usr/include/paths.h . Isso deve ser o mesmo de quando executado com env ou find -exec , por exemplo.

Certamente não deve usar o shell de login do usuário. O fato de você estar vendo bash acima é porque ele é bash (o shell em que você insere essa linha de comando) que tenta executá-lo e quando recebe um código de erro ENOEXEC de execve decide interpretar em si mesmo (no modo de compatibilidade sh ).

    
por 27.09.2013 / 11:51
5

Como você não usa a opção -s , então sudo usará _PATH_BSHELL (que é definido em /usr/include/paths.h no Ubuntu 12.04 LTS) para definir $SHELL . Olhando para o código-fonte sudo :

/* Stash user's shell for use with the -s flag; don't pass to plugin. */
    if ((ud->shell = getenv("SHELL")) == NULL || ud->shell[0] == '
$ cat ./test.sh
ps | grep "$$" | awk '{ print $4 }'

$ ./test.sh
bash

$ sudo -s ./test.sh
bash
') { ud->shell = pw->pw_shell[0] ? pw->pw_shell : _PATH_BSHELL; }

Se você usar a opção -s , sudo usará seu $SHELL em vez de _PATH_BSHELL :

/* Stash user's shell for use with the -s flag; don't pass to plugin. */
    if ((ud->shell = getenv("SHELL")) == NULL || ud->shell[0] == '
$ cat ./test.sh
ps | grep "$$" | awk '{ print $4 }'

$ ./test.sh
bash

$ sudo -s ./test.sh
bash
') { ud->shell = pw->pw_shell[0] ? pw->pw_shell : _PATH_BSHELL; }
    
por 27.09.2013 / 12:26
4

O kernel só pode executar imagens executáveis binárias. Então, como os scripts são executados? Afinal, posso digitar my_script_without_shebang em um prompt do shell e não recebo um erro ENOEXEC . A execução de scripts é feita não pelo kernel, mas pelo shell. O código exec no shell geralmente parece algo como:

/* try to run the program */
execl(program, basename(program), (char *)0);

/* the exec failed -- maybe it is a shell script without shebang? */
if (errno == ENOEXEC)
    execl ("/bin/sh", "sh", "-c", program, (char *)0);

Você pode verificar isso com o rastreamento de um script de shell simulado sem shebang:

cat > /tmp/foo.sh <<EOF
echo
EOF

chmod u+x /tmp/foo.sh

strace /tmp/foo.sh 2>&1 | grep exec
execve("/tmp/foo.sh", ["/tmp/foo.sh"], [/* 28 vars */]) = -1 ENOEXEC (Exec format error)

Então, a execução prossegue como Stephane descreveu - shell padrão é usado (no trecho de código acima é codificado). Esta agradável FAQ do UNIX pode responder mais.

    
por 27.09.2013 / 12:28