`ssh ... "$(typeset -f foo); foo"` 관용구는 얼마나 안전합니까?

`ssh ... "$(typeset -f foo); foo"` 관용구는 얼마나 안전합니까?

foo현재 쉘 세션에 쉘 함수가 정의되어 있다고 가정합니다 . 그런 다음 명령

typeset -f foo

함수의 소스 코드를 인쇄합니다. 이는 최소한 원칙적으로는 다음 ssh과 같은 작업을 수행하여 원격 호스트에서 이 기능을 수행할 수 있음을 의미합니다.

ssh <REMOTE-HOST> "$(typeset -f foo); foo"

(이 질문의 목적을 위해 언급된 모든 명령과 파일 시스템 경로를 foo사용할 수 있다고 가정합니다 <REMOTE-HOST>. 또한 bash양쪽 끝이 셸이라고 가정합니다.)

foo내 직감으로는 이와 같이 자동으로 생성된 소스 코드를 맹목적으로 잡는 것은 매우 취약할 것이지만 이 관용구가 실패하는 함수의 예를 생각해낼 수는 없습니다 .

제 질문은 이 관용어가 얼마나 안전한가요?입니다. 안전하지 않은 경우 누군가 나에게 이것이 어떻게 실패하는지에 대한 구체적인 예를 줄 수 있습니까? (안전 질문에는 다음이 포함됩니다. bash이 사용이 typeset -f안전하다고 보장됩니까?)

알아채다:이 게시물에서 저는 대안을 찾고 있는 것이 아닙니다. 저는 단지 이 특정 관용구의 속성을 이해하고 싶습니다.


편집: 명확히 하기 위해 이것은 bash양쪽 끝에 있는 쉘입니다.

답변1

코드가 생성된 로케일과 동일한 로케일에서 해석되지 않는 경우(또는 로케일이이름동일하지만 SSH 클라이언트 호스트와 서버 호스트 간에 로케일 정의가 다릅니다.

blank특히 중요한 것은 alpha클래스, 클래스 및 클래스의 문자 인코딩과 문자 멤버십 입니다 alnum.

예를 들어, αBIG5 문자 세트(그리스어 소문자 알파)의 문자는 \ASCII(및 BIG5를 포함한 모든 문자 세트)에서 0xa3 0x5c, 0x5c로 인코딩됩니다.

foo따라서 해당 문자 집합으로 함수를 정의 하면 다음과 같습니다 .

foo() {
  echo α
}

typeset -f이와 같이 출력되지만 다른 로케일(예: C)로 해석되면 0xa3 0x5c는 a로 처리되지 않고 α알 수 없는 0xa3 문자로 처리되며 그 뒤에 백슬래시가 붙습니다. 다음과 같이 사용할 수 있습니다.

$ env LC_ALL=zh_TW.big5 $'BASH_FUNC_foo%%=() { echo \xa3\\\\;}; echo gotcha; }' bash -c 'typeset -f foo' | bash
gotcha
bash: line 5: syntax error near unexpected token `}'
bash: line 5: `}'

다른 지역으로 해석하면 이렇게 foo() { echo α\;}; echo gotcha; }됩니다.foo() { echo <0xa3>\\; }; echo gotcha; }

다른 문제:

UTF-8의 문자 인코딩은 à0xc3 0xa0입니다. iso8859-1 및 기타 여러 iso8859문자 집합에서 0xa0은 줄 바꿈하지 않는 공백 문자입니다. 일부 시스템에서는 이 문자가공백문자 클래스이므로 bash는 이를 구문에서 토큰 구분 기호로 사용합니다.

Solaris는 U+00A0이 공백으로 처리되는 시스템 중 하나입니다.

$ env $'BASH_FUNC_foo%%=() { nawk -v x=àBEGIN\'{system("echo gotcha")}\' 1;}' bash -c 'typeset -f foo; echo foo'  | ssh solaris LC_ALL=en_GB.ISO8859-1 bash
gotcha

방법을 확인하세요:

nawk -v x=àBEGIN... 1

다음과 같이 설명되었습니다.

nawk -v x=<0xc3> 'BEGIN{system("...")}' 1

함수가 0xa0이 비어 있지 않거나 0xa3 0x5c가 알파인 로케일에 정의된 경우, typeset -f비어 있는 로케일에서 호출되더라도 여전히 동일한 결과를 출력합니다(해석 시 다른 출력 생성).

$ LC_ALL=zh_TW.big5 bash -c $'f() { echo \xa3\x5c$(uname); }; export LC_ALL=C; typeset -f f | bash'
bash: line 3: syntax error near unexpected token `('
bash: line 3: `    echo �\$(uname)'

보다 일반적으로 출력 typesetalias다음 과 같습니다 export -p.setlocale의미는셸에 다시 입력하는 데는 좋지만 이러한 로케일 문제 외에도 다양한 구현에 몇 가지 알려진 문제가 있으며 더 많은 문제가 있어도 놀라지 않을 것입니다.

그렇습니다. 저는 이것이 위험하고 좋은 생각이라는 점에 동의합니다. 그리고 출력 데이터가 어디에서 오는지 알고 있는 상황에서만 사용하는 것이 가장 좋습니다. 예를 들어 의 경우 다음을 만족하는 함수에만 typeset -f foo사용하세요.foo정의됩니다(그리고 ASCII가 아닌 문자를 사용하지 마십시오).

관련 정보