C 내에서 쉘 명령을 호출하는 것이 좋은 생각입니까?


50

udevadm info -q path -n /dev/ttyUSB2C 프로그램에서 호출하려는 유닉스 쉘 명령 ( )이 있습니다. 아마 약 일주일의 투쟁으로, 나는 그것을 직접 구현할 수는 있지만 그렇게하고 싶지 않습니다.

전화를 거는 것이 좋은 습관 popen("my_command", "r");인지, 아니면 받아 들일 수없는 보안 문제가 발생하고 호환성 문제가 전달 되는가? 이런 일을하는 것은 나에게 기분이 좋지 않지만 왜 나쁜지에 손가락을 넣을 수는 없습니다.


8
고려해야 할 한 가지는 주입 공격입니다.
MetaFight 2016 년

8
나는 주로 사용자 입력을 쉘 명령 인수로 제공 한 경우를 생각하고있었습니다.
MetaFight 2016 년

8
누군가 udevadm프로그램과 같은 디렉토리에 악성 실행 파일을 넣고 권한을 에스컬레이션하는 데 사용할 수 있습니까? 유닉스 보안에 대해 잘 모르지만 프로그램이 함께 실행 setuid root됩니까?
Andrew Piliser 2018 년

7
@AndrewPiliser 현재 디렉토리가에 있지 않다면, no- PATH로 실행해야 ./udevadm합니다. 그러나 IIRC Windows는 동일한 디렉토리 실행 파일을 실행합니다.
이즈 카타

4
가능할 때마다 쉘을 거치지 않고 원하는 프로그램을 직접 호출하십시오.
코드 InChaos

답변:


58

특별히 나쁘지는 않지만 몇 가지주의 사항이 있습니다.

  1. 솔루션을 얼마나 휴대 할 수 있습니까? 선택한 바이너리가 모든 곳에서 동일하게 작동하고 결과를 동일한 형식으로 출력합니까? LANG등의 설정에서 다르게 출력 됩니까?
  2. 이것이 프로세스에 얼마나 많은 추가 부하를 가합니까? 바이너리를 포킹하면 라이브러리 호출 (일반적으로 말하기)을 실행하는 것보다 훨씬 많은로드가 발생하고 더 많은 리소스가 필요합니다. 시나리오에서 이것이 허용됩니까?
  3. 보안 문제가 있습니까? 당신이 선택한 바이너리를 다른 바이너리로 대체하여 사악한 행위를 할 수 있습니까? 바이너리에 사용자 제공 인수를 사용합니까 ;rm -rf /(예를 들어) 제공 할 수 있습니까 (일부 API에서는 명령 행에서 제공하는 것보다 더 안전하게 인수를 지정할 수 있습니다)

필자는 알려진 환경에서 바이너리 출력을 구문 분석하기 쉬운 경우 (필요한 경우 종료 코드가 필요할 수 있음) 바이너리를 실행하는 것이 일반적이며 행복하지도 않습니다. 자주.

앞에서 언급했듯이 다른 문제는 바이너리가하는 일을 복제하는 것이 얼마나 많은가입니다. 활용할 수있는 라이브러리를 사용합니까?


13
Forking a binary results in a lot more load and requires more resources than executing library calls (generally speaking). 이것이 Windows에 있다면 동의합니다. 그러나 OP는 라이브러리를 동적으로로드하는 것이 분기하는 것보다 나쁜지 말하기가 어렵 기 때문에 포크가 낮은 비용으로 Unix를 지정합니다.
wallyk 2016 년

1
바이너리는 여러 번 실행될 수 있지만 일반적으로 라이브러리는 한 번 로드 될 것으로 예상 됩니다. 그 어느 때보 다 사용 시나리오에 따라 다르지만 고려해야합니다 (이후 해산되는 경우)
Brian Agnew

3
Windows에는 "포킹 (forking)"이 없으므로 인용문 유닉스 전용이어야합니다.
코디 그레이

5
NT 커널은 Win32를 통해 노출되지 않지만 포크를 지원합니다. 어쨌든 외부 프로그램을 실행하는 비용은에서 exec보다 더 많이 올 것이라고 생각 합니다 fork. 섹션로드, 공유 객체 연결, 각각에 대한 초기화 코드 실행 그런 다음 모든 데이터를 텍스트로 변환하여 입력 및 출력 모두에서 구문 분석 할 수 있습니다.
스펙트럼

8
공평하게, udevadm info -q path -n /dev/ttyUSB2어쨌든 Windows에서 작동하지 않을 것이므로 전체 토론 토론은 약간 이론적입니다.
MSalters 2016 년

37

