From a20e1acf01f109ab325b114a3dc246a2e3083775 Mon Sep 17 00:00:00 2001 From: Masamichi Takagi Date: Fri, 17 Jul 2020 13:49:36 +0900 Subject: [PATCH] syscall: add prlimit64 Change-Id: Iad882813d54b439c236c0df74dc81508190e6707 --- arch/arm64/kernel/include/rlimit.h | 6 +- arch/arm64/kernel/include/syscall_list.h | 1 + arch/x86_64/kernel/include/rlimit.h | 6 +- arch/x86_64/kernel/include/syscall_list.h | 1 + kernel/syscall.c | 183 ++++++++++++++++------ 5 files changed, 149 insertions(+), 48 deletions(-) diff --git a/arch/arm64/kernel/include/rlimit.h b/arch/arm64/kernel/include/rlimit.h index da2c50a3..da9d6ca6 100644 --- a/arch/arm64/kernel/include/rlimit.h +++ b/arch/arm64/kernel/include/rlimit.h @@ -85,7 +85,11 @@ enum __rlimit_resource __RLIMIT_RTPRIO = 14, #define RLIMIT_RTPRIO __RLIMIT_RTPRIO - __RLIMIT_NLIMITS = 15, + /* timeout for RT tasks in us */ + __RLIMIT_RTTIME = 15, +#define RLIMIT_RTTIME __RLIMIT_RTTIME + + __RLIMIT_NLIMITS = 16, __RLIM_NLIMITS = __RLIMIT_NLIMITS #define RLIMIT_NLIMITS __RLIMIT_NLIMITS #define RLIM_NLIMITS __RLIM_NLIMITS diff --git a/arch/arm64/kernel/include/syscall_list.h b/arch/arm64/kernel/include/syscall_list.h index 902720e8..3236b715 100644 --- a/arch/arm64/kernel/include/syscall_list.h +++ b/arch/arm64/kernel/include/syscall_list.h @@ -118,6 +118,7 @@ SYSCALL_HANDLED(241, perf_event_open) SYSCALL_DELEGATED(241, perf_event_open) #endif // PERF_ENABLE SYSCALL_HANDLED(260, wait4) +SYSCALL_HANDLED(261, prlimit64) SYSCALL_HANDLED(270, process_vm_readv) SYSCALL_HANDLED(271, process_vm_writev) SYSCALL_HANDLED(281, execveat) diff --git a/arch/x86_64/kernel/include/rlimit.h b/arch/x86_64/kernel/include/rlimit.h index 46b03cbd..86527e1b 100644 --- a/arch/x86_64/kernel/include/rlimit.h +++ b/arch/x86_64/kernel/include/rlimit.h @@ -84,7 +84,11 @@ enum __rlimit_resource __RLIMIT_RTPRIO = 14, #define RLIMIT_RTPRIO __RLIMIT_RTPRIO - __RLIMIT_NLIMITS = 15, + /* timeout for RT tasks in us */ + __RLIMIT_RTTIME = 15, +#define RLIMIT_RTTIME __RLIMIT_RTTIME + + __RLIMIT_NLIMITS = 16, __RLIM_NLIMITS = __RLIMIT_NLIMITS #define RLIMIT_NLIMITS __RLIMIT_NLIMITS #define RLIM_NLIMITS __RLIM_NLIMITS diff --git a/arch/x86_64/kernel/include/syscall_list.h b/arch/x86_64/kernel/include/syscall_list.h index 270ab1ed..84132e36 100644 --- a/arch/x86_64/kernel/include/syscall_list.h +++ b/arch/x86_64/kernel/include/syscall_list.h @@ -158,6 +158,7 @@ SYSCALL_HANDLED(289, signalfd4) #ifdef ENABLE_PERF SYSCALL_HANDLED(298, perf_event_open) #endif +SYSCALL_HANDLED(302, prlimit64) #ifdef DCFA_KMOD SYSCALL_HANDLED(303, mod_call) #endif diff --git a/kernel/syscall.c b/kernel/syscall.c index 76bd78d7..bcd3f2c8 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -6596,71 +6596,162 @@ static int rlimits[] = { #endif }; -SYSCALL_DECLARE(setrlimit) +static int do_prlimit64(int pid, int resource, struct rlimit *_new_limit, + struct rlimit *old_limit) { - int rc; - int resource = ihk_mc_syscall_arg0(ctx); - struct rlimit *rlm = (struct rlimit *)ihk_mc_syscall_arg1(ctx); - struct thread *thread = cpu_local_var(current); - int i; - struct rlimit new_rlim; - int mcresource; + struct rlimit new_limit; + int resource_found; + int i; + int mcresource; + struct process *proc; + struct resource_set *rset = cpu_local_var(resource_set); + int hash; + struct process_hash *phash = rset->process_hash; + struct mcs_rwlock_node exist_lock; + struct mcs_rwlock_node update_lock; + unsigned long irqstate; + int found; + int ret; + ihk_mc_user_context_t ctx; - if (copy_from_user(&new_rlim, rlm, sizeof(*rlm))) { - return -EFAULT; - } - if (new_rlim.rlim_cur > new_rlim.rlim_max) { + if (resource < 0 || resource >= RLIMIT_NLIMITS) { return -EINVAL; } - switch(resource){ - case RLIMIT_FSIZE: - case RLIMIT_NOFILE: - case RLIMIT_LOCKS: - case RLIMIT_MSGQUEUE: - rc = syscall_generic_forwarding(__NR_setrlimit, ctx); - if(rc < 0) - return rc; - break; - } + if (_new_limit) { + if (copy_from_user(&new_limit, _new_limit, + sizeof(struct rlimit))) { + return -EFAULT; + } - for(i = 0; i < sizeof(rlimits) / sizeof(int); i += 2) - if(rlimits[i] == resource){ - mcresource = rlimits[i + 1]; + if (new_limit.rlim_cur > new_limit.rlim_max) { + return -EINVAL; + } + + /* update Linux side value as well */ + switch (resource) { + case RLIMIT_FSIZE: + case RLIMIT_NOFILE: + case RLIMIT_LOCKS: + case RLIMIT_MSGQUEUE: + ihk_mc_syscall_arg0(&ctx) = pid; + ihk_mc_syscall_arg1(&ctx) = resource; + ihk_mc_syscall_arg2(&ctx) = + (unsigned long)_new_limit; + ihk_mc_syscall_arg3(&ctx) = + (unsigned long)old_limit; + ret = syscall_generic_forwarding(__NR_prlimit64, &ctx); + if (ret < 0) + return ret; break; } - if(i >= sizeof(rlimits) / sizeof(int)){ - return syscall_generic_forwarding(__NR_setrlimit, ctx); } - memcpy(thread->proc->rlimit + mcresource, &new_rlim, - sizeof(new_rlim)); + /* translate resource */ + resource_found = 0; + for (i = 0; i < sizeof(rlimits) / sizeof(int); i += 2) { + if (rlimits[i] == resource) { + mcresource = rlimits[i + 1]; + resource_found = 1; + break; + } + } - return 0; + if (!resource_found) { + ihk_mc_syscall_arg0(&ctx) = pid; + ihk_mc_syscall_arg1(&ctx) = resource; + ihk_mc_syscall_arg2(&ctx) = + (unsigned long)_new_limit; + ihk_mc_syscall_arg3(&ctx) = + (unsigned long)old_limit; + return syscall_generic_forwarding(__NR_prlimit64, &ctx); + } + + /* find process */ + found = 0; + + if (pid == 0) { + struct thread *thread = cpu_local_var(current); + + pid = thread->proc->pid; + } + + irqstate = cpu_disable_interrupt_save(); + hash = process_hash(pid); + mcs_rwlock_reader_lock_noirq(&phash->lock[hash], &exist_lock); + + list_for_each_entry(proc, &phash->list[hash], hash_list) { + if (proc->pid == pid) { + found = 1; + break; + } + } + + if (!found) { + mcs_rwlock_reader_unlock_noirq(&phash->lock[hash], &exist_lock); + cpu_restore_interrupt(irqstate); + return -ESRCH; + } + + if (_new_limit) { + mcs_rwlock_writer_lock_noirq(&proc->update_lock, &update_lock); + } else { + mcs_rwlock_reader_lock_noirq(&proc->update_lock, &update_lock); + } + + if (old_limit) { + if (copy_to_user(old_limit, proc->rlimit + mcresource, + sizeof(struct rlimit))) { + ret = -EFAULT; + goto out; + } + } + + if (_new_limit) { + memcpy(proc->rlimit + mcresource, &new_limit, + sizeof(struct rlimit)); + } + + ret = 0; + out: + if (_new_limit) { + mcs_rwlock_writer_unlock_noirq(&proc->update_lock, + &update_lock); + } else { + mcs_rwlock_reader_unlock_noirq(&proc->update_lock, + &update_lock); + } + + mcs_rwlock_reader_unlock_noirq(&phash->lock[hash], &exist_lock); + cpu_restore_interrupt(irqstate); + + return ret; +} + +SYSCALL_DECLARE(setrlimit) +{ + int resource = ihk_mc_syscall_arg0(ctx); + struct rlimit *new_limit = (struct rlimit *)ihk_mc_syscall_arg1(ctx); + + return do_prlimit64(0, resource, new_limit, NULL); } SYSCALL_DECLARE(getrlimit) { int resource = ihk_mc_syscall_arg0(ctx); - struct rlimit *rlm = (struct rlimit *)ihk_mc_syscall_arg1(ctx); - struct thread *thread = cpu_local_var(current); - int i; - int mcresource; + struct rlimit *old_limit = (struct rlimit *)ihk_mc_syscall_arg1(ctx); - for(i = 0; i < sizeof(rlimits) / sizeof(int); i += 2) - if(rlimits[i] == resource){ - mcresource = rlimits[i + 1]; - break; - } - if(i >= sizeof(rlimits) / sizeof(int)){ - return syscall_generic_forwarding(__NR_getrlimit, ctx); - } + return do_prlimit64(0, resource, NULL, old_limit); +} -// TODO: check limit - if(copy_to_user(rlm, thread->proc->rlimit + mcresource, sizeof(struct rlimit))) - return -EFAULT; +SYSCALL_DECLARE(prlimit64) +{ + int pid = ihk_mc_syscall_arg0(ctx); + int resource = ihk_mc_syscall_arg1(ctx); + struct rlimit *new_limit = (struct rlimit *)ihk_mc_syscall_arg2(ctx); + struct rlimit *old_limit = (struct rlimit *)ihk_mc_syscall_arg3(ctx); - return 0; + return do_prlimit64(pid, resource, new_limit, old_limit); } SYSCALL_DECLARE(getrusage)