2011-03-10 3 views
8

리눅스에서 rt_sigqueue 시스템 호출을 직접 호출하여 si_uidsi_pid 필드에 원하는 내용을 넣을 수 있습니다. 그러면 호출이 성공하고 잘못된 값을 기쁘게 전달합니다. 당연히 신호를 보내는 것에 대한 UID 제한은 이러한 종류의 스푸핑에 대한 보호를 제공하지만이 정보에 의존하는 것이 위험 할 수도 있습니다. 내가 읽을 수있는 주제에 대한 좋은 문서가 있습니까? 왜 리눅스는 발신자가 커널 공간에서 생성하지 않고 siginfo 매개 변수를 지정하도록하는 명백하게 잘못된 동작을 허용합니까? 특히 users sysspace에서 uid/gid를 얻기 위해 여분의 sys 호출 (따라서 성능 비용)이 필요할 수 있기 때문에 무의미한 것처럼 보입니다.siginfo의 데이터가 신뢰할 수 있습니까?

편집 : (나를 강조 효과) POSIX 내 판독 기준 :

si_code가 SI_USER 또는 SI_QUEUE [XSI] 또는 임의의 값이 0보다 작거나 같으면 다음 신호이면 프로세스에 의해 생성되었고 si_pid와 si_uid 은 각각 프로세스 ID와 송신자의 실제 사용자 ID로 설정되어야한다.

저는 Linux의 이러한 동작이 부적합하고 심각한 버그라고 생각합니다.

+0

당신은 그 것처럼 보입니다. 아마도 리눅스 커널 메일 링리스트를 시도해야 할 것이다 : http://www.kernel.org/pub/linux/docs/lkml/ –

답변

5

당신은 또한 인용는 POSIX 페이지의 섹션은 무엇 si-code 수단을 나열하고 여기에 의미가 있다는 :

신호에 의해 생성되지 않은 경우 : 섹션 말에 들어가

SI_QUEUE 
    The signal was sent by the sigqueue() function. 

위의 , si_code은 XBD에 설명 된 또는에 설명 된 신호 특정 값 중 하나에 중 하나를 설정해야합니다구현 정의 값 은 위의 값 중 하나와 같지 않습니다.

sigqueue() 함수 만 SI_QUEUE을 사용하면 아무 것도 위반되지 않습니다. 당신의 시나리오는 을 사용하는 sigqueue() 함수가 아닌 코드를 포함합니다. 문제는 POSIX가 시스템 호출을하도록 허용 된 특정 라이브러리 함수 (POSIX 정의 라이브러리 함수가 아닌 일부 함수와 반대)를 실행하는 운영 체제를 계획하는지 여부입니다. 어떤 특징이 있습니다. 나는 대답이 "아니오"라고 생각한다. 2011-03-26의 같은

편집, 태평양 표준시 14시 : 페이지를하지 것이기 때문에

이 편집 8 시간 전부터 R ..의 코멘트에 대한 응답입니다 나는 적절하게 볼륨있는 코멘트를 남긴다 :

나는 당신이 기본적으로 옳다고 생각한다. 그러나 시스템이 POSIX 호환이거나 그렇지 않습니다. 비 라이브러리 함수가 uid, pid 및 'si_code'의 비 호환 조합을 초래하는 syscall을 수행하는 경우, 인용 한 두 번째 명령문은 호출 자체가 호환되지 않음을 분명히합니다. 하나는 이것을 두 가지 방식으로 해석 할 수 있습니다. 한 가지 방법은 다음과 같습니다. "사용자가이 규칙을 위반하면 시스템이 정책을 준수하지 않게됩니다." 하지만 당신 말이 맞아, 나는 바보 같아. 비 권유 사용자가 비 호환 사용자가 될 수있는 시스템이 무슨 소용입니까?필자가 보았 듯이이 수정은 시스템 호출을하는 라이브러리의 sigqueue()가 아니라는 것을 시스템에 알리기 위해 커널 자체가 'si_code'를 'SI_QUEUE'가 아닌 다른 것으로 설정해야합니다. uid와 pid를 설정합니다. 제 견해로, 여러분은 커널 사람들과 함께 이것을 제기해야합니다. 그러나 그들은 어려움을 겪을 수 있습니다. 특정 라이브러리 기능에 의해 시스템 호출이 생성되었는지 여부를 감지하여 라이브러리가 작동하는 방식을 확인하는 보안 방법을 모르겠습니다. 거의 정의상, 단지 syscall을 둘러싼 편의성 래퍼 일 뿐이다. 그리고 그것은 그들이 취하는 입장 일 수도 있습니다. 나는 실망 할 것입니다. 2011-03-26 18:00 PST 비 등

