diff --git a/headers/private/kernel/compat/OS_compat.h b/headers/private/kernel/compat/OS_compat.h index 0fbc7a952a..7f4531ce91 100644 --- a/headers/private/kernel/compat/OS_compat.h +++ b/headers/private/kernel/compat/OS_compat.h @@ -163,6 +163,34 @@ static_assert(sizeof(compat_thread_info) == 76, "size of compat_thread_info mismatch"); +inline status_t +copy_ref_var_to_user(thread_info &info, thread_info* userInfo) +{ + if (!IS_USER_ADDRESS(userInfo)) + return B_BAD_ADDRESS; + Thread* thread = thread_get_current_thread(); + bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0; + if (compatMode) { + compat_thread_info compatInfo; + compatInfo.thread = info.thread; + compatInfo.team = info.team; + strlcpy(compatInfo.name, info.name, sizeof(compatInfo.name)); + compatInfo.state = info.state; + compatInfo.priority = info.priority; + compatInfo.sem = info.sem; + compatInfo.user_time = info.user_time; + compatInfo.kernel_time = info.kernel_time; + compatInfo.stack_base = (uint32)(addr_t)info.stack_base; + compatInfo.stack_end = (uint32)(addr_t)info.stack_end; + if (user_memcpy(userInfo, &compatInfo, sizeof(compatInfo)) < B_OK) + return B_BAD_ADDRESS; + } else if (user_memcpy(userInfo, &info, sizeof(info)) < B_OK) { + return B_BAD_ADDRESS; + } + return B_OK; +} + + inline status_t copy_ref_var_to_user(void* &addr, void** userAddr) { diff --git a/headers/private/kernel/compat/resource_compat.h b/headers/private/kernel/compat/resource_compat.h new file mode 100644 index 0000000000..4a3c5db5e5 --- /dev/null +++ b/headers/private/kernel/compat/resource_compat.h @@ -0,0 +1,60 @@ +/* + * Copyright 2018, Haiku Inc. All rights reserved. + * + * Distributed under the terms of the MIT License. + */ +#ifndef _KERNEL_COMPAT_RESOURCE_H +#define _KERNEL_COMPAT_RESOURCE_H + + +#include + + +typedef uint32 compat_rlim_t; +struct compat_rlimit { + compat_rlim_t rlim_cur; /* current soft limit */ + compat_rlim_t rlim_max; /* hard limit */ +}; + + +inline status_t +copy_ref_var_to_user(struct rlimit &rl, struct rlimit* urlp) +{ + if (!IS_USER_ADDRESS(urlp)) + return B_BAD_ADDRESS; + Thread* thread = thread_get_current_thread(); + bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0; + if (compatMode) { + struct compat_rlimit compat_rl; + compat_rl.rlim_cur = rl.rlim_cur; + compat_rl.rlim_max = rl.rlim_max; + if (user_memcpy(urlp, &compat_rl, sizeof(compat_rl)) < B_OK) + return B_BAD_ADDRESS; + } else if (user_memcpy(urlp, &rl, sizeof(rl)) < B_OK) { + return B_BAD_ADDRESS; + } + return B_OK; +} + + +inline status_t +copy_ref_var_from_user(struct rlimit* urlp, struct rlimit &rl) +{ + if (!IS_USER_ADDRESS(urlp)) + return B_BAD_ADDRESS; + Thread* thread = thread_get_current_thread(); + bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0; + if (compatMode) { + struct compat_rlimit compat_rl; + if (user_memcpy(&compat_rl, urlp, sizeof(compat_rl)) < B_OK) + return B_BAD_ADDRESS; + rl.rlim_cur = compat_rl.rlim_cur; + rl.rlim_max = compat_rl.rlim_max; + } else if (user_memcpy(&rl, urlp, sizeof(rl)) < B_OK) { + return B_BAD_ADDRESS; + } + return B_OK; +} + + +#endif // _KERNEL_COMPAT_RESOURCE_H diff --git a/headers/private/kernel/compat/thread_defs_compat.h b/headers/private/kernel/compat/thread_defs_compat.h new file mode 100644 index 0000000000..340df5adfd --- /dev/null +++ b/headers/private/kernel/compat/thread_defs_compat.h @@ -0,0 +1,61 @@ +/* + * Copyright 2018, Haiku Inc. All rights reserved. + * + * Distributed under the terms of the MIT License. + */ +#ifndef _KERNEL_COMPAT_THREAD_DEFS_H +#define _KERNEL_COMPAT_THREAD_DEFS_H + + +#include + + +#define compat_ptr_t uint32 +struct compat_thread_creation_attributes { + compat_ptr_t entry; + compat_ptr_t name; + int32 priority; + compat_ptr_t args1; + compat_ptr_t args2; + compat_ptr_t stack_address; + uint32_t stack_size; + uint32_t guard_size; + compat_ptr_t pthread; + uint32 flags; +} _PACKED; + + +static_assert(sizeof(struct compat_thread_creation_attributes) == 40, + "size of compat_thread_creation_attributes mismatch"); + + +inline status_t +copy_ref_var_from_user(BKernel::ThreadCreationAttributes* userAttrs, + BKernel::ThreadCreationAttributes &attrs) +{ + if (!IS_USER_ADDRESS(userAttrs)) + return B_BAD_ADDRESS; + Thread* thread = thread_get_current_thread(); + bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0; + if (compatMode) { + struct compat_thread_creation_attributes compatAttrs; + if (user_memcpy(&compatAttrs, userAttrs, sizeof(compatAttrs)) < B_OK) + return B_BAD_ADDRESS; + attrs.entry = (int32 (*)(void*, void*))(addr_t)compatAttrs.entry; + attrs.name = (const char*)(addr_t)compatAttrs.name; + attrs.priority = compatAttrs.priority; + attrs.args1 = (void*)(addr_t)compatAttrs.args1; + attrs.args2 = (void*)(addr_t)compatAttrs.args2; + attrs.stack_address = (void*)(addr_t)compatAttrs.stack_address; + attrs.stack_size = compatAttrs.stack_size; + attrs.guard_size = compatAttrs.guard_size; + attrs.pthread = (pthread_t)(addr_t)compatAttrs.pthread; + attrs.flags = compatAttrs.flags; + } else if (user_memcpy(&attrs, userAttrs, sizeof(attrs)) < B_OK) { + return B_BAD_ADDRESS; + } + return B_OK; +} + + +#endif // _KERNEL_COMPAT_THREAD_DEFS_H diff --git a/src/system/kernel/arch/x86/64/thread.cpp b/src/system/kernel/arch/x86/64/thread.cpp index 7a6a35d724..1382ff5060 100644 --- a/src/system/kernel/arch/x86/64/thread.cpp +++ b/src/system/kernel/arch/x86/64/thread.cpp @@ -18,9 +18,6 @@ #include #include #include -#ifdef _COMPAT_MODE -# include -#endif #include #include #include @@ -30,6 +27,10 @@ #include #include +#ifdef _COMPAT_MODE +# include +#endif + #include "paging/X86PagingStructures.h" #include "paging/X86VMTranslationMap.h" diff --git a/src/system/kernel/arch/x86/arch_thread.cpp b/src/system/kernel/arch/x86/arch_thread.cpp index 931c74b099..598c02460f 100644 --- a/src/system/kernel/arch/x86/arch_thread.cpp +++ b/src/system/kernel/arch/x86/arch_thread.cpp @@ -192,6 +192,23 @@ arch_team_init_team_struct(Team* p, bool kernel) status_t arch_thread_init_tls(Thread* thread) { +#ifdef _COMPAT_MODE + if ((thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0) { + uint32 tls[TLS_FIRST_FREE_SLOT]; + + thread->user_local_storage = thread->user_stack_base + + thread->user_stack_size; + + // initialize default TLS fields + memset(tls, 0, sizeof(tls)); + tls[TLS_BASE_ADDRESS_SLOT] = thread->user_local_storage; + tls[TLS_THREAD_ID_SLOT] = thread->id; + tls[TLS_USER_THREAD_SLOT] = (uint32)(addr_t)thread->user_thread; + + return user_memcpy((void*)thread->user_local_storage, tls, sizeof(tls)); + } +#endif + addr_t tls[TLS_FIRST_FREE_SLOT]; thread->user_local_storage = thread->user_stack_base diff --git a/src/system/kernel/thread.cpp b/src/system/kernel/thread.cpp index b10f32a4e5..cece263bf3 100644 --- a/src/system/kernel/thread.cpp +++ b/src/system/kernel/thread.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -50,6 +51,12 @@ #include #include +#ifdef _COMPAT_MODE +# include +# include +# include +#endif + #include "TeamThreadTables.h" @@ -552,11 +559,14 @@ status_t ThreadCreationAttributes::InitFromUserAttributes( const thread_creation_attributes* userAttributes, char* nameBuffer) { - if (userAttributes == NULL || !IS_USER_ADDRESS(userAttributes) - || user_memcpy((thread_creation_attributes*)this, userAttributes, - sizeof(thread_creation_attributes)) != B_OK) { + if (userAttributes == NULL) return B_BAD_ADDRESS; - } + + status_t status = copy_ref_var_from_user( + (BKernel::ThreadCreationAttributes*)userAttributes, + *this); + if (status != B_OK) + return status; if (stack_size != 0 && (stack_size < MIN_USER_STACK_SIZE @@ -815,6 +825,10 @@ create_thread_user_stack(Team* team, Thread* thread, void* _stackBase, thread->name, thread->id); stackBase = (uint8*)USER_STACK_REGION; +#ifdef _COMPAT_MODE + if ((thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0) + stackBase = (uint8*)USER32_STACK_REGION; +#endif virtual_address_restrictions virtualRestrictions = {}; virtualRestrictions.address_specification = B_RANDOMIZED_BASE_ADDRESS; @@ -900,6 +914,12 @@ thread_create_thread(const ThreadCreationAttributes& attributes, bool kernel) (int32)THREAD_MAX_SET_PRIORITY); thread->state = B_THREAD_SUSPENDED; +#ifdef _COMPAT_MODE + Thread* currentThread = thread_get_current_thread(); + if ((currentThread->flags & THREAD_FLAGS_COMPAT_MODE) != 0) + thread->flags |= THREAD_FLAGS_COMPAT_MODE; +#endif + thread->sig_block_mask = attributes.signal_mask; // init debug structure @@ -3510,10 +3530,8 @@ _user_get_thread_info(thread_id id, thread_info *userInfo) status = _get_thread_info(id, &info, sizeof(thread_info)); - if (status >= B_OK - && user_memcpy(userInfo, &info, sizeof(thread_info)) < B_OK) - return B_BAD_ADDRESS; - + if (status >= B_OK) + status = copy_ref_var_to_user(info, userInfo); return status; } @@ -3534,11 +3552,9 @@ _user_get_next_thread_info(team_id team, int32 *userCookie, if (status < B_OK) return status; - if (user_memcpy(userCookie, &cookie, sizeof(int32)) < B_OK - || user_memcpy(userInfo, &info, sizeof(thread_info)) < B_OK) + if (user_memcpy(userCookie, &cookie, sizeof(int32)) < B_OK) return B_BAD_ADDRESS; - - return status; + return copy_ref_var_to_user(info, userInfo); } @@ -3720,9 +3736,9 @@ _user_getrlimit(int resource, struct rlimit *urlp) ret = common_getrlimit(resource, &rl); if (ret == 0) { - ret = user_memcpy(urlp, &rl, sizeof(struct rlimit)); - if (ret < 0) - return ret; + status_t status = copy_ref_var_to_user(rl, urlp); + if (status != B_OK) + return status; return 0; } @@ -3739,10 +3755,10 @@ _user_setrlimit(int resource, const struct rlimit *userResourceLimit) if (userResourceLimit == NULL) return EINVAL; - if (!IS_USER_ADDRESS(userResourceLimit) - || user_memcpy(&resourceLimit, userResourceLimit, - sizeof(struct rlimit)) < B_OK) - return B_BAD_ADDRESS; + status_t status = copy_ref_var_from_user((struct rlimit*)userResourceLimit, + resourceLimit); + if (status != B_OK) + return status; return common_setrlimit(resource, &resourceLimit); }