Search code examples
ckernelsystem-callspid

Is there a way to check whether a given pid matches any process in kernel space?


Is there a way to check whether a given PID matches any process in kernel space?

I am building a system call that changes the weight of custom weighted round robin scheduler.

I would like to do a check before calling find_task_by_vpid(pid) to avoid calling that function if the PID is invalid (i.e. there is no process that has this PID value).

This is because if an invalid PID is used, my virtual machine crashes. So I would like to do a check and return an error value of -ESRCH back to user space.

Is there a checking function for that?

Or is it possible to check whether or not find_task_by_vpid(pid) == NULL to determine if PID is valid or not? I couldn't find a documentation that specifies what the return is for find_task_by_vpid(pid) when pid is invalid.

SYSCALL_DEFINE2(set_wrr_weight, pid_t, pid, int, weight){
   struct sched_wrr_entity *wrr_se;
   // I want to do a check here to see if given pid is valid or not
   wrr_se = &find_task_by_vpid(pid)->wrr;
   wrr_se->wrr_weight = weight;
   return 0;
}

Solution

  • Checking the return value of find_task_by_vpid() should be enough to ensure the pid is valid. If it wasn't, it wouldn't have had an associated task_struct in the first place. If you need a confirmation, this is exactly how the getsid syscall handles the PID passed from userspace:

    // ...
        retval = -ESRCH;
        p = find_task_by_vpid(pid);
        if (!p)
            goto out;
    // ...
    out:
        rcu_read_unlock();
        return retval;
    }
    

    There's a different problem in your code though: as far as I can tell, you aren't handling the task_struct properly. You should use find_get_task_by_vpid() instead of find_task_by_vpid(). This function will call get_task_struct() for you, incrementing the task_struct refcount to avoid race conditions (since as it seems from your code, your syscall can sleep). After that, you can use put_task_struct() to decrement the refcount.

    Something like this:

    SYSCALL_DEFINE2(set_wrr_weight, pid_t, pid, int, weight) {
        struct sched_wrr_entity *wrr_se;
        struct task_struct *tsk;
    
        tsk = find_get_task_by_vpid(pid);
        if (!tsk)
            return -ESRCH;
    
        wrr_se = &tsk->wrr;
        wrr_se->wrr_weight = weight;
    
        put_task_struct(tsk);
        return 0;
    }
    

    By the way, I don't know if you are doing wrr_se = &tsk->wrr; because you need it somewhere else in the code, but if you don't, then you should be able to set the weight directly doing tsk->wrr.weight = weight;.