int ckpt_restore_sigpending(struct sigpending *sigpending, int shared, ckpt_desc_t desc) { int i; ckpt_sigqueue_t queue; ckpt_sigpending_t pending; struct siginfo *info = &queue.info; if (ckpt_read(desc, &pending, sizeof(ckpt_sigpending_t)) != sizeof(ckpt_sigpending_t)) { log_err("failed to get sigpending"); return -EIO; } for (i = 0; i < pending.count; i++) { if (ckpt_read(desc, &queue, sizeof(ckpt_sigqueue_t)) != sizeof(ckpt_sigqueue_t)) { log_err("failed to get sigqueue"); return -EIO; } if (shared) { read_lock((rwlock_t *)TASKLIST_LOCK); group_send_sig_info(info->si_signo, info, current); read_unlock((rwlock_t *)TASKLIST_LOCK); } else send_sig_info(info->si_signo, info, current); } spin_lock_irq(¤t->sighand->siglock); sigorsets(&sigpending->signal, &sigpending->signal, &pending.signal); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); return 0; }
int ckpt_restore_fs(ckpt_desc_t desc) { int length; int ret = 0; char *path = (char *)kmalloc(CKPT_PATH_MAX, GFP_KERNEL); log_restore_fs("restoring fs ..."); if (!path) { log_err("no memory"); return -ENOMEM; } if (ckpt_read(desc, &length, sizeof(int)) != sizeof(int)) { log_err("invalid cwd"); ret = -EIO; goto out; } if (length <= 0) { log_err("invalid cwd"); ret = -EINVAL; goto out; } if (ckpt_read(desc, path, length) != length) { log_err("invalid cwd"); ret = -EIO; goto out; } log_restore_fs("cwd=%s", path); ret = ckpt_set_cwd(path); if (ret) { log_err("failed to set cwd"); goto out; } if (ckpt_read(desc, &length, sizeof(int)) != sizeof(int)) { log_err("invalid root"); ret = -EIO; goto out; } if (length <= 0) { log_err("invalid root"); ret = -EINVAL; goto out; } if (ckpt_read(desc, path, length) != length) { log_err("invalid root"); ret = -EIO; goto out; } log_restore_fs("root=%s", path); ret = ckpt_set_root(path); if (ret) { log_err("failed to set root"); goto out; } log_restore_pos(desc); out: kfree(path); return ret; }
int ckpt_restore_files(ckpt_desc_t desc) { int mode; int ret = 0; ckpt_files_struct_t fs; log_restore_files("restoring files ..."); if (ckpt_read(desc, &fs, sizeof(ckpt_files_struct_t)) != sizeof(ckpt_files_struct_t)) { log_err("failed to read"); return -EIO; } do { if (ckpt_read(desc, &mode, sizeof(int)) != sizeof(int)) { log_err("failed to read"); return -EIO; } switch (mode) { case S_IFREG: case S_IFDIR: ret = ckpt_restore_file(desc); break; default: break; } if (ret) { log_err("failed to restore file"); return ret; } } while (mode); log_restore_pos(desc); return ret; }
int ckpt_restore_pages(ckpt_vma_t *area, ckpt_desc_t desc) { int count = 0; unsigned long addr = 0; for (;;) { if (ckpt_read(desc, &addr, sizeof(addr)) != sizeof(addr)) { log_err("failed to get address"); return -EIO; } if (!addr) break; if ((addr < area->start) || (addr >= area->end)) { log_err("invalid address"); return -EINVAL; } if (ckpt_uread(desc, (void *)addr, PAGE_SIZE) != PAGE_SIZE) { log_err("failed to get page"); return -EIO; } count++; } if (ckpt_get_vma_prot(area) & PROT_EXEC) flush_icache_range(area->start, area->end); return count; }
int ckpt_restore_file(ckpt_desc_t desc) { int sz; int ret = 0; ckpt_file_t file; struct file *filp; char *path = kmalloc(CKPT_PATH_MAX, GFP_KERNEL); if (!path) { log_err("no memory"); return -ENOMEM; } if (ckpt_read(desc, &file, sizeof(ckpt_file_t)) != sizeof(ckpt_file_t)) { log_err("failed to get file"); ret = -EIO; goto out; } if (!file.sz) { log_err("invalid file name"); ret = -EINVAL; goto out; } sz = file.sz; if (ckpt_read(desc, path, sz) != sz) { log_err("failed to get path"); ret = -EIO; goto out; } filp = ckpt_reopen_file(&file, path); if (IS_ERR(filp)) { log_err("failed to reopen file"); ret = -EINVAL; goto out; } log_restore_file("%s", path); out: kfree(path); return ret; }
int ckpt_restore_mem(char *node, pid_t gpid, ckpt_desc_t desc) { int i; int ret; ckpt_mm_t memory; struct mm_struct *mm = current->mm; log_restore_mem("restoring mem ..."); if (ckpt_read(desc, &memory, sizeof(ckpt_mm_t)) != sizeof(ckpt_mm_t)) { log_err("failed to get mem"); return -EIO; } while (mm->mmap) { struct vm_area_struct *vma = mm->mmap; if (vma->vm_start >= TASK_SIZE) break; ret = do_munmap(mm, vma->vm_start, vma->vm_end - vma->vm_start); if (ret) { log_err("failed to unmap"); return ret; } } down_write(&mm->mmap_sem); mm->task_size = TASK_SIZE; arch_pick_mmap_layout(mm); mm->mmap_base = memory.mmap_base; mm->free_area_cache = memory.mmap_base; mm->cached_hole_size = ~0UL; mm->start_code = memory.start_code; mm->end_code = memory.end_code; mm->start_data = memory.start_data; mm->end_data = memory.end_data; mm->start_brk = memory.start_brk; mm->brk = memory.brk; mm->start_stack = memory.start_stack; mm->arg_start = memory.arg_start; mm->arg_end = memory.arg_end; mm->env_start = memory.env_start; mm->env_end = memory.env_end; up_write(&mm->mmap_sem); for (i = 0; i < memory.map_count; i++) { ret = ckpt_restore_vma(node, gpid, desc); if (ret) { log_err("failed to restore vma"); return ret; } } log_restore_pos(desc); return 0; }
int ckpt_restore_fpu(ckpt_desc_t desc) { int ret; int flag; log_restore_fpu("restoring fpu ..."); if (ckpt_read(desc, &flag, sizeof(int)) != sizeof(int)) { log_err("failed to get file"); return -EIO; } kernel_fpu_begin(); clear_used_math(); if (flag) { if (!ckpt_get_i387(current)) { init_fpu(current); if (!ckpt_get_i387(current)) { log_err("failed to get i387"); return -EFAULT; } } if (ckpt_read(desc, ckpt_get_i387(current), xstate_size) != xstate_size) { log_err("failed to get i387"); return -EFAULT; } ret = ckpt_check_fpu_state(); if (ret) { log_err("failed to restore i387"); return ret; } set_used_math(); } kernel_fpu_end(); log_restore_pos(desc); return 0; }
int ckpt_restore_cpu(ckpt_desc_t desc) { int i; ckpt_cpu_t cpu; unsigned long fs; unsigned long gs; struct pt_regs *regs = task_pt_regs(current); if (ckpt_read(desc, &cpu, sizeof(ckpt_cpu_t)) != sizeof(ckpt_cpu_t)) { log_err("failed to restore cpu"); return -EIO; } log_restore_cpu("restoring regs ..."); fs = cpu.regs.fs; gs = cpu.regs.gs; cpu.regs.fs = 0; cpu.regs.gs = 0; cpu.regs.cs = __USER_CS; cpu.regs.ds = __USER_DS; cpu.regs.es = __USER_DS; cpu.regs.ss = __USER_DS; cpu.regs.flags = 0x200 | (cpu.regs.flags & 0xff); *regs = cpu.regs; log_restore_cpu("restoring tls ..."); for (i = 0; i < GDT_ENTRY_TLS_ENTRIES; i++) { if ((cpu.tls_array[i].b & 0x00207000) != 0x00007000) { cpu.tls_array[i].a = 0; cpu.tls_array[i].b = 0; } current->thread.tls_array[i] = cpu.tls_array[i]; } load_TLS(¤t->thread, get_cpu()); put_cpu(); i = fs >> 3; if ((i < GDT_ENTRY_TLS_MIN) || (i > GDT_ENTRY_TLS_MAX) || ((fs & 7) != 3)) fs = 0; i = gs >> 3; if ((i < GDT_ENTRY_TLS_MIN) || (i > GDT_ENTRY_TLS_MAX) || ((gs & 7) != 3)) gs = 0; regs->fs = fs; regs->gs = gs; log_regs(regs); current_thread_info()->sysenter_return = cpu.sysenter_return; log_restore_pos(desc); return 0; }
int ckpt_restore_ext(ckpt_desc_t desc) { int ret; ckpt_ext_t ext; mm_segment_t fs; log_restore_ext("restoring extra attributes ..."); if (ckpt_read(desc, &ext, sizeof(ckpt_ext_t)) != sizeof(ckpt_ext_t)) { log_err("failed to read extra attributes"); return -EIO; } set_personality(ext.personality); current->clear_child_tid = ext.clear_child_tid; fs = get_fs(); set_fs(KERNEL_DS); ret = sys_prctl(PR_SET_NAME, (unsigned long)ext.comm, 0, 0, 0); set_fs(fs); log_restore_pos(desc); return ret; }
int ckpt_restore_cred(ckpt_desc_t desc) { int ret = 0; ckpt_cred_t cred; gid_t *groups = NULL; const struct cred *curr_cred = current->cred; log_restore_cred("restoring cred ..."); if (ckpt_read(desc, &cred, sizeof(ckpt_cred_t)) != sizeof(ckpt_cred_t)) { log_err("failed to get cred"); return -EIO; } if (cred.ngroups > NGROUPS_MAX) { log_err("ngroups (%d) > NGROUPS_MAX", cred.ngroups); return -EINVAL; } if (cred.ngroups > 0) { int i; size_t size = cred.ngroups * sizeof(gid_t); struct group_info *gi = curr_cred->group_info; groups = vmalloc(size); if (!groups) { log_err("no memory"); return -ENOMEM; } if (ckpt_read(desc, groups, size) != size) { log_err("failed to get groups"); ret = -EIO; goto out; } for (i = 0; i < cred.ngroups; i++) { if (!groups_search(gi, groups[i])) { mm_segment_t fs = get_fs(); set_fs(KERNEL_DS); ret = sys_setgroups(cred.ngroups, groups); set_fs(fs); if (ret < 0) { log_err("failed to set groups"); goto out; } break; } } } current->gpid = cred.gpid; ret = sys_setresgid(cred.gid, cred.egid, cred.sgid); if (ret < 0) { log_err("failed to restore gid"); goto out; } ret = sys_setresuid(cred.uid, cred.euid, cred.suid); if (ret < 0) { log_err("failed to restore uid"); goto out; } if ((curr_cred->euid == curr_cred->uid) && (curr_cred->egid == curr_cred->gid)) set_dumpable(current->mm, 1); else set_dumpable(current->mm, *compat_suid_dumpable); log_restore_pos(desc); out: if (groups) vfree(groups); return ret; }
int ckpt_restore_vma(char *node, pid_t gpid, ckpt_desc_t desc) { int ret; int nr_pages = -1; char *path = NULL; ckpt_vma_t area; if (ckpt_read(desc, &area, sizeof(ckpt_vma_t)) != sizeof(ckpt_vma_t)) { log_err("failed to get area"); return -EIO; } if (area.arch) { void *vdso; void *sysenter_return = current_thread_info()->sysenter_return; current->mm->context.vdso = (void *)(~0UL); ret = arch_setup_additional_pages(NULL, 0); if (ret < 0) { log_err("failed to setup additional pages"); return ret; } vdso = current->mm->context.vdso; if ((vdso != (void *)(0UL)) && (vdso != (void *)area.start)) { ret = ckpt_vma_remap((unsigned long)vdso, &area); if (ret < 0) { log_err("failed to remap vma"); return ret; } } current->mm->context.vdso = (void *)area.start; current_thread_info()->sysenter_return = sysenter_return; } else { int sz = area.sz; if (sz) { path = (char *)kmalloc(CKPT_PATH_MAX, GFP_KERNEL); if (!path) { log_err("no memory"); return -ENOMEM; } if (ckpt_read(desc, path, sz) != sz) { log_err("failed to get path"); kfree(path); return -EIO; } } if (ckpt_is_mapped_area(&area)) { unsigned long prot = ckpt_get_vma_prot(&area); unsigned long flags = ckpt_get_vma_flags(&area); ret = ckpt_map_attach(node, gpid, area.start, area.end - area.start, prot, flags); if (ret) { log_err("failed to attach"); return ret; } } else { ret = ckpt_vma_map(path, &area); if (ret) { log_err("failed to map vma"); return ret; } nr_pages = ckpt_restore_pages(&area, desc); if (nr_pages < 0) { log_err("failed to restore pages"); return nr_pages; } } sys_mprotect(area.start, area.end - area.start, ckpt_get_vma_prot(&area)); } log_restore_vma(area.start, area.end, path, nr_pages, ckpt_debug_checksum(current->mm, NULL, area.start)); return 0; }
int ckpt_restore_signals(ckpt_desc_t desc) { int i; int ret; stack_t sigstack; sigset_t sigblocked; log_restore_signals("restoring sigstack ..."); if (ckpt_read(desc, &sigstack, sizeof(stack_t)) != sizeof(stack_t)) { log_err("failed to get sigstack"); return -EIO; } ret = compat_sigaltstack(current, &sigstack, NULL, 0); if (ret) { log_err("failed to restore sigstack (ret=%d)", ret); return ret; } log_restore_signals("restoring sigblocked ..."); if (ckpt_read(desc, &sigblocked, sizeof(sigset_t)) != sizeof(sigset_t)) { log_err("failed to restore sigstack"); return -EIO; } sigdelsetmask(&sigblocked, sigmask(SIGKILL) | sigmask(SIGSTOP)); spin_lock_irq(¤t->sighand->siglock); current->blocked = sigblocked; recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); log_restore_signals("restoring pending ..."); ret = ckpt_restore_sigpending(¤t->pending, 0, desc); if (ret) { log_err("failed to restore pending"); return ret; } ret = ckpt_restore_sigpending(¤t->signal->shared_pending, 1, desc); if (ret) { log_err("failed to restore shared_pending"); return ret; } log_restore_signals("restoring sigaction ..."); for (i = 0; i < _NSIG; i++) { struct k_sigaction sigaction; if (ckpt_read(desc, &sigaction, sizeof(struct k_sigaction)) != sizeof(struct k_sigaction)) { log_err("failed to get sigaction"); return -EIO; } if ((i != SIGKILL - 1) && (i != SIGSTOP - 1)) { ret = do_sigaction(i + 1, &sigaction, 0); if (ret) { log_err("failed to restore sigaction (ret=%d)", ret); return ret; } } } log_restore_pos(desc); return 0; }
int main(int argc, char **argv) { char *ckptname = "ckpt_test"; char *sec = "default"; char *val; void *h; char buf[64]; int ret; int op = 0; while((ret = getopt(argc, argv, "c:w:r:d:j?")) != EOF) { switch(ret) { case 'c': ckptname = optarg; break; case 'w': op = 'w'; sec = optarg; break; case 'r': op = 'r'; sec = optarg; break; case 'd': val = optarg; break; case '?': case 'h': usage(0); default: usage(1); } } if (!op) { usage(1); } if (!sec) { usage(1); } h = ckpt_init(ckptname, 262144, 4096, 64, 10); if (!h) { perror("ckpt_init"); return -1; } if (op == 'w') { if (ckpt_write(h, sec, val, strlen(val)+1) < 0) { perror("ckpt_write"); return 1; } } else if (op == 'r') { ret = ckpt_read(h, sec, buf, sizeof(buf)); if (ret < 0) { perror("ckpt_read"); return 1; } printf("%d bytes\nDATA for '%s':\n%s\n", ret, sec, buf); } ckpt_finish(h); return 0; }