Is the data in siginfo trustworthy?

后端 未结 2 2179
轻奢々
轻奢々 2021-02-14 11:12

I\'ve found that on Linux, by making my own call to the rt_sigqueue syscall, I can put whatever I like in the si_uid and si_pid fields and

2条回答
  •  伪装坚强ぢ
    2021-02-14 11:41

    That section of the POSIX page you quote also lists what si-code means, and here's the meaning:

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

    That section goes on to say:

    If the signal was not generated by one of the functions or events listed above, si_code shall be set either to one of the signal-specific values described in XBD , or to an implementation-defined value that is not equal to any of the values defined above.

    Nothing is violated if only the sigqueue() function uses SI_QUEUE. Your scenario involves code other than the sigqueue() function using SI_QUEUE The question is whether POSIX envisions an operating system enforcing that only a specified library function (as opposed to some function which is not a POSIX-defined library function) be permitted to make a system call with certain characteristics. I believe the answer is "no".

    EDIT as of 2011-03-26, 14:00 PST:

    This edit is in response to R..'s comment from eight hours ago, since the page wouldn't let me leave an adequately voluminous comment:

    I think you're basically right. But either a system is POSIX compliant or it is not. If a non-library function does a syscall which results in a non-compliant combination of uid, pid, and 'si_code', then the second statement I quoted makes it clear that the call itself is not compliant. One can interpret this in two ways. One ways is: "If a user breaks this rule, then he makes the system non-compliant." But you're right, I think that's silly. What good is a system when any nonprivileged user can make it noncompliant? The fix, as I see it, is somehow to have the system know that it's not the library 'sigqueue()' making the system call, then the kernel itself should set 'si_code' to something other than 'SI_QUEUE', and leave the uid and pid as you set them. In my opinion, you should raise this with the kernel folks. They may have difficulty, however; I don't know of any secure way for them to detect whether a syscall is made by a particular library function, seeing as how the library functions. almost by definition, are merely convenience wrappers around the syscalls. And that may be the position they take, which I know will be a disappointment.

    (voluminous) EDIT as of 2011-03-26, 18:00 PST:

    Again because of limitations on comment length.

    This is in response to R..'s comment of about an hour ago.

    I'm a little new to the syscall subject, so please bear with me.

    By "the kernel sysqueue syscall", do you mean the `__NR_rt_sigqueueinfo' call? That's the only one that I found when I did this:

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

    If that's the case, I think I'm not understanding your original point. The kernel will let (non-root) me use SI-QUEUE with a faked pid and uid without error. If I have the sending side coded thus:

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    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() */
    

    and the receiving side coded thus:

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    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() */
    

    I can then run (non-root) the receiving side thus:

    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$ 
    

    And see this (non-root) on the send end:

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

    As you can see, the third event has spoofed pid and uid. Isn't that what you originally objected to? There's no EINVAL or EPERM in sight. I guess I'm confused.

提交回复
热议问题