Index: patch_offline.cc |
diff --git a/patch_offline.cc b/patch_offline.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..ee5c3b5f4bbfaf5b3188954d29f4c44db6aa3a5d |
--- /dev/null |
+++ b/patch_offline.cc |
@@ -0,0 +1,136 @@ |
+// Copyright (c) 2011 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include <assert.h> |
+#include <elf.h> |
+#include <stdio.h> |
+#include <stdlib.h> |
+#include <string.h> |
+ |
+#include "x86_decode.h" |
+ |
+// This tool patches ELF libraries and executables so that they can be |
+// used with elf_loader.cc. It rewrites system call instructions so |
+// that they will work inside the sandbox. |
Markus (顧孟勤)
2011/11/17 22:15:19
I suspect, in the long run, you probably want a to
|
+ |
+ |
+static void CheckBounds(char *data, size_t data_size, |
+ void *ptr, size_t inside_size) { |
+ assert(data <= (char *) ptr); |
+ assert((char *) ptr + inside_size <= data + data_size); |
+} |
+ |
+static int FixUpSection(bool is64bit, char *code, size_t code_size) { |
+ int patch_count = 0; |
+ char *pos = code; |
+ char *end = code + code_size; |
+ while (pos < end) { |
+ const char *ip = pos; |
+ playground::next_inst(&ip, is64bit); |
+ if (is64bit |
+ ? (pos[0] == '\x0f' && pos[1] == '\x05') /* syscall */ |
+ : (pos[0] == '\xcd' && pos[1] == '\x80') /* int $0x80 */) { |
+ // Replace the instruction with "int $0". This is the simplest |
+ // thing to do since it does not involve moving any instructions |
+ // around or extending the code segment. However, executing |
+ // system calls via "int $0" is not very fast at run time. |
+ pos[0] = '\xcd'; |
+ pos[1] = '\x00'; |
+ patch_count++; |
+ } |
+ pos = (char *) ip; |
+ } |
+ return patch_count; |
+} |
+ |
+struct Elf32 { |
+ typedef Elf32_Ehdr Ehdr; |
+ typedef Elf32_Shdr Shdr; |
+}; |
+ |
+struct Elf64 { |
+ typedef Elf64_Ehdr Ehdr; |
+ typedef Elf64_Shdr Shdr; |
+}; |
+ |
+template <class Elf> |
+static void FixUpElf(char *data, size_t data_size) { |
+ typename Elf::Ehdr *header = (typename Elf::Ehdr *) data; |
+ CheckBounds(data, data_size, header, sizeof(*header)); |
+ assert(memcmp(header->e_ident, ELFMAG, strlen(ELFMAG)) == 0); |
+ |
+ int patch_count = 0; |
+ for (int index = 0; index < header->e_shnum; index++) { |
+ typename Elf::Shdr *section = |
+ (typename Elf::Shdr *) (data + header->e_shoff + |
+ header->e_shentsize * index); |
+ CheckBounds(data, data_size, section, sizeof(*section)); |
+ |
+ if ((section->sh_flags & SHF_EXECINSTR) != 0) { |
+ CheckBounds(data, data_size, |
+ data + section->sh_offset, section->sh_size); |
+ patch_count += FixUpSection(header->e_machine == EM_X86_64, |
+ data + section->sh_offset, section->sh_size); |
+ } |
+ } |
+ printf("patched %i syscall instructions\n", patch_count); |
+} |
+ |
+static void FixUpElfFile(const char *input_file, const char *output_file) { |
+ FILE *fp; |
+ size_t file_size; |
+ char *data; |
+ size_t got; |
+ size_t written; |
+ |
+ // Read whole ELF file and write it back with modifications. |
+ fp = fopen(input_file, "rb"); |
+ if (fp == NULL) { |
+ fprintf(stderr, "Failed to open input file: %s\n", input_file); |
+ exit(1); |
+ } |
+ // Find the file size. |
+ fseek(fp, 0, SEEK_END); |
+ file_size = ftell(fp); |
+ data = (char *) malloc(file_size); |
+ assert(data != NULL); |
+ fseek(fp, 0, SEEK_SET); |
+ got = fread(data, 1, file_size, fp); |
+ assert(got == file_size); |
+ fclose(fp); |
+ |
+ switch (data[EI_CLASS]) { |
+ case ELFCLASS64: |
+ FixUpElf<Elf64>(data, file_size); |
+ break; |
+ case ELFCLASS32: |
+ FixUpElf<Elf32>(data, file_size); |
+ break; |
+ default: |
+ fprintf(stderr, "Unknown ELF class\n"); |
+ exit(1); |
+ } |
+ |
+ fp = fopen(output_file, "wb"); |
+ if (fp == NULL) { |
+ fprintf(stderr, "Failed to open output file: %s\n", output_file); |
+ exit(1); |
+ } |
+ written = fwrite(data, 1, file_size, fp); |
+ assert(written == file_size); |
+ fclose(fp); |
+ free(data); |
+} |
+ |
+int main(int argc, char **argv) { |
+ if (argc != 4 || strcmp(argv[2], "-o") != 0) { |
+ fprintf(stderr, "Usage: %s <input-file> -o <output-file>\n\n", argv[0]); |
+ fprintf(stderr, |
+ "This tool rewrites ELF objects to patch system call instructions\n" |
+ "to be redirected via the seccomp-sandbox's handler.\n"); |
+ return 1; |
+ } |
+ FixUpElfFile(argv[1], argv[3]); |
+ return 0; |
+} |