在OpenBSD内核代码中uint64_t ps_pledge varibale的目的是什么?

时间:2018-02-10 08:57:48

标签: c kernel openbsd

我正在使用OpenBSD内核代码,尤其是这个文件sys/kern/sched_bsd.c

    void
    schedcpu(void *arg)
    {
......

......

    LIST_FOREACH(p, &allproc, p_list) {
        /*
         * Increment sleep time (if sleeping). We ignore overflow.
         */
        if (p->p_stat == SSLEEP || p->p_stat == SSTOP)
            p->p_slptime++;
        p->p_pctcpu = (p->p_pctcpu * ccpu) >> FSHIFT;
        /*
         * If the process has slept the entire second,
         * stop recalculating its priority until it wakes up.
         */
        if (p->p_slptime > 1)
            continue;
        SCHED_LOCK(s);
        /*
         * p_pctcpu is only for diagnostic tools such as ps.
         */
....

....
LIST_FOREACH(TYPE *var, LIST_HEAD *head, LIST_ENTRY NAME);
The macro LIST_FOREACH traverses the list referenced by head in the forward direction, assigning each element in turn to var.

现在,p将包含文件中的struct proc eery进程结构的地址

  

SYS / SYS / proc.h

现在,这个结构再次包含另一个struct process *p_p结构,它表示每个进程的属性,如pidflagsthreads等。

    struct proc {
        TAILQ_ENTRY(proc) p_runq;
        LIST_ENTRY(proc) p_list;    /* List of all threads. */

        struct  process *p_p;       /* The process of this thread. */
        TAILQ_ENTRY(proc) p_thr_link;   /* Threads in a process linkage. */

        TAILQ_ENTRY(proc) p_fut_link;   /* Threads in a futex linkage. */
        struct  futex   *p_futex;   /* Current sleeping futex. */

        /* substructures: */
        struct  filedesc *p_fd;     /* copy of p_p->ps_fd */
        struct  vmspace *p_vmspace; /* copy of p_p->ps_vmspace */
#define p_rlimit    p_p->ps_limit->pl_rlimit

    ....

    ....

现在,结果struct process包含uint64_t ps_plegde

struct process {
    /*
     * ps_mainproc is the original thread in the process.
     * It's only still special for the handling of p_xstat and
     * some signal and ptrace behaviors that need to be fixed.
     */
    struct  proc *ps_mainproc;
    struct  ucred *ps_ucred;    /* Process owner's identity. */

....

....

    u_short ps_acflag;      /* Accounting flags. */

    uint64_t ps_pledge;
    uint64_t ps_execpledge; 

....

....

现在,我在void schedcpu()功能代码中写了一些修改。

void
schedcpu(void *arg)
{
    pid_t pid;
    uint64_t pledge_bit;
....

....


    LIST_FOREACH(p, &allproc, p_list) {

    pid=p->p_p->pid;
    pledge_bit=p->p_p->ps_pledge;

    if (pledge_bit) {
            printf("pid: %10d pledge_bit: %10llu pledge_xbit:%10llx\n",pid,pledge_bit,pledge_bit);
}

        /*
         * Increment sleep time (if sleeping). We ignore overflow.
         */
        if (p->p_stat == SSLEEP || p->p_stat == SSTOP)
            p->p_slptime++;
        p->p_pctcpu = (p->p_pctcpu * ccpu) >> FS 
....

....
  

此处,内核日志

pid:      37846 pledge_bit:     393359 pledge_xbit:      6008f
pid:      96037 pledge_bit:     393544 pledge_xbit:      60148
pid:      86032 pledge_bit:     264297 pledge_xbit:      40869
pid:      72264 pledge_bit:     393480 pledge_xbit:      60108
pid:      40102 pledge_bit:          8 pledge_xbit:          8
pid:        841 pledge_bit: 2148162527 pledge_xbit:   800a5bdf
pid:      49970 pledge_bit: 2148096143 pledge_xbit:   8009588f
pid:      68505 pledge_bit:         40 pledge_xbit:         28
pid:      46106 pledge_bit:         72 pledge_xbit:         48
pid:      77690 pledge_bit:     537161 pledge_xbit:      83249
pid:      44005 pledge_bit:     262152 pledge_xbit:      40008
pid:      82731 pledge_bit: 2148096143 pledge_xbit:   8009588f
pid:      71609 pledge_bit:     262472 pledge_xbit:      40148
pid:      54330 pledge_bit:     662063 pledge_xbit:      a1a2f
pid:      77764 pledge_bit:    1052776 pledge_xbit:     101068
pid:        699 pledge_bit: 2148096143 pledge_xbit:   8009588f
pid:      84265 pledge_bit:    1052776 pledge_xbit:     101068

....

....

现在,通过查看从上面输出得到的pledge_bit(十进制或十六进制值),可以知道哪个进程保证了哪些权限?

我接受了dhclient进程的承诺十六进制值,即0x8009588f,然后,我用pledge("STDIO",NULL);编写了一个示例hello world程序,然后我再次查看dmesg并获得了与hello world相同的pledge_bit,即{{1 }}。

然后,这次我查看了dhclient源代码并发现,dhclient代码承诺0x8009588f

但是,那么,如何为不同的承诺参数获得相同的质量十六进制位呢?

1 个答案:

答案 0 :(得分:0)

我一遍又一遍地阅读源代码后得到了答案。

所以,我只想贡献我的知识,以便未来的开发人员不会在这个问题或混乱中遇到任何问题。

第一个理解:

我写了这样的问候世界,

void
main() {
pledge("STDIO", NULL);   /* wrong use of pledge call */
printf("Hello world\n");
}

以上代码的更正:

void
main() {

if (pledge("stdio", NULL) == -1) {
        printf("Error\n");
}
printf("Hello world\n");
}

我忘了检查承诺()的返回值。

第二个理解:

dhclient.c代码包含pledge()调用:

int
main(int argc, char *argv[])
{
    struct ieee80211_nwid    nwid;
    struct ifreq         ifr;
    struct stat      sb;
    const char      *tail_path = "/etc/resolv.conf.tail";
....

....


fork_privchld(ifi, socket_fd[0], socket_fd[1]);

....

....


    if ((cmd_opts & OPT_FOREGROUND) == 0) {
        if (pledge("stdio inet dns route proc", NULL) == -1)
            fatal("pledge");
    } else {
        if (pledge("stdio inet dns route", NULL) == -1)
            fatal("pledge");
    }

....

....

void
fork_privchld(struct interface_info *ifi, int fd, int fd2)
{
    struct pollfd    pfd[1];
    struct imsgbuf  *priv_ibuf;
    ssize_t      n;
    int      ioctlfd, routefd, nfds, rslt;

    switch (fork()) {
    case -1:
        fatal("fork");
        break;
    case 0:
        break;
    default:
        return;
    }
....

....

}

现在,我编写了示例hello world代码,其中包含与dhclient相同的参数:

void
main() {

if(pledge("stdio inet proc route dns", NULL) == -1) {
        printf("Error\n");
}

while(1) {}
}

现在,我测试了上面的示例hello world代码,并将pledge_bit作为0x101068以十六进制表示,这是正确的。

但是,正如我之前在问题中告诉你的那样,当我看到dhclient的不同pledge_bit时,我感到很困惑。因为,你们知道他们的承诺()中都有相同的参数。

然后,怎么可能?

现在,这是捕获,

在不断查看dhclient源代码之后,我发现了一个名为fork_privchld()的函数。

在dhclient中承诺之前调用了这个函数,因此,就像没有承诺这个函数一样,因为它在认捐之前被调用了。

所以,只是为了再次验证我写了样本问候世界代码,但这次没有任何承诺()系统调用。

void
main() {
printf("hello\n");
}

而且,猜猜看,我得到了与0x8009588f相同的pledge_bit。

因此,在验证之后,验证fork_privchld()函数没有设置任何保证位,因为它在dhclient中认捐之前被调用。

此函数为dhclient创建[priv]子进程。

# ps aux|grep dhclient
root     26416  0.0  0.1   608   544 ??  Is     8:36AM    0:00.00 dhclient: em0 [priv] (dhclient)
_dhcp    33480  0.0  0.1   744   716 ??  Isp    8:36AM    0:00.00 dhclient: em0 (dhclient)

而且,我不知道为什么我只关注第一个过程,即[priv] (dhclient)。此过程是由fork_privchld()函数创建的过程。

这就是为什么这个过程有0x8009588f保证位(由于在认捐之前被召集,因此,此时没有认捐)。

而且,当我检查第二个过程,即_dhcp时,我得到了我预期的pledge_bit,即0x101068(由于认捐)。

所以,我希望看完之后事情会清楚。

注意:如果我忘记或错过任何内容,请随时更新我。