diff --git a/patch-server/patch_user_xml.cpp b/patch-server/patch_user_xml.cpp index 00e422e..3717c4b 100644 --- a/patch-server/patch_user_xml.cpp +++ b/patch-server/patch_user_xml.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include @@ -130,6 +131,37 @@ static uintptr_t check_mapbase(const uintptr_t mapbase) return !mapbase ? NO_ASLR_ADDR : mapbase; } +static void checked_write(const patch_xml_context& ctx, + const uintptr_t addr, + const void* data, + const size_t len) +{ + if (!data || !len) + { + throw std::invalid_argument(FILE_FUNC_LINE ": Invalid patch data"); + } + + const uintptr_t mapbase = check_mapbase(ctx.info.obj.mapbase); + const uintptr_t mapsize = (uintptr_t)ctx.info.obj.mapsize; + if (!mapsize || mapbase > std::numeric_limits::max() - mapsize) + { + throw std::out_of_range(FILE_FUNC_LINE ": Invalid executable module range"); + } + + const uintptr_t mapend = mapbase + mapsize; + if (addr < mapbase || addr >= mapend || len > mapend - addr) + { + throw std::out_of_range(FILE_FUNC_LINE ": Patch span is outside the executable module"); + } + + const int r = userland_copyin2(ctx.read_client.clientPid, addr, data, len); + if (r != 0) + { + throw std::runtime_error(std::string(FILE_FUNC_LINE ": userland_copyin2 failed with result ") + + std::to_string(r)); + } +} + static uintptr_t scan_pattern(int pid, const dynlib_info& info, const char* pattern, size_t offset = 0) { return pid_chunk_scan(pid, check_mapbase(info.obj.mapbase), info.obj.mapsize, pattern, offset); @@ -176,21 +208,21 @@ void patch_xml_context::apply_patch(const patch_line& pline) { const uintptr_t addr = resolve_addr(pline.address, info, pline.imagebase); const uint8_t v = (uint8_t)std::stoull(pline.value, nullptr, convertNumBase(pline.value)); - userland_copyin2(pid, addr, &v, sizeof(v)); + checked_write(*this, addr, &v, sizeof(v)); break; } case sid("bytes16"): { const uintptr_t addr = resolve_addr(pline.address, info, pline.imagebase); const uint16_t v = (uint16_t)std::stoull(pline.value, nullptr, convertNumBase(pline.value)); - userland_copyin2(pid, addr, &v, sizeof(v)); + checked_write(*this, addr, &v, sizeof(v)); break; } case sid("bytes32"): { const uintptr_t addr = resolve_addr(pline.address, info, pline.imagebase); const uint32_t v = (uint32_t)std::stoull(pline.value, nullptr, convertNumBase(pline.value)); - userland_copyin2(pid, addr, &v, sizeof(v)); + checked_write(*this, addr, &v, sizeof(v)); break; } case sid("bytes64"): @@ -198,7 +230,7 @@ void patch_xml_context::apply_patch(const patch_line& pline) const uintptr_t addr = resolve_addr(pline.address, info, pline.imagebase); const int nb = convertNumBase(pline.value); const auto v = nb == 16 ? std::stoull(pline.value, nullptr, nb) : std::stoll(pline.value, nullptr, nb); - userland_copyin2(pid, addr, &v, sizeof(v)); + checked_write(*this, addr, &v, sizeof(v)); break; } @@ -206,14 +238,14 @@ void patch_xml_context::apply_patch(const patch_line& pline) { const uintptr_t addr = resolve_addr(pline.address, info, pline.imagebase); const float val = std::stof(pline.value); - userland_copyin2(pid, addr, &val, sizeof(val)); + checked_write(*this, addr, &val, sizeof(val)); break; } case sid("float64"): { const uintptr_t addr = resolve_addr(pline.address, info, pline.imagebase); const double val = std::stod(pline.value); - userland_copyin2(pid, addr, &val, sizeof(val)); + checked_write(*this, addr, &val, sizeof(val)); break; } @@ -221,14 +253,14 @@ void patch_xml_context::apply_patch(const patch_line& pline) { const uintptr_t addr = resolve_addr(pline.address, info, pline.imagebase); const std::string s = unescape_utf8(pline.value); - userland_copyin2(pid, addr, s.data(), s.size()); + checked_write(*this, addr, s.data(), s.size()); break; } case sid("utf16"): { const uintptr_t addr = resolve_addr(pline.address, info, pline.imagebase); const std::wstring ws = unescape_utf16(pline.value); - userland_copyin2(pid, addr, ws.data(), ws.size() * sizeof(wchar_t)); + checked_write(*this, addr, ws.data(), ws.size() * sizeof(wchar_t)); break; } @@ -236,7 +268,7 @@ void patch_xml_context::apply_patch(const patch_line& pline) { const uintptr_t addr = resolve_addr(pline.address, info, pline.imagebase); const auto payload = split_hex(pline.value); - userland_copyin2(pid, addr, payload.data(), payload.size()); + checked_write(*this, addr, payload.data(), payload.size()); break; } case sid("mask"): @@ -250,7 +282,7 @@ void patch_xml_context::apply_patch(const patch_line& pline) const uintptr_t patch_addr = found + (offset < 0 ? offset : 0); const auto payload = split_hex(pline.value); - userland_copyin2(pid, patch_addr, payload.data(), payload.size()); + checked_write(*this, patch_addr, payload.data(), payload.size()); break; } case sid("mask_jump32"): @@ -278,14 +310,14 @@ void patch_xml_context::apply_patch(const patch_line& pline) const auto cave_payload = split_hex(pline.value); const uintptr_t cave_end = cave_addr + cave_payload.size(); - userland_copyin2(pid, cave_addr, cave_payload.data(), cave_payload.size()); + checked_write(*this, cave_addr, cave_payload.data(), cave_payload.size()); { uint8_t jmp[5]; const int32_t rel = (int32_t)((intptr_t)(patch_addr + jump_size) - (intptr_t)(cave_end + 5)); jmp[0] = 0xE9; std::memcpy(&jmp[1], &rel, 4); - userland_copyin2(pid, cave_end, jmp, sizeof(jmp)); + checked_write(*this, cave_end, jmp, sizeof(jmp)); } { @@ -293,7 +325,7 @@ void patch_xml_context::apply_patch(const patch_line& pline) const int32_t rel = (int32_t)((intptr_t)cave_addr - (intptr_t)(patch_addr + 5)); jmp_in[0] = 0xE9; std::memcpy(&jmp_in[1], &rel, 4); - userland_copyin2(pid, patch_addr, jmp_in.data(), jmp_in.size()); + checked_write(*this, patch_addr, jmp_in.data(), jmp_in.size()); } break; } @@ -534,7 +566,7 @@ int patch_xml_context::read_xml() pline.address, pline.value, e.what()); - continue; + return -1; } } diff --git a/patch-server/server_patch.cpp b/patch-server/server_patch.cpp index 35e0898..9a56918 100644 --- a/patch-server/server_patch.cpp +++ b/patch-server/server_patch.cpp @@ -295,8 +295,10 @@ void run_elf_user_patch(client_data& read_client) .metadata = meta, // .exec_name = mod_base // }; - patch.read_xml(); - run_prx_load_patch(read_client, id_hash); + if (patch.read_xml() >= 0) + { + run_prx_load_patch(read_client, id_hash); + } } } } diff --git a/shared/proc_rw.c b/shared/proc_rw.c index 70abf57..81ae88c 100644 --- a/shared/proc_rw.c +++ b/shared/proc_rw.c @@ -1,207 +1,515 @@ #include "proc_rw.h" -#include "my_assert.h" -#include "../shared/platform_mdbg.h" #include "../shared/platform_kernel.h" +#include "../shared/platform_mdbg.h" + +#include +#include +#include #include +#include #include -#include + +#if defined(__PROSPERO__) +#define COPYIN_LOCK_ATTEMPTS 1000000UL + +static volatile int copyin_lock = 0; + +static int lock_copyin(void) +{ + for (unsigned long attempt = 0; attempt < COPYIN_LOCK_ATTEMPTS; ++attempt) + { + if (__atomic_exchange_n(©in_lock, 1, __ATOMIC_ACQUIRE) == 0) + { + return 0; + } + } + return -1; +} + +static void unlock_copyin(void) +{ + __atomic_store_n(©in_lock, 0, __ATOMIC_RELEASE); +} +#endif int userland_copyout_(pid_t pid, intptr_t addr, void* buf, size_t len, const char* user) { - // unpatched on 8.20+ - const int r = mdbg_copyout(pid, addr, buf, len); - if (0 && r == 0) + // mdbg copyout is unpatched on 8.20+. + const int result = mdbg_copyout(pid, addr, buf, len); + if (0 && result == 0) { printf("%s: copied out okay from %s\n", __FUNCSIG__, user); } - return r; + return result; } #if defined(__PROSPERO__) +static int checked_add_ulong(unsigned long left, unsigned long right, unsigned long* result) +{ + if (result == NULL || right > ULONG_MAX - left) + { + return -1; + } + *result = left + right; + return 0; +} + +static int valid_user_range(intptr_t addr, size_t len) +{ + if (addr < 0 || len == 0) + { + return len == 0; + } + + const unsigned long start = (unsigned long)addr; + unsigned long end = 0; + if ((unsigned long)(len - 1) > ULONG_MAX || + checked_add_ulong(start, (unsigned long)(len - 1), &end) != 0) + { + return 0; + } + + // Target process mappings used here must be in the low canonical half. + return (start >> 47) == 0 && (end >> 47) == 0; +} + +static int valid_local_range(const void* buffer, size_t len) +{ + if (len == 0) + { + return 1; + } + if (buffer == NULL) + { + return 0; + } + + const uintptr_t start = (uintptr_t)buffer; + return (len - 1) <= UINTPTR_MAX - start; +} + +#define MAX_PROC_SCAN_COUNT 65536UL +#define PHYSICAL_ADDRESS_LIMIT (1UL << 52) + +typedef struct remote_address_space +{ + pid_t pid; + unsigned long proc; + unsigned long vmspace; + unsigned long pmap; + unsigned long pml4; + unsigned long cr3; + unsigned long dmap; +} remote_address_space; + +static int is_canonical_address(unsigned long address) +{ + const unsigned long high = address >> 47; + return high == 0 || high == 0x1FFFF; +} + +static int is_kernel_pointer(unsigned long address) +{ + return address != 0 && is_canonical_address(address) && (address & (1UL << 63)) != 0; +} + static unsigned int get_fw_version(void) { - static int cache_fw_version = 0; - if (cache_fw_version == 0) + static unsigned int cached_fw_version = 0; + if (cached_fw_version == 0) { - cache_fw_version = kernel_get_fw_version() >> 16; + cached_fw_version = kernel_get_fw_version() >> 16; } - return cache_fw_version; + return cached_fw_version; } -static unsigned long vmspace_pmap(unsigned long vmspace_kaddr) +static unsigned long vmspace_pmap_offset(void) { switch (get_fw_version()) { case 0x100 ... 0x102: - return vmspace_kaddr + 0x2C0; + return 0x2C0; case 0x105 ... 0x550: - return vmspace_kaddr + 0x2E0; + return 0x2E0; case 0x600 ... 0x1340: - return vmspace_kaddr + 0x2E8; + return 0x2E8; default: - return 0; // unsupported fw version + return 0; } } -static unsigned long cache_kernel_dmap_base = 0; +static int add_kernel_offset(unsigned long base, off_t offset, unsigned long* result) +{ + if (offset < 0) + { + return -1; + } + return checked_add_ulong(base, (unsigned long)offset, result); +} -static unsigned long kernel_get_proc_cr3(int pid) +static int read_proc_pid(unsigned long proc, pid_t* pid) { - unsigned long proc = kernel_get_proc(pid); - if (proc == 0) + unsigned long address = 0; + if (!is_kernel_pointer(proc) || pid == NULL || + add_kernel_offset(proc, KERNEL_OFFSET_PROC_P_PID, &address) != 0 || + !is_kernel_pointer(address)) { - return 0; + return -1; } - unsigned long vmspace = kernel_getlong(proc + KERNEL_OFFSET_PROC_P_VMSPACE); - if (vmspace == 0) + unsigned int value = 0; + if (kernel_copyout(address, &value, sizeof(value)) != 0) { - return 0; + return -1; } + *pid = (pid_t)value; + return 0; +} - // read pm_pml4 + pm_cr3, its free to read the extra 8 bytes and this way we can populate the dmap base cache - unsigned long pmap = vmspace_pmap(vmspace); - if (pmap == 0) +static int find_proc_uncached(pid_t requested_pid, unsigned long* result) +{ + if (result == NULL) { - return 0; + return -1; } - unsigned long data[2]; - if (kernel_copyout(pmap + 32, data, sizeof(data))) + + const pid_t pid = requested_pid > 0 ? requested_pid : getpid(); + const unsigned long allproc = (unsigned long)KERNEL_ADDRESS_ALLPROC; + unsigned long proc = 0; + if (!is_kernel_pointer(allproc) || + kernel_copyout(allproc, &proc, sizeof(proc)) != 0) { - return 0; + return -1; } - unsigned long pm_pml4 = data[0]; // KVA of level 4 page table - always within the direct map - unsigned long pm_cr3 = data[1]; + for (unsigned long count = 0; count < MAX_PROC_SCAN_COUNT && proc != 0; ++count) + { + if (!is_kernel_pointer(proc)) + { + return -1; + } + + pid_t current_pid = 0; + if (read_proc_pid(proc, ¤t_pid) != 0) + { + return -1; + } + if (current_pid == pid) + { + *result = proc; + return 0; + } + + unsigned long next = 0; + if (kernel_copyout(proc, &next, sizeof(next)) != 0 || next == proc) + { + return -1; + } + proc = next; + } - cache_kernel_dmap_base = pm_pml4 - pm_cr3; - return pm_cr3; + return -1; } -static unsigned long kernel_get_dmap_base(void) +static int read_proc_vmspace(unsigned long proc, unsigned long* vmspace) { - if (cache_kernel_dmap_base == 0) + unsigned long address = 0; + if (!is_kernel_pointer(proc) || vmspace == NULL || + add_kernel_offset(proc, KERNEL_OFFSET_PROC_P_VMSPACE, &address) != 0 || + !is_kernel_pointer(address) || + kernel_copyout(address, vmspace, sizeof(*vmspace)) != 0 || + !is_kernel_pointer(*vmspace)) { - kernel_get_proc_cr3(-1); // implicitly sets cache_kernel_dmap_base + return -1; } + return 0; +} - return cache_kernel_dmap_base; +static int read_pmap_words(unsigned long pmap, unsigned long* pml4, unsigned long* cr3) +{ + unsigned long words_address = 0; + unsigned long words[2] = {0}; + if (!is_kernel_pointer(pmap) || pml4 == NULL || cr3 == NULL || + checked_add_ulong(pmap, 0x20, &words_address) != 0 || + !is_kernel_pointer(words_address) || + kernel_copyout(words_address, words, sizeof(words)) != 0) + { + return -1; + } + + *pml4 = words[0]; + *cr3 = words[1]; + return 0; +} + +static int load_remote_address_space(pid_t requested_pid, remote_address_space* space) +{ + if (space == NULL) + { + return -1; + } + + memset(space, 0, sizeof(*space)); + space->pid = requested_pid > 0 ? requested_pid : getpid(); + + const unsigned long pmap_offset = vmspace_pmap_offset(); + if (pmap_offset == 0 || find_proc_uncached(space->pid, &space->proc) != 0) + { + return -1; + } + + pid_t observed_pid = 0; + if (read_proc_pid(space->proc, &observed_pid) != 0 || observed_pid != space->pid || + read_proc_vmspace(space->proc, &space->vmspace) != 0 || + checked_add_ulong(space->vmspace, pmap_offset, &space->pmap) != 0 || + !is_kernel_pointer(space->pmap) || + read_pmap_words(space->pmap, &space->pml4, &space->cr3) != 0) + { + return -1; + } + + const unsigned long cr3_frame = space->cr3 & PG_FRAME; + if (!is_kernel_pointer(space->pml4) || (space->pml4 & 0xFFF) != 0 || + cr3_frame == 0 || cr3_frame >= PHYSICAL_ADDRESS_LIMIT || + space->pml4 < cr3_frame) + { + return -1; + } + + space->dmap = space->pml4 - cr3_frame; + if (!is_kernel_pointer(space->dmap) || + read_proc_pid(space->proc, &observed_pid) != 0 || observed_pid != space->pid) + { + return -1; + } + + unsigned long observed_vmspace = 0; + if (read_proc_vmspace(space->proc, &observed_vmspace) != 0 || + observed_vmspace != space->vmspace) + { + return -1; + } + + return 0; } -// based on: -// https://github.com/sleirsgoevy/ps4jb-payloads/blob/6f2aad7c4773591913aecea405c54bb547d12822/ps5-kstuff/uelf/utils.c#L8 -// https://github.com/sleirsgoevy/ps4jb-payloads/blob/6f2aad7c4773591913aecea405c54bb547d12822/ps5-kstuff/main.c#L235 -static unsigned long virt2phys(unsigned long cr3, unsigned long va, unsigned long* phys_limit) +static int revalidate_remote_address_space(const remote_address_space* space) { - unsigned long kernel_dmap_base = kernel_get_dmap_base(); + unsigned long current_proc = 0; + unsigned long current_vmspace = 0; + unsigned long current_pml4 = 0; + unsigned long current_cr3 = 0; + pid_t observed_pid = 0; + + if (space == NULL || find_proc_uncached(space->pid, ¤t_proc) != 0 || + current_proc != space->proc || + read_proc_pid(space->proc, &observed_pid) != 0 || observed_pid != space->pid || + read_proc_vmspace(space->proc, ¤t_vmspace) != 0 || + current_vmspace != space->vmspace || + read_pmap_words(space->pmap, ¤t_pml4, ¤t_cr3) != 0 || + current_pml4 != space->pml4 || current_cr3 != space->cr3) + { + return -1; + } + return 0; +} - cr3 &= PG_FRAME; +static int virt2phys(const remote_address_space* space, + unsigned long virtual_address, + unsigned long* physical_address, + size_t* page_remaining) +{ + if (space == NULL || physical_address == NULL || page_remaining == NULL || + (virtual_address >> 47) != 0) + { + return -1; + } - // PML4SHIFT (39) -> PDPSHIFT (30) -> PDRSHIFT (21) -> PAGE_SHIFT (12) - for (int i = 39; i >= 12; i -= 9) + unsigned long table = space->cr3 & PG_FRAME; + for (int shift = 39; shift >= 12; shift -= 9) { - unsigned long index = (va >> i) & ((1ull << 9) - 1); - unsigned long entry_offset = index * sizeof(unsigned long); // pml4_entry_t is unsigned long - cr3 = kernel_getlong(kernel_dmap_base + cr3 + entry_offset); + if (table == 0 || table >= PHYSICAL_ADDRESS_LIMIT) + { + return -1; + } - if (!(cr3 & X86_PG_V)) - { // not present/valid + const unsigned long index = (virtual_address >> shift) & 0x1FF; + const unsigned long entry_offset = index * sizeof(unsigned long); + unsigned long table_address = 0; + unsigned long entry_address = 0; + unsigned long entry = 0; + if (checked_add_ulong(space->dmap, table, &table_address) != 0 || + checked_add_ulong(table_address, entry_offset, &entry_address) != 0 || + !is_kernel_pointer(entry_address) || + kernel_copyout(entry_address, &entry, sizeof(entry)) != 0 || + (entry & X86_PG_V) == 0) + { return -1; } - if ((cr3 & X86_PG_PS) || i == 12) - { // large page or last level - cr3 &= (1ull << 52) - (1ull << i); // PG_PS_FRAME/PG_FRAME - cr3 |= va & ((1ull << i) - 1); // PDPMASK/PDRMASK/PAGE_MASK - if (phys_limit) + + const int is_large_page = (entry & X86_PG_PS) != 0; + if (is_large_page && shift != 30 && shift != 21) + { + return -1; + } + + if (is_large_page || shift == 12) + { + const unsigned long page_size = 1UL << shift; + const unsigned long page_offset = virtual_address & (page_size - 1); + const unsigned long frame_mask = (1UL << 52) - page_size; + const unsigned long frame = entry & frame_mask; + const unsigned long physical = frame | page_offset; + if (frame >= PHYSICAL_ADDRESS_LIMIT || physical >= PHYSICAL_ADDRESS_LIMIT) { - *phys_limit = (cr3 | ((1ull << i) - 1)) + 1; + return -1; } - return cr3; + + *physical_address = physical; + *page_remaining = (size_t)(page_size - page_offset); + return *page_remaining != 0 ? 0 : -1; } - cr3 &= PG_FRAME; + + table = entry & PG_FRAME; } - assert_always(0 && "unreachable code reached"); - return 0; + return -1; } -static int phys_copy_to_remote(unsigned long cr3, const void* from_local_vaddr, unsigned long to_remote_vaddr, unsigned long len) +static int phys_copy_to_remote(const remote_address_space* space, + const void* source_buffer, + unsigned long remote_address, + size_t len) { - const unsigned char* p_src = from_local_vaddr; - unsigned long phys, phys_end; - unsigned long kernel_dmap_base = kernel_get_dmap_base(); - if (kernel_dmap_base == 0) + if (space == NULL || (source_buffer == NULL && len != 0)) { return -1; } - while (len) + + const unsigned char* source = source_buffer; + size_t remaining = len; + while (remaining != 0) { - phys = virt2phys(cr3, to_remote_vaddr, &phys_end); - if (phys == -1) + unsigned long physical = 0; + size_t page_remaining = 0; + if (revalidate_remote_address_space(space) != 0 || + virt2phys(space, remote_address, &physical, &page_remaining) != 0) { return -1; } - size_t chk = phys_end - phys; - if (len < chk) + + const size_t chunk = remaining < page_remaining ? remaining : page_remaining; + unsigned long kernel_target = 0; + unsigned long kernel_target_end = 0; + if (chunk == 0 || + checked_add_ulong(space->dmap, physical, &kernel_target) != 0 || + checked_add_ulong(kernel_target, (unsigned long)(chunk - 1), &kernel_target_end) != 0 || + !is_kernel_pointer(kernel_target) || !is_kernel_pointer(kernel_target_end)) { - chk = len; + return -1; } - if (kernel_copyin(p_src, kernel_dmap_base + phys, chk)) + unsigned long verified_physical = 0; + size_t verified_page_remaining = 0; + if (revalidate_remote_address_space(space) != 0 || + virt2phys(space, remote_address, &verified_physical, &verified_page_remaining) != 0 || + verified_physical != physical || verified_page_remaining < chunk) { return -1; } - to_remote_vaddr += chk; - p_src += chk; - len -= chk; + if (kernel_copyin(source, kernel_target, chunk) != 0) + { + return -1; + } + + unsigned long next_remote = 0; + if (checked_add_ulong(remote_address, (unsigned long)chunk, &next_remote) != 0) + { + return -1; + } + remote_address = next_remote; + source += chunk; + remaining -= chunk; } + return 0; } + +static int validate_copyin_arguments(const void* buffer, intptr_t addr, size_t len) +{ + return valid_local_range(buffer, len) && valid_user_range(addr, len) ? 0 : -1; +} + +static int copyin_physical(pid_t pid, const void* buf, intptr_t addr, size_t len) +{ + // Fault every target page in before walking its page tables. + unsigned char* original = malloc(len); + if (original == NULL) + { + return -1; + } + if (mdbg_copyout(pid, addr, original, len) != 0) + { + free(original); + return -1; + } + free(original); + + remote_address_space space; + if (load_remote_address_space(pid, &space) != 0) + { + return -1; + } + return phys_copy_to_remote(&space, buf, (unsigned long)addr, len); +} #endif int userland_copyin_(pid_t pid, const void* buf, intptr_t addr, size_t len, const char* user) { #if defined(__ORBIS__) - const int r = mdbg_copyin(pid, buf, addr, len); - if (0 && r == 0) + const int result = mdbg_copyin(pid, buf, addr, len); + if (0 && result == 0) { printf("%s: copied in okay from %s\n", __FUNCSIG__, user); } - return r; + return result; #elif defined(__PROSPERO__) - // mdbg copyin works up to 8.20 + // mdbg copyin works up to 8.20. if (get_fw_version() <= 0x820) { - const int r = mdbg_copyin(pid, buf, addr, len); - if (0 && r == 0) + const int result = mdbg_copyin(pid, buf, addr, len); + if (0 && result == 0) { printf("%s: copied in okay from %s\n", __FUNCSIG__, user); } - return r; + return result; } - // make sure the target has the addr faulted in - void* tmp = malloc(len); - if (tmp == NULL) + + if (len == 0) { - return -1; + return 0; } - - int res = userland_copyout(pid, addr, tmp, len); - free(tmp); - if (res) + if (validate_copyin_arguments(buf, addr, len) != 0) { return -1; } - unsigned long cr3 = kernel_get_proc_cr3(pid); - if (cr3 == 0) + if (lock_copyin() != 0) { return -1; } - - return phys_copy_to_remote(cr3, buf, addr, len); + const int result = copyin_physical(pid, buf, addr, len); + unlock_copyin(); + return result; +#else + (void)pid; + (void)buf; + (void)addr; + (void)len; + (void)user; + return -1; #endif }