aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Chagin <dchagin@FreeBSD.org>2021-06-07 02:55:34 +0000
committerDmitry Chagin <dchagin@FreeBSD.org>2021-06-07 02:55:34 +0000
commit9c1045ff00935a4bb0592d8c00ca1981d3e6eb8b (patch)
treea49eb13d45acb3625fc490cc917dd18c27997dd5
parente29ea22f7012bb94f5f427349aa4580539cf2b7c (diff)
downloadsrc-9c1045ff00935a4bb0592d8c00ca1981d3e6eb8b.tar.gz
src-9c1045ff00935a4bb0592d8c00ca1981d3e6eb8b.zip
linux(4): Properly convert linux siginfo to native siginfo
add input validation. MFC after: 2 weeks
-rw-r--r--sys/compat/linux/linux_mib.h1
-rw-r--r--sys/compat/linux/linux_signal.c59
-rw-r--r--sys/compat/linux/linux_signal.h3
3 files changed, 47 insertions, 16 deletions
diff --git a/sys/compat/linux/linux_mib.h b/sys/compat/linux/linux_mib.h
index b3d5949c9630..c4d3d1e83f7e 100644
--- a/sys/compat/linux/linux_mib.h
+++ b/sys/compat/linux/linux_mib.h
@@ -59,6 +59,7 @@ int linux_kernver(struct thread *td);
#define LINUX_KERNVER_2004000 LINUX_KERNVER(2,4,0)
#define LINUX_KERNVER_2006000 LINUX_KERNVER(2,6,0)
+#define LINUX_KERNVER_2006039 LINUX_KERNVER(2,6,39)
#define linux_use26(t) (linux_kernver(t) >= LINUX_KERNVER_2006000)
diff --git a/sys/compat/linux/linux_signal.c b/sys/compat/linux/linux_signal.c
index a479c9cc769c..02abfe961e6b 100644
--- a/sys/compat/linux/linux_signal.c
+++ b/sys/compat/linux/linux_signal.c
@@ -50,6 +50,7 @@ __FBSDID("$FreeBSD$");
#include <machine/../linux/linux.h>
#include <machine/../linux/linux_proto.h>
#endif
+#include <compat/linux/linux_mib.h>
#include <compat/linux/linux_signal.h>
#include <compat/linux/linux_timer.h>
#include <compat/linux/linux_util.h>
@@ -651,17 +652,40 @@ siginfo_to_lsiginfo(const siginfo_t *si, l_siginfo_t *lsi, l_int sig)
}
}
-void
-lsiginfo_to_ksiginfo(const l_siginfo_t *lsi, ksiginfo_t *ksi, int sig)
+int
+lsiginfo_to_siginfo(struct thread *td, const l_siginfo_t *lsi,
+ siginfo_t *si, int sig)
{
- ksi->ksi_signo = sig;
- ksi->ksi_code = lsi->lsi_code; /* XXX. Convert. */
- ksi->ksi_pid = lsi->lsi_pid;
- ksi->ksi_uid = lsi->lsi_uid;
- ksi->ksi_status = lsi->lsi_status;
- ksi->ksi_addr = PTRIN(lsi->lsi_addr);
- ksi->ksi_info.si_value.sival_int = lsi->lsi_int;
+ switch (lsi->lsi_code) {
+ case LINUX_SI_TKILL:
+ if (linux_kernver(td) >= LINUX_KERNVER_2006039) {
+ linux_msg(td, "SI_TKILL forbidden since 2.6.39");
+ return (EPERM);
+ }
+ si->si_code = SI_LWP;
+ case LINUX_SI_QUEUE:
+ si->si_code = SI_QUEUE;
+ break;
+ case LINUX_SI_TIMER:
+ si->si_code = SI_TIMER;
+ break;
+ case LINUX_SI_MESGQ:
+ si->si_code = SI_MESGQ;
+ break;
+ case LINUX_SI_ASYNCIO:
+ si->si_code = SI_ASYNCIO;
+ break;
+ default:
+ si->si_code = lsi->lsi_code;
+ break;
+ }
+
+ si->si_signo = sig;
+ si->si_pid = td->td_proc->p_pid;
+ si->si_uid = td->td_ucred->cr_ruid;
+ si->si_value.sival_ptr = PTRIN(lsi->lsi_value.sival_ptr);
+ return (0);
}
int
@@ -681,9 +705,14 @@ linux_rt_sigqueueinfo(struct thread *td, struct linux_rt_sigqueueinfo_args *args
return (error);
if (linfo.lsi_code >= 0)
+ /* SI_USER, SI_KERNEL */
return (EPERM);
sig = linux_to_bsd_signal(args->sig);
+ ksiginfo_init(&ksi);
+ error = lsiginfo_to_siginfo(td, &linfo, &ksi.ksi_info, sig);
+ if (error != 0)
+ return (error);
error = ESRCH;
if ((p = pfind_any(args->pid)) != NULL) {
@@ -692,9 +721,6 @@ linux_rt_sigqueueinfo(struct thread *td, struct linux_rt_sigqueueinfo_args *args
PROC_UNLOCK(p);
return (error);
}
-
- ksiginfo_init(&ksi);
- lsiginfo_to_ksiginfo(&linfo, &ksi, sig);
error = tdsendsignal(p, NULL, sig, &ksi);
PROC_UNLOCK(p);
}
@@ -721,12 +747,15 @@ linux_rt_tgsigqueueinfo(struct thread *td, struct linux_rt_tgsigqueueinfo_args *
if (linfo.lsi_code >= 0)
return (EPERM);
+ sig = linux_to_bsd_signal(args->sig);
+ ksiginfo_init(&ksi);
+ error = lsiginfo_to_siginfo(td, &linfo, &ksi.ksi_info, sig);
+ if (error != 0)
+ return (error);
+
tds = linux_tdfind(td, args->tid, args->tgid);
if (tds == NULL)
return (ESRCH);
- sig = linux_to_bsd_signal(args->sig);
- ksiginfo_init(&ksi);
- lsiginfo_to_ksiginfo(&linfo, &ksi, sig);
return (linux_do_tkill(td, tds, &ksi));
}
diff --git a/sys/compat/linux/linux_signal.h b/sys/compat/linux/linux_signal.h
index 5df74fb71029..bb34613fa2be 100644
--- a/sys/compat/linux/linux_signal.h
+++ b/sys/compat/linux/linux_signal.h
@@ -46,6 +46,7 @@
int linux_do_sigaction(struct thread *, int, l_sigaction_t *, l_sigaction_t *);
void ksiginfo_to_lsiginfo(const ksiginfo_t *ksi, l_siginfo_t *lsi, l_int sig);
void siginfo_to_lsiginfo(const siginfo_t *si, l_siginfo_t *lsi, l_int sig);
-void lsiginfo_to_ksiginfo(const l_siginfo_t *lsi, ksiginfo_t *ksi, int sig);
+int lsiginfo_to_siginfo(struct thread *td, const l_siginfo_t *lsi,
+ siginfo_t *si, int sig);
#endif /* _LINUX_SIGNAL_H_ */