this repo has no description
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Quite a few syscall updates; working execve; new tool

* Many syscalls have been updated to use darlingserver RPC calls instead of LKM calls.
* The elfcalls threading glue now performs checkins and checkouts for non-main threads.
* mldr's main stack allocation logic has been fixed to not overwrite the commpage.
* execve now works properly with mldr and informs the server of the success or failure of the execve call (using some close-on-exec FD trickery; see the corresponding commit in darlingserver for more details).

One very useful additional that merits its own paragraph is the new `darling-coredump` tool. binfmt_misc provides no way to register a coredump handler, and trying to intercept all the possible signals that can generate a coredump in-process and handle them appropriately is more trouble than it's worth. Therefore, I created a new tool that converts a kernel-generated ELF coredump into a proper Mach-O coredump. The tool is currently only compatible with kernel-generated coredumps; coredumps produced with `gcore` seem to be missing certain information that causes the tool to produce an invalid coredump (and I'm not quite sure what is wrong with it).

+1195 -144
+1
src/CMakeLists.txt
··· 55 55 #add_subdirectory(libmach-o) 56 56 #add_subdirectory(libdyld) 57 57 add_subdirectory(buildtools) 58 + add_subdirectory(hosttools) 58 59 add_subdirectory(libelfloader/wrapgen) 59 60 add_subdirectory(libsimple) 60 61 add_subdirectory(external/darlingserver)
+15
src/hosttools/CMakeLists.txt
··· 1 + project(hosttools) 2 + 3 + add_executable(darling-coredump 4 + src/coredump/main.c 5 + ) 6 + 7 + target_include_directories(darling-coredump PRIVATE 8 + # TEMPORARY 9 + # this set of includes should probably be moved out because we probably want to be able to use Mach-O headers 10 + # in non-Darling compilation environments more often. by non-Darling, i mean when compiling directly for Linux 11 + # as we do in mldr and now here. 12 + ../startup/mldr/include 13 + ) 14 + 15 + install(TARGETS darling-coredump DESTINATION bin)
+722
src/hosttools/src/coredump/main.c
··· 1 + #include <stdio.h> 2 + #include <unistd.h> 3 + #include <fcntl.h> 4 + #include <sys/mman.h> 5 + #include <stdlib.h> 6 + #include <string.h> 7 + #include <stdbool.h> 8 + #include <errno.h> 9 + #include <sys/stat.h> 10 + 11 + #include <mach-o/loader.h> 12 + #include <elf.h> 13 + 14 + #include <linux/time_types.h> 15 + 16 + #if __x86_64__ 17 + #include "x86_64.h" 18 + #else 19 + #error Not implemented 20 + #endif 21 + 22 + // interestingly enough, there are no existing tools that can perform this conversion (ELF coredump to Mach-O coredump). 23 + // neither objcopy nor llvm-objcopy support Mach-O conversion like that, nor does objconv (it considers coredumps to be executables and refuses to operate on them). 24 + // porting our existing code from the LKM is simple enough, so that's what we do here. 25 + 26 + struct vm_area { 27 + const char* filename; 28 + uintptr_t memory_address; 29 + size_t memory_size; 30 + size_t file_offset; 31 + size_t file_size; 32 + uint8_t protection; 33 + bool valid; 34 + }; 35 + 36 + struct nt_file_header { 37 + uint64_t count; 38 + uint64_t page_size; 39 + }; 40 + 41 + struct nt_file_entry { 42 + uint64_t start; 43 + uint64_t end; 44 + uint64_t offset; 45 + }; 46 + 47 + struct nt_prstatus { 48 + int signal_number; 49 + int signal_code; 50 + int signal_errno; 51 + short current_signal; 52 + unsigned long pending_signals; 53 + unsigned long held_signals; 54 + pid_t pid; 55 + pid_t ppid; 56 + pid_t pgrp; 57 + pid_t sid; 58 + struct __kernel_old_timeval user_time; 59 + struct __kernel_old_timeval system_time; 60 + struct __kernel_old_timeval cumulative_user_time; 61 + struct __kernel_old_timeval cumulative_system_time; 62 + struct nt_prstatus_registers general_registers; 63 + }; 64 + 65 + struct thread_info { 66 + const struct nt_prstatus* prstatus; 67 + }; 68 + 69 + struct coredump_params { 70 + int input_corefile; 71 + int output_corefile; 72 + size_t input_corefile_size; 73 + const void* input_corefile_mapping; 74 + const Elf64_Ehdr* input_header; 75 + const Elf64_Phdr* input_program_headers; 76 + const Elf64_Phdr* input_program_headers_end; 77 + const Elf64_Nhdr* input_notes; 78 + size_t input_notes_size; 79 + struct vm_area* vm_areas; 80 + size_t vm_area_count; 81 + const struct nt_file_header* nt_file; 82 + const char** nt_file_filenames; 83 + struct thread_info* thread_infos; 84 + size_t thread_info_count; 85 + size_t written; 86 + }; 87 + 88 + static char default_output_name[4096]; 89 + 90 + static uint64_t round_up_pow2(uint64_t number, uint64_t multiple) { 91 + return (number + (multiple - 1)) & -multiple; 92 + }; 93 + 94 + static uint64_t round_down_pow2(uint64_t number, uint64_t multiple) { 95 + return (number) & -multiple; 96 + }; 97 + 98 + static const char* note_name(const Elf64_Nhdr* note) { 99 + return (const char*)note + sizeof(*note); 100 + }; 101 + 102 + static const void* note_data(const Elf64_Nhdr* note) { 103 + return note_name(note) + round_up_pow2(note->n_namesz, 8); 104 + }; 105 + 106 + static const Elf64_Nhdr* find_next_note(const Elf64_Nhdr* note) { 107 + uint64_t length = sizeof(*note) + round_up_pow2(note->n_namesz, 8) + round_up_pow2(note->n_descsz, 8); 108 + return (Elf64_Nhdr*)((char*)note + length); 109 + }; 110 + 111 + void macho_coredump(struct coredump_params* cprm); 112 + 113 + int main(int argc, char** argv) { 114 + if (argc < 2) { 115 + fprintf(stderr, "Usage: %s <input-coredump> [output-coredump]\n", (argc > 0 ? argv[0] : "darling-coredump")); 116 + return 1; 117 + } 118 + 119 + if (snprintf(default_output_name, sizeof(default_output_name), "darlingcore-%s", argv[1]) < 0) { 120 + perror("snprintf"); 121 + return 1; 122 + } 123 + 124 + struct coredump_params cprm = {0}; 125 + 126 + cprm.input_corefile = open(argv[1], O_RDONLY); 127 + if (cprm.input_corefile < 0) { 128 + perror("open input"); 129 + return 1; 130 + } 131 + 132 + struct stat input_corefile_stats; 133 + if (fstat(cprm.input_corefile, &input_corefile_stats) < 0) { 134 + perror("fstat"); 135 + return 1; 136 + } 137 + cprm.input_corefile_size = input_corefile_stats.st_size; 138 + cprm.input_corefile_mapping = mmap(NULL, cprm.input_corefile_size, PROT_READ, MAP_PRIVATE, cprm.input_corefile, 0); 139 + 140 + cprm.output_corefile = open((argc > 2 ? argv[2] : default_output_name), O_WRONLY | O_TRUNC | O_CREAT, 0644); 141 + if (cprm.output_corefile < 0) { 142 + perror("open output"); 143 + return 1; 144 + } 145 + 146 + cprm.input_header = cprm.input_corefile_mapping; 147 + 148 + if ( 149 + cprm.input_header->e_ident[EI_MAG0] != ELFMAG0 || 150 + cprm.input_header->e_ident[EI_MAG1] != ELFMAG1 || 151 + cprm.input_header->e_ident[EI_MAG2] != ELFMAG2 || 152 + cprm.input_header->e_ident[EI_MAG3] != ELFMAG3 || 153 + cprm.input_header->e_ident[EI_CLASS] != ELFCLASS64 || 154 + cprm.input_header->e_ident[EI_VERSION] != EV_CURRENT || 155 + cprm.input_header->e_version != EV_CURRENT || 156 + cprm.input_header->e_type != ET_CORE 157 + ) { 158 + fprintf(stderr, "Input file is not a valid corefile\n"); 159 + return 1; 160 + } 161 + 162 + #if __x86_64__ 163 + if (cprm.input_header->e_machine != EM_X86_64) { 164 + fprintf(stderr, "Input file is not a valid x86_64 corefile\n"); 165 + return 1; 166 + } 167 + #else 168 + #error Not implemented! 169 + #endif 170 + 171 + cprm.input_program_headers = (const void*)((const char*)cprm.input_corefile_mapping + cprm.input_header->e_phoff); 172 + cprm.input_program_headers_end = (const Elf64_Phdr*)((const char*)cprm.input_program_headers + (cprm.input_header->e_phentsize * cprm.input_header->e_phnum)); 173 + 174 + // first, count how many VM areas we have 175 + for (const Elf64_Phdr* program_header = cprm.input_program_headers; program_header < cprm.input_program_headers_end; program_header = (const Elf64_Phdr*)((const char*)program_header + cprm.input_header->e_phentsize)) { 176 + if (program_header->p_type == PT_LOAD) { 177 + ++cprm.vm_area_count; 178 + } else if (program_header->p_type == PT_NOTE) { 179 + // while we're at it, also load the NOTE segment 180 + 181 + // XXX: ignoring it is probably not the best choice 182 + if (cprm.input_notes) { 183 + printf("warning: ignoring extra PT_NOTE segment\n"); 184 + continue; 185 + } 186 + 187 + cprm.input_notes = (const void*)((const char*)cprm.input_corefile_mapping + program_header->p_offset); 188 + cprm.input_notes_size = program_header->p_filesz; 189 + } 190 + } 191 + 192 + if (!cprm.input_notes) { 193 + fprintf(stderr, "Input corefile does not contain PT_NOTE segment\n"); 194 + return 1; 195 + } 196 + 197 + for (const Elf64_Nhdr* note_header = cprm.input_notes; note_header < (const Elf64_Nhdr*)((const char*)cprm.input_notes + cprm.input_notes_size); note_header = find_next_note(note_header)) { 198 + if (note_header->n_type == NT_FILE) { 199 + cprm.nt_file = note_data(note_header); 200 + 201 + cprm.nt_file_filenames = malloc(cprm.nt_file->count * sizeof(const char*)); 202 + if (!cprm.nt_file_filenames) { 203 + perror("malloc"); 204 + return 1; 205 + } 206 + 207 + const char* filenames = (const char*)cprm.nt_file + sizeof(struct nt_file_header) + (sizeof(struct nt_file_entry) * cprm.nt_file->count); 208 + for (size_t i = 0, offset = 0; i < cprm.nt_file->count; ++i) { 209 + cprm.nt_file_filenames[i] = &filenames[offset]; 210 + offset += strlen(&filenames[offset]) + 1; 211 + } 212 + } else if (note_header->n_type == NT_PRSTATUS) { 213 + ++cprm.thread_info_count; 214 + } else { 215 + continue; 216 + } 217 + } 218 + 219 + if (!cprm.nt_file) { 220 + fprintf(stderr, "Input corefile does not contain NT_FILE note\n"); 221 + return 1; 222 + } 223 + 224 + cprm.thread_infos = malloc(sizeof(struct thread_info) * cprm.thread_info_count); 225 + if (!cprm.thread_infos) { 226 + perror("malloc"); 227 + return 1; 228 + } 229 + 230 + size_t thread_info_index = 0; 231 + for (const Elf64_Nhdr* note_header = cprm.input_notes; note_header < (const Elf64_Nhdr*)((const char*)cprm.input_notes + cprm.input_notes_size); note_header = find_next_note(note_header)) { 232 + if (note_header->n_type == NT_PRSTATUS) { 233 + cprm.thread_infos[thread_info_index++].prstatus = note_data(note_header); 234 + } else { 235 + continue; 236 + } 237 + } 238 + 239 + // determine if we have extra mappings in NT_FILE that aren't present in the program headers (gcore tends to do this) 240 + for (size_t i = 0; i < cprm.nt_file->count; ++i) { 241 + const struct nt_file_entry* entry = &((const struct nt_file_entry*)((const char*)cprm.nt_file + sizeof(struct nt_file_header)))[i]; 242 + const char* filename = cprm.nt_file_filenames[i]; 243 + bool found = false; 244 + 245 + for (const Elf64_Phdr* program_header = cprm.input_program_headers; program_header < cprm.input_program_headers_end; program_header = (const Elf64_Phdr*)((const char*)program_header + cprm.input_header->e_phentsize)) { 246 + if (program_header->p_type != PT_LOAD) { 247 + continue; 248 + } 249 + 250 + if (entry->start == program_header->p_vaddr) { 251 + found = true; 252 + break; 253 + } 254 + } 255 + 256 + if (found) { 257 + continue; 258 + } 259 + 260 + ++cprm.vm_area_count; 261 + 262 + break; 263 + } 264 + 265 + // now allocate the VM area array 266 + cprm.vm_areas = malloc(sizeof(*cprm.vm_areas) * cprm.vm_area_count); 267 + if (!cprm.vm_areas) { 268 + perror("malloc"); 269 + return 1; 270 + } 271 + 272 + // now load up the VM area array 273 + size_t vm_area_index = 0; 274 + for (const Elf64_Phdr* program_header = cprm.input_program_headers; program_header < cprm.input_program_headers_end; program_header = (const Elf64_Phdr*)((const char*)program_header + cprm.input_header->e_phentsize)) { 275 + if (program_header->p_type == PT_LOAD) { 276 + struct vm_area* vm_area = &cprm.vm_areas[vm_area_index++]; 277 + 278 + vm_area->valid = true; 279 + vm_area->memory_address = program_header->p_vaddr; 280 + vm_area->memory_size = program_header->p_memsz; 281 + vm_area->file_offset = program_header->p_offset; 282 + 283 + vm_area->protection = 0; 284 + if (program_header->p_flags & PF_R) { 285 + vm_area->protection |= PROT_READ; 286 + } 287 + if (program_header->p_flags & PF_W) { 288 + vm_area->protection |= PROT_WRITE; 289 + } 290 + if (program_header->p_flags & PF_X) { 291 + vm_area->protection |= PROT_EXEC; 292 + } 293 + 294 + if (program_header->p_filesz == 0) { 295 + // contents contained within original file 296 + 297 + // in this case, the file size *should* be the same as the size in memory 298 + vm_area->file_size = vm_area->memory_size; 299 + 300 + // let's look for the NT_FILE entry 301 + const struct nt_file_entry* entries = (const struct nt_file_entry*)((const char*)cprm.nt_file + sizeof(struct nt_file_header)); 302 + for (size_t i = 0; i < cprm.nt_file->count; ++i) { 303 + const struct nt_file_entry* entry = &entries[i]; 304 + const char* filename = cprm.nt_file_filenames[i]; 305 + 306 + if (entry->start != vm_area->memory_address) { 307 + continue; 308 + } 309 + 310 + vm_area->filename = filename; 311 + vm_area->file_offset = entry->offset * cprm.nt_file->page_size; 312 + vm_area->file_size = entry->end - entry->start; 313 + 314 + break; 315 + } 316 + 317 + if (!vm_area->filename) { 318 + // ignore it if starts at 0; that's most likely the __PAGEZERO segment 319 + if (vm_area->memory_address != 0) { 320 + printf("warning: missing NT_FILE entry for zero-sized memory region\n"); 321 + } 322 + vm_area->valid = false; 323 + } 324 + } else { 325 + // contents contained within this corefile 326 + vm_area->filename = NULL; 327 + vm_area->file_size = program_header->p_filesz; 328 + } 329 + 330 + if (vm_area->memory_address == 0) { 331 + // overrides for the __PAGEZERO segment 332 + vm_area->valid = false; 333 + vm_area->file_size = 0; 334 + vm_area->protection = 0; 335 + } 336 + } 337 + } 338 + 339 + // load in extra mappings from NT_FILE 340 + for (size_t i = 0; i < cprm.nt_file->count; ++i) { 341 + const struct nt_file_entry* entry = &((const struct nt_file_entry*)((const char*)cprm.nt_file + sizeof(struct nt_file_header)))[i]; 342 + const char* filename = cprm.nt_file_filenames[i]; 343 + bool found = false; 344 + 345 + for (const Elf64_Phdr* program_header = cprm.input_program_headers; program_header < cprm.input_program_headers_end; program_header = (const Elf64_Phdr*)((const char*)program_header + cprm.input_header->e_phentsize)) { 346 + if (program_header->p_type != PT_LOAD) { 347 + continue; 348 + } 349 + 350 + if (entry->start == program_header->p_vaddr) { 351 + found = true; 352 + break; 353 + } 354 + } 355 + 356 + if (found) { 357 + continue; 358 + } 359 + 360 + struct vm_area* vm_area = &cprm.vm_areas[vm_area_index++]; 361 + 362 + vm_area->filename = filename; 363 + vm_area->memory_address = entry->start; 364 + vm_area->memory_size = entry->end - entry->start; 365 + vm_area->file_size = vm_area->memory_size; 366 + vm_area->file_offset = entry->offset * cprm.nt_file->page_size; 367 + vm_area->protection = VM_PROT_READ; 368 + vm_area->valid = true; 369 + 370 + break; 371 + } 372 + 373 + macho_coredump(&cprm); 374 + 375 + #warning TODO: cleanup 376 + 377 + return 0; 378 + }; 379 + 380 + static bool dump_emit(struct coredump_params* cprm, const void* buffer, size_t buffer_size) { 381 + return write(cprm->output_corefile, buffer, buffer_size) == buffer_size; 382 + }; 383 + 384 + static bool dump_skip(struct coredump_params* cprm, size_t size) { 385 + // leaving holes seems to confuse LLDB 386 + #if 0 387 + if (lseek(cprm->output_corefile, size, SEEK_CUR) < 0) { 388 + perror("lseek"); 389 + return false; 390 + } 391 + #else 392 + static char zeros[4096]; 393 + while (sizeof(zeros) < size) { 394 + if (!dump_emit(cprm, zeros, sizeof(zeros))) 395 + return false; 396 + size -= sizeof(zeros); 397 + } 398 + if (!dump_emit(cprm, zeros, size)) 399 + return false; 400 + #endif 401 + return true; 402 + }; 403 + 404 + // the following coredump code has been imported from the LKM and adapted for use in userspace 405 + 406 + struct thread_flavor 407 + { 408 + // preceded by struct thread_command and other flavors 409 + uint32_t flavor; 410 + uint32_t count; 411 + char state[0]; 412 + // followed by x86_thread_state32_t, for example 413 + }; 414 + 415 + static 416 + void fill_thread_state32(x86_thread_state32_t* state, const struct thread_info* info) 417 + { 418 + // TODO 419 + memset(state, 0, sizeof(*state)); 420 + } 421 + 422 + static 423 + void fill_float_state32(x86_float_state32_t* state, const struct thread_info* info) 424 + { 425 + // TODO 426 + memset(state, 0, sizeof(*state)); 427 + } 428 + 429 + static 430 + void fill_thread_state64(x86_thread_state64_t* state, const struct thread_info* info) 431 + { 432 + state->rax = info->prstatus->general_registers.ax; 433 + state->rbx = info->prstatus->general_registers.bx; 434 + state->rcx = info->prstatus->general_registers.cx; 435 + state->rdx = info->prstatus->general_registers.dx; 436 + state->rdi = info->prstatus->general_registers.di; 437 + state->rsi = info->prstatus->general_registers.si; 438 + state->rbp = info->prstatus->general_registers.bp; 439 + state->rsp = info->prstatus->general_registers.sp; 440 + state->r8 = info->prstatus->general_registers.r8; 441 + state->r9 = info->prstatus->general_registers.r9; 442 + state->r10 = info->prstatus->general_registers.r10; 443 + state->r11 = info->prstatus->general_registers.r11; 444 + state->r12 = info->prstatus->general_registers.r12; 445 + state->r13 = info->prstatus->general_registers.r13; 446 + state->r14 = info->prstatus->general_registers.r14; 447 + state->r15 = info->prstatus->general_registers.r15; 448 + state->rip = info->prstatus->general_registers.ip; 449 + state->rflags = info->prstatus->general_registers.flags; 450 + state->cs = info->prstatus->general_registers.cs; 451 + state->fs = info->prstatus->general_registers.fs; 452 + state->gs = info->prstatus->general_registers.gs; 453 + } 454 + 455 + static 456 + void fill_float_state64(x86_float_state64_t* state, const struct thread_info* info) 457 + { 458 + // TODO 459 + memset(state, 0, sizeof(*state)); 460 + } 461 + 462 + static 463 + bool macho_dump_headers32(struct coredump_params* cprm) 464 + { 465 + // Count memory segments and threads 466 + unsigned int segs = cprm->vm_area_count; 467 + unsigned int threads = cprm->thread_info_count; 468 + 469 + struct mach_header mh; 470 + 471 + mh.magic = MH_MAGIC; 472 + #ifdef __x86_64__ 473 + mh.cputype = CPU_TYPE_X86; 474 + mh.cpusubtype = CPU_SUBTYPE_X86_ALL; 475 + #else 476 + #error Missing code for this arch 477 + #endif 478 + mh.filetype = MH_CORE; 479 + mh.ncmds = segs + threads; 480 + 481 + const int statesize = sizeof(x86_thread_state32_t) + sizeof(x86_float_state32_t) + sizeof(struct thread_flavor) * 2; 482 + 483 + mh.sizeofcmds = segs * sizeof(struct segment_command) + threads * (sizeof(struct thread_command) + statesize); 484 + 485 + if (!dump_emit(cprm, &mh, sizeof(mh))) 486 + goto fail; 487 + 488 + uint32_t file_offset = mh.sizeofcmds + sizeof(mh); 489 + 490 + for (size_t i = 0; i < cprm->vm_area_count; ++i) { 491 + const struct vm_area* vma = &cprm->vm_areas[i]; 492 + struct segment_command sc; 493 + 494 + sc.cmd = LC_SEGMENT; 495 + sc.cmdsize = sizeof(sc); 496 + sc.segname[0] = 0; 497 + sc.nsects = 0; 498 + sc.flags = 0; 499 + sc.vmaddr = vma->memory_address; 500 + sc.vmsize = vma->memory_size; 501 + sc.fileoff = file_offset; 502 + 503 + if (sc.vmaddr > 0) // avoid dumping the __PAGEZERO segment which may be really large 504 + sc.filesize = vma->file_size; 505 + else 506 + sc.filesize = 0; 507 + sc.initprot = 0; 508 + 509 + if (vma->protection & PROT_READ) 510 + sc.initprot |= VM_PROT_READ; 511 + if (vma->protection & PROT_WRITE) 512 + sc.initprot |= VM_PROT_WRITE; 513 + if (vma->protection & PROT_EXEC) 514 + sc.initprot |= VM_PROT_EXECUTE; 515 + sc.maxprot = sc.initprot; 516 + 517 + if (!dump_emit(cprm, &sc, sizeof(sc))) 518 + goto fail; 519 + 520 + file_offset += sc.filesize; 521 + } 522 + 523 + const int memsize = sizeof(struct thread_command) + statesize; 524 + uint8_t* buffer = malloc(memsize); 525 + 526 + for (size_t i = 0; i < cprm->thread_info_count; ++i) { 527 + const struct thread_info* thread_info = &cprm->thread_infos[i]; 528 + struct thread_command* tc = (struct thread_command*) buffer; 529 + struct thread_flavor* tf = (struct thread_flavor*)(tc+1); 530 + 531 + tc->cmd = LC_THREAD; 532 + tc->cmdsize = memsize; 533 + 534 + // General registers 535 + tf->flavor = x86_THREAD_STATE32; 536 + tf->count = x86_THREAD_STATE32_COUNT; 537 + 538 + fill_thread_state32((x86_thread_state32_t*)tf->state, thread_info); 539 + 540 + // Float registers 541 + tf = (struct thread_flavor*) (((char*) tf) + sizeof(x86_thread_state32_t)); 542 + tf->flavor = x86_FLOAT_STATE32; 543 + tf->count = x86_FLOAT_STATE32_COUNT; 544 + 545 + fill_float_state32((x86_float_state32_t*)tf->state, thread_info); 546 + 547 + if (!dump_emit(cprm, buffer, memsize)) 548 + { 549 + free(buffer); 550 + goto fail; 551 + } 552 + } 553 + free(buffer); 554 + 555 + return true; 556 + fail: 557 + return false; 558 + } 559 + 560 + static 561 + bool macho_dump_headers64(struct coredump_params* cprm) 562 + { 563 + // Count memory segments and threads 564 + unsigned int segs = cprm->vm_area_count; 565 + unsigned int threads = cprm->thread_info_count; 566 + struct mach_header_64 mh; 567 + 568 + mh.magic = MH_MAGIC_64; 569 + #ifdef __x86_64__ 570 + mh.cputype = CPU_TYPE_X86_64; 571 + mh.cpusubtype = CPU_SUBTYPE_X86_64_ALL; 572 + #else 573 + #warning Missing code for this arch 574 + #endif 575 + mh.filetype = MH_CORE; 576 + mh.ncmds = segs + threads; 577 + 578 + const int statesize = sizeof(x86_thread_state64_t) + sizeof(x86_float_state64_t) + sizeof(struct thread_flavor) * 2; 579 + mh.sizeofcmds = segs * sizeof(struct segment_command_64) + threads * (sizeof(struct thread_command) + statesize); 580 + mh.reserved = 0; 581 + 582 + if (!dump_emit(cprm, &mh, sizeof(mh))) 583 + goto fail; 584 + 585 + struct vm_area_struct* vma; 586 + uint32_t file_offset = mh.sizeofcmds + sizeof(mh); 587 + 588 + for (size_t i = 0; i < cprm->vm_area_count; ++i) { 589 + const struct vm_area* vma = &cprm->vm_areas[i]; 590 + struct segment_command_64 sc; 591 + 592 + sc.cmd = LC_SEGMENT_64; 593 + sc.cmdsize = sizeof(sc); 594 + sc.segname[0] = 0; 595 + sc.nsects = 0; 596 + sc.flags = 0; 597 + sc.vmaddr = vma->memory_address; 598 + sc.vmsize = vma->memory_size; 599 + sc.fileoff = file_offset; 600 + 601 + if (sc.vmaddr > 0) // avoid dumping the __PAGEZERO segment which may be really large 602 + sc.filesize = vma->file_size; 603 + else 604 + sc.filesize = 0; 605 + sc.initprot = 0; 606 + 607 + if (vma->protection & PROT_READ) 608 + sc.initprot |= VM_PROT_READ; 609 + if (vma->protection & PROT_WRITE) 610 + sc.initprot |= VM_PROT_WRITE; 611 + if (vma->protection & PROT_EXEC) 612 + sc.initprot |= VM_PROT_EXECUTE; 613 + sc.maxprot = sc.initprot; 614 + 615 + if (!dump_emit(cprm, &sc, sizeof(sc))) 616 + goto fail; 617 + 618 + file_offset += sc.filesize; 619 + } 620 + 621 + const int memsize = sizeof(struct thread_command) + statesize; 622 + uint8_t* buffer = malloc(memsize); 623 + 624 + for (size_t i = 0; i < cprm->thread_info_count; ++i) { 625 + const struct thread_info* thread_info = &cprm->thread_infos[i]; 626 + struct thread_command* tc = (struct thread_command*) buffer; 627 + struct thread_flavor* tf = (struct thread_flavor*)(tc+1); 628 + 629 + tc->cmd = LC_THREAD; 630 + tc->cmdsize = memsize; 631 + 632 + // General registers 633 + tf->flavor = x86_THREAD_STATE64; 634 + tf->count = x86_THREAD_STATE64_COUNT; 635 + 636 + fill_thread_state64((x86_thread_state64_t*)tf->state, thread_info); 637 + 638 + // Float registers 639 + tf = (struct thread_flavor*) (tf->state + sizeof(x86_thread_state64_t)); 640 + tf->flavor = x86_FLOAT_STATE64; 641 + tf->count = x86_FLOAT_STATE64_COUNT; 642 + 643 + fill_float_state64((x86_float_state64_t*)tf->state, thread_info); 644 + 645 + if (!dump_emit(cprm, buffer, memsize)) 646 + { 647 + free(buffer); 648 + goto fail; 649 + } 650 + } 651 + free(buffer); 652 + 653 + return true; 654 + fail: 655 + return false; 656 + } 657 + 658 + void macho_coredump(struct coredump_params* cprm) 659 + { 660 + #warning TODO: 32-bit coredump support 661 + #if TODO 662 + // Write the Mach-O header and loader commands 663 + if (!check_64bit_mode(current_pt_regs())) 664 + { 665 + // 32-bit executables 666 + if (!macho_dump_headers32(cprm)) 667 + exit(EXIT_FAILURE); 668 + } 669 + else 670 + #endif 671 + { 672 + // 64-bit executables 673 + if (!macho_dump_headers64(cprm)) 674 + exit(EXIT_FAILURE); 675 + } 676 + 677 + // Dump memory contents 678 + 679 + // Inspired by elf_core_dump() 680 + for (size_t i = 0; i < cprm->vm_area_count; ++i) { 681 + const struct vm_area* vma = &cprm->vm_areas[i]; 682 + unsigned long addr; 683 + 684 + if (vma->memory_address == 0) 685 + continue; // skip __PAGEZERO dumping 686 + 687 + if (!vma->valid) { 688 + if (!dump_skip(cprm, vma->file_size)) 689 + exit(EXIT_FAILURE); 690 + } else { 691 + if (vma->filename) { 692 + int fd = open(vma->filename, O_RDONLY); 693 + if (fd < 0) { 694 + fprintf(stderr, "Failed to open %s: %d (%s)\n", vma->filename, errno, strerror(errno)); 695 + exit(EXIT_FAILURE); 696 + } 697 + 698 + uintptr_t aligned_offset = round_down_pow2(vma->file_offset, sysconf(_SC_PAGESIZE)); 699 + size_t aligned_size = round_up_pow2(vma->file_size, _SC_PAGESIZE); 700 + void* mapping = mmap(NULL, aligned_size, PROT_READ, MAP_PRIVATE, fd, aligned_offset); 701 + if (mapping == MAP_FAILED) { 702 + perror("mmap"); 703 + exit(EXIT_FAILURE); 704 + } 705 + const void* start = (const char*)mapping + (vma->file_offset - aligned_offset); 706 + 707 + if (!dump_emit(cprm, start, vma->file_size)) 708 + exit(EXIT_FAILURE); 709 + 710 + if (munmap(mapping, aligned_size) < 0) { 711 + perror("munmap"); 712 + exit(EXIT_FAILURE); 713 + } 714 + 715 + close(fd); 716 + } else { 717 + if (!dump_emit(cprm, (const char*)cprm->input_corefile_mapping + vma->file_offset, vma->file_size)) 718 + exit(EXIT_FAILURE); 719 + } 720 + } 721 + } 722 + }
+211
src/hosttools/src/coredump/x86_64.h
··· 1 + #ifndef _DARLING_COREDUMP_X86_64_H_ 2 + #define _DARLING_COREDUMP_X86_64_H_ 3 + 4 + #include <stdint.h> 5 + 6 + struct nt_prstatus_registers { 7 + unsigned long r15; 8 + unsigned long r14; 9 + unsigned long r13; 10 + unsigned long r12; 11 + unsigned long bp; 12 + unsigned long bx; 13 + unsigned long r11; 14 + unsigned long r10; 15 + unsigned long r9; 16 + unsigned long r8; 17 + unsigned long ax; 18 + unsigned long cx; 19 + unsigned long dx; 20 + unsigned long si; 21 + unsigned long di; 22 + unsigned long orig_ax; 23 + unsigned long ip; 24 + unsigned long cs; 25 + unsigned long flags; 26 + unsigned long sp; 27 + unsigned long ss; 28 + unsigned long fs_base; 29 + unsigned long gs_base; 30 + unsigned long ds; 31 + unsigned long es; 32 + unsigned long fs; 33 + unsigned long gs; 34 + }; 35 + 36 + typedef struct x86_thread_state32 { 37 + unsigned int eax; 38 + unsigned int ebx; 39 + unsigned int ecx; 40 + unsigned int edx; 41 + unsigned int edi; 42 + unsigned int esi; 43 + unsigned int ebp; 44 + unsigned int esp; 45 + unsigned int ss; 46 + unsigned int eflags; 47 + unsigned int eip; 48 + unsigned int cs; 49 + unsigned int ds; 50 + unsigned int es; 51 + unsigned int fs; 52 + unsigned int gs; 53 + } x86_thread_state32_t; 54 + 55 + struct fpu_mmst { 56 + char mmst_reg[10]; 57 + char mmst_rsrv[6]; 58 + }; 59 + 60 + struct fpu_xmm { 61 + char xmm_reg[16]; 62 + }; 63 + 64 + struct fpu_control { 65 + unsigned short 66 + invalid: 1, 67 + denorm: 1, 68 + zdiv: 1, 69 + ovrfl: 1, 70 + undfl: 1, 71 + precis: 1, 72 + : 2, 73 + pc: 2, 74 + rc: 2, 75 + /*inf*/: 1, 76 + :3; 77 + }; 78 + 79 + struct fpu_status { 80 + unsigned short 81 + invalid: 1, 82 + denorm: 1, 83 + zdiv: 1, 84 + ovrfl: 1, 85 + undfl: 1, 86 + precis: 1, 87 + stkflt: 1, 88 + errsumm: 1, 89 + c0: 1, 90 + c1: 1, 91 + c2: 1, 92 + tos: 3, 93 + c3: 1, 94 + busy: 1; 95 + }; 96 + 97 + typedef struct x86_float_state32 { 98 + int fpu_reserved[2]; 99 + struct fpu_control fpu_fcw; 100 + struct fpu_status fpu_fsw; 101 + uint8_t fpu_ftw; 102 + uint8_t fpu_rsrv1; 103 + uint16_t fpu_fop; 104 + uint32_t fpu_ip; 105 + uint16_t fpu_cs; 106 + uint16_t fpu_rsrv2; 107 + uint32_t fpu_dp; 108 + uint16_t fpu_ds; 109 + uint16_t fpu_rsrv3; 110 + uint32_t fpu_mxcsr; 111 + uint32_t fpu_mxcsrmask; 112 + struct fpu_mmst fpu_stmm0; 113 + struct fpu_mmst fpu_stmm1; 114 + struct fpu_mmst fpu_stmm2; 115 + struct fpu_mmst fpu_stmm3; 116 + struct fpu_mmst fpu_stmm4; 117 + struct fpu_mmst fpu_stmm5; 118 + struct fpu_mmst fpu_stmm6; 119 + struct fpu_mmst fpu_stmm7; 120 + struct fpu_xmm fpu_xmm0; 121 + struct fpu_xmm fpu_xmm1; 122 + struct fpu_xmm fpu_xmm2; 123 + struct fpu_xmm fpu_xmm3; 124 + struct fpu_xmm fpu_xmm4; 125 + struct fpu_xmm fpu_xmm5; 126 + struct fpu_xmm fpu_xmm6; 127 + struct fpu_xmm fpu_xmm7; 128 + char fpu_rsrv4[14 * 16]; 129 + int fpu_reserved1; 130 + } x86_float_state32_t; 131 + 132 + typedef struct x86_thread_state64 { 133 + uint64_t rax; 134 + uint64_t rbx; 135 + uint64_t rcx; 136 + uint64_t rdx; 137 + uint64_t rdi; 138 + uint64_t rsi; 139 + uint64_t rbp; 140 + uint64_t rsp; 141 + uint64_t r8; 142 + uint64_t r9; 143 + uint64_t r10; 144 + uint64_t r11; 145 + uint64_t r12; 146 + uint64_t r13; 147 + uint64_t r14; 148 + uint64_t r15; 149 + uint64_t rip; 150 + uint64_t rflags; 151 + uint64_t cs; 152 + uint64_t fs; 153 + uint64_t gs; 154 + } x86_thread_state64_t; 155 + 156 + typedef struct x86_float_state64 { 157 + int fpu_reserved[2]; 158 + struct fpu_control fpu_fcw; 159 + struct fpu_status fpu_fsw; 160 + uint8_t fpu_ftw; 161 + uint8_t fpu_rsrv1; 162 + uint16_t fpu_fop; 163 + uint32_t fpu_ip; 164 + uint16_t fpu_cs; 165 + uint16_t fpu_rsrv2; 166 + uint32_t fpu_dp; 167 + uint16_t fpu_ds; 168 + uint16_t fpu_rsrv3; 169 + uint32_t fpu_mxcsr; 170 + uint32_t fpu_mxcsrmask; 171 + struct fpu_mmst fpu_stmm0; 172 + struct fpu_mmst fpu_stmm1; 173 + struct fpu_mmst fpu_stmm2; 174 + struct fpu_mmst fpu_stmm3; 175 + struct fpu_mmst fpu_stmm4; 176 + struct fpu_mmst fpu_stmm5; 177 + struct fpu_mmst fpu_stmm6; 178 + struct fpu_mmst fpu_stmm7; 179 + struct fpu_xmm fpu_xmm0; 180 + struct fpu_xmm fpu_xmm1; 181 + struct fpu_xmm fpu_xmm2; 182 + struct fpu_xmm fpu_xmm3; 183 + struct fpu_xmm fpu_xmm4; 184 + struct fpu_xmm fpu_xmm5; 185 + struct fpu_xmm fpu_xmm6; 186 + struct fpu_xmm fpu_xmm7; 187 + struct fpu_xmm fpu_xmm8; 188 + struct fpu_xmm fpu_xmm9; 189 + struct fpu_xmm fpu_xmm10; 190 + struct fpu_xmm fpu_xmm11; 191 + struct fpu_xmm fpu_xmm12; 192 + struct fpu_xmm fpu_xmm13; 193 + struct fpu_xmm fpu_xmm14; 194 + struct fpu_xmm fpu_xmm15; 195 + char fpu_rsrv4[6 * 16]; 196 + int fpu_reserved1; 197 + } x86_float_state64_t; 198 + 199 + #define x86_THREAD_STATE32 1 200 + #define x86_FLOAT_STATE32 2 201 + #define x86_THREAD_STATE64 4 202 + #define x86_FLOAT_STATE64 5 203 + 204 + #define x86_THREAD_STATE32_COUNT ((uint32_t)(sizeof(x86_thread_state32_t) / sizeof(int))) 205 + #define x86_FLOAT_STATE32_COUNT ((uint32_t)(sizeof(x86_float_state32_t) / sizeof(unsigned int))) 206 + 207 + 208 + #define x86_THREAD_STATE64_COUNT ((uint32_t)(sizeof(x86_thread_state64_t) / sizeof(int))) 209 + #define x86_FLOAT_STATE64_COUNT ((uint32_t)(sizeof(x86_float_state64_t) / sizeof(unsigned int))) 210 + 211 + #endif // _DARLING_COREDUMP_X86_64_H_
+12 -11
src/kernel/emulation/linux/bsdthread/bsdthread_register.c
··· 3 3 #include "../errno.h" 4 4 #include <sys/errno.h> 5 5 #include "../signal/sigexc.h" 6 - #include "../mach/lkm.h" 7 - #include "../../../../external/lkm/api.h" 6 + #include <darlingserver/rpc.h> 8 7 #include <stdint.h> 9 8 #include <pthread/tsd_private.h> 10 9 #include <linux-syscalls/linux.h> 10 + #include "../simple.h" 11 11 12 12 int pthread_obj_size; 13 13 bsdthread_entry_t pthread_entry_point; ··· 40 40 wqueue_entry_point = (bsdwqthread_entry_t) wqthread; 41 41 g_pth_regdata = *pth_regdata; 42 42 43 - struct set_thread_handles_args args; 44 - args.pthread_handle = (unsigned long) _pthread_getspecific_direct(_PTHREAD_TSD_SLOT_PTHREAD_SELF); 45 - args.dispatch_qaddr = args.pthread_handle + g_pth_regdata.tsd_offset + g_pth_regdata.dispatch_queue_offset; 46 - 47 - lkm_call(NR_set_thread_handles, &args); 43 + uintptr_t pthread_handle = _pthread_getspecific_direct(_PTHREAD_TSD_SLOT_PTHREAD_SELF); 44 + uintptr_t dispatch_qaddr = pthread_handle + g_pth_regdata.tsd_offset + g_pth_regdata.dispatch_queue_offset; 45 + if (dserver_rpc_set_thread_handles(pthread_handle, dispatch_qaddr) < 0) { 46 + __simple_abort(); 47 + } 48 48 49 49 return /* WORKQ_FEATURE_KEVENT | WORKQ_FEATURE_FINEPRIO | PTHREAD_FEATURE_QOS_MAINTENANCE 50 50 | PTHREAD_FEATURE_DISPATCHFUNC | PTHREAD_FEATURE_QOS_DEFAULT */ 0; ··· 55 55 { 56 56 sigexc_thread_setup(); 57 57 58 - struct set_thread_handles_args args; 59 - args.pthread_handle = (unsigned long) self; 60 - args.dispatch_qaddr = args.pthread_handle + g_pth_regdata.tsd_offset + g_pth_regdata.dispatch_queue_offset; 58 + uintptr_t pthread_handle = (unsigned long) self; 59 + uintptr_t dispatch_qaddr = pthread_handle + g_pth_regdata.tsd_offset + g_pth_regdata.dispatch_queue_offset; 60 + if (dserver_rpc_set_thread_handles(pthread_handle, dispatch_qaddr) < 0) { 61 + __simple_abort(); 62 + } 61 63 62 - lkm_call(NR_set_thread_handles, &args); 63 64 pthread_entry_point(self, thread_port, funptr, funarg, stack_addr, flags); 64 65 } 65 66
+7 -6
src/kernel/emulation/linux/mach/mach_traps.c
··· 390 390 mach_port_name_t name 391 391 ) 392 392 { 393 - struct mach_port_deallocate_args args = { 394 - .task_right_name = target, 395 - .port_right_name = name 396 - }; 393 + int code = dserver_rpc_mach_port_deallocate(target, name); 394 + 395 + if (code < 0) { 396 + __simple_printf("mach_port_deallocate failed (internally): %d\n", code); 397 + __simple_abort(); 398 + } 397 399 398 - return lkm_call(NR__kernelrpc_mach_port_deallocate, 399 - &args); 400 + return code; 400 401 } 401 402 402 403 kern_return_t _kernelrpc_mach_port_mod_refs_trap_impl(
+111 -6
src/kernel/emulation/linux/process/execve.c
··· 17 17 #include "../bsdthread/per_thread_wd.h" 18 18 #include "../simple.h" 19 19 20 + #include <darlingserver/rpc.h> 21 + #include "../unistd/write.h" 22 + #include <mach-o/loader.h> 23 + #include <mach-o/fat.h> 24 + 25 + #undef memcpy 26 + #include "../resources/dserver-rpc-defs.h" 20 27 extern bool isspace(char c); 21 28 22 29 static inline bool istext(char c) ··· 24 31 return c >= 0x20 && c < 0x7F; 25 32 } 26 33 27 - long sys_execve(char* fname, char** argvp, char** envp) 34 + long sys_execve(const char* fname, const char** argvp, const char** envp) 28 35 { 29 36 int ret; 30 37 struct vchroot_expand_args vc; 38 + char mldr_path[4096]; 39 + uint64_t mldr_path_length; 40 + const char* path_to_exec = vc.path; 41 + 42 + ret = dserver_rpc_mldr_path(mldr_path, sizeof(mldr_path), &mldr_path_length); 43 + if (ret < 0) { 44 + return errno_linux_to_bsd(ret); 45 + } 31 46 32 47 vc.flags = VCHROOT_FOLLOW; 33 48 vc.dfd = get_perthread_wd(); ··· 51 66 close_internal(fd); 52 67 53 68 bool is_script = false; 54 - 55 - if (ret >= 4) 69 + bool is_macho = false; 70 + 71 + if (ret < 4) { 72 + return -ENOEXEC; 73 + } 74 + 75 + //if (ret >= 4) 56 76 { 57 77 is_script = shebang[0] == '#' && shebang[1] == '!'; 58 78 if (!is_script) ··· 65 85 } 66 86 } 67 87 88 + uint32_t magic = *(uint32_t*)shebang; 89 + is_macho = magic == MH_MAGIC || magic == MH_CIGAM || magic == MH_MAGIC_64 || magic == MH_CIGAM_64 || magic == FAT_MAGIC || magic == FAT_CIGAM; 90 + 68 91 if (is_script) 69 92 { 70 93 char *nl, *interp, *arg; 71 - char** modargvp; 94 + const char** modargvp; 72 95 int i, j, len = 0; 73 96 74 97 nl = memchr(shebang, '\n', ret); ··· 101 124 while (argvp[len++]); 102 125 103 126 // Allocate a new argvp 104 - modargvp = (char**) __builtin_alloca(sizeof(void*) * (len+2)); 127 + modargvp = (const char**) __builtin_alloca(sizeof(void*) * (len+3)); 105 128 106 129 i = 0; 130 + modargvp[i++] = mldr_path; 107 131 modargvp[i++] = interp; 108 132 if (arg != NULL) 109 133 modargvp[i++] = arg; ··· 119 143 ret = vchroot_expand(&vc); 120 144 if (ret < 0) 121 145 return ret; 146 + 147 + path_to_exec = mldr_path; 148 + } else if (is_macho) { 149 + const char** modargvp; 150 + char *buf; 151 + int len = 0; 152 + 153 + // count original arguments 154 + while (argvp[len++]); 155 + 156 + // allocate a new argvp and argv0 157 + modargvp = (const char**) __builtin_alloca(sizeof(void*) * (len+1)); 158 + buf = __builtin_alloca(strlen(mldr_path) + 2 + strlen(vc.path)); 159 + 160 + // set up the new argv0 (mldr path + "!" + executable path) 161 + strcpy(buf, mldr_path); 162 + strcat(buf, "!"); 163 + strcat(buf, vc.path); 164 + modargvp[0] = buf; 165 + 166 + // append original arguments 167 + for (int i = 1; i < len+1; i++) 168 + modargvp[i] = argvp[i-1]; 169 + 170 + argvp = modargvp; 171 + path_to_exec = mldr_path; 122 172 } 123 173 174 + // set up the __mldr_sockpath env var if we're executing mldr 175 + if (is_script || is_macho) { 176 + const char** modenvp; 177 + char* buf; 178 + int len = 0; 179 + struct linux_sockaddr_un* server_socket_address = dserver_rpc_hooks_get_server_address(); 180 + const char* server_socket_path = server_socket_address->sun_path; 181 + 182 + // count original env vars 183 + while (envp[len++]); 184 + 185 + // allocate a new envp and env0 186 + modenvp = (const char**)__builtin_alloca(sizeof(void*) * (len + 1)); 187 + buf = __builtin_alloca(strlen(server_socket_path) + sizeof("__mldr_sockpath=")); 188 + 189 + // set up the new env0 190 + strcpy(buf, "__mldr_sockpath="); 191 + strcat(buf, server_socket_path); 192 + modenvp[0] = buf; 193 + 194 + // append original env vars 195 + for (int i = 1; i < len+1; i++) 196 + modenvp[i] = envp[i-1]; 197 + 198 + envp = modenvp; 199 + } 200 + 201 + // otherwise it's a Linux executable (ELF or something else binfmt handles); 202 + // this is the default 203 + 124 204 linux_sigset_t set; 125 205 set = (1ull << (SIGNAL_SIGEXC_SUSPEND-1)); 126 206 //set |= (1ull << (SIGNAL_SIGEXC_THUPDATE-1)); 127 207 208 + // darlingserver needs to know whether the execve completes successfully or not. 209 + // since pidfds don't notify on execve, we have to use a pipe with close-on-exec 210 + // that darlingserver will monitor. if it reads EOF, it knows the execve succeeded. 211 + // if it reads a single byte (that we send it), it knows the execve failed. 212 + 213 + int dserver_execve_pipe[2]; 214 + 215 + // open a pipe with FD_CLOEXEC set 216 + ret = LINUX_SYSCALL(__NR_pipe2, dserver_execve_pipe, LINUX_O_CLOEXEC); 217 + if (ret < 0) 218 + return errno_linux_to_bsd(ret); 219 + 220 + // send a copy of the read end to the server (along with whether or not we're executing another Darling-managed binary) 221 + ret = dserver_rpc_checkout(dserver_execve_pipe[0], is_script || is_macho); 222 + if (ret < 0) 223 + return errno_linux_to_bsd(ret); 224 + 225 + // close the read end for ourselves 226 + close_internal(dserver_execve_pipe[0]); 227 + 128 228 LINUX_SYSCALL(__NR_rt_sigprocmask, 0 /* LINUX_SIG_BLOCK */, 129 229 &set, NULL, sizeof(linux_sigset_t)); 130 230 131 - ret = LINUX_SYSCALL(__NR_execve, vc.path, argvp, envp); 231 + ret = LINUX_SYSCALL(__NR_execve, path_to_exec, argvp, envp); 132 232 if (ret < 0) 133 233 ret = errno_linux_to_bsd(ret); 234 + 235 + // the execve failed; write to the write end of the pipe. 236 + // ignore errors. 237 + sys_write_nocancel(dserver_execve_pipe[1], "\x01", 1); 238 + close_internal(dserver_execve_pipe[1]); 134 239 135 240 LINUX_SYSCALL(__NR_rt_sigprocmask, 1 /* LINUX_SIG_UNBLOCK */, 136 241 &set, NULL, sizeof(linux_sigset_t));
+1 -1
src/kernel/emulation/linux/process/execve.h
··· 1 1 #ifndef LINUX_EXECVE_H 2 2 #define LINUX_EXECVE_H 3 3 4 - long sys_execve(char* fname, char** argvp, char** envp); 4 + long sys_execve(const char* fname, const char** argvp, const char** envp); 5 5 6 6 #endif 7 7
+9
src/kernel/emulation/linux/process/fork.c
··· 6 6 #include "../unistd/fchdir.h" 7 7 #include <linux-syscalls/linux.h> 8 8 9 + #include <darlingserver/rpc.h> 10 + #include "../simple.h" 11 + 9 12 long sys_fork(void) 10 13 { 11 14 int ret; ··· 20 23 ret = errno_linux_to_bsd(ret); 21 24 else if (ret == 0) 22 25 { 26 + // in the child 27 + if (dserver_rpc_checkin(true) < 0) { 28 + // we can't do ANYTHING if darlingserver fails to acknowledge us 29 + __simple_printf("Failed to checkin with darlingserver after fork\n"); 30 + __simple_abort(); 31 + } 23 32 if (wdfd >= 0) 24 33 sys_fchdir(wdfd); 25 34 }
+5 -11
src/kernel/emulation/linux/process/vfork.c
··· 4 4 #include "../signal/duct_signals.h" 5 5 #include <linux-syscalls/linux.h> 6 6 7 + #include "fork.h" 8 + 7 9 long sys_vfork(void) 8 10 { 9 - int ret; 10 - 11 - #ifdef SYS_fork 12 - ret = LINUX_SYSCALL(__NR_fork); 13 - #else 14 - ret = LINUX_SYSCALL(__NR_clone, LINUX_SIGCHLD, 0); 15 - #endif 16 - if (ret < 0) 17 - ret = errno_linux_to_bsd(ret); 18 - 19 - return ret; 11 + // this used to be a separate implementation, but it did everything exactly the same as sys_fork, 12 + // so now it just calls sys_fork to avoid duplicating code 13 + return sys_fork(); 20 14 } 21 15
-5
src/kernel/emulation/linux/unistd/close.c
··· 22 22 return 0; 23 23 } 24 24 25 - struct closing_descriptor_args args = { 26 - .fd = fd, 27 - }; 28 - lkm_call(NR_closing_descriptor, &args); 29 - 30 25 ret = LINUX_SYSCALL1(__NR_close, fd); 31 26 if (ret < 0) 32 27 ret = errno_linux_to_bsd(ret);
-7
src/kernel/emulation/linux/unistd/dup2.c
··· 10 10 { 11 11 int ret; 12 12 13 - if (fd_from != fd_to) { 14 - struct closing_descriptor_args args = { 15 - .fd = fd_to, 16 - }; 17 - lkm_call(NR_closing_descriptor, &args); 18 - } 19 - 20 13 #if defined(__NR_dup2) 21 14 ret = LINUX_SYSCALL2(__NR_dup2, fd_from, fd_to); 22 15 #else
+7 -5
src/kernel/emulation/linux/unistd/getegid.c
··· 1 1 #include "getegid.h" 2 2 #include "../base.h" 3 3 #include <stddef.h> 4 - #include "../mach/lkm.h" 5 - #include "../../../../external/lkm/api.h" 4 + #include <darlingserver/rpc.h> 5 + #include "../simple.h" 6 6 7 7 long sys_getegid(void) 8 8 { 9 - struct uidgid ug; 10 - lkm_call(NR_getuidgid, &ug); 11 - return ug.gid; 9 + int32_t gid; 10 + if (dserver_rpc_uidgid(-1, -1, NULL, &gid) < 0) { 11 + __simple_abort(); 12 + } 13 + return gid; 12 14 } 13 15
+7 -5
src/kernel/emulation/linux/unistd/geteuid.c
··· 1 1 #include "geteuid.h" 2 2 #include "../base.h" 3 3 #include <stddef.h> 4 - #include "../mach/lkm.h" 5 - #include "../../../../external/lkm/api.h" 4 + #include <darlingserver/rpc.h> 5 + #include "../simple.h" 6 6 7 7 long sys_geteuid(void) 8 8 { 9 - struct uidgid ug; 10 - lkm_call(NR_getuidgid, &ug); 11 - return ug.uid; 9 + int32_t uid; 10 + if (dserver_rpc_uidgid(-1, -1, &uid, NULL) < 0) { 11 + __simple_abort(); 12 + } 13 + return uid; 12 14 } 13 15
+7 -5
src/kernel/emulation/linux/unistd/getgid.c
··· 1 1 #include "getgid.h" 2 2 #include "../base.h" 3 3 #include <stddef.h> 4 - #include "../mach/lkm.h" 5 - #include "../../../../external/lkm/api.h" 4 + #include <darlingserver/rpc.h> 5 + #include "../simple.h" 6 6 7 7 long sys_getgid(void) 8 8 { 9 - struct uidgid ug; 10 - lkm_call(NR_getuidgid, &ug); 11 - return ug.gid; 9 + int32_t gid; 10 + if (dserver_rpc_uidgid(-1, -1, NULL, &gid) < 0) { 11 + __simple_abort(); 12 + } 13 + return gid; 12 14 } 13 15
+5 -10
src/kernel/emulation/linux/unistd/gettid.c
··· 1 1 #include "gettid.h" 2 2 #include "../base.h" 3 3 #include <stddef.h> 4 - #include "../mach/lkm.h" 5 - #include "../../../../external/lkm/api.h" 4 + #include <darlingserver/rpc.h> 5 + #include "../simple.h" 6 6 7 7 long sys_gettid(int* uid, int* gid) 8 8 { 9 - struct uidgid ug; 10 - lkm_call(NR_getuidgid, &ug); 11 - 12 - if (uid) 13 - *uid = ug.uid; 14 - 15 - if (gid) 16 - *gid = ug.gid; 9 + if (dserver_rpc_uidgid(-1, -1, uid, gid) < 0) { 10 + __simple_abort(); 11 + } 17 12 18 13 return 0; 19 14 }
+7 -5
src/kernel/emulation/linux/unistd/getuid.c
··· 1 1 #include "getuid.h" 2 2 #include "../base.h" 3 3 #include <stddef.h> 4 - #include "../mach/lkm.h" 5 - #include "../../../../external/lkm/api.h" 4 + #include <darlingserver/rpc.h> 5 + #include "../simple.h" 6 6 7 7 long sys_getuid(void) 8 8 { 9 - struct uidgid ug; 10 - lkm_call(NR_getuidgid, &ug); 11 - return ug.uid; 9 + int32_t uid; 10 + if (dserver_rpc_uidgid(-1, -1, &uid, NULL) < 0) { 11 + __simple_abort(); 12 + } 13 + return uid; 12 14 } 13 15
+4 -8
src/kernel/emulation/linux/unistd/setegid.c
··· 1 1 #include "setegid.h" 2 2 #include "../base.h" 3 - #include "../mach/lkm.h" 4 - #include "../../../../external/lkm/api.h" 3 + #include <darlingserver/rpc.h> 4 + #include "../errno.h" 5 + #include <stddef.h> 5 6 6 7 long sys_setegid(int egid) 7 8 { 8 - struct uidgid ug = { 9 - .uid = -1, 10 - .gid = egid 11 - }; 12 - 13 - return lkm_call(NR_setuidgid, &ug); 9 + return errno_linux_to_bsd(dserver_rpc_uidgid(-1, egid, NULL, NULL)); 14 10 } 15 11
+4 -8
src/kernel/emulation/linux/unistd/seteuid.c
··· 1 1 #include "seteuid.h" 2 2 #include "../base.h" 3 - #include "../mach/lkm.h" 4 - #include "../../../../external/lkm/api.h" 3 + #include <darlingserver/rpc.h> 4 + #include "../errno.h" 5 + #include <stddef.h> 5 6 6 7 long sys_seteuid(int euid) 7 8 { 8 - struct uidgid ug = { 9 - .uid = euid, 10 - .gid = -1 11 - }; 12 - 13 - return lkm_call(NR_setuidgid, &ug); 9 + return errno_linux_to_bsd(dserver_rpc_uidgid(euid, -1, NULL, NULL)); 14 10 } 15 11
+4 -8
src/kernel/emulation/linux/unistd/setgid.c
··· 1 1 #include "setgid.h" 2 2 #include "../base.h" 3 - #include "../mach/lkm.h" 4 - #include "../../../../external/lkm/api.h" 3 + #include <darlingserver/rpc.h> 4 + #include "../errno.h" 5 + #include <stddef.h> 5 6 6 7 long sys_setgid(int gid) 7 8 { 8 - struct uidgid ug = { 9 - .uid = -1, 10 - .gid = gid 11 - }; 12 - 13 - return lkm_call(NR_setuidgid, &ug); 9 + return errno_linux_to_bsd(dserver_rpc_uidgid(-1, gid, NULL, NULL)); 14 10 } 15 11
+4 -8
src/kernel/emulation/linux/unistd/settid.c
··· 1 1 #include "settid.h" 2 2 #include "../base.h" 3 - #include "../mach/lkm.h" 4 - #include "../../../../external/lkm/api.h" 3 + #include <darlingserver/rpc.h> 4 + #include "../errno.h" 5 + #include <stddef.h> 5 6 6 7 long sys_settid(int uid, int gid) 7 8 { 8 - struct uidgid ug = { 9 - .uid = uid, 10 - .gid = gid 11 - }; 12 - 13 - return lkm_call(NR_setuidgid, &ug); 9 + return errno_linux_to_bsd(dserver_rpc_uidgid(uid, gid, NULL, NULL)); 14 10 } 15 11
+4 -8
src/kernel/emulation/linux/unistd/setuid.c
··· 1 1 #include "setuid.h" 2 2 #include "../base.h" 3 - #include "../mach/lkm.h" 4 - #include "../../../../external/lkm/api.h" 3 + #include <darlingserver/rpc.h> 4 + #include "../errno.h" 5 + #include <stddef.h> 5 6 6 7 long sys_setuid(int uid) 7 8 { 8 - struct uidgid ug = { 9 - .uid = uid, 10 - .gid = -1 11 - }; 12 - 13 - return lkm_call(NR_setuidgid, &ug); 9 + return errno_linux_to_bsd(dserver_rpc_uidgid(uid, -1, NULL, NULL)); 14 10 } 15 11
+1 -1
src/kernel/emulation/linux/vchroot_userspace.c
··· 112 112 int rv; 113 113 114 114 #ifndef TEST 115 - rv = lkm_call(NR_vchroot, dfd); 115 + rv = errno_linux_to_bsd(dserver_rpc_vchroot(dfd)); 116 116 if (rv != 0) 117 117 return rv; 118 118 #endif
+22 -1
src/startup/mldr/elfcalls/threads.c
··· 32 32 33 33 #include "dthreads.h" 34 34 35 + #include <darlingserver/rpc.h> 36 + 35 37 // The point of this file is build macOS threads on top of native libc's threads, 36 38 // otherwise it would not be possible to make native calls from these threads. 37 39 ··· 198 200 dthread_t dthread = args.pth; 199 201 uintptr_t* flags = args.is_workqueue ? &args.arg2 : &args.arg3; 200 202 203 + // checkin with darlingserver on this new thread 204 + if (dserver_rpc_checkin(false) < 0) { 205 + // we can't do ANYTHING if darlingserver doesn't acknowledge us successfully 206 + abort(); 207 + } 208 + 201 209 // libpthread now expects the kernel to set the TSD 202 210 // so, since we're pretending to be the kernel handling threads... 203 211 args.callbacks->thread_set_tsd_base(&dthread->tsd[0], 0); 204 212 *flags |= args.is_workqueue ? DWQ_FLAG_THREAD_TSD_BASE_SET : DTHREAD_START_TSD_BASE_SET; 205 213 206 - args.port = dthread->tsd[DTHREAD_TSD_SLOT_MACH_THREAD_SELF] = args.callbacks->thread_self_trap(); 214 + int thread_self_port = args.callbacks->thread_self_trap(); 215 + dthread->tsd[DTHREAD_TSD_SLOT_MACH_THREAD_SELF] = (void*)(intptr_t)thread_self_port; 216 + args.port = thread_self_port; 207 217 208 218 in_args->pth = NULL; 209 219 ··· 253 263 "1:\n" 254 264 "ret\n" // Jump to the address pushed at the beginning 255 265 :: "c" (&args), "d" (args.pth)); 266 + #else 267 + #error Not implemented 256 268 #endif 257 269 __builtin_unreachable(); 258 270 } ··· 270 282 271 283 while (1) 272 284 sigsuspend(&mask); 285 + } 286 + 287 + // only threads that aren't the main thread should checkout 288 + // the main thread will automatically checkout when the process dies 289 + if (dserver_rpc_checkout(-1, false) < 0) { 290 + // failing to checkout is not fatal. 291 + // it's not ideal, but it's not fatal. 292 + #define CHECKOUT_FAILURE_MESSAGE "Failed to checkout" 293 + dserver_rpc_kprintf(CHECKOUT_FAILURE_MESSAGE, sizeof(CHECKOUT_FAILURE_MESSAGE) - 1); 273 294 } 274 295 275 296 t_freeaddr = stackaddr;
+25 -25
src/startup/mldr/mldr.c
··· 79 79 // UUID of the main executable 80 80 uint8_t exe_uuid[16]; 81 81 82 - // Data for TASK_DYLD_INFO 83 - uintptr_t dyld_all_image_location; 84 - size_t dyld_all_image_size; 82 + // globally visible for debugging/core-dumping purposes 83 + // however, this should not be relied on; a pointer to this should passed around to whoever needs the load_results structure 84 + __attribute__((used)) 85 + struct load_results mldr_load_results = {0}; 85 86 86 87 static uint32_t stack_size = 0; 87 88 ··· 90 91 void** sp; 91 92 int pushCount = 0; 92 93 char *filename, *p = NULL; 93 - struct load_results lr = {0}; 94 94 95 - lr.kernfd = -1; 96 - lr.argc = argc; 97 - lr.argv = argv; 95 + mldr_load_results.kernfd = -1; 96 + mldr_load_results.argc = argc; 97 + mldr_load_results.argv = argv; 98 98 99 - while (envp[lr.envc] != NULL) { 100 - ++lr.envc; 99 + while (envp[mldr_load_results.envc] != NULL) { 100 + ++mldr_load_results.envc; 101 101 } 102 - lr.envp = envp; 102 + mldr_load_results.envp = envp; 103 103 104 104 // sys_execve() passes the original file path appended to the mldr path in argv[0]. 105 105 if (argc > 0) ··· 129 129 } 130 130 131 131 #ifdef __i386__ 132 - load(filename, CPU_TYPE_X86, false, argv, &lr); // accept i386 only 132 + load(filename, CPU_TYPE_X86, false, argv, &mldr_load_results); // accept i386 only 133 133 #else 134 - load(filename, 0, false, argv, &lr); 134 + load(filename, 0, false, argv, &mldr_load_results); 135 135 #endif 136 136 137 137 // this was previously necessary when we were loading the binary from the LKM ··· 139 139 // but this shouldn't be necessary for loading Mach-O's from userspace (the heap space should already be set up properly). 140 140 // see https://github.com/darlinghq/darling/issues/469 for the issue this originally fixed in the LKM 141 141 #if 0 142 - if (prctl(PR_SET_MM, PR_SET_MM_BRK, PAGE_ALIGN(lr.vm_addr_max), 0, 0) < 0) { 142 + if (prctl(PR_SET_MM, PR_SET_MM_BRK, PAGE_ALIGN(mldr_load_results.vm_addr_max), 0, 0) < 0) { 143 143 fprintf(stderr, "Failed to set BRK value\n"); 144 144 return 1; 145 145 } 146 146 147 - if (prctl(PR_SET_MM, PR_SET_MM_START_BRK, PAGE_ALIGN(lr.vm_addr_max), 0, 0) < 0) { 147 + if (prctl(PR_SET_MM, PR_SET_MM_START_BRK, PAGE_ALIGN(mldr_load_results.vm_addr_max), 0, 0) < 0) { 148 148 fprintf(stderr, "Failed to set BRK start\n"); 149 149 return 1; 150 150 } 151 151 #endif 152 152 153 - if (prctl(PR_SET_MM, PR_SET_MM_START_STACK, lr.stack_top, 0, 0) < 0) { 153 + if (prctl(PR_SET_MM, PR_SET_MM_START_STACK, mldr_load_results.stack_top, 0, 0) < 0) { 154 154 fprintf(stderr, "Failed to set stack start\n"); 155 155 return 1; 156 156 } 157 157 158 158 // adjust argv (remove mldr's argv[0]) 159 - --lr.argc; 160 - for (size_t i = 0; i < lr.argc; ++i) { 161 - lr.argv[i] = lr.argv[i + 1]; 159 + --mldr_load_results.argc; 160 + for (size_t i = 0; i < mldr_load_results.argc; ++i) { 161 + mldr_load_results.argv[i] = mldr_load_results.argv[i + 1]; 162 162 } 163 - lr.argv[lr.argc] = NULL; 163 + mldr_load_results.argv[mldr_load_results.argc] = NULL; 164 164 165 - if (lr._32on64) 166 - setup_stack32(filename, &lr); 165 + if (mldr_load_results._32on64) 166 + setup_stack32(filename, &mldr_load_results); 167 167 else 168 168 #ifdef __x86_64__ 169 - setup_stack64(filename, &lr); 169 + setup_stack64(filename, &mldr_load_results); 170 170 #elif __aarch64__ 171 171 #error TODO: aarch64 172 172 #else ··· 175 175 176 176 // TODO: tell darlingserver about our dyld info 177 177 178 - start_thread(&lr); 178 + start_thread(&mldr_load_results); 179 179 180 180 __builtin_unreachable(); 181 181 } ··· 453 453 size = limit.rlim_cur; 454 454 } 455 455 456 - if (mmap((void*)lr->stack_top, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED | MAP_GROWSDOWN, -1, 0) == MAP_FAILED) { 456 + if (mmap((void*)(lr->stack_top - size), size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED_NOREPLACE | MAP_GROWSDOWN, -1, 0) == MAP_FAILED) { 457 457 fprintf(stderr, "Failed to allocate stack of %lu bytes: %d (%s)\n", size, errno, strerror(errno)); 458 458 exit(1); 459 459 } ··· 474 474 475 475 __dserver_main_thread_socket_fd = lr->kernfd; 476 476 477 - if (dserver_rpc_checkin() < 0) { 477 + if (dserver_rpc_checkin(false) < 0) { 478 478 fprintf(stderr, "Failed to checkin with darlingserver\n"); 479 479 exit(1); 480 480 }