您引用的 POSIX 页面的该部分还列出了si-code
含义,其含义如下:
SI_QUEUE
The signal was sent by the sigqueue() function.
该部分继续说:
如果信号不是由上面列出的函数或事件之一生成,si_code
则应设置为 XBD 中描述的信号特定值之一,或设置为不等于任何上述值的实现定义值.
如果仅sigqueue()
函数使用SI_QUEUE
. sigqueue()
您的场景涉及使用函数以外的代码SI_QUEUE
问题是 POSIX 是否设想操作系统强制只允许指定的库函数(而不是某些不是 POSIX 定义的库函数的函数)进行系统调用特征。我相信答案是“不”。
编辑截至 2011 年 3 月 26 日,太平洋标准时间 14:00:
此编辑是对八小时前R..的评论的回应,因为该页面不允许我留下足够多的评论:
我认为你基本上是对的。但是系统要么符合 POSIX,要么不符合。如果非库函数执行系统调用导致 uid、pid 和 'si_code' 的组合不合规,那么我引用的第二条语句清楚地表明调用本身不合规。人们可以用两种方式解释这一点。一种方法是:“如果用户违反了这条规则,那么他就会使系统不合规。” 但你是对的,我认为这很愚蠢。当任何非特权用户都可以使其不合规时,系统有什么好处?正如我所看到的,修复方法是让系统知道不是库'sigqueue()'进行系统调用,然后内核本身应该将'si_code'设置为'SI_QUEUE'以外的其他值,然后离开uid 和 pid 设置它们。在我看来,你应该向内核人员提出这个问题。然而,他们可能有困难;我不知道他们有任何安全的方法来检测系统调用是否由特定的库函数进行,看看库是如何运行的。几乎按照定义,它们只是系统调用的便利包装。这可能是他们采取的立场,我知道这会令人失望。
(大量)编辑截至 2011 年 3 月 26 日,太平洋标准时间 18:00:
再次因为评论长度的限制。
这是对R..大约一个小时前的评论的回应。
我对系统调用主题有点陌生,所以请多多包涵。
“内核sysqueue
系统调用”是指“__NR_rt_sigqueueinfo”调用吗?这是我在执行此操作时发现的唯一一个:
grep -Ri 'NR.*queue' /usr/include
如果是这样的话,我想我不明白你的原点。内核将允许(非 root)我使用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() */
然后我可以运行(非root)接收端:
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$
并在发送端看到这个(非root):
wally:~/tmp/20110326$ send 9023
wally:~/tmp/20110326$
如您所见,第三个事件欺骗了 pid 和 uid。这不是你最初反对的吗?没有EINVAL
或EPERM
看不到。我想我很困惑。