kernel/x86_64: setup a new thread in compatibility mode.
* define compat_thread_info, compat_rlim_t, compat_rlimit and compat_thread_creation_attributes to be used when applicable in compatibility mode. * handle 32-bit types in _user_spawn_thread(), _user_get_thread_info(), _user_get_next_thread_info(), _user_getrlimit(), _user_setrlimit(), other syscalls are compatible as is. * init TLS for compatibility mode threads. Change-Id: I483ba95e6198ddac9d240671bcb56fcd2ad831d2
This commit is contained in:
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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 <sys/resource.h>
|
||||
|
||||
|
||||
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
|
||||
@@ -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 <thread_defs.h>
|
||||
|
||||
|
||||
#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
|
||||
@@ -18,9 +18,6 @@
|
||||
#include <debug.h>
|
||||
#include <kernel.h>
|
||||
#include <ksignal.h>
|
||||
#ifdef _COMPAT_MODE
|
||||
# include <compat/ksignal_compat.h>
|
||||
#endif
|
||||
#include <int.h>
|
||||
#include <team.h>
|
||||
#include <thread.h>
|
||||
@@ -30,6 +27,10 @@
|
||||
#include <vm/vm_types.h>
|
||||
#include <vm/VMAddressSpace.h>
|
||||
|
||||
#ifdef _COMPAT_MODE
|
||||
# include <compat/ksignal_compat.h>
|
||||
#endif
|
||||
|
||||
#include "paging/X86PagingStructures.h"
|
||||
#include "paging/X86VMTranslationMap.h"
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
#include <syscall_restart.h>
|
||||
#include <team.h>
|
||||
#include <tls.h>
|
||||
#include <util/syscall_args.h>
|
||||
#include <user_runtime.h>
|
||||
#include <user_thread.h>
|
||||
#include <vfs.h>
|
||||
@@ -50,6 +51,12 @@
|
||||
#include <vm/VMAddressSpace.h>
|
||||
#include <wait_for_objects.h>
|
||||
|
||||
#ifdef _COMPAT_MODE
|
||||
# include <OS_compat.h>
|
||||
# include <resource_compat.h>
|
||||
# include <thread_defs_compat.h>
|
||||
#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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user