잠재적 인 벡터를 도입 한 후에는 주입 취약점으로부터 보호하기 위해 매우주의해야합니다. 그것은 지금 당신의 마음의 최전선에 있지만 나중에 선택할 수있는 능력이 필요할 수 있습니다 ttyUSB0-3. 그런 다음 그 목록은 다른 곳에서 사용될 것이므로 단일 책임 원칙을 따르기 위해 고객이 요구할 것입니다. 목록에 임의의 장치가 있으며, 개발자 변경하면 목록이 안전하지 않은 방식으로 사용된다는 것을 알 수 없습니다.

다시 말해, 당신이 알고있는 가장 부주의 한 개발자 인 것처럼 보이는 것은 코드의 관련이없는 부분에서 안전하지 않은 변경을하는 것입니다.

둘째, CLI 도구의 출력은 문서에서 특별히 표시하지 않는 한 일반적으로 안정적인 인터페이스로 간주되지 않습니다. 문제를 해결할 수는 있지만 고객에게 배포 한 스크립트는 실행하지 않는 스크립트를 사용하는 것이 좋습니다.

셋째, 소프트웨어에서 가치를 쉽게 추출 할 수있는 방법을 원한다면 다른 사람도 그것을 원할 가능성이 있습니다. 이미 원하는 것을 수행하는 라이브러리를 찾으십시오. libudev내 시스템에 이미 설치되어 있습니다.

#include <libudev.h>
#include <sys/stat.h>
#include <stdio.h>

int main(int argc, char* argv[]) {
    struct stat statbuf;

    if (stat("dev/ttyUSB2", &statbuf) < 0)
        return -1;
    struct udev* udev = udev_new();
    struct udev_device *dev = udev_device_new_from_devnum(udev, 'c', statbuf.st_rdev);

    printf("%s\n", udev_device_get_devpath(dev));

    udev_device_unref(dev);
    udev_unref(udev);
    return 0;
}

해당 라이브러리에는 다른 유용한 기능이 있습니다. 내 생각에 당신이 이것을 필요로하면 관련 기능 중 일부도 유용 할 수 있습니다.


2
감사합니다. 나는 libudev를 찾는 데 너무 오래 보냈다. 나는 그것을 찾을 수 없었다!
johnny_boy 2016 년

2
다른 사용자가 환경을 제어 할 때 OP의 프로그램이 호출되지 않는 한 여기에서 "주입 취약점"이 어떻게 문제가되는지 보지 못합니다. cgi 및 ssh 강제 명령). 일반 프로그램을 실행중인 사용자에 대해 강화해야 할 이유가 없습니다.
R ..

2
@R .. : "주입 취약점"은 일반화 ttyUSB2하고 사용할 때 sprintf(buf, "udevadm info -q path -n /dev/%s", argv[1])입니다. 이제 상당히 안전 표시되지만 어떤 경우 argv[1]이다 "nul || echo OOPS"?
MSalters 2016 년

3
@R .. : 더 많은 상상력이 필요합니다. 먼저 고정 문자열이고 사용자가 제공 한 인수이고 사용자가 실행하는 다른 프로그램에서 제공하는 인수이지만 이해하지 못한다는 것은 브라우저가 웹 페이지에서 추출한 인수입니다. 상황이 계속 "내리막"상태가되면 결국 누군가가 투입물을 소독하는 데 책임을 져야하며 Karl은 해당 지점을 어디에서든지 식별하기 위해 각별한주의를 기울여야한다고 말합니다.
Steve Jessop

6
사전 예방 원칙이 실제로 "부주의 한 부주의 한 개발자가 안전하지 않은 변경을하고 있다고 가정"하고 악용을 초래할 수없는 코드를 작성해야한다면 개인적으로 잠자리에서 나올 수 없었습니다. 내가 아는 가장 부주의 한 개발자는 Machievelli가 시도 조차하지 않는 것처럼 보이게한다 .
Steve Jessop

16

호출하려는 특정 경우 에는 라이브러리로 udevadm가져 와서 udev대안으로 적절한 함수 호출을 할 수 있다고 생각합니다 .

예를 들어, 당신은 "정보"모드에서 호출 할 때 udevadm 자체가 무엇을하고 있는지를 살펴 걸릴 수 : https://github.com/gentoo/eudev/blob/master/src/udev/udevadm-info.c을 하고 당량 통화를 할 수 udevadm이 만들고있는 것입니다.

이것은 Brian Agnew의 훌륭한 답변에 열거 된 많은 단점을 피할 수 있습니다. 예를 들어 특정 경로에 존재하는 이진 파일에 의존하지 않고 포크 비용을 피하는 등


고마워, 나는 그 정확한 레포를 찾았고 결국 그것을 통해 끝났다.
johnny_boy 2016 년

1
… libudev는 특히 사용하기 어렵지 않습니다. 오류 처리에는 약간 부족하지만 API 열거, 쿼리 및 모니터링은 매우 간단합니다. 당신이 그것을 시도하면 당신의 두려움은 2 시간 미만으로 나타날 수 있습니다.
스펙트럼