(부피) 편집 : 코멘트 길이

다시 때문에 제한.

이 게시물에 대한 답변은 R .. 님의 댓글 1 시간 전에 작성되었습니다.

저는 시스코 대상에게 조금 새로운 것이므로 제발 참아주십시오.

"커널 sysqueue syscall"이란 말은`__NR_rt_sigqueueinfo '호출을 의미합니까? 즉, 단지 내가 이런 짓을 할 때 내가 찾은 하나 : 그런 경우

grep -Ri 'NR.*queue' /usr/include 

, 내가 원래 점을 이해하지 못하는 것 같아요. 커널은 (루트가 아닌) SI-QUEUE을 위조 된 pid와 uid로 오류없이 사용하게합니다.

#include <sys/syscall.h> 
#include <sys/types.h> 
#include <signal.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 

int main(int argc, 
     char **argv 
     ) 
{ 
    long john_silver; 

    siginfo_t my_siginfo; 

    if(argc!=2) 
    { 
    fprintf(stderr,"missing pid argument\n"); 

    exit(1); 
    } 

    john_silver=strtol(argv[1],NULL,0); 

    if(kill(john_silver,SIGUSR1)) 
    { 
    fprintf(stderr,"kill() fail\n"); 

    exit(1); 
    } 

    sleep(1); 

    my_siginfo.si_signo=SIGUSR1; 
    my_siginfo.si_code=SI_QUEUE; 
    my_siginfo.si_pid=getpid(); 
    my_siginfo.si_uid=getuid(); 
    my_siginfo.si_value.sival_int=41; 

    if(syscall(__NR_rt_sigqueueinfo,john_silver,SIGUSR1,&my_siginfo)) 
    { 
    perror("syscall()"); 

    exit(1); 
    } 

    sleep(1); 

    my_siginfo.si_signo=SIGUSR2; 
    my_siginfo.si_code=SI_QUEUE; 
    my_siginfo.si_pid=getpid()+1; 
    my_siginfo.si_uid=getuid()+1; 
    my_siginfo.si_value.sival_int=42; 

    if(syscall(__NR_rt_sigqueueinfo,john_silver,SIGUSR2,&my_siginfo)) 
    { 
    perror("syscall()"); 

    exit(1); 
    } 

    return 0; 

} /* main() */ 

과 수신 측 따라서 코딩 : 나는 송신 측 따라서 코딩 한 경우

#include <sys/types.h> 
#include <signal.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <unistd.h> 

int signaled_flag=0; 

siginfo_t received_information; 

void 
my_handler(int  signal_number, 
      siginfo_t *signal_information, 
      void  *we_ignore_this 
     ) 
{ 
    memmove(&received_information, 
      signal_information, 
      sizeof(received_information) 
     ); 

    signaled_flag=1; 

} /* my_handler() */ 

/*--------------------------------------------------------------------------*/ 

int 
main(void) 
{ 
    pid_t   myself; 

    struct sigaction the_action; 

    myself=getpid(); 

    printf("signal receiver is process %d\n",myself); 

    the_action.sa_sigaction=my_handler; 
    sigemptyset(&the_action.sa_mask); 
    the_action.sa_flags=SA_SIGINFO; 

    if(sigaction(SIGUSR1,&the_action,NULL)) 
    { 
    fprintf(stderr,"sigaction(SIGUSR1) fail\n"); 

    exit(1); 
    } 

    if(sigaction(SIGUSR2,&the_action,NULL)) 
    { 
    fprintf(stderr,"sigaction(SIGUSR2) fail\n"); 

    exit(1); 
    } 

    for(;;) 
    { 
    while(!signaled_flag) 
    { 
     sleep(1); 
    } 

    printf("si_signo: %d\n",received_information.si_signo); 
    printf("si_pid : %d\n",received_information.si_pid ); 
    printf("si_uid : %d\n",received_information.si_uid ); 

    if(received_information.si_signo==SIGUSR2) 
    { 
     break; 
    } 

    signaled_flag=0; 
    } 

    return 0; 

} /* main() */ 
나는 그 (루트가 아닌) 따라서 수신 측 실행할 수 있습니다

:

wally:~/tmp/20110326$ receive 
signal receiver is process 9023 
si_signo: 10 
si_pid : 9055 
si_uid : 4000 
si_signo: 10 
si_pid : 9055 
si_uid : 4000 
si_signo: 12 
si_pid : 9056 
si_uid : 4001 
wally:~/tmp/20110326$ 

그리고 전송 끝에서 다음을 참조하십시오 (루트가 아님) :

wally:~/tmp/20110326$ send 9023 
wally:~/tmp/20110326$ 

보시다시피, 세 번째 이벤트는 pid 및 uid를 스푸핑했습니다. 당신이 원래 반대 한 것이 아닌가요? 시야에 EINVAL 또는 EPERM이 없습니다. 나는 혼란 스러울 것 같아.

+0

이것이 내가 인용 한 문단과 uid와 pid가 요구하는 요구 사항과 모순되는 것을 나는 볼 수 없다. 'si_code'가 프로세스 생성 신호를 나타내는 값 집합 중 하나를 취할 때 유효합니다. 필자가 인용 한 텍스트의 "shall"은 신호를 보내는 데 사용 된 인터페이스와 표준인지 여부에 관계없이 애플리케이션이 신호 처리기가 호출 될 때 항상 충족되는 제약 조건에 의존 할 수 있음을 나타내는 것으로 해석합니다. –

+0

나는 여기에 내 모든 의견을 남길 수 없었다. 페이지는 내가 충분한 인물이 없다고 말했다. 위의 내 대답 편집을 참조하십시오. –

+0

필자는 규약 준수 여부에 따라 'si_code'가 'SI_QUEUE'이거나 다른 특수 값 중 하나가 시스템의 신호 전달 * 메커니즘의 요구 사항이거나 ' sigqueue '기능을 제공합니다. 제가 말할 수있는 한, 후자가 아닌 전입니다. 어쨌든 나는 커널이 권한 제한 필드가되어야하는 것을 채우기 위해 왜 커널이 응용 프로그램에 그것을 남겨두고 (그리고 그것을 신뢰하는지) 혼란 스럽다. –

0

나는 si_uidsi_pid이 신뢰할 만하다는 것에 동의하며 그렇지 않은 경우 버그입니다. 그러나 이는 자식 프로세스의 상태 변경에 의해 생성 된 신호가 SIGCHLD이거나 si_codeSI_USER 또는 SI_QUEUE이거나 시스템이 XSI 옵션과 si_code <= 0을 지원하는 경우에만 필요합니다. 다른 경우에는 Linux/glibc도 si_uidsi_pid 값을 전달합니다. 이들은 종종 신뢰성이 없지만 POSIX 적합성 문제는 아닙니다.

물론 kill()의 경우 신호가 대기열에 들어 가지 않을 수 있으며이 경우 siginfo_t은 추가 정보를 제공하지 않습니다.

rt_sigqueueinfo이 단지 SI_QUEUE 이상을 허용하는 이유는 아마도 최소한의 커널 지원으로 POSIX 비동기 I/O, 메시지 큐 및 프로세스 당 타이머를 구현할 수 있기 때문입니다. 이러한 사용자 영역을 구현하려면 SI_ASYNCIO, SI_MESGQSI_TIMER의 신호를 보낼 수 있어야합니다.나는 glibc가 신호를 미리 대기열에 넣는 방법을 모릅니다. 나에게 그것은 그것이 같지 않고 단지 희망한다 rt_sigqueueinfo가 실패하지 않는 것처럼 본다. POSIX는 타이머 만료 (비동기 I/O 완료, 메시지 대기열에 대한 메시지 도착) 알림을 명시 적으로 폐기하는 것을 금지합니다. 이는 너무 많은 신호가 만료시 대기열에 들어 있기 때문입니다. 부족한 자원이있는 경우 구현시 등록 또는 등록을 거부해야합니다. 객체는 각 I/O 요청, 메시지 대기열 또는 타이머가 한 번에 최대 하나의 신호를 전달할 수 있도록 신중하게 정의되었습니다.

+0

하지만'rt_sigqueueinfo'는'si_code <= 0'을 적용합니다.이 경우 uid와 pid는 유효해야합니다. 맞습니까? –

+0

예,'si_code <= 0'이고 시스템이 XSI 옵션을 지원하면, uid와 pid가 유효해야합니다. 그러나 'SI_QUEUE'또는 'SI_TIMER'와 같은 코드가 음수 또는 0 일 필요는 없습니다. FreeBSD는 XSI 옵션의이 부분을 지원하지 않습니다. 추가 정보가 없으면'si_code = 0' (일명'SI_NOINFO')을 설정합니다; 이 경우 uid와 pid는 유효하지 않습니다. – jilles

+0

그러나 Linux에서는이 값이 음수입니다. –

관련 문제