서로 다른 /bin/sh를 사용하여 환경 분리

서로 다른 /bin/sh를 사용하여 환경 분리

/bin/sh와 동일하다고 잘못 생각하는 쉘 스크립트가 많이 있습니다 . 예를 들어 shebang이 /bin/bash있지만 (점) 대신 명령을 사용합니다.#!/bin/shsource.

/bin/sh에 연결되는 Ubuntu 16을 실행 중이므로 dashbash-isms는 지원되지 않습니다.

주기적으로 스크립트를 실행해야 합니다. 또한 가끔은 이 특정 버그를 수정하고 싶어하지 않는 원저작자로부터 업데이트해야 할 때도 있습니다. 이러한 파일을 모두 수정하는 것을 피하고 싶습니다(파일이 많고 내 것이 아니며 업데이트 후에는 모든 변경 사항이 손실됩니다). 또한 다른 스크립트가 손상될 수 있으므로 시스템 전체를 변경하는 것을 피하고 싶습니다.

/bin/sh전역 시스템을 건드리지 않고 이러한 스크립트에 사용할 수 있는 bash를 가리키는 (임시 또는 비임시) 환경을 어떻게든 생성할 수 있는 방법이 있습니까 /bin/sh?

답변1

나는 마운트 네임스페이스나 그와 유사한 것이 그것이 무엇인지에 대한 다른 아이디어를 가지고 다른 프로세스/사용자를 예약하는 데 사용될 수 있다고 상상합니다 /bin/sh.

그러나 이는 해킹처럼 들리며 "시스템을 영구적으로 변경하는 것"으로 간주될 수도 있습니다. 한 줄 수정을 수행하는 것이 더 쉬울 수도 있습니다. 업데이트 프로세스의 수정 부분을 만들고 버그 보고서를 게시하고 버그의 해시뱅에 업스트림 패치를 적용합니다.

GNU의 경우 sed이를 수정하려면 다음을 수행해야 합니다.

sed -i -e '1s,^#! */bin/sh,#!/bin/bash,' /all/the/scripts/*

답변2

/bin/sh->가 /bin/dash내 시스템에서처럼 시스템에서 동적으로 링크된 실행 파일인 경우 (file(1)을 사용하여 확인할 수 있음) 해킹을 사용하여 LD_PRELOAD이를 달성할 수 있습니다.

다음과 같이 작동합니다. LD_PRELOADglibc __libc_start_main(실행 파일의 함수를 호출하는 함수 )를 재정의하는 작은 동적 라이브러리를 로드한 다음 main()동일한 인수 ( 제외 )를 사용하여 argv[0] == /bin/shexec를 수행합니다. 그렇지 않으면 아무 일도 일어나지 않은 것처럼 원본을 호출합니다 ./bin/bashargv[0]__libc_start_main

$ cat sh_is_bash.c
#define _GNU_SOURCE     /* for RTLD_NEXT */
#include <string.h>
#include <unistd.h>
#include <dlfcn.h>
#include <err.h>
int __libc_start_main(
        int (*main)(int,char**,char**), int ac, char **av,
        int (*init)(int,char**,char**), void (*fini)(void),
        void (*rtld_fini)(void), void *stack_end)
{
        typeof(__libc_start_main) *real_lsm;
        if(ac > 0 && !strcmp(av[0], "/bin/sh")){
                av[0] = "/bin/bash";
                execv(av[0], av);
                err(1, "execv %s", av[0]);
        }else if(real_lsm = dlsym(RTLD_NEXT, "__libc_start_main"))
                return real_lsm(main, ac, av, init, fini, rtld_fini, stack_end);
        else
                errx(1, "BUG: dlsym: %s", dlerror());
}
$ cc -fPIC -shared -Wall -W -Wno-parentheses sh_is_bash.c -o sh_is_bash.so -ldl
$ LD_PRELOAD=`pwd`/sh_is_bash.so program ...

Shebang이 있는 모든 스크립트는 실행하는 대신 환경 변수에 절대 경로가 포함되어 있으면 실행됩니다 #! /bin/sh./bin/bash/bin/shLD_PRELOADsh_is_bash.so

보기 흉하지만 시스템이나 스크립트를 크게 변경할 필요가 없고 배포 및 관리가 쉽고 특별한 권한이 필요하지 않습니다.

답변3

시스템을 손상시키지 않고도 쉽게 문제를 해결할 수 있습니다!

find . -name '*.sh' -type f -exec sed -i '1s|^#! */bin/sh|#!/bin/bash|' {} +

답변4

귀하의 경우 POSIX가 아닌 확장이 포함된 스크립트에는 관련 올바른 #!헤더가 있어야 합니다.

#!/bin/bash

따라서 잘못된 스크립트를 모두 편집할 수 있는 방법은 없다고 생각합니다.

참고: 정말로 확신한다면 bash에 대한 임시 링크를 만들고 이름을 바꿀 수 있습니다.

cd /bin
ln -s bash nsh
mv nsh sh

원자적으로 작업 하므로 mv항상 작업이 보장됩니다./bin/sh

따라서 현재 실행 중인 스크립트 및 기타 셸은 이름을 바꿔도 계속 작동하며, 이름을 바꾼 후에는 대시 대신 bash를 호출합니다.

그러나 시스템이 스크립트 편집을 허용하는 방식으로 실행된다면 스크립트를 편집하는 편이 낫습니다.

/bin/sh링크를 로 대체한 경우 bash작업이 완료되면 다시 /bin/sh링크가 되도록 수정하는 것을 잊지 마세요.dash

문제의 스크립트가 바이너리 패키지의 일부인 경우 문제 업스트림에 대한 버그 보고서를 제출하는 것을 잊지 마세요.

관련 정보