[syscall][fix] kernel overwrite ustack data in timer create

This commit is contained in:
wangxiaoyao 2023-02-28 10:45:05 +08:00 committed by guo
parent 892ef3dc5b
commit 31bfc855c1
1 changed files with 37 additions and 6 deletions

View File

@ -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);