├── .gitignore ├── .clang-format ├── os-handler ├── fuzzRunner.h ├── Makefile └── main.c ├── CMakeLists.txt ├── src ├── mutation.cpp ├── mutation.h ├── snapshot.h ├── breakpoint.h ├── breakpoint.cpp ├── kernelVM.h ├── snapshot.cpp ├── main.cpp └── kernelVM.cpp ├── plot.plt ├── README.md └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | build-* 3 | .vscode/ -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | # Generated from CLion C/C++ Code Style settings 2 | BasedOnStyle: LLVM 3 | TabWidth: 4 4 | -------------------------------------------------------------------------------- /os-handler/fuzzRunner.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef TUSCAN_LEATHER_FUZZRUNNER_H 3 | #define TUSCAN_LEATHER_FUZZRUNNER_H 4 | 5 | #define TAKE_SNAPSHOT 0 6 | #define RESTORE_VM 1 7 | #define ENABLE_DEBUG 2 8 | #endif // TUSCAN_LEATHER_FUZZRUNNER_H 9 | -------------------------------------------------------------------------------- /os-handler/Makefile: -------------------------------------------------------------------------------- 1 | obj-m := os_handler.o 2 | os_handler-objs := main.o 3 | 4 | LinuxSourcePath := /home/scott/LinuxVR/linux-5.13.9 5 | 6 | all: 7 | make -C $(LinuxSourcePath) M=$(PWD) modules 8 | 9 | clean: 10 | make -C $(LinuxSourcePath) M=$(PWD) clean -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.16) 2 | project(Tuscan-Leather) 3 | 4 | set(CMAKE_CXX_STANDARD 17) 5 | set(CMAKE_C_COMPILER clang) 6 | set(CMAKE_CXX_COMPILER clang++) 7 | set(CMAKE_EXPORT_COMPILE_COMMANDS On) 8 | 9 | add_executable(Tuscan-Leather src/main.cpp src/kernelVM.cpp src/kernelVM.h src/snapshot.cpp src/snapshot.h src/breakpoint.cpp src/breakpoint.h src/mutation.cpp src/mutation.h) 10 | -------------------------------------------------------------------------------- /src/mutation.cpp: -------------------------------------------------------------------------------- 1 | #include "mutation.h" 2 | 3 | std::unordered_set coveragePCs; 4 | uint64_t seed; 5 | 6 | uint64_t getSizeOfSet() { return coveragePCs.size(); } 7 | 8 | int addPC(uint64_t newPC) { 9 | auto result = coveragePCs.emplace(newPC); 10 | return result.second; 11 | } 12 | 13 | int initializeMutationEngine(uint64_t newSeed) { 14 | seed = newSeed; 15 | srand(time(nullptr)); 16 | return 0; 17 | } -------------------------------------------------------------------------------- /src/mutation.h: -------------------------------------------------------------------------------- 1 | #ifndef TUSCAN_LEATHER_MUTATION_H 2 | #define TUSCAN_LEATHER_MUTATION_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | extern std::unordered_set coveragePCs; 10 | extern uint64_t seed; 11 | 12 | int initializeMutationEngine(uint64_t newSeed); 13 | int addPC(uint64_t newPC); 14 | uint64_t getNewByteSequence(); 15 | uint64_t getSizeOfSet(); 16 | 17 | #endif // TUSCAN_LEATHER_MUTATION_H -------------------------------------------------------------------------------- /src/snapshot.h: -------------------------------------------------------------------------------- 1 | #ifndef TUSCAN_LEATHER_SNAPSHOT_H 2 | #define TUSCAN_LEATHER_SNAPSHOT_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "kernelVM.h" 9 | 10 | #define NUMBER_OF_BITS 64 11 | 12 | struct snapshot { 13 | void *mem; 14 | struct kvm_regs regs; 15 | struct kvm_sregs sregs; 16 | }; 17 | 18 | int restoreSnapshot(kernelGuest *guest); 19 | int createSnapshot(kernelGuest *guest); 20 | 21 | #endif // TUSCAN_LEATHER_SNAPSHOT_H 22 | -------------------------------------------------------------------------------- /plot.plt: -------------------------------------------------------------------------------- 1 | set term png size 1366, 768 2 | set output "graph.png" 3 | set xlabel 'Time (seconds)' 4 | set ylabel 'Share of Execution Time' 5 | set logscale x 6 | set multiplot layout 1,2 7 | set grid mxtics, xtics, ytics, mytics 8 | set key left 9 | 10 | set title "VM-Exec vs. Reset" 11 | plot 'stats.txt' using 1:2 with lines title 'reset', 'stats.txt' using 1:3 with lines title 'vm-exec' 12 | 13 | set title 'Rate of Cases/Sec' 14 | set ylabel 'Cases/Sec' 15 | #unset logscale x 16 | plot 'stats.txt' using 1:5 with lines title 'Cases/Sec' 17 | -------------------------------------------------------------------------------- /src/breakpoint.h: -------------------------------------------------------------------------------- 1 | #ifndef TUSCAN_LEATHER_BREAKPOINT_H 2 | #define TUSCAN_LEATHER_BREAKPOINT_H 3 | 4 | #include "kernelVM.h" 5 | 6 | /* 7 | * Breakpoint API 8 | * Through this API, we are able to set software breakpoints on the vm. This 9 | * will allow us to set breakpoints on important functions like `kasan_report` 10 | * and have the vm kick out to userspace to handle it. From there we can reset 11 | * the vm or save the testcase used to trip kasan. 12 | * */ 13 | int addBreakpoint(kernelGuest *guest, uint64_t addr); 14 | 15 | int delBreakpoint(kernelGuest *guest, uint64_t addr); 16 | 17 | int loadAddresses(const char *filePath); 18 | 19 | #endif // TUSCAN_LEATHER_BREAKPOINT_H 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tuscan Leather 2 | 3 | A Linux Kernel Snapshot Fuzzer using KVM. 4 | 5 | Tuscan Leather is a Linux Kernel snapshot fuzzer. The goal for this project is to be able to fuzz kernel systems that 6 | would ordinarily require time-consuming environment setup that would be difficult to reproduce solely using unsupervised 7 | coverage based fuzzing. To aid us in this project we will use the 8 | [Kernel Virtual Machine Platform](https://www.linux-kvm.org/page/Main_Page) (KVM) to create our virtual machines. The 9 | design of the fuzzer component of this project will be based on LibFuzzer where the developer has to define the fuzzing 10 | environment through the use of a C program acting as an initrd and an ioctl-based API provided by the OS Handler device 11 | driver. 12 | 13 | ## Usage 14 | 15 | `./Tuscan-Leather -j ` 16 | 17 | ## OS Handler 18 | 19 | The OS Handler is a character device driver that allows the fuzz case runner to issue IOCTL commands that are received 20 | by the KVM hypervisor. Available commands are in [fuzzRunner.h](os-handler/fuzzRunner.h). 21 | -------------------------------------------------------------------------------- /src/breakpoint.cpp: -------------------------------------------------------------------------------- 1 | #include "breakpoint.h" 2 | 3 | int addBreakpoint(kernelGuest *guest, uint64_t virtAddr) { 4 | struct kvm_translation kvmTranslation = {.linear_address = virtAddr}; 5 | if (ioctl(guest->vcpu_fd, KVM_TRANSLATE, &kvmTranslation) < 0) 6 | ERR("KVM_TRANSLATE Failed"); 7 | 8 | *(uint8_t *)((uint8_t *)guest->mem + kvmTranslation.physical_address) = 0xcc; 9 | return 0; 10 | } 11 | 12 | int delBreakpoint(kernelGuest *guest, uint64_t addr) { return 0; } 13 | 14 | int loadAddresses(const char *filePath) { 15 | FILE *systemMapFD = fopen(filePath, "r"); 16 | char line[256]; 17 | uint64_t countOfTextSymbols = 0; 18 | 19 | // count number of text symbols 20 | while (fgets(line, sizeof(line), systemMapFD)) { 21 | unsigned long long addr; 22 | uint8_t symbolType; 23 | char symbolName[128]; 24 | scanf(line, "%llx %c %s", &addr, &symbolType, symbolName); 25 | if (symbolType == 'T' || symbolType == 't') { 26 | countOfTextSymbols++; 27 | } 28 | } 29 | printf("[*] Number of Text Symbols: %ld\n", countOfTextSymbols); 30 | 31 | fclose(systemMapFD); 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /src/kernelVM.h: -------------------------------------------------------------------------------- 1 | #ifndef TUSCAN_LEATHER_KERNELVM_H 2 | #define TUSCAN_LEATHER_KERNELVM_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #define MEM_SIZE 1 << 30 23 | #define BITMAP_SIZE_QWORDS 0x1000 24 | #define BITMAP_SIZE_BITS 0x40000 25 | #define PAGE_SIZE 0x1000 26 | 27 | #define BOOT_PARAM_ADDR 0x10000 28 | #define CMDLINE_ADDR 0x20000 29 | #define KERNEL_ADDR 0x100000 30 | #define INITRD_ADDR 0xf000000 31 | #define E820Ram 1 32 | #define E820Reserved 2 33 | 34 | #define RealModeIvtBegin 0x00000000 35 | #define EBDAStart 0x0009fc00 36 | #define VGARAMBegin 0x000a0000 37 | #define MBBIOSBegin 0x000f0000 38 | #define MBBIOSEnd 0x000fffff 39 | 40 | // KVM Constants - not supported in kernel 5.4 41 | #define KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE (1 << 0) 42 | 43 | #define ERR(s) err(-1, "[!] " s) 44 | 45 | // Have to modify everytime we re-compile the kernel 46 | #define KASAN_REPORT_COLD 0xffffffff83755621 47 | 48 | typedef struct { 49 | uint64_t cycles_run; 50 | uint64_t cycles_reset; 51 | uint64_t cycles_vmexit; 52 | uint64_t cases; 53 | uint64_t numOfPagesReset; 54 | uint64_t totalPCs; 55 | pthread_mutex_t *lock; 56 | } statistics; 57 | 58 | typedef struct { 59 | int vmfd; 60 | int vcpu_fd; 61 | int kvm_fd; 62 | void *mem; 63 | void *initrdMemAddr; 64 | void *kernelMemAddr; 65 | uint64_t *dirty_bitmap; 66 | uint64_t pcs; 67 | statistics *stats; 68 | struct snapshot *snapshot; 69 | } kernelGuest; 70 | 71 | int createKernelVM(kernelGuest *guest); 72 | int loadKernelVM(kernelGuest *guest, const char *kernelImagePath, 73 | const char *initrdImagePath); 74 | int cleanupKernelVM(kernelGuest *guest); 75 | int runKernelVM(kernelGuest *guest); 76 | int initVMRegs(kernelGuest *guest); 77 | int createCPUID(kernelGuest *guest); 78 | int filterCPUID(struct kvm_cpuid2 *cpuid); 79 | int addE820Entry(struct boot_params *boot, uint64_t addr, uint64_t size, 80 | uint32_t type); 81 | int dumpVCPURegs(kernelGuest *guest); 82 | int enableDebug(kernelGuest *guest); 83 | 84 | #endif // TUSCAN_LEATHER_KERNELVM_H 85 | -------------------------------------------------------------------------------- /os-handler/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include //kmalloc() 18 | #include //copy_to/from_user() 19 | 20 | #include "fuzzRunner.h" 21 | 22 | #define DEV_MAJOR 24 23 | #define DEVICE_NAME "tl-hypervisor" 24 | #define PORT_1 0xdead 25 | 26 | // Function Prototypes 27 | static int tl_driver_init(void); 28 | static void tl_driver_exit(void); 29 | static int open(struct inode *inode, struct file *file); 30 | static int release(struct inode *inode, struct file *file); 31 | static ssize_t read(struct file *filp, char __user *buf, size_t len, 32 | loff_t *off); 33 | static ssize_t write(struct file *filp, const char *buf, size_t len, 34 | loff_t *off); 35 | static long tl_ioctl(struct file *file, unsigned int cmd, unsigned long arg); 36 | 37 | // File operation sturcture 38 | static struct file_operations fops = { 39 | .owner = THIS_MODULE, 40 | .read = read, 41 | .write = write, 42 | .open = open, 43 | .unlocked_ioctl = tl_ioctl, 44 | .release = release, 45 | }; 46 | 47 | static dev_t device_major; 48 | 49 | // This function will be called when we open the Device file 50 | static int open(struct inode *inode, struct file *file) { 51 | pr_alert("[!] tl-hypervisor opened\n"); 52 | return 0; 53 | } 54 | 55 | // This function will be called when we close the Device file 56 | static int release(struct inode *inode, struct file *file) { return 0; } 57 | 58 | // This function will be called when we read the Device file 59 | static ssize_t read(struct file *filp, char __user *buf, size_t len, 60 | loff_t *off) { 61 | pr_info("Read Function\n"); 62 | return 0; 63 | } 64 | 65 | // This function will be called when we write the Device file 66 | static ssize_t write(struct file *filp, const char __user *buf, size_t len, 67 | loff_t *off) { 68 | return len; 69 | } 70 | 71 | // This function will be called when we write IOCTL on the Device file 72 | static long tl_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { 73 | // pr_alert("[!] tl-hypervisor ioctl issued - cmd: %d\n", cmd); 74 | 75 | switch (cmd) { 76 | case TAKE_SNAPSHOT: 77 | // pr_alert("[*] Snapshoting VM\n"); 78 | outb_p(TAKE_SNAPSHOT, PORT_1); 79 | break; 80 | case RESTORE_VM: 81 | // pr_alert("[*] Restoring VM\n"); 82 | outb_p(RESTORE_VM, PORT_1); 83 | break; 84 | default: 85 | break; 86 | } 87 | 88 | return 0; 89 | } 90 | 91 | // Module Init function 92 | static int __init tl_driver_init(void) { 93 | device_major = register_chrdev(32, DEVICE_NAME, &fops); 94 | 95 | if (device_major < 0) { 96 | printk(KERN_ALERT "Device Registration failed with %d\n", device_major); 97 | return device_major; 98 | } 99 | 100 | if (!request_region(PORT_1, 1, DEVICE_NAME)) { 101 | pr_alert("[!] IO port allocation of %x failed\n", PORT_1); 102 | return -ENODEV; 103 | } 104 | 105 | return 0; 106 | } 107 | 108 | // Module exit function 109 | static void tl_driver_exit(void) { 110 | // Not needed since VM will be destroyed 111 | } 112 | 113 | module_init(tl_driver_init); 114 | module_exit(tl_driver_exit); 115 | 116 | MODULE_LICENSE("GPL"); 117 | MODULE_AUTHOR("Scott Lagler "); 118 | MODULE_DESCRIPTION("Tuscan Leather - OS Handler"); 119 | MODULE_VERSION("1.0"); -------------------------------------------------------------------------------- /src/snapshot.cpp: -------------------------------------------------------------------------------- 1 | #include "snapshot.h" 2 | 3 | /* 4 | * restoreSnapshot 5 | * restores a prior saved snapshot of the vm to reset the kernel environment. 6 | * */ 7 | int restoreSnapshot(kernelGuest *guest) { 8 | struct snapshot *snapshot = guest->snapshot; 9 | if (ioctl(guest->vcpu_fd, KVM_KVMCLOCK_CTRL) < 0) 10 | ERR("Unable to set KVMCLOCK_CTRL"); 11 | 12 | // Fetch Dirty Log 13 | struct kvm_dirty_log dirty_log = { 14 | .slot = 0, // The ID for the kvm memory slot 15 | .dirty_bitmap = guest->dirty_bitmap, 16 | }; 17 | 18 | if (ioctl(guest->vmfd, KVM_GET_DIRTY_LOG, &dirty_log) < 0) 19 | ERR("Failed to get Dirty Log"); 20 | 21 | int numOfPagesReset = 0; 22 | 23 | // Walk bitmap and queue dirty pages for restoration 24 | for (uint64_t QwordIdx = 0; QwordIdx < BITMAP_SIZE_QWORDS; QwordIdx++) { 25 | const uint64_t DirtyQword = guest->dirty_bitmap[QwordIdx]; 26 | if (DirtyQword == 0) { 27 | continue; 28 | } 29 | 30 | for (uint64_t BitIdx = 0; BitIdx < NUMBER_OF_BITS; BitIdx++) { 31 | const uint8_t DirtyBit = (DirtyQword >> BitIdx) & 1; 32 | if (DirtyBit == 0) { 33 | continue; 34 | } 35 | 36 | const uint64_t DirtyPageIdx = (QwordIdx * NUMBER_OF_BITS) + BitIdx; 37 | const uint64_t guestPhysAddr = DirtyPageIdx * PAGE_SIZE; 38 | 39 | numOfPagesReset++; 40 | // memcpy to restore page 41 | void *guestVirtAddr = ((uint8_t *)guest->mem) + guestPhysAddr; 42 | void *snapshotVirtAddr = ((uint8_t *)snapshot->mem) + guestPhysAddr; 43 | 44 | memcpy(guestVirtAddr, snapshotVirtAddr, PAGE_SIZE); 45 | } 46 | } 47 | 48 | // Clear Dirty Log 49 | struct kvm_clear_dirty_log ClearDirtyLog = { 50 | .slot = 0, 51 | .num_pages = (uint32_t)0x40000, 52 | .first_page = 0, 53 | .dirty_bitmap = guest->dirty_bitmap, 54 | }; 55 | 56 | if (ioctl(guest->vmfd, KVM_CLEAR_DIRTY_LOG, &ClearDirtyLog) < 0) 57 | ERR("Failed to clear the dirty log - restore"); 58 | 59 | if (ioctl(guest->vcpu_fd, KVM_SET_SREGS, &snapshot->sregs) < 0) 60 | ERR("Failed to set special registers - restore"); 61 | 62 | if (ioctl(guest->vcpu_fd, KVM_SET_REGS, &snapshot->regs) < 0) 63 | ERR("Failed to set registers - restore"); 64 | 65 | return numOfPagesReset; 66 | } 67 | 68 | /* 69 | * createSnapshot 70 | * Creates a snapshot of the vm and stores it for later use in restoration. 71 | * */ 72 | int createSnapshot(kernelGuest *guest) { 73 | if (ioctl(guest->vcpu_fd, KVM_KVMCLOCK_CTRL) < 0) 74 | ERR("Unable to set KVMCLOCK_CTRL"); 75 | 76 | struct snapshot *snapshot = 77 | (struct snapshot *)malloc(sizeof(struct snapshot)); 78 | memset(snapshot, 0x0, sizeof(struct snapshot)); 79 | 80 | guest->snapshot = snapshot; 81 | 82 | if (ioctl(guest->vcpu_fd, KVM_GET_SREGS, &snapshot->sregs) < 0) 83 | ERR("Failed to get special registers"); 84 | 85 | if (ioctl(guest->vcpu_fd, KVM_GET_REGS, &snapshot->regs) < 0) 86 | ERR("Failed to get registers"); 87 | 88 | snapshot->regs.rip += 1; // needed to go past out instruction in ioctl handler 89 | snapshot->mem = malloc(MEM_SIZE); // Allocate VM memory 90 | memcpy(snapshot->mem, guest->mem, MEM_SIZE); 91 | 92 | // Get KVM Dirty Log 93 | struct kvm_dirty_log dirty_log = { 94 | .slot = 0, // The ID for the only slot in memory 95 | .dirty_bitmap = guest->dirty_bitmap, 96 | }; 97 | if (ioctl(guest->vmfd, KVM_GET_DIRTY_LOG, &dirty_log) < 0) 98 | ERR("Failed to get Dirty Log"); 99 | 100 | // Clear Dirty Log 101 | struct kvm_clear_dirty_log ClearDirtyLog = { 102 | .slot = 0, 103 | .num_pages = (uint32_t)0x40000, 104 | .first_page = 0, 105 | .dirty_bitmap = guest->dirty_bitmap, 106 | }; 107 | 108 | if (ioctl(guest->vmfd, KVM_CLEAR_DIRTY_LOG, &ClearDirtyLog) < 0) { 109 | ERR("KVM_CLEAR_DIRTY_LOG"); 110 | } 111 | 112 | return 0; 113 | } 114 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "kernelVM.h" 9 | 10 | struct worker_args { 11 | char *kernel_img_path; 12 | char *initrd_img_path; 13 | kernelGuest *guest; 14 | }; 15 | 16 | uint64_t numberOfJobs = 0; 17 | pid_t *childPids; 18 | 19 | void kill_child() { 20 | if (childPids == nullptr) 21 | return; 22 | for (int i = 0; i < numberOfJobs; ++i) { 23 | kill(childPids[i], SIGKILL); 24 | } 25 | exit(0); 26 | } 27 | 28 | void worker(struct worker_args *args) { 29 | args->guest->kvm_fd = open("/dev/kvm", O_RDWR | O_CLOEXEC); 30 | if (args->guest->kvm_fd == -1) 31 | ERR("/dev/kvm"); 32 | 33 | // Make sure we have the stable version of the API 34 | int ret = ioctl(args->guest->kvm_fd, KVM_GET_API_VERSION, NULL); 35 | if (ret == -1) 36 | ERR("KVM_GET_API_VERSION"); 37 | if (ret != 12) 38 | errx(-1, "[!] KVM_GET_API_VERSION %d, expected 12", ret); 39 | 40 | createKernelVM(args->guest); 41 | loadKernelVM(args->guest, args->kernel_img_path, args->initrd_img_path); 42 | 43 | printf("[*] Starting up VM\n"); 44 | runKernelVM(args->guest); 45 | cleanupKernelVM(args->guest); 46 | printf("[*] Destroyed Kernel VM - Success\n"); 47 | } 48 | 49 | int main(int argc, char **argv) { 50 | if (argc != 5) { 51 | fprintf(stderr, "Usage: ./Tuscan-Leather -j \n"); 52 | return -1; 53 | } 54 | 55 | printf("Tuscan-Leather - Linux Kernel Fuzzer\n"); 56 | 57 | // Initialize statistics Structure 58 | statistics *stats = (statistics *)mmap(nullptr, sizeof(statistics), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); 59 | stats->cycles_reset = 0; 60 | stats->cycles_run = 0; 61 | stats->cycles_vmexit = 0; 62 | stats->cases = 0; 63 | stats->numOfPagesReset = 0; 64 | 65 | stats->lock = (pthread_mutex_t *)malloc(sizeof(pthread_mutex_t)); 66 | pthread_mutex_init(stats->lock, nullptr); 67 | 68 | kernelGuest *guest = (kernelGuest *)mmap(nullptr, sizeof(kernelGuest), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); 69 | guest->stats = stats; 70 | 71 | struct worker_args args = { 72 | .kernel_img_path = argv[1], 73 | .initrd_img_path = argv[2], 74 | .guest = guest, 75 | }; 76 | 77 | signal(SIGINT, (void (*)(int))kill_child); 78 | numberOfJobs = strtoul(argv[4], nullptr, 10); 79 | childPids = (pid_t *)malloc(numberOfJobs * sizeof(pid_t)); 80 | 81 | for (int i = 0; i < numberOfJobs; i++) { 82 | pid_t pid = fork(); 83 | if (pid == 0) { 84 | worker(&args); 85 | exit(0); 86 | } else if (pid == -1) { 87 | ERR("Fork Failed"); 88 | } 89 | childPids[i] = pid; 90 | } 91 | 92 | // open stats.txt 93 | FILE *statslogFD = fopen("stats.txt", "w"); 94 | 95 | // Wait for snapshot to be created 96 | printf("[*] Waiting for VM to update stats\n"); 97 | sleep(5); 98 | 99 | struct timespec start { 100 | }, end{}; 101 | clock_gettime(CLOCK_THREAD_CPUTIME_ID, &start); 102 | while (true) { 103 | struct timespec ts = { 104 | .tv_sec = 0, 105 | .tv_nsec = 100000000, 106 | }; 107 | nanosleep(&ts, nullptr); 108 | 109 | clock_gettime(CLOCK_THREAD_CPUTIME_ID, &end); 110 | double duration = (double)(end.tv_nsec - start.tv_nsec) / 1e6; 111 | 112 | statistics localStats; 113 | pthread_mutex_lock(stats->lock); 114 | memcpy(&localStats, stats, sizeof(statistics)); 115 | pthread_mutex_unlock(stats->lock); 116 | 117 | uint64_t ctot = localStats.cycles_reset + localStats.cycles_run; 118 | double prst = (double)localStats.cycles_reset / (double)ctot; 119 | double prun = (double)localStats.cycles_run / (double)ctot; 120 | double cps = (double)localStats.cases / duration; 121 | 122 | if (duration > 60.0f) { 123 | kill_child(); 124 | return 0; 125 | } 126 | printf("[%f] cps %f | reset %f | run %f | cases %lu | cov %lu\n", duration, 127 | cps, prst, prun, localStats.cases, localStats.totalPCs); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /src/kernelVM.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../os-handler/fuzzRunner.h" 4 | #include "breakpoint.h" 5 | #include "mutation.h" 6 | #include "snapshot.h" 7 | 8 | statistics local_stats; 9 | uint64_t last_report; 10 | 11 | int createKernelVM(kernelGuest *guest) { 12 | if ((guest->vmfd = ioctl(guest->kvm_fd, KVM_CREATE_VM, 0)) < 0) 13 | ERR("VM creation failed"); 14 | 15 | if (ioctl(guest->kvm_fd, KVM_CHECK_EXTENSION, 16 | KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2) < 0) 17 | ERR("KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 is not supported"); 18 | 19 | struct kvm_enable_cap cap = {.cap = KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2, 20 | .args = {KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE}}; 21 | if (ioctl(guest->vmfd, KVM_ENABLE_CAP, &cap) < 0) 22 | ERR("Enable cap KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 failed"); 23 | 24 | if (ioctl(guest->vmfd, KVM_SET_TSS_ADDR, 0xfffbd000) < 0) 25 | ERR("Failed to set TSS addr"); 26 | 27 | uint64_t map_addr = 0xffffc000; 28 | if (ioctl(guest->vmfd, KVM_SET_IDENTITY_MAP_ADDR, &map_addr) < 0) 29 | ERR("Failed to set identity map addr"); 30 | 31 | if (ioctl(guest->vmfd, KVM_CREATE_IRQCHIP, 0) < 0) 32 | ERR("Failed to create irq chip"); 33 | 34 | struct kvm_pit_config pit = {.flags = 0}; 35 | if (ioctl(guest->vmfd, KVM_CREATE_PIT2, &pit) < 0) 36 | ERR("Failed to create i8254 interval timer"); 37 | 38 | guest->mem = mmap(nullptr, MEM_SIZE, PROT_READ | PROT_WRITE, 39 | MAP_SHARED | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0); 40 | 41 | if (!guest->mem) 42 | ERR("Failed to mmap VM memory"); 43 | 44 | madvise(guest->mem, MEM_SIZE, MADV_MERGEABLE); 45 | 46 | struct kvm_userspace_memory_region region = {.slot = 0, 47 | .flags = KVM_MEM_LOG_DIRTY_PAGES, 48 | .guest_phys_addr = 0, 49 | .memory_size = MEM_SIZE, 50 | .userspace_addr = 51 | (uint64_t)guest->mem}; 52 | 53 | if (ioctl(guest->vmfd, KVM_SET_USER_MEMORY_REGION, ®ion) < 0) 54 | ERR("Failed to set user memory region"); 55 | 56 | guest->vcpu_fd = ioctl(guest->vmfd, KVM_CREATE_VCPU, 0); 57 | if (guest->vcpu_fd < 0) 58 | ERR("Failed to create vcpu"); 59 | 60 | // Enabling dirty_log tracking 61 | guest->dirty_bitmap = (uint64_t *)malloc(BITMAP_SIZE_BITS); 62 | // Tracking for 1GB vm memory 63 | 64 | initVMRegs(guest); 65 | createCPUID(guest); 66 | return 0; 67 | } 68 | 69 | /* 70 | * loadKernelVM 71 | * Opens bzImage and initrd and reads them into their proper memory locations. 72 | * This is also where we set up the boot parameters in accordance with the 73 | * linux x86 boot protocol and inform the kernel of the memory locations 74 | * via e820 entries. 75 | * */ 76 | int loadKernelVM(kernelGuest *guest, const char *kernelImagePath, 77 | const char *initrdImagePath) { 78 | int kernelFD = open(kernelImagePath, O_RDONLY); 79 | int initrdFD = open(initrdImagePath, O_RDONLY); 80 | 81 | // TODO Make this configurable at runtime 82 | const char *kernelCmdline = "nokaslr quiet root=/dev/vda"; 83 | 84 | if ((kernelFD == -1) || (initrdFD == -1)) { 85 | ERR("Cannot open kernel image and/or initrd"); 86 | } 87 | 88 | struct stat st {}; 89 | fstat(kernelFD, &st); 90 | size_t kernelFileSize = st.st_size; 91 | void *kernelFile = mmap(nullptr, kernelFileSize, PROT_READ | PROT_WRITE, 92 | MAP_PRIVATE, kernelFD, 0); 93 | close(kernelFD); 94 | 95 | fstat(initrdFD, &st); 96 | size_t initrdFileSize = st.st_size; 97 | void *initrdFile = mmap(nullptr, initrdFileSize, PROT_READ | PROT_WRITE, 98 | MAP_PRIVATE, initrdFD, 0); 99 | close(initrdFD); 100 | 101 | // Setup initrd 102 | guest->initrdMemAddr = (void *)(((uint8_t *)guest->mem) + INITRD_ADDR); 103 | memset(guest->initrdMemAddr, 0, initrdFileSize); 104 | memmove(guest->initrdMemAddr, initrdFile, initrdFileSize); 105 | 106 | // Setup boot loader, cmdline, and kernel 107 | auto *boot = 108 | (struct boot_params *)(((uint8_t *)guest->mem) + BOOT_PARAM_ADDR); 109 | void *cmdline = (void *)(((uint8_t *)guest->mem) + CMDLINE_ADDR); 110 | guest->kernelMemAddr = (void *)(((uint8_t *)guest->mem) + KERNEL_ADDR); 111 | 112 | memset(boot, 0, sizeof(struct boot_params)); 113 | memmove(boot, kernelFile, sizeof(struct boot_params)); 114 | size_t offset = (boot->hdr.setup_sects + 1) * 512; 115 | boot->hdr.vid_mode = 0xfff; // VGA 116 | boot->hdr.type_of_loader = 0xff; 117 | boot->hdr.ramdisk_image = INITRD_ADDR; 118 | boot->hdr.ramdisk_size = initrdFileSize; 119 | boot->hdr.loadflags |= 120 | CAN_USE_HEAP | LOADED_HIGH | KEEP_SEGMENTS; // | 0x01 | KEEP_SEGMENTS; 121 | boot->hdr.heap_end_ptr = 0xFE00; 122 | boot->hdr.cmd_line_ptr = CMDLINE_ADDR; 123 | boot->hdr.cmdline_size = strlen(kernelCmdline); 124 | memset(cmdline, 0, boot->hdr.cmdline_size); 125 | memcpy(cmdline, kernelCmdline, strlen(kernelCmdline)); 126 | memmove(guest->kernelMemAddr, (char *)kernelFile + offset, 127 | kernelFileSize - offset); 128 | 129 | // Setup E820Entries 130 | addE820Entry(boot, RealModeIvtBegin, EBDAStart - RealModeIvtBegin, E820Ram); 131 | addE820Entry(boot, EBDAStart, VGARAMBegin - EBDAStart, E820Reserved); 132 | addE820Entry(boot, MBBIOSBegin, MBBIOSEnd - MBBIOSBegin, E820Reserved); 133 | addE820Entry(boot, KERNEL_ADDR, (MEM_SIZE)-KERNEL_ADDR, E820Ram); 134 | return 0; 135 | } 136 | 137 | int addE820Entry(struct boot_params *boot, uint64_t addr, uint64_t size, 138 | uint32_t type) { 139 | size_t i = boot->e820_entries; 140 | boot->e820_table[i] = (struct boot_e820_entry){ 141 | .addr = addr, 142 | .size = size, 143 | .type = type, 144 | }; 145 | boot->e820_entries = i + 1; 146 | return 0; 147 | } 148 | 149 | int cleanupKernelVM(kernelGuest *guest) { 150 | close(guest->vcpu_fd); 151 | close(guest->vmfd); 152 | close(guest->kvm_fd); 153 | free(guest->dirty_bitmap); 154 | munmap(guest->mem, 1 << 30); 155 | return 0; 156 | } 157 | 158 | int enableDebug(kernelGuest *guest) { 159 | /* For some reason the alternative_instructions function in the kernel is 160 | * triggered cause an interrupt. Don't know a way to resolve and proceed 161 | */ 162 | struct kvm_guest_debug debug = { 163 | .control = KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP, 164 | }; 165 | 166 | if (ioctl(guest->vcpu_fd, KVM_SET_GUEST_DEBUG, &debug) < 0) 167 | ERR("KVM_SET_GUEST_DEBUG failed"); 168 | 169 | return 0; 170 | } 171 | 172 | int updateStats(kernelGuest *guest) { 173 | pthread_mutex_lock(guest->stats->lock); 174 | guest->stats->cycles_reset += local_stats.cycles_reset; 175 | guest->stats->cycles_run += local_stats.cycles_run; 176 | guest->stats->cases += local_stats.cases; 177 | guest->stats->totalPCs = local_stats.totalPCs; 178 | 179 | // Single sample 180 | // guest->stats->numOfPagesReset = local_stats.numOfPagesReset; 181 | 182 | pthread_mutex_unlock(guest->stats->lock); 183 | 184 | local_stats.cycles_reset = 0; 185 | local_stats.cycles_run = 0; 186 | local_stats.cases = 0; 187 | 188 | last_report = __rdtsc(); 189 | return 0; 190 | } 191 | 192 | /* 193 | * runKernelVM 194 | * The main execution loop for the VM. 195 | * */ 196 | int runKernelVM(kernelGuest *guest) { 197 | local_stats.cycles_reset = 0; 198 | local_stats.cycles_run = 0; 199 | local_stats.cases = 0; 200 | local_stats.totalPCs = 0; 201 | last_report = 0; 202 | 203 | int run_size = ioctl(guest->kvm_fd, KVM_GET_VCPU_MMAP_SIZE, 0); 204 | auto *run = (struct kvm_run *)mmap(nullptr, run_size, PROT_READ | PROT_WRITE, 205 | MAP_SHARED, guest->vcpu_fd, 0); 206 | 207 | for (;;) { 208 | uint64_t start_cyc_run = __rdtsc(); 209 | int ret = ioctl(guest->vcpu_fd, KVM_RUN, 0); 210 | if (ret < 0) { 211 | cleanupKernelVM(guest); 212 | ERR("kvm_run failed"); 213 | } 214 | local_stats.cycles_run += __rdtsc() - start_cyc_run; 215 | 216 | // Check if we can report stats to main thread 217 | // On a 2.1 Ghz processor this is 105 reports a second. 218 | if (__rdtsc() - last_report > 20000000) { 219 | updateStats(guest); 220 | } 221 | 222 | printf("[*] Exit Reason: %d\n", run->exit_reason); 223 | switch (run->exit_reason) { 224 | case KVM_EXIT_IO: // TODO: Add system for ttys to be sent to stdout. 225 | switch (run->io.port) { 226 | case 0x3f8: 227 | if (run->io.direction == KVM_EXIT_IO_OUT) 228 | write(STDOUT_FILENO, (char *)run + run->io.data_offset, 1); 229 | break; 230 | case 0x3fd: 231 | if (run->io.direction == KVM_EXIT_IO_IN) 232 | *((char *)run + run->io.data_offset) = 233 | 0x20; // for console input to be replaced by emulation framework 234 | break; 235 | case 0xdead: // Port Reserved by os-handler kernel module 236 | if (run->io.direction == KVM_EXIT_IO_OUT) { 237 | uint8_t *ioctl_cmd = (uint8_t *)run + run->io.data_offset; 238 | uint64_t start_reset; 239 | 240 | switch (*ioctl_cmd) { 241 | case TAKE_SNAPSHOT: 242 | enableDebug(guest); 243 | 244 | // Breakpoint on kasan reporting function 245 | addBreakpoint(guest, KASAN_REPORT_COLD); 246 | createSnapshot(guest); 247 | break; 248 | case RESTORE_VM: 249 | start_reset = __rdtsc(); 250 | local_stats.cases += 1; 251 | local_stats.numOfPagesReset = restoreSnapshot(guest); 252 | local_stats.cycles_reset += __rdtsc() - start_reset; 253 | break; 254 | default: 255 | printf("[!] Unknown ioctl command: %d\n", *ioctl_cmd); 256 | break; 257 | } 258 | } 259 | break; 260 | case 0xbeef: 261 | uint32_t *newPC; 262 | if (run->io.direction != KVM_EXIT_IO_OUT) 263 | break; 264 | newPC = (uint32_t *)run + run->io.data_offset; 265 | if (addPC(*newPC) == 1) { 266 | printf("hello!\n"); 267 | local_stats.totalPCs += 1; 268 | } 269 | break; 270 | default: 271 | break; 272 | } 273 | break; 274 | case KVM_EXIT_HLT: 275 | printf("\n\t[!] Encountered HLT instruction\n\n"); 276 | dumpVCPURegs(guest); 277 | exit(-1); 278 | case KVM_EXIT_FAIL_ENTRY: 279 | err(1, "[!] FAIL_ENTRY: hw bits failure reason: 0x%llx\n", 280 | run->fail_entry.hardware_entry_failure_reason); 281 | case KVM_EXIT_SHUTDOWN: 282 | printf("[!] Shutdown Received\n"); 283 | dumpVCPURegs(guest); 284 | return 0; 285 | case KVM_EXIT_DEBUG: 286 | printf("[!] Encountered Debug event\n"); 287 | printf("[!] KASAN tripped!\n[!] Dumping vcpu registers"); 288 | dumpVCPURegs(guest); 289 | exit(-1); 290 | default: 291 | printf("[!] Unknown Exit Reason: %d\n", run->exit_reason); 292 | return -1; 293 | } 294 | } 295 | } 296 | 297 | /* 298 | * initVMRegs 299 | * Sets up registers for the VM. 300 | * Sourced from the Linux x86 boot protocol. 301 | * */ 302 | int initVMRegs(kernelGuest *guest) { 303 | struct kvm_regs regs {}; 304 | struct kvm_sregs sregs {}; 305 | if (ioctl(guest->vcpu_fd, KVM_GET_SREGS, &sregs) < 0) 306 | ERR("Failed to get special registers"); 307 | 308 | sregs.cs.base = 0; 309 | sregs.cs.limit = ~0; 310 | sregs.cs.g = 1; 311 | 312 | sregs.ds.base = 0; 313 | sregs.ds.limit = ~0; 314 | sregs.ds.g = 1; 315 | 316 | sregs.fs.base = 0; 317 | sregs.fs.limit = ~0; 318 | sregs.fs.g = 1; 319 | 320 | sregs.gs.base = 0; 321 | sregs.gs.limit = ~0; 322 | sregs.gs.g = 1; 323 | 324 | sregs.es.base = 0; 325 | sregs.es.limit = ~0; 326 | sregs.es.g = 1; 327 | 328 | sregs.ss.base = 0; 329 | sregs.ss.limit = ~0; 330 | sregs.ss.g = 1; 331 | 332 | sregs.cs.db = 1; 333 | sregs.ss.db = 1; 334 | sregs.cr0 |= 1; // enable protected mode 335 | 336 | if (ioctl(guest->vcpu_fd, KVM_SET_SREGS, &sregs) < 0) 337 | ERR("Failed to set special registers"); 338 | 339 | if (ioctl(guest->vcpu_fd, KVM_GET_REGS, ®s) < 0) 340 | ERR("Failed to get registers"); 341 | 342 | regs = (struct kvm_regs){ 343 | .rsi = BOOT_PARAM_ADDR, 344 | .rip = KERNEL_ADDR, 345 | .rflags = 2, 346 | }; 347 | 348 | if (ioctl(guest->vcpu_fd, KVM_SET_REGS, ®s) < 0) 349 | ERR("Failed to set registers"); 350 | return 0; 351 | } 352 | 353 | /* 354 | * createCPUID 355 | * Set up the CPUID instruction for linux to recognize this harness as KVM and 356 | * what processor features are available to the operating system. 357 | * */ 358 | int createCPUID(kernelGuest *guest) { 359 | struct kvm_cpuid2 *kvm_cpuid; 360 | 361 | kvm_cpuid = (struct kvm_cpuid2 *)calloc( 362 | 1, sizeof(*kvm_cpuid) + 100 * sizeof(*kvm_cpuid->entries)); 363 | 364 | kvm_cpuid->nent = 100; 365 | if (ioctl(guest->kvm_fd, KVM_GET_SUPPORTED_CPUID, kvm_cpuid) < 0) 366 | ERR("KVM_GET_SUPPORTED_CPUID failed"); 367 | 368 | filterCPUID(kvm_cpuid); 369 | 370 | if (ioctl(guest->vcpu_fd, KVM_SET_CPUID2, kvm_cpuid) < 0) 371 | ERR("KVM_SET_CPUID2 failed"); 372 | 373 | free(kvm_cpuid); 374 | return 0; 375 | } 376 | 377 | int filterCPUID(struct kvm_cpuid2 *cpuid) { 378 | // Remove CPUID functions that are not supported by Tuscan-Leather 379 | for (unsigned int i = 0; i < cpuid->nent; i++) { 380 | struct kvm_cpuid_entry2 *entry = &cpuid->entries[i]; 381 | 382 | switch (entry->function) { 383 | case KVM_CPUID_FEATURES: 384 | // Vendor name 385 | entry->eax = KVM_CPUID_FEATURES; 386 | entry->ebx = 0x4b4d564b; 387 | entry->ecx = 0x564b4d56; 388 | entry->edx = 0x4d; 389 | break; 390 | case 1: 391 | // Set X86_FEATURE_HYPERVISOR 392 | if (entry->index == 0) 393 | entry->ecx |= (1 << 31); 394 | break; 395 | case 6: 396 | // Clear X86_FEATURE_EPB 397 | entry->ecx = entry->ecx & ~(1 << 3); 398 | break; 399 | case 10: { // Architectural Performance Monitoring 400 | union cpuid10_eax { 401 | struct { 402 | unsigned int version_id : 8; 403 | unsigned int num_counters : 8; 404 | unsigned int bit_width : 8; 405 | unsigned int mask_length : 8; 406 | } split; 407 | unsigned int full; 408 | } eax{}; 409 | 410 | /* 411 | * If the host has perf system running, 412 | * but no architectural events available 413 | * through kvm pmu -- disable perf support, 414 | * thus guest won't even try to access msr 415 | * registers. 416 | */ 417 | if (entry->eax) { 418 | eax.full = entry->eax; 419 | if (eax.split.version_id != 2u || !eax.split.num_counters) 420 | entry->eax = 0; 421 | } 422 | break; 423 | } 424 | default: 425 | // Keep the CPUID function as -is 426 | break; 427 | } 428 | } 429 | return 0; 430 | } 431 | 432 | int dumpVCPURegs(kernelGuest *guest) { 433 | struct kvm_regs regs {}; 434 | if (ioctl(guest->vcpu_fd, KVM_GET_REGS, ®s) < 0) 435 | ERR("Failed to get registers - dumpVCPURegs"); 436 | 437 | printf("[*] Register Dump\n"); 438 | printf("[*] rax: 0x%016llx\n", regs.rax); 439 | printf("[*] rbx: 0x%016llx\n", regs.rbx); 440 | printf("[*] rcx: 0x%016llx\n", regs.rcx); 441 | printf("[*] rdx: 0x%016llx\n", regs.rdx); 442 | printf("[*] rsp: 0x%016llx\n", regs.rsp); 443 | printf("[*] rbp: 0x%016llx\n", regs.rbp); 444 | printf("[*] rsi: 0x%016llx\n", regs.rsi); 445 | printf("[*] rdi: 0x%016llx\n", regs.rdi); 446 | printf("[*] rip: 0x%016llx\n", regs.rip); 447 | printf("[*] r8: 0x%016llx\n", regs.r8); 448 | printf("[*] r9: 0x%016llx\n", regs.r9); 449 | printf("[*] r10: 0x%016llx\n", regs.r10); 450 | printf("[*] r11: 0x%016llx\n", regs.r11); 451 | printf("[*] r12: 0x%016llx\n", regs.r12); 452 | printf("[*] r13: 0x%016llx\n", regs.r13); 453 | printf("[*] r14: 0x%016llx\n", regs.r14); 454 | printf("[*] r15: 0x%016llx\n", regs.r15); 455 | 456 | return 0; 457 | } 458 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | --------------------------------------------------------------------------------