kernel/x86_64: compatibility syscalls for vm.cpp.
* define compat_area_info to be used when applicable in compatibility mode. * handle 32-bit types in _user_reserve_address_range(), _user_get_area_info(), _user_get_next_area_info(), _user_transfer_area(), _user_clone_area(), _user_create_area(), _user_map_file(), other syscalls are compatible as is. * _get_next_area_info() doesn't work well with a 32-bit address cookie (address could be in 64-bit range). Instead use _compat_get_next_area_info() which uses the area id as cookie, though the areas are not ordered by address any more. Change-Id: Ic7519ca8824aa2d534b0f03ea75a1bf6ae321535
This commit is contained in:
@@ -95,4 +95,183 @@ copy_ref_var_to_user(system_info &info, system_info* userInfo)
|
||||
}
|
||||
|
||||
|
||||
#define compat_size_t uint32
|
||||
#define compat_ptr_t uint32
|
||||
typedef struct compat_area_info {
|
||||
area_id area;
|
||||
char name[B_OS_NAME_LENGTH];
|
||||
compat_size_t size;
|
||||
uint32 lock;
|
||||
uint32 protection;
|
||||
team_id team;
|
||||
uint32 ram_size;
|
||||
uint32 copy_count;
|
||||
uint32 in_count;
|
||||
uint32 out_count;
|
||||
compat_ptr_t address;
|
||||
} _PACKED compat_area_info;
|
||||
|
||||
|
||||
static_assert(sizeof(compat_area_info) == 0x48,
|
||||
"size of compat_area_info mismatch");
|
||||
|
||||
|
||||
inline status_t
|
||||
copy_ref_var_to_user(area_info &info, area_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_area_info compatInfo;
|
||||
compatInfo.area = info.area;
|
||||
strlcpy(compatInfo.name, info.name, B_OS_NAME_LENGTH);
|
||||
compatInfo.size = info.size;
|
||||
compatInfo.lock = info.lock;
|
||||
compatInfo.protection = info.protection;
|
||||
compatInfo.team = info.team;
|
||||
compatInfo.ram_size = info.ram_size;
|
||||
compatInfo.copy_count = info.copy_count;
|
||||
compatInfo.in_count = info.in_count;
|
||||
compatInfo.out_count = info.out_count;
|
||||
compatInfo.address = (compat_ptr_t)(addr_t)info.address;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
typedef struct {
|
||||
thread_id thread;
|
||||
team_id team;
|
||||
char name[B_OS_NAME_LENGTH];
|
||||
thread_state state;
|
||||
int32 priority;
|
||||
sem_id sem;
|
||||
bigtime_t user_time;
|
||||
bigtime_t kernel_time;
|
||||
uint32 stack_base;
|
||||
uint32 stack_end;
|
||||
} _PACKED compat_thread_info;
|
||||
|
||||
|
||||
static_assert(sizeof(compat_thread_info) == 76,
|
||||
"size of compat_thread_info mismatch");
|
||||
|
||||
|
||||
inline status_t
|
||||
copy_ref_var_to_user(void* &addr, void** userAddr)
|
||||
{
|
||||
if (!IS_USER_ADDRESS(userAddr))
|
||||
return B_BAD_ADDRESS;
|
||||
Thread* thread = thread_get_current_thread();
|
||||
bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0;
|
||||
if (compatMode) {
|
||||
compat_ptr_t compatAddr = (uint32)(addr_t)addr;
|
||||
if (user_memcpy(userAddr, &compatAddr, sizeof(compatAddr)) < B_OK)
|
||||
return B_BAD_ADDRESS;
|
||||
} else if (user_memcpy(userAddr, &addr, sizeof(addr)) < B_OK) {
|
||||
return B_BAD_ADDRESS;
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
inline status_t
|
||||
copy_ref_var_from_user(void** userAddr, void* &addr)
|
||||
{
|
||||
if (!IS_USER_ADDRESS(userAddr))
|
||||
return B_BAD_ADDRESS;
|
||||
Thread* thread = thread_get_current_thread();
|
||||
bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0;
|
||||
if (compatMode) {
|
||||
compat_ptr_t compatAddr;
|
||||
if (user_memcpy(&compatAddr, userAddr, sizeof(compatAddr)) < B_OK)
|
||||
return B_BAD_ADDRESS;
|
||||
addr = (void*)(addr_t)compatAddr;
|
||||
} else if (user_memcpy(&addr, userAddr, sizeof(addr)) < B_OK) {
|
||||
return B_BAD_ADDRESS;
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
inline status_t
|
||||
copy_ref_var_to_user(addr_t &addr, addr_t* userAddr)
|
||||
{
|
||||
if (!IS_USER_ADDRESS(userAddr))
|
||||
return B_BAD_ADDRESS;
|
||||
Thread* thread = thread_get_current_thread();
|
||||
bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0;
|
||||
if (compatMode) {
|
||||
uint32 compatAddr = (uint32)addr;
|
||||
if (user_memcpy(userAddr, &compatAddr, sizeof(compatAddr)) < B_OK)
|
||||
return B_BAD_ADDRESS;
|
||||
} else if (user_memcpy(userAddr, &addr, sizeof(addr)) < B_OK) {
|
||||
return B_BAD_ADDRESS;
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
inline status_t
|
||||
copy_ref_var_from_user(addr_t* userAddr, addr_t &addr)
|
||||
{
|
||||
if (!IS_USER_ADDRESS(userAddr))
|
||||
return B_BAD_ADDRESS;
|
||||
Thread* thread = thread_get_current_thread();
|
||||
bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0;
|
||||
if (compatMode) {
|
||||
uint32 compatAddr;
|
||||
if (user_memcpy(&compatAddr, userAddr, sizeof(compatAddr)) < B_OK)
|
||||
return B_BAD_ADDRESS;
|
||||
addr = (addr_t)compatAddr;
|
||||
} else if (user_memcpy(&addr, userAddr, sizeof(addr)) < B_OK) {
|
||||
return B_BAD_ADDRESS;
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
inline status_t
|
||||
copy_ref_var_to_user(ssize_t &size, ssize_t* userSize)
|
||||
{
|
||||
if (!IS_USER_ADDRESS(userSize))
|
||||
return B_BAD_ADDRESS;
|
||||
Thread* thread = thread_get_current_thread();
|
||||
bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0;
|
||||
if (compatMode) {
|
||||
int32 compatSize = (int32)size;
|
||||
if (user_memcpy(userSize, &compatSize, sizeof(compatSize)) < B_OK)
|
||||
return B_BAD_ADDRESS;
|
||||
} else if (user_memcpy(userSize, &size, sizeof(size)) < B_OK) {
|
||||
return B_BAD_ADDRESS;
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
inline status_t
|
||||
copy_ref_var_from_user(ssize_t* userSize, ssize_t &size)
|
||||
{
|
||||
if (!IS_USER_ADDRESS(userSize))
|
||||
return B_BAD_ADDRESS;
|
||||
Thread* thread = thread_get_current_thread();
|
||||
bool compatMode = (thread->flags & THREAD_FLAGS_COMPAT_MODE) != 0;
|
||||
if (compatMode) {
|
||||
int32 compatSize;
|
||||
if (user_memcpy(&compatSize, userSize, sizeof(compatSize)) < B_OK)
|
||||
return B_BAD_ADDRESS;
|
||||
size = (ssize_t)compatSize;
|
||||
} else if (user_memcpy(&size, userSize, sizeof(size)) < B_OK) {
|
||||
return B_BAD_ADDRESS;
|
||||
}
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
#endif // _KERNEL_COMPAT_OS_H
|
||||
|
||||
+100
-39
@@ -47,12 +47,17 @@
|
||||
#include <team.h>
|
||||
#include <tracing.h>
|
||||
#include <util/AutoLock.h>
|
||||
#include <util/syscall_args.h>
|
||||
#include <vm/vm_page.h>
|
||||
#include <vm/vm_priv.h>
|
||||
#include <vm/VMAddressSpace.h>
|
||||
#include <vm/VMArea.h>
|
||||
#include <vm/VMCache.h>
|
||||
|
||||
#ifdef _COMPAT_MODE
|
||||
# include <OS_compat.h>
|
||||
#endif
|
||||
|
||||
#include "VMAddressSpaceLocking.h"
|
||||
#include "VMAnonymousCache.h"
|
||||
#include "VMAnonymousNoSwapCache.h"
|
||||
@@ -6003,6 +6008,44 @@ _get_next_area_info(team_id team, ssize_t* cookie, area_info* info, size_t size)
|
||||
}
|
||||
|
||||
|
||||
#ifdef _COMPAT_MODE
|
||||
status_t
|
||||
_compat_get_next_area_info(team_id team, ssize_t* cookie, area_info* info, size_t size)
|
||||
{
|
||||
area_id nextID = *(area_id*)cookie;
|
||||
|
||||
// we're already through the list
|
||||
if (nextID == (area_id)-1)
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
|
||||
if (team == B_CURRENT_TEAM)
|
||||
team = team_get_current_team_id();
|
||||
|
||||
AddressSpaceReadLocker locker(team);
|
||||
if (!locker.IsLocked())
|
||||
return B_BAD_TEAM_ID;
|
||||
|
||||
VMArea* area;
|
||||
for (VMAddressSpace::AreaIterator it
|
||||
= locker.AddressSpace()->GetAreaIterator();
|
||||
(area = it.Next()) != NULL;) {
|
||||
if (area->id > nextID)
|
||||
break;
|
||||
}
|
||||
|
||||
if (area == NULL) {
|
||||
nextID = (area_id)-1;
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
}
|
||||
|
||||
fill_area_info(area, info, size);
|
||||
*cookie = (ssize_t)(area->id);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
status_t
|
||||
set_area_protection(area_id area, uint32 newProtection)
|
||||
{
|
||||
@@ -6132,23 +6175,22 @@ _user_reserve_address_range(addr_t* userAddress, uint32 addressSpec,
|
||||
|
||||
addr_t address;
|
||||
|
||||
if (!IS_USER_ADDRESS(userAddress)
|
||||
|| user_memcpy(&address, userAddress, sizeof(address)) != B_OK)
|
||||
return B_BAD_ADDRESS;
|
||||
status_t status = copy_ref_var_from_user(userAddress, address);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
status_t status = vm_reserve_address_range(
|
||||
status = vm_reserve_address_range(
|
||||
VMAddressSpace::CurrentID(), (void**)&address, addressSpec, size,
|
||||
RESERVED_AVOID_BASE);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
if (user_memcpy(userAddress, &address, sizeof(address)) != B_OK) {
|
||||
status = copy_ref_var_to_user(address, userAddress);
|
||||
if (status != B_OK) {
|
||||
vm_unreserve_address_range(VMAddressSpace::CurrentID(),
|
||||
(void*)address, size);
|
||||
return B_BAD_ADDRESS;
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
@@ -6194,10 +6236,8 @@ _user_get_area_info(area_id area, area_info* userInfo)
|
||||
// TODO: do we want to prevent userland from seeing kernel protections?
|
||||
//info.protection &= B_USER_PROTECTION;
|
||||
|
||||
if (user_memcpy(userInfo, &info, sizeof(area_info)) < B_OK)
|
||||
return B_BAD_ADDRESS;
|
||||
return copy_ref_var_to_user(info, userInfo);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
@@ -6207,21 +6247,28 @@ _user_get_next_area_info(team_id team, ssize_t* userCookie, area_info* userInfo)
|
||||
ssize_t cookie;
|
||||
|
||||
if (!IS_USER_ADDRESS(userCookie)
|
||||
|| !IS_USER_ADDRESS(userInfo)
|
||||
|| user_memcpy(&cookie, userCookie, sizeof(ssize_t)) < B_OK)
|
||||
|| !IS_USER_ADDRESS(userInfo))
|
||||
return B_BAD_ADDRESS;
|
||||
|
||||
status_t status = copy_ref_var_from_user(userCookie, cookie);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
area_info info;
|
||||
status_t status = _get_next_area_info(team, &cookie, &info,
|
||||
#ifdef _COMPAT_MODE
|
||||
status = _compat_get_next_area_info(team, &cookie, &info,
|
||||
#else
|
||||
status = _get_next_area_info(team, &cookie, &info,
|
||||
#endif
|
||||
sizeof(area_info));
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
//info.protection &= B_USER_PROTECTION;
|
||||
|
||||
if (user_memcpy(userCookie, &cookie, sizeof(ssize_t)) < B_OK
|
||||
|| user_memcpy(userInfo, &info, sizeof(area_info)) < B_OK)
|
||||
return B_BAD_ADDRESS;
|
||||
status = copy_ref_var_to_user(cookie, userCookie);
|
||||
if (status == B_OK)
|
||||
status = copy_ref_var_to_user(info, userInfo);
|
||||
|
||||
return status;
|
||||
}
|
||||
@@ -6259,16 +6306,17 @@ _user_transfer_area(area_id area, void** userAddress, uint32 addressSpec,
|
||||
}
|
||||
|
||||
void* address;
|
||||
if (!IS_USER_ADDRESS(userAddress)
|
||||
|| user_memcpy(&address, userAddress, sizeof(address)) < B_OK)
|
||||
return B_BAD_ADDRESS;
|
||||
status_t status = copy_ref_var_from_user(userAddress, address);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
area_id newArea = transfer_area(area, &address, addressSpec, target, false);
|
||||
if (newArea < B_OK)
|
||||
return newArea;
|
||||
|
||||
if (user_memcpy(userAddress, &address, sizeof(address)) < B_OK)
|
||||
return B_BAD_ADDRESS;
|
||||
status = copy_ref_var_to_user(address, userAddress);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
return newArea;
|
||||
}
|
||||
@@ -6291,11 +6339,13 @@ _user_clone_area(const char* userName, void** userAddress, uint32 addressSpec,
|
||||
return B_BAD_VALUE;
|
||||
|
||||
if (!IS_USER_ADDRESS(userName)
|
||||
|| !IS_USER_ADDRESS(userAddress)
|
||||
|| user_strlcpy(name, userName, sizeof(name)) < B_OK
|
||||
|| user_memcpy(&address, userAddress, sizeof(address)) < B_OK)
|
||||
|| user_strlcpy(name, userName, sizeof(name)) < B_OK)
|
||||
return B_BAD_ADDRESS;
|
||||
|
||||
status_t status = copy_ref_var_from_user(userAddress, address);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
fix_protection(&protection);
|
||||
|
||||
area_id clonedArea = vm_clone_area(VMAddressSpace::CurrentID(), name,
|
||||
@@ -6304,9 +6354,10 @@ _user_clone_area(const char* userName, void** userAddress, uint32 addressSpec,
|
||||
if (clonedArea < B_OK)
|
||||
return clonedArea;
|
||||
|
||||
if (user_memcpy(userAddress, &address, sizeof(address)) < B_OK) {
|
||||
status = copy_ref_var_to_user(address, userAddress);
|
||||
if (status < B_OK) {
|
||||
delete_area(clonedArea);
|
||||
return B_BAD_ADDRESS;
|
||||
return status;
|
||||
}
|
||||
|
||||
return clonedArea;
|
||||
@@ -6330,11 +6381,13 @@ _user_create_area(const char* userName, void** userAddress, uint32 addressSpec,
|
||||
return B_BAD_VALUE;
|
||||
|
||||
if (!IS_USER_ADDRESS(userName)
|
||||
|| !IS_USER_ADDRESS(userAddress)
|
||||
|| user_strlcpy(name, userName, sizeof(name)) < B_OK
|
||||
|| user_memcpy(&address, userAddress, sizeof(address)) < B_OK)
|
||||
|| user_strlcpy(name, userName, sizeof(name)) < B_OK)
|
||||
return B_BAD_ADDRESS;
|
||||
|
||||
status_t status = copy_ref_var_from_user(userAddress, address);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
if (addressSpec == B_EXACT_ADDRESS
|
||||
&& IS_KERNEL_ADDRESS(address))
|
||||
return B_BAD_VALUE;
|
||||
@@ -6354,10 +6407,12 @@ _user_create_area(const char* userName, void** userAddress, uint32 addressSpec,
|
||||
size, lock, protection, 0, 0, &virtualRestrictions,
|
||||
&physicalRestrictions, false, &address);
|
||||
|
||||
if (area >= B_OK
|
||||
&& user_memcpy(userAddress, &address, sizeof(address)) < B_OK) {
|
||||
delete_area(area);
|
||||
return B_BAD_ADDRESS;
|
||||
if (area >= B_OK) {
|
||||
status = copy_ref_var_to_user(address, userAddress);
|
||||
if (status < B_OK) {
|
||||
delete_area(area);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
return area;
|
||||
@@ -6391,11 +6446,14 @@ _user_map_file(const char* userName, void** userAddress, uint32 addressSpec,
|
||||
|
||||
fix_protection(&protection);
|
||||
|
||||
if (!IS_USER_ADDRESS(userName) || !IS_USER_ADDRESS(userAddress)
|
||||
|| user_strlcpy(name, userName, B_OS_NAME_LENGTH) < B_OK
|
||||
|| user_memcpy(&address, userAddress, sizeof(address)) < B_OK)
|
||||
if (!IS_USER_ADDRESS(userName)
|
||||
|| user_strlcpy(name, userName, B_OS_NAME_LENGTH) < B_OK)
|
||||
return B_BAD_ADDRESS;
|
||||
|
||||
status_t status = copy_ref_var_from_user(userAddress, address);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
if (addressSpec == B_EXACT_ADDRESS) {
|
||||
if ((addr_t)address + size < (addr_t)address
|
||||
|| (addr_t)address % B_PAGE_SIZE != 0) {
|
||||
@@ -6413,8 +6471,11 @@ _user_map_file(const char* userName, void** userAddress, uint32 addressSpec,
|
||||
if (area < B_OK)
|
||||
return area;
|
||||
|
||||
if (user_memcpy(userAddress, &address, sizeof(address)) < B_OK)
|
||||
return B_BAD_ADDRESS;
|
||||
status = copy_ref_var_to_user(address, userAddress);
|
||||
if (status < B_OK) {
|
||||
delete_area(area);
|
||||
return status;
|
||||
}
|
||||
|
||||
return area;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user