rt_sigqueueinfo and rt_tgsigqueueinfo syscalls are used to signal and pass siginfo_t type data to a process. PCuABI specification requires that the data should be transmitted along with the capability pointer tags in case of signal delivered to the same process. In case of different process no tag details should be copied and any tag present in siginfo_t should be treated as an -EINVAL type error.
Modify function __copy_siginfo_from_user() to have a bool current_pid argument which is obtained by comparing received pid with the virtual pid of the current process. However the siginfo_t tag validation checks for non current process is marked as a TODO for now.
Signed-off-by: Amit Daniel Kachhap amit.kachhap@arm.com --- kernel/signal.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-)
diff --git a/kernel/signal.c b/kernel/signal.c index e9d6a399a47e..355195b665b6 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -3377,9 +3377,16 @@ static int post_copy_siginfo_from_user(kernel_siginfo_t *info, }
static int __copy_siginfo_from_user(int signo, kernel_siginfo_t *to, - const siginfo_t __user *from) + const siginfo_t __user *from, + bool current_pid) { - if (copy_from_user(to, from, sizeof(struct kernel_siginfo))) + /* + * TODO [PCuABI]: In case target pid differs from the current pid, this + * code silently ignores the tag copy. Revisit this later to treat this + * as an error(-EINVAL) for PCuABI. + */ + if (current_pid ? copy_from_user_with_ptr(to, from, sizeof(struct kernel_siginfo)) + : copy_from_user(to, from, sizeof(struct kernel_siginfo))) return -EFAULT; to->si_signo = signo; return post_copy_siginfo_from_user(to, from); @@ -4025,7 +4032,7 @@ SYSCALL_DEFINE3(rt_sigqueueinfo, pid_t, pid, int, sig, siginfo_t __user *, uinfo) { kernel_siginfo_t info; - int ret = __copy_siginfo_from_user(sig, &info, uinfo); + int ret = __copy_siginfo_from_user(sig, &info, uinfo, (pid == task_pid_vnr(current))); if (unlikely(ret)) return ret; return do_rt_sigqueueinfo(pid, sig, &info); @@ -4065,7 +4072,7 @@ SYSCALL_DEFINE4(rt_tgsigqueueinfo, pid_t, tgid, pid_t, pid, int, sig, siginfo_t __user *, uinfo) { kernel_siginfo_t info; - int ret = __copy_siginfo_from_user(sig, &info, uinfo); + int ret = __copy_siginfo_from_user(sig, &info, uinfo, (pid == task_pid_vnr(current))); if (unlikely(ret)) return ret; return do_rt_tgsigqueueinfo(tgid, pid, sig, &info);