fix REQ-36
This commit is contained in:
@@ -2184,6 +2184,128 @@ int copy_from_user(void *dst, const void *src, size_t siz)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int strlen_user(const char *s)
|
||||||
|
{
|
||||||
|
struct process_vm *vm = cpu_local_var(current)->vm;
|
||||||
|
struct vm_range *range;
|
||||||
|
unsigned long pgstart;
|
||||||
|
int maxlen;
|
||||||
|
const char *head = s;
|
||||||
|
|
||||||
|
maxlen = 4096 - (((unsigned long)s) & 0x0000000000000fffUL);
|
||||||
|
pgstart = ((unsigned long)s) & 0xfffffffffffff000UL;
|
||||||
|
if(!pgstart || pgstart >= MAP_KERNEL_START)
|
||||||
|
return -EFAULT;
|
||||||
|
ihk_mc_spinlock_lock_noirq(&vm->memory_range_lock);
|
||||||
|
for(;;){
|
||||||
|
range = lookup_process_memory_range(vm, pgstart, pgstart+1);
|
||||||
|
if(range == NULL){
|
||||||
|
ihk_mc_spinlock_unlock_noirq(&vm->memory_range_lock);
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
if((range->flag & VR_PROT_MASK) == VR_PROT_NONE){
|
||||||
|
ihk_mc_spinlock_unlock_noirq(&vm->memory_range_lock);
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
while(*s && maxlen > 0){
|
||||||
|
s++;
|
||||||
|
maxlen--;
|
||||||
|
}
|
||||||
|
if(!*s)
|
||||||
|
break;
|
||||||
|
maxlen = 4096;
|
||||||
|
pgstart += 4096;
|
||||||
|
}
|
||||||
|
ihk_mc_spinlock_unlock_noirq(&vm->memory_range_lock);
|
||||||
|
return s - head;
|
||||||
|
}
|
||||||
|
|
||||||
|
int strcpy_from_user(char *dst, const char *src)
|
||||||
|
{
|
||||||
|
struct process_vm *vm = cpu_local_var(current)->vm;
|
||||||
|
struct vm_range *range;
|
||||||
|
unsigned long pgstart;
|
||||||
|
int maxlen;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
maxlen = 4096 - (((unsigned long)src) & 0x0000000000000fffUL);
|
||||||
|
pgstart = ((unsigned long)src) & 0xfffffffffffff000UL;
|
||||||
|
if(!pgstart || pgstart >= MAP_KERNEL_START)
|
||||||
|
return -EFAULT;
|
||||||
|
ihk_mc_spinlock_lock_noirq(&vm->memory_range_lock);
|
||||||
|
for(;;){
|
||||||
|
range = lookup_process_memory_range(vm, pgstart, pgstart + 1);
|
||||||
|
if(range == NULL){
|
||||||
|
err = -EFAULT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if((range->flag & VR_PROT_MASK) == VR_PROT_NONE){
|
||||||
|
err = -EFAULT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
while(*src && maxlen > 0){
|
||||||
|
*(dst++) = *(src++);
|
||||||
|
maxlen--;
|
||||||
|
}
|
||||||
|
if(!*src){
|
||||||
|
*dst = '\0';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
maxlen = 4096;
|
||||||
|
pgstart += 4096;
|
||||||
|
}
|
||||||
|
ihk_mc_spinlock_unlock_noirq(&vm->memory_range_lock);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
long getlong_user(const long *p)
|
||||||
|
{
|
||||||
|
struct process_vm *vm = cpu_local_var(current)->vm;
|
||||||
|
struct vm_range *range;
|
||||||
|
unsigned long plong = (unsigned long)p;
|
||||||
|
unsigned long pgstart;
|
||||||
|
|
||||||
|
pgstart = plong & 0xfffffffffffff000UL;
|
||||||
|
if(!pgstart || pgstart >= MAP_KERNEL_START)
|
||||||
|
return -EFAULT;
|
||||||
|
ihk_mc_spinlock_lock_noirq(&vm->memory_range_lock);
|
||||||
|
range = lookup_process_memory_range(vm, plong, plong + sizeof(long));
|
||||||
|
if(range == NULL){
|
||||||
|
ihk_mc_spinlock_unlock_noirq(&vm->memory_range_lock);
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
if((range->flag & VR_PROT_MASK) == VR_PROT_NONE){
|
||||||
|
ihk_mc_spinlock_unlock_noirq(&vm->memory_range_lock);
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
ihk_mc_spinlock_unlock_noirq(&vm->memory_range_lock);
|
||||||
|
return *p;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getint_user(const int *p)
|
||||||
|
{
|
||||||
|
struct process_vm *vm = cpu_local_var(current)->vm;
|
||||||
|
struct vm_range *range;
|
||||||
|
unsigned long pint = (unsigned long)p;
|
||||||
|
unsigned long pgstart;
|
||||||
|
|
||||||
|
pgstart = pint & 0xfffffffffffff000UL;
|
||||||
|
if(!pgstart || pgstart >= MAP_KERNEL_START)
|
||||||
|
return -EFAULT;
|
||||||
|
ihk_mc_spinlock_lock_noirq(&vm->memory_range_lock);
|
||||||
|
range = lookup_process_memory_range(vm, pint, pint + sizeof(int));
|
||||||
|
if(range == NULL){
|
||||||
|
ihk_mc_spinlock_unlock_noirq(&vm->memory_range_lock);
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
if((range->flag & VR_PROT_MASK) == VR_PROT_NONE){
|
||||||
|
ihk_mc_spinlock_unlock_noirq(&vm->memory_range_lock);
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
ihk_mc_spinlock_unlock_noirq(&vm->memory_range_lock);
|
||||||
|
return *p;
|
||||||
|
}
|
||||||
|
|
||||||
int read_process_vm(struct process_vm *vm, void *kdst, const void *usrc, size_t siz)
|
int read_process_vm(struct process_vm *vm, void *kdst, const void *usrc, size_t siz)
|
||||||
{
|
{
|
||||||
const uintptr_t ustart = (uintptr_t)usrc;
|
const uintptr_t ustart = (uintptr_t)usrc;
|
||||||
@@ -2267,6 +2389,58 @@ int copy_to_user(void *dst, const void *src, size_t siz)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int setlong_user(long *dst, long data)
|
||||||
|
{
|
||||||
|
struct process_vm *vm = cpu_local_var(current)->vm;
|
||||||
|
struct vm_range *range;
|
||||||
|
unsigned long plong = (unsigned long)dst;
|
||||||
|
unsigned long pgstart;
|
||||||
|
|
||||||
|
pgstart = plong & 0xfffffffffffff000UL;
|
||||||
|
if(!pgstart || pgstart >= MAP_KERNEL_START)
|
||||||
|
return -EFAULT;
|
||||||
|
ihk_mc_spinlock_lock_noirq(&vm->memory_range_lock);
|
||||||
|
range = lookup_process_memory_range(vm, plong, plong + sizeof(long));
|
||||||
|
if(range == NULL){
|
||||||
|
ihk_mc_spinlock_unlock_noirq(&vm->memory_range_lock);
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
if(((range->flag & VR_PROT_MASK) == VR_PROT_NONE) ||
|
||||||
|
!(range->flag & VR_PROT_WRITE)){
|
||||||
|
ihk_mc_spinlock_unlock_noirq(&vm->memory_range_lock);
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
ihk_mc_spinlock_unlock_noirq(&vm->memory_range_lock);
|
||||||
|
*dst = data;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int setint_user(int *dst, int data)
|
||||||
|
{
|
||||||
|
struct process_vm *vm = cpu_local_var(current)->vm;
|
||||||
|
struct vm_range *range;
|
||||||
|
unsigned long pint = (unsigned long)dst;
|
||||||
|
unsigned long pgstart;
|
||||||
|
|
||||||
|
pgstart = pint & 0xfffffffffffff000UL;
|
||||||
|
if(!pgstart || pgstart >= MAP_KERNEL_START)
|
||||||
|
return -EFAULT;
|
||||||
|
ihk_mc_spinlock_lock_noirq(&vm->memory_range_lock);
|
||||||
|
range = lookup_process_memory_range(vm, pint, pint + sizeof(int));
|
||||||
|
if(range == NULL){
|
||||||
|
ihk_mc_spinlock_unlock_noirq(&vm->memory_range_lock);
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
if(((range->flag & VR_PROT_MASK) == VR_PROT_NONE) ||
|
||||||
|
!(range->flag & VR_PROT_WRITE)){
|
||||||
|
ihk_mc_spinlock_unlock_noirq(&vm->memory_range_lock);
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
ihk_mc_spinlock_unlock_noirq(&vm->memory_range_lock);
|
||||||
|
*dst = data;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int write_process_vm(struct process_vm *vm, void *udst, const void *ksrc, size_t siz)
|
int write_process_vm(struct process_vm *vm, void *udst, const void *ksrc, size_t siz)
|
||||||
{
|
{
|
||||||
const uintptr_t ustart = (uintptr_t)udst;
|
const uintptr_t ustart = (uintptr_t)udst;
|
||||||
|
|||||||
@@ -1660,14 +1660,14 @@ SYSCALL_DECLARE(execve)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Flatten argv and envp into kernel-space buffers */
|
/* Flatten argv and envp into kernel-space buffers */
|
||||||
argv_flat_len = flatten_strings(-1, (desc->shell_path[0] ?
|
argv_flat_len = flatten_strings_from_user(-1, (desc->shell_path[0] ?
|
||||||
desc->shell_path : NULL), argv, &argv_flat);
|
desc->shell_path : NULL), argv, &argv_flat);
|
||||||
if (argv_flat_len == 0) {
|
if (argv_flat_len == 0) {
|
||||||
kprintf("ERROR: no argv for executable: %s?\n", filename);
|
kprintf("ERROR: no argv for executable: %s?\n", filename);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
envp_flat_len = flatten_strings(-1, NULL, envp, &envp_flat);
|
envp_flat_len = flatten_strings_from_user(-1, NULL, envp, &envp_flat);
|
||||||
if (envp_flat_len == 0) {
|
if (envp_flat_len == 0) {
|
||||||
kprintf("ERROR: no envp for executable: %s?\n", filename);
|
kprintf("ERROR: no envp for executable: %s?\n", filename);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|||||||
@@ -31,5 +31,6 @@ void *memset(void *s, int n, size_t l);
|
|||||||
|
|
||||||
unsigned long strtol(const char *cp, char **endp, unsigned int base);
|
unsigned long strtol(const char *cp, char **endp, unsigned int base);
|
||||||
int flatten_strings(int nr_strings, char *first, char **strings, char **flat);
|
int flatten_strings(int nr_strings, char *first, char **strings, char **flat);
|
||||||
|
int flatten_strings_from_user(int nr_strings, char *first, char **strings, char **flat);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
71
lib/string.c
71
lib/string.c
@@ -13,6 +13,10 @@
|
|||||||
#include <kmalloc.h>
|
#include <kmalloc.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
extern int strlen_user(const char *);
|
||||||
|
extern int strcpy_from_user(char *, const char *);
|
||||||
|
extern long getlong_user(const void *);
|
||||||
|
|
||||||
size_t strlen(const char *p)
|
size_t strlen(const char *p)
|
||||||
{
|
{
|
||||||
const char *head = p;
|
const char *head = p;
|
||||||
@@ -268,3 +272,70 @@ int flatten_strings(int nr_strings, char *first, char **strings, char **flat)
|
|||||||
return full_len;
|
return full_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int flatten_strings_from_user(int nr_strings, char *first, char **strings, char **flat)
|
||||||
|
{
|
||||||
|
int full_len, string_i;
|
||||||
|
long *_flat;
|
||||||
|
char *p;
|
||||||
|
long r;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
/* How many strings do we have? */
|
||||||
|
if (nr_strings == -1) {
|
||||||
|
for (nr_strings = 0; (r = getlong_user(strings + nr_strings)) > 0; ++nr_strings);
|
||||||
|
if(r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Count full length */
|
||||||
|
full_len = sizeof(long) + sizeof(char *); // Counter and terminating NULL
|
||||||
|
if (first) {
|
||||||
|
int len = strlen(first);
|
||||||
|
|
||||||
|
if(len < 0)
|
||||||
|
return len;
|
||||||
|
full_len += sizeof(char *) + len + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (string_i = 0; string_i < nr_strings; ++string_i) {
|
||||||
|
char *userp = (char *)getlong_user(strings + string_i);
|
||||||
|
int len = strlen_user(userp);
|
||||||
|
|
||||||
|
if(len < 0)
|
||||||
|
return len;
|
||||||
|
// Pointer + actual value
|
||||||
|
full_len += sizeof(char *) + len + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
full_len = (full_len + sizeof(long) - 1) & ~(sizeof(long) - 1);
|
||||||
|
|
||||||
|
_flat = kmalloc(full_len, IHK_MC_AP_NOWAIT);
|
||||||
|
if (!_flat) {
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Number of strings */
|
||||||
|
n = first? 1: 0;
|
||||||
|
_flat[0] = nr_strings + n;
|
||||||
|
|
||||||
|
// Actual offset
|
||||||
|
p = (char *)(_flat + nr_strings + 2 + n);
|
||||||
|
|
||||||
|
n = 1;
|
||||||
|
if (first) {
|
||||||
|
_flat[n++] = p - (char *)_flat;
|
||||||
|
strcpy(p, first);
|
||||||
|
p = strchr(p, '\0') + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (string_i = 0; string_i < nr_strings; ++string_i) {
|
||||||
|
char *userp = (char *)getlong_user(strings + string_i);
|
||||||
|
_flat[n++] = p - (char *)_flat;
|
||||||
|
strcpy_from_user(p, userp);
|
||||||
|
p = strchr(p, '\0') + 1;
|
||||||
|
}
|
||||||
|
_flat[n] = 0;
|
||||||
|
|
||||||
|
*flat = (char *)_flat;
|
||||||
|
return full_len;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user