summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwangxiaoyao <[email protected]>2023-02-28 10:45:05 +0800
committerguo <[email protected]>2023-03-02 15:48:46 +0800
commit31bfc855c1a361fdb9e7bde2c31a91d4ad250406 (patch)
treed205eef701d9fbee826d8b3e8aeb0b47bd25cc20
parent892ef3dc5bcb6e504629513b57ec4e1023a0d9d1 (diff)
[syscall][fix] kernel overwrite ustack data in timer create
-rw-r--r--components/lwp/lwp_syscall.c43
1 files changed, 37 insertions, 6 deletions
diff --git a/components/lwp/lwp_syscall.c b/components/lwp/lwp_syscall.c
index 6995e7dc9d..88e8f7c33c 100644
--- a/components/lwp/lwp_syscall.c
+++ b/components/lwp/lwp_syscall.c
@@ -18,6 +18,7 @@
#include <board.h>
#include <mm_aspace.h>
#include <string.h>
+#include <stdint.h>
#include <lwp.h>
#ifdef ARCH_MM_MMU
@@ -1312,12 +1313,22 @@ rt_err_t sys_rt_timer_control(rt_timer_t timer, int cmd, void *arg)
return rt_timer_control(timer, cmd, arg);
}
+/* MUSL compatible */
+struct ksigevent
+{
+ union sigval sigev_value;
+ int sigev_signo;
+ int sigev_notify;
+ int sigev_tid;
+};
+
rt_err_t sys_timer_create(clockid_t clockid, struct sigevent *restrict sevp, timer_t *restrict timerid)
{
int ret = 0;
#ifdef ARCH_MM_MMU
struct sigevent sevp_k;
timer_t timerid_k;
+ int utimer;
if (sevp == NULL)
{
@@ -1326,12 +1337,28 @@ rt_err_t sys_timer_create(clockid_t clockid, struct sigevent *restrict sevp, tim
sevp = &sevp_k;
}
else
- lwp_get_from_user(&sevp_k, (void *)sevp, sizeof sevp_k);
- lwp_get_from_user(&timerid_k, (void *)timerid, sizeof timerid_k);
+ {
+ /* clear extra bytes if any */
+ if (sizeof(struct ksigevent) < sizeof(struct sigevent))
+ memset(&sevp_k, 0, sizeof(sevp_k));
+
+ /* musl passes `struct ksigevent` to kernel, we shoule only get size of that bytes */
+ lwp_get_from_user(&sevp_k, (void *)sevp, sizeof(struct ksigevent));
+ }
+ lwp_get_from_user(&timerid_k, (void *)timerid, sizeof(timerid_k));
+
+ /* to protect unsafe implementation in current rt-smart toolchain */
+ RT_ASSERT(((struct ksigevent *)sevp)->sigev_tid == (rt_ubase_t)sevp_k.sigev_notify_function);
+
ret = timer_create(clockid, &sevp_k, &timerid_k);
+
+ /* ID should not extend 32-bits size for libc */
+ RT_ASSERT((rt_ubase_t)timerid_k < UINT32_MAX);
+ utimer = (rt_ubase_t)timerid_k;
+
if (ret != -RT_ERROR){
- lwp_put_to_user(sevp, (void *)&sevp_k, sizeof sevp_k);
- lwp_put_to_user(timerid, (void *)&timerid_k, sizeof timerid_k);
+ lwp_put_to_user(sevp, (void *)&sevp_k, sizeof(struct ksigevent));
+ lwp_put_to_user(timerid, (void *)&utimer, sizeof(utimer));
}
#else
ret = timer_create(clockid, sevp, timerid);
@@ -1354,8 +1381,12 @@ rt_err_t sys_timer_settime(timer_t timerid, int flags,
struct itimerspec new_value_k;
struct itimerspec old_value_k;
- lwp_get_from_user(&new_value_k, (void *)new_value, sizeof new_value_k);
- lwp_get_from_user(&old_value_k, (void *)timerid, sizeof old_value_k);
+ if (!lwp_get_from_user(&new_value_k, (void *)new_value, sizeof(*new_value)) ||
+ (old_value && !lwp_get_from_user(&old_value_k, (void *)old_value, sizeof(*old_value))))
+ {
+ return -EFAULT;
+ }
+
ret = timer_settime(timerid, flags, &new_value_k, &old_value_k);
lwp_put_to_user(old_value, (void *)&old_value_k, sizeof old_value_k);