7

귀하의 질문은 숲 답변을 요구하는 것처럼 보였으며 여기의 답변은 나무 답변처럼 보입니다. 그래서 나는 당신에게 숲 답변을 줄 것이라고 생각했습니다.

이것은 C 프로그램이 작성되는 방법은 매우 드 rare니다. 항상 셸 스크립트가 작성되는 방식이며 때로는 Python, perl 또는 Ruby 프로그램이 작성되는 방식입니다.

사람들은 일반적으로 시스템 라이브러리를 쉽게 사용하고 OS 시스템 호출에 대한 낮은 수준의 액세스 및 속도를 위해 C로 작성합니다. C는 작성하기 어려운 언어이므로 사람들이 그러한 것을 필요로하지 않으면 C를 사용하지 않습니다. 또한 C 프로그램은 일반적으로 공유 라이브러리 및 구성 파일에만 의존해야합니다.

하위 프로세스로의 셸링은 특히 빠르지 않으며 하위 수준의 시스템 기능에 대한 세밀하고 제어 된 액세스가 필요하지 않으며 외부 실행 파일에 대한 놀라운 의존성을 유발하므로 드물게 볼 수 있습니다. C 프로그램에서.

추가적인 우려가 있습니다. 사람들이 언급 한 보안 및 이식성 문제는 완전히 유효합니다. 그것들은 물론 쉘 스크립트에도 똑같이 유효하지만 사람들은 쉘 스크립트에서 이러한 종류의 문제를 기대하고 있습니다. 그러나 C 프로그램은 일반적으로 이러한 종류의 보안 문제를 예상하지 않으므로 더 위험합니다.

그러나 제 생각에는 가장 큰 관심사는 popen프로그램의 나머지 부분과 상호 작용 하는 방식과 관련이 있습니다. popen하위 프로세스를 작성하고 출력을 읽고 종료 상태를 수집해야합니다. 그 동안 해당 프로세스의 stderr은 프로그램과 동일한 stderr에 연결되어 혼란스러운 결과를 초래할 수 있으며 stdin은 프로그램과 동일하므로 다른 흥미로운 문제가 발생할 수 있습니다. 쉘이 해석 </dev/null 2>/dev/null하기 popen때문에 전달한 문자열을 포함 시켜서 해결할 수 있습니다 .

그리고 popen자식 프로세스를 만듭니다. 신호 처리 또는 포크 프로세스와 관련된 작업을 수행하면 이상한 SIGCHLD신호 가 발생할 수 있습니다 . 귀하의 전화가 wait이상하게 상호 작용 popen하고 이상한 경주 조건을 만들 수 있습니다.

보안 및 이식성 문제는 물론 존재합니다. 쉘 스크립트 또는 시스템에서 다른 실행 파일을 시작하는 모든 것입니다. 그리고 당신은 당신의 프로그램을 사용하는 사람들은 당신이에 전달하는 문자열에 쉘 메타 charcaters를 얻을 수없는 것을 조심해야 popen하는 문자열에 주어진 때문에 shsh -c <string from popen as a single argument>.

그러나 나는 그들이 C 프로그램을 사용하는 것이 이상한 이유라고 생각하지 않습니다 popen. 이상한 이유는 C가 일반적으로 저수준 언어이고 저수준이 아니기 때문 popen입니다. 그리고 popen프로그램 의 장소 디자인 제약 조건을 사용 하면 프로그램의 표준 입력 및 출력과 이상하게 상호 작용하고 자체 프로세스 관리 또는 신호 처리를 수행하는 데 어려움이 있기 때문에 프로그램에 배치 디자인 제약 조건이 사용 되기 때문입니다. 그리고 C 프로그램은 일반적으로 외부 실행 파일에 의존하지 않을 것으로 예상됩니다.


0

프로그램은 해킹 등의 대상이 될 수 있습니다. 이러한 유형의 활동으로부터 자신을 보호하는 한 가지 방법은 현재 시스템 환경의 사본을 작성하고 chroot라는 시스템을 사용하여 프로그램을 실행하는 것입니다.

프로그램의 관점에서 정상적인 환경에서 실행, 보안 측면에서 누군가가 프로그램을 중단하면 복사 할 때 제공 한 요소에만 액세스 할 수 있습니다.

자세한 내용은 chroot jail을 참조하십시오 .

일반적으로 공개적으로 액세스 가능한 서버 등을 설정하는 데 사용됩니다.


3
OP는 신뢰할 수없는 바이너리 또는 자체 시스템에서 소스를 사용하지 않고 다른 사람들이 실행할 수있는 프로그램을 작성 중입니다.
Peter Cordes
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.