static int csops_task(SecTaskRef task, int ops, void *blob, size_t size) { int rc; if (task->pid_self==-1) { pid_t pid; audit_token_to_au32(task->token, NULL, NULL, NULL, NULL, NULL, &pid, NULL, NULL); rc = csops_audittoken(pid, ops, blob, size, &task->token); } else rc = csops(task->pid_self, ops, blob, size); task->lastFailure = (rc == -1) ? errno : 0; return rc; }
void InjectLibrary(int pid, int argc, const char *const argv[]) { auto cynject(LibraryFor(reinterpret_cast<void *>(&main))); auto slash(cynject.rfind('/')); _assert(slash != std::string::npos); cynject = cynject.substr(0, slash) + "/cynject"; auto library(LibraryFor(reinterpret_cast<void *>(&MSmain0))); #if defined(__APPLE__) && (defined(__i386__) || defined(__x86_64__)) off_t offset; _assert(csops(pid, CS_OPS_PIDOFFSET, &offset, sizeof(offset)) != -1); // XXX: implement a safe version of this char path[4096]; int writ(proc_pidpath(pid, path, sizeof(path))); _assert(writ != 0); auto fd(_syscall(open(path, O_RDONLY))); auto page(getpagesize()); auto size(page * 4); auto map(_syscall(mmap(NULL, size, PROT_READ, MAP_SHARED, fd, offset))); _syscall(close(fd)); // XXX: _scope auto header(reinterpret_cast<mach_header *>(map)); auto command(reinterpret_cast<load_command *>(header + 1)); switch (header->magic) { case MH_MAGIC_64: command = shift(command, sizeof(uint32_t)); case MH_MAGIC: break; default: _assert(false); } bool ios(false); for (decltype(header->ncmds) i(0); i != header->ncmds; ++i) { if (command->cmd == LC_VERSION_MIN_IPHONEOS) ios = true; command = shift(command, command->cmdsize); } _syscall(munmap(map, size)); // XXX: _scope auto length(library.size()); _assert(length >= 6); length -= 6; _assert(library.substr(length) == ".dylib"); library = library.substr(0, length); library += ios ? "-sim" : "-sys"; library += ".dylib"; #endif std::ostringstream inject; inject << cynject << " " << std::dec << pid << " " << library; for (decltype(argc) i(0); i != argc; ++i) inject << " " << argv[i]; _assert(system(inject.str().c_str()) == 0); }
int main(int argc, const char * argv[]) { uint32_t status; int rcent; pid_t pid; pid = getpid(); if (get_blob(pid, CS_OPS_ENTITLEMENTS_BLOB)) errx(1, "failed to get entitlements"); if (get_blob(0, CS_OPS_ENTITLEMENTS_BLOB)) errx(1, "failed to get entitlements"); if (get_blob(pid, CS_OPS_BLOB)) errx(1, "failed to get blob"); if (get_blob(0, CS_OPS_BLOB)) errx(1, "failed to get blob"); if (get_blob(pid, CS_OPS_IDENTITY)) errx(1, "failed to get identity"); if (get_blob(0, CS_OPS_IDENTITY)) errx(1, "failed to get identity"); rcent = csops(pid, CS_OPS_SET_STATUS, &status, sizeof(status) - 1); if (rcent == 0) err(1, "passed when passed in too short status buffer"); status = htonl(CS_RESTRICT); rcent = csops(pid, CS_OPS_SET_STATUS, &status, sizeof(status)); if (rcent != 0) errx(1, "failed to mark proc RESTRICTED"); rcent = csops(pid, CS_OPS_MARKINVALID, NULL, 0); if (rcent != 0) errx(1, "failed to mark proc invalid"); status = htonl(CS_VALID); rcent = csops(pid, CS_OPS_SET_STATUS, &status, sizeof(status)); if (rcent == 0) errx(1, "managed set flags on an INVALID proc"); if (!get_blob(pid, CS_OPS_ENTITLEMENTS_BLOB)) errx(1, "got entitlements while invalid"); if (!get_blob(pid, CS_OPS_IDENTITY)) errx(1, "got identity"); if (!get_blob(0, CS_OPS_IDENTITY)) errx(1, "got identity"); if (!get_blob(pid, CS_OPS_BLOB)) errx(1, "got blob"); return 0; }
int get_blob(pid_t pid, int op) { uint8_t header[8]; unsigned int cnt; int rcent; for (cnt = 0; cnt < sizeof(header); cnt++) { rcent = csops(pid, op, header, 1); if (rcent != -1 && errno != ERANGE) err(1, "errno != ERANGE for short header"); } rcent = csops(pid, op, header, sizeof(header)); if (rcent == -1 && errno == ERANGE) { uint32_t len, bufferlen, bufferlen2; memcpy(&len, &header[4], 4); bufferlen = ntohl(len); if (bufferlen > 1024 * 1024) errx(1, "invalid length on blob from kernel"); else if (bufferlen == 0) errx(1, "bufferlen == 0"); else if (bufferlen < 8) errx(1, "bufferlen <8 0"); uint8_t buffer[bufferlen + 1]; rcent = csops(pid, op, buffer, bufferlen - 1); if (rcent != -1 && errno != ERANGE) errx(1, "csops with full buffer - 1 failed"); rcent = csops(pid, op, buffer, bufferlen); if (rcent != 0) errx(1, "csops with full buffer failed"); memcpy(&len, &buffer[4], 4); bufferlen2 = ntohl(len); if (op == CS_OPS_BLOB) { if (bufferlen2 > bufferlen) errx(1, "buffer larger on second try"); if (bufferlen2 != bufferlen) warnx("buffer shrunk since codesign can't tell the right size to codesign_allocate"); } else { if (bufferlen2 != bufferlen) errx(1, "buffer sizes different"); } rcent = csops(pid, op, buffer, bufferlen + 1); if (rcent != 0) errx(1, "csops with full buffer + 1 didn't pass"); return 0; } else if (rcent == 0) { return 0; } else { return 1; } }