def spec_lemma_nr_dmapages_refcnt(kernelstate): conj = [] pid = util.FreshBitVec('pid', dt.pid_t) dmapn = util.FreshBitVec('dmapn', dt.dmapn_t) # General invariant -- a free dma page has no owner conj.append( z3.ForAll([dmapn], z3.Implies( is_dmapn_valid(dmapn), is_pid_valid(kernelstate.dmapages[dmapn].owner) == ( kernelstate.dmapages[dmapn].type != dt.page_type.PAGE_TYPE_FREE)))) # PROC_UNUSED state implies refcount is 0 (sys_clone needs this) conj.append( z3.ForAll( [pid], z3.Implies( is_pid_valid(pid), z3.Implies( kernelstate.procs[pid].state == dt.proc_state.PROC_UNUSED, kernelstate.procs[pid].nr_dmapages() == z3.BitVecVal( 0, dt.size_t))))) # # Correctness definition for `permutation` based refcount kernelstate.procs.nr_dmapages.check( conj, is_owner_valid=is_pid_valid, is_owned_valid=is_dmapn_valid, max_refs=dt.NDMAPAGE, ownerfn=lambda dmapn: kernelstate.dmapages[dmapn].owner) return z3.And(*conj)
def spec_lemma_nr_fds_refcnt(kernelstate): conj = [] pid = util.FreshBitVec('pid', dt.pid_t) fd = util.FreshBitVec('fd', dt.fd_t) # unused procs do not have any fds. # valid(pid) & state(pid)== PROC_UNUSED ==> pid.nr_fds == 0 conj.append( z3.ForAll( [pid], z3.Implies( is_pid_valid(pid), z3.Implies( kernelstate.procs[pid].state == dt.proc_state.PROC_UNUSED, kernelstate.procs[pid].nr_fds() == z3.BitVecVal( 0, dt.size_t))))) # unused procs do not have any opened files # valid(pid) & valid(fd) & state(pid) == PROC_UNUSED ==> !valid(openedfile(pid, fd)) conj.append( z3.ForAll( [pid, fd], z3.Implies( z3.And(is_pid_valid(pid), is_fd_valid(fd)), z3.Implies( kernelstate.procs[pid].state == dt.proc_state.PROC_UNUSED, z3.Not(is_fn_valid(kernelstate.procs[pid].ofile(fd))))))) # a procs have opened a file, the state of this procs must not be UNUSED # valid(pid) & valid(fd) & valid(fn) ==> state(pid) != PROC_UNUSED conj.append( z3.ForAll( [pid, fd], z3.Implies( z3.And(is_pid_valid(pid), is_fd_valid(fd), is_fn_valid(kernelstate.procs[pid].ofile(fd))), kernelstate.procs[pid].state != dt.proc_state.PROC_UNUSED))) # Correctness definition for `permutation` based refcount kernelstate.procs.nr_fds.check( conj, is_owner_valid=is_pid_valid, is_owned_valid=is_fd_valid, max_refs=dt.NOFILE, ownedby=lambda pid, fd: is_fn_valid(kernelstate.procs[pid].ofile(fd))) return z3.And(*conj)
def spec_lemma_nr_pages_refcnt(kernelstate): conj = [] pid = util.FreshBitVec('pid', dt.pid_t) # PROC_UNUSED state implies refcount is 0 (sys_clone needs this) conj.append( z3.ForAll( [pid], z3.Implies( is_pid_valid(pid), z3.Implies( kernelstate.procs[pid].state == dt.proc_state.PROC_UNUSED, kernelstate.procs[pid].nr_pages() == z3.BitVecVal( 0, dt.size_t))))) # Correctness definition for `permutation` based refcount kernelstate.procs.nr_pages.check( conj, is_owner_valid=is_pid_valid, is_owned_valid=is_pn_valid, max_refs=dt.NPAGE, ownerfn=lambda pn: kernelstate.pages[pn].owner) return z3.And(*conj)
def spec_corollary_pgwalk(kernelstate): pid = util.FreshBitVec('pid', dt.pid_t) va = dt.FreshVA() pml4 = kernelstate.procs[pid].page_table_root # Abstract model of a page_walk starting from some root page, writable, present = page_walk(kernelstate, pml4, *va) # If a four level page-walk from some pid returns a page, # that page must be exclusively owned by the pid. # furthermore, if the page is writable, # it has to be a frame. isolation = util.Implies( present, kernelstate.pages[page].owner == pid, z3.Implies( writable, kernelstate.pages[page].type == dt.page_type.PAGE_TYPE_FRAME)) # valid(pid) & pid.state == active & valid(va) ==> page.owner == pid && page.type == FRAME (active is either EMBRYO, RUNNABLE or RUNNING) return z3.ForAll([pid] + va, z3.Implies( z3.And( is_pid_valid(pid), is_status_live(kernelstate.procs[pid].state), is_va_valid(va), ), isolation))
def spec_lemma_nr_ports_refcnt(kernelstate): conj = [] pid = util.FreshBitVec('pid', dt.pid_t) port = util.FreshBitVec('port', dt.uint16_t) # unused procs don't own any ports # valid([port:pid]) ==> [port:pid].state != UNUSED conj.append( z3.ForAll([port], z3.Implies( is_pid_valid(kernelstate.io[port].owner), kernelstate.procs[kernelstate.io[port].owner].state != dt.proc_state.PROC_UNUSED))) # pid.state == UNUSED ==> pid.nr_ports == 0 conj.append( z3.ForAll( [pid], z3.Implies( kernelstate.procs[pid].state == dt.proc_state.PROC_UNUSED, kernelstate.procs[pid].nr_ports() == z3.BitVecVal( 0, dt.size_t)))) # Correctness definition for `permutation` based refcount kernelstate.procs.nr_ports.check( conj, is_owner_valid=is_pid_valid, is_owned_valid=lambda n: z3.BoolVal(True), max_refs=2**dt.uint16_t.size(), ownerfn=lambda port0: kernelstate.io[port0].owner) return z3.And(*conj)
def sys_reap(old, pid): cond = z3.And( is_pid_valid(pid), # Only the owner can reap a child old.procs[pid].ppid == old.current, # The pid to reap is a zombie old.procs[pid].state == dt.proc_state.PROC_ZOMBIE, # The proc has no children/open fds/pages/devices/ports old.procs[pid].nr_devs() == z3.BitVecVal(0, dt.size_t), old.procs[pid].nr_children() == z3.BitVecVal(0, dt.size_t), old.procs[pid].nr_fds() == z3.BitVecVal(0, dt.size_t), old.procs[pid].nr_pages() == z3.BitVecVal(0, dt.size_t), old.procs[pid].nr_dmapages() == z3.BitVecVal(0, dt.size_t), old.procs[pid].nr_ports() == z3.BitVecVal(0, dt.size_t), old.procs[pid].nr_vectors() == z3.BitVecVal(0, dt.size_t), old.procs[pid].nr_intremaps() == z3.BitVecVal(0, dt.size_t), ) new = old.copy() new.procs[old.current].nr_children[pid] -= 1 new.procs[pid].state = dt.proc_state.PROC_UNUSED new.procs[pid].ppid = z3.BitVecVal(0, dt.pid_t) new.procs[pid].page_table_root = z3.BitVecVal(0, dt.pn_t) new.procs[pid].stack = z3.BitVecVal(0, dt.pn_t) new.procs[pid].killed = z3.BoolVal(False) new.procs[pid].hvm = z3.BitVecVal(0, dt.pn_t) new.procs[pid].use_io_bitmap = z3.BoolVal(False) new.procs[pid].io_bitmap_a = z3.BitVecVal(0, dt.pn_t) new.procs[pid].io_bitmap_b = z3.BitVecVal(0, dt.pn_t) return cond, util.If(cond, new, old)
def spec_lemma_nr_devs_refcnt(kernelstate): conj = [] pid = util.FreshBitVec('pid', dt.pid_t) devid = util.FreshBitVec('devid', dt.devid_t) # unused procs don't own any devices conj.append( z3.ForAll([devid], z3.Implies( is_pid_valid(kernelstate.pci[devid].owner), kernelstate.procs[kernelstate.pci[devid].owner].state != dt.proc_state.PROC_UNUSED))) conj.append( z3.ForAll( [pid], z3.Implies( kernelstate.procs[pid].state == dt.proc_state.PROC_UNUSED, kernelstate.procs[pid].nr_devs() == z3.BitVecVal(0, dt.size_t)))) # Correctness definition for `permutation` based refcount kernelstate.procs.nr_devs.check( conj, is_owner_valid=is_pid_valid, is_owned_valid=lambda n: z3.BoolVal(True), max_refs=2**dt.devid_t.size(), ownerfn=lambda devid0: kernelstate.pci[devid0].owner) return z3.And(*conj)
def sys_close(old, pid, fd): cond = z3.And( is_pid_valid(pid), is_fd_valid(fd), # pid is either current or a zombie z3.Or( pid == old.current, old.procs[pid].state == dt.proc_state.PROC_ZOMBIE), is_fn_valid(old.procs[pid].ofile(fd)), ) new = old.copy() fn = new.procs[pid].ofile(fd) new.procs[pid].ofile[fd] = z3.BitVecVal(0, dt.fn_t) new.procs[pid].nr_fds[fd] -= 1 # decrement file refcnt new.files[fn].refcnt[(pid, fd)] -= 1 ref = new.files[fn].refcnt() # If the refcnt is zero, clear the file slot new2 = new.copy() new2.files[fn].type = dt.file_type.FD_NONE new2.files[fn].value = z3.BitVecVal(0, dt.uint64_t) new2.files[fn].offset = z3.BitVecVal(0, dt.off_t) new2.files[fn].omode = z3.BitVecVal(0, dt.uint64_t) return cond, util.If(cond, util.If(ref == 0, new2, new), old)
def sys_dup(old, oldfd, pid, newfd): cond = z3.And( is_pid_valid(pid), # the pid is either current or an embryo belonging to current z3.Or(pid == old.current, z3.And( old.procs[pid].ppid == old.current, old.procs[pid].state == dt.proc_state.PROC_EMBRYO)), is_fd_valid(oldfd), is_fn_valid(old.procs[old.current].ofile(oldfd)), is_fd_valid(newfd), z3.Not(is_fn_valid(old.procs[pid].ofile(newfd))), ) new = old.copy() fn = new.procs[old.current].ofile(oldfd) new.procs[pid].ofile[newfd] = fn new.procs[pid].nr_fds[newfd] += 1 # bump file refcnt new.files[fn].refcnt[(pid, newfd)] += 1 return cond, util.If(cond, new, old)
def sys_recv(old, pid, pn, fd): cond = z3.And( is_pid_valid(pid), old.procs[pid].state == dt.proc_state.PROC_RUNNABLE, is_pn_valid(pn), old.pages[pn].owner == old.current, old.pages[pn].type == dt.page_type.PAGE_TYPE_FRAME, z3.Implies(is_fd_valid(fd), z3.Not(is_fn_valid(old.procs[old.current].ofile(fd)))) ) new = old.copy() new.procs[old.current].ipc_from = z3.BitVecVal(0, dt.pid_t) new.procs[old.current].ipc_page = pn new.procs[old.current].ipc_size = z3.BitVecVal(0, dt.size_t) new.procs[old.current].ipc_fd = fd new.procs[old.current].state = dt.proc_state.PROC_SLEEPING new.procs[pid].state = dt.proc_state.PROC_RUNNING new.current = pid return cond, util.If(cond, new, old)
def sys_copy_frame(old, frm, pid, to): cond = z3.And( # frm is a valid FRAME owned by current is_pn_valid(frm), old.pages[frm].type == dt.page_type.PAGE_TYPE_FRAME, old.pages[frm].owner == old.current, # to is a valid frame owned by pid is_pid_valid(pid), is_pn_valid(to), old.pages[to].type == dt.page_type.PAGE_TYPE_FRAME, old.pages[to].owner == pid, # the pid is either current or an embryo belonging to current z3.Or(pid == old.current, z3.And( old.procs[pid].ppid == old.current, old.procs[pid].state == dt.proc_state.PROC_EMBRYO)), ) new = old.copy() # copy contents of page frm to page to new.pages.data = lambda pn, idx, oldfn: \ util.If(pn == to, oldfn(frm, idx), oldfn(pn, idx)) return cond, util.If(cond, new, old)
def kk_wait(old,pid,w_len): cond = z3.And( is_pid_valid(pid), ) new = old.copy() new.esbs[pid].primitive=dt.K5_WAIT new.esbs[pid].dst_port=old.current return cond,util.If(cond,new,old)
def sys_dup2(old, oldfd, pid, newfd): cond = z3.And( is_pid_valid(pid), # the pid is either current or an embryo belonging to current z3.Or(pid == old.current, z3.And( old.procs[pid].ppid == old.current, old.procs[pid].state == dt.proc_state.PROC_EMBRYO)), is_fd_valid(oldfd), is_fn_valid(old.procs[old.current].ofile(oldfd)), is_fd_valid(newfd), ) new1 = old.copy() newfn = new1.procs[pid].ofile(newfd) # If fn != 0 new1.procs[pid].ofile[newfd] = z3.BitVecVal(0, dt.fn_t) new1.procs[pid].nr_fds[newfd] -= 1 # decrement file refcnt new1.files[newfn].refcnt[(pid, newfd)] -= 1 ref = new1.files[newfn].refcnt() # If the refcnt is zero, clear the file slot new1.files[newfn].type = util.If(ref == 0, dt.file_type.FD_NONE, new1.files[newfn].type) new1.files[newfn].value = util.If(ref == 0, z3.BitVecVal(0, dt.uint64_t), new1.files[newfn].value) new1.files[newfn].offset = util.If(ref == 0, z3.BitVecVal(0, dt.off_t), new1.files[newfn].offset) new1.files[newfn].omode = util.If(ref == 0, z3.BitVecVal(0, dt.uint64_t), new1.files[newfn].omode) new2 = util.If(is_fn_valid(old.procs[pid].ofile(newfd)), new1, old.copy()) # un-conditional fn = new2.procs[old.current].ofile(oldfd) new2.procs[pid].ofile[newfd] = fn new2.procs[pid].nr_fds[newfd] += 1 # bump file refcnt new2.files[fn].refcnt[(pid, newfd)] += 1 # posix: if fds are the same, do nothing new3 = util.If(z3.And(old.current == pid, oldfd == newfd), old.copy(), new2) return cond, util.If(cond, new3, old)
def alloc_page_table(old, pid, frm, index, to, perm, from_type, to_type): cond = z3.And( # The to argument is a valid page and is marked as free is_pn_valid(to), old.pages[to].type == dt.page_type.PAGE_TYPE_FREE, # The pid is valid and is either current running process or child embryo is_pid_valid(pid), z3.Or(pid == old.current, z3.And( old.procs[pid].ppid == old.current, old.procs[pid].state == dt.proc_state.PROC_EMBRYO)), # The from parameter is valid and of type PML4 and owned by pid is_pn_valid(frm), old.pages[frm].owner == pid, old.pages[frm].type == from_type, # Index is a valid page index z3.ULT(index, 512), # perm has no unsafe bits on it and it is present perm & (dt.MAX_INT64 ^ dt.PTE_PERM_MASK) == 0, perm & dt.PTE_P != 0, # index does not have the P bit in PML4 old.pages[frm].data(index) & dt.PTE_P == 0, ) new = old.copy() new.pages[to].owner = pid new.pages[to].type = to_type new.pages[frm].data[index] = ( (z3.UDiv(new.pages_ptr_to_int, util.i64(dt.PAGE_SIZE)) + to) << dt.PTE_PFN_SHIFT) | perm # Zero out the new page new.pages[to].data = util.i64(0) # Maintain the "shadow" pgtable new.pages[frm].pgtable_pn[index] = to new.pages[to].pgtable_reverse_pn = frm new.pages[to].pgtable_reverse_idx = index new.pages[frm].pgtable_perm[index] = perm new.pages[frm].pgtable_type[index] = dt.PGTYPE_PAGE new.pages[to].pgtable_pn = util.i64(0) new.pages[to].pgtable_perm = util.i64(0) new.pages[to].pgtable_type = dt.PGTYPE_NONE new.procs[pid].nr_pages[to] += 1 new.flush_tlb(pid) return cond, util.If(cond, new, old)
def sys_set_runnable(old, pid): cond = z3.And( is_pid_valid(pid), old.procs[pid].ppid == old.current, old.procs[pid].state == dt.proc_state.PROC_EMBRYO) new = old.copy() new.procs[pid].state = dt.proc_state.PROC_RUNNABLE return cond, util.If(cond, new, old)
def sys_reparent(old, pid): cond = z3.And( is_pid_valid(pid), is_pid_valid(old.procs[pid].ppid), old.procs[old.procs[pid].ppid].state == dt.proc_state.PROC_ZOMBIE, z3.Or( old.procs[dt.INITPID].state == dt.proc_state.PROC_RUNNABLE, old.procs[dt.INITPID].state == dt.proc_state.PROC_RUNNING, ), ) new = old.copy() new.procs[dt.INITPID].nr_children[pid] += 1 new.procs[old.procs[pid].ppid].nr_children[pid] -= 1 new.procs[pid].ppid = dt.INITPID return cond, util.If(cond, new, old)
def kk_call(old,pid,service,c_len): cond = z3.And( is_pid_valid(pid), is_service_valid(service), ) new = old.copy() #new.esbs[pid].primitive=dt.K5_CALL new.esbs[pid].src_port=old.to.src_port new.esbs[pid].dst_port=old.to.dst_port return cond,util.If(cond,new,old)
def kk_reply(old,pid,ack_err,s_len): cond = z3.And( is_pid_valid(pid), ) new = old.copy() new.esbs[pid].primitive=dt.K5_REPLY new.esbs[pid].src_port=old.current new.esbs[pid].dst_port=pid #new.esbs[pid].head return cond,util.If(cond,new,old)
def spec_lemma_nr_fds_refcnt(kernelstate): conj = [] pid = util.FreshBitVec('pid', dt.pid_t) fd = util.FreshBitVec('fd', dt.fd_t) conj.append( z3.ForAll( [pid], z3.Implies( is_pid_valid(pid), z3.Implies( kernelstate.procs[pid].state == dt.proc_state.PROC_UNUSED, kernelstate.procs[pid].nr_fds() == z3.BitVecVal( 0, dt.size_t))))) conj.append( z3.ForAll( [pid, fd], z3.Implies( z3.And(is_pid_valid(pid), is_fd_valid(fd)), z3.Implies( kernelstate.procs[pid].state == dt.proc_state.PROC_UNUSED, z3.Not(is_fn_valid(kernelstate.procs[pid].ofile(fd))))))) conj.append( z3.ForAll( [pid, fd], z3.Implies( z3.And(is_pid_valid(pid), is_fd_valid(fd), is_fn_valid(kernelstate.procs[pid].ofile(fd))), kernelstate.procs[pid].state != dt.proc_state.PROC_UNUSED))) kernelstate.procs.nr_fds.check( conj, is_owner_valid=is_pid_valid, is_owned_valid=is_fd_valid, max_refs=dt.NOFILE, ownedby=lambda pid, fd: is_fn_valid(kernelstate.procs[pid].ofile(fd))) return z3.And(*conj)
def sys_kill(old, pid): cond = z3.And( is_pid_valid(pid), old.procs[pid].state != dt.proc_state.PROC_UNUSED, old.procs[pid].state != dt.proc_state.PROC_ZOMBIE ) new = old.copy() new.procs[pid].killed = z3.BoolVal(True) new.procs[pid].state = util.If( old.procs[pid].state != dt.proc_state.PROC_RUNNING, dt.proc_state.PROC_ZOMBIE, old.procs[pid].state) return cond, util.If(cond, new, old)
def sys_reclaim_port(old, port): pid = old.io[port].owner cond = z3.And( is_pid_valid(pid), old.procs[pid].state == dt.proc_state.PROC_ZOMBIE ) new = old.copy() new.procs[pid].nr_ports[port] -= 1 new.io[port].owner = z3.BitVecVal(0, dt.pid_t) return cond, util.If(cond, new, old)
def sys_reclaim_vector(old, vector): pid = old.vectors[vector].owner cond = z3.And( is_pid_valid(pid), old.procs[pid].state == dt.proc_state.PROC_ZOMBIE, old.procs[pid].nr_intremaps() == 0, ) new = old.copy() new.vectors[vector].owner = z3.BitVecVal(0, dt.pid_t) new.procs[pid].nr_vectors[vector] -= 1 return cond, util.If(cond, new, old)
def sys_send(old, pid, val, pn, size, fd): cond = z3.And( is_pid_valid(pid), old.procs[pid].state == dt.proc_state.PROC_SLEEPING, is_pn_valid(pn), old.pages[pn].owner == old.current, z3.ULE(size, dt.PAGE_SIZE), z3.Implies(is_fd_valid(fd), is_fn_valid(old.procs[old.current].ofile(fd))), ) new = old.copy() new.procs[pid].ipc_from = old.current new.procs[pid].ipc_val = val new.procs[pid].ipc_size = size # memcpy new.pages.data = lambda pn0, idx0, oldfn: \ util.If(z3.And(pn0 == old.procs[pid].ipc_page, z3.ULT(idx0, size)), oldfn(pn, idx0), oldfn(pn0, idx0)) ######## new2 = new.copy() cond2 = z3.And(is_fd_valid(fd), is_fd_valid(new2.procs[pid].ipc_fd)) fn = old.procs[old.current].ofile(fd) fd = old.procs[pid].ipc_fd new2.procs[pid].ofile[fd] = fn # bump proc nr_fds new2.procs[pid].nr_fds[fd] += 1 # bump file refcnt new2.files[fn].refcnt[(pid, fd)] += 1 new3 = util.If(cond2, new2, new) new3.procs[pid].state = dt.proc_state.PROC_RUNNING new3.procs[old.current].state = dt.proc_state.PROC_RUNNABLE new3.current = pid return cond, util.If(cond, new3, old)
def spec_lemma_nr_children_refcnt(kernelstate): conj = [] pid = util.FreshBitVec('pid', dt.pid_t) # pid has a parent <=> pid is not PROC_UNUSED # valid(pid) & valid(ppid) ==> state(pid) != PROC_UNUSED conj.append( z3.ForAll([pid], z3.Implies( is_pid_valid(pid), is_pid_valid(kernelstate.procs[pid].ppid) == ( kernelstate.procs[pid].state != dt.proc_state.PROC_UNUSED)))) # valid(pid) & state(pid) == PROC_UNUSED ==> !valid(ppid) conj.append( z3.ForAll( [pid], z3.Implies( is_pid_valid(pid), z3.Implies( kernelstate.procs[pid].state == dt.proc_state.PROC_UNUSED, z3.Not(is_pid_valid(kernelstate.procs[pid].ppid)))))) # PROC_UNUSED state implies refcnt is 0 # valid(pid) & state(pid) == PROC_UNUSED ==> pid.nr_children == 0 conj.append( z3.ForAll( [pid], z3.Implies( is_pid_valid(pid), z3.Implies( kernelstate.procs[pid].state == dt.proc_state.PROC_UNUSED, kernelstate.procs[pid].nr_children() == z3.BitVecVal( 0, dt.size_t))))) # unused procs don't have a parent conj.append( z3.ForAll( [pid], z3.Implies( z3.And( is_pid_valid(pid), kernelstate.procs[pid].state == dt.proc_state.PROC_UNUSED), kernelstate.procs[pid].ppid == z3.BitVecVal(0, dt.pid_t)))) # Correctness definition for `permutation` based refcount kernelstate.procs.nr_children.check( conj, is_owner_valid=is_pid_valid, is_owned_valid=is_pid_valid, max_refs=dt.NPROC - 1, ownerfn=lambda pid0: kernelstate.procs[pid0].ppid) return z3.And(*conj)
def sys_reclaim_page(old, pn): cond = z3.And( is_pn_valid(pn), old.pages[pn].type != dt.page_type.PAGE_TYPE_FREE, is_pid_valid(old.pages[pn].owner), old.procs[old.pages[pn].owner].state == dt.proc_state.PROC_ZOMBIE, old.procs[old.pages[pn].owner].nr_devs() == z3.BitVecVal(0, dt.size_t), ) new = old.copy() new.procs[new.pages[pn].owner].nr_pages[pn] -= 1 new.pages[pn].type = dt.page_type.PAGE_TYPE_FREE new.pages[pn].owner = z3.BitVecVal(0, dt.pid_t) return cond, util.If(cond, new, old)
def sys_switch(old, pid): cond = z3.And( is_pid_valid(pid), old.procs[pid].state == dt.proc_state.PROC_RUNNABLE, # This is implied by pid having state runnable, # current is always running old.current != pid, ) new = old.copy() new.procs[old.current].state = util.If( old.procs[old.current].killed, dt.proc_state.PROC_ZOMBIE, dt.proc_state.PROC_RUNNABLE) new.procs[pid].state = dt.proc_state.PROC_RUNNING new.current = pid return cond, util.If(cond, new, old)
def sys_reclaim_iommu_root(old, devid): pid = old.pci[devid].owner cond = z3.And( is_pid_valid(pid), old.procs[pid].state == dt.proc_state.PROC_ZOMBIE, old.procs[pid].nr_intremaps() == 0, ) new = old.copy() new.procs[pid].nr_devs[devid] -= 1 # Clear the page_table_root new.pci[devid].page_table_root = z3.BitVecVal(-1, dt.pn_t) new.pci[devid].owner = z3.BitVecVal(0, dt.pid_t) new.flush_iotlb() return cond, util.If(cond, new, old)
def extintr(old, vector): pid = old.vectors[vector].owner cond = is_pid_valid(pid) cond2 = z3.And(cond, old.procs[pid].state == dt.proc_state.PROC_SLEEPING) vector = z3.ZeroExt(64 - vector.size(), vector) idx = z3.UDiv(vector, 64) mask = 1 << (vector % 64) new = old.copy() new.procs[pid].intr[idx] = new.procs[pid].intr(idx) | mask new2 = new.copy() new2.procs[pid].state = dt.proc_state.PROC_RUNNABLE new2.procs[pid].ipc_from = z3.BitVecVal(0, dt.pid_t) new2.procs[pid].ipc_val = vector new2.procs[pid].ipc_size = z3.BitVecVal(0, dt.size_t) return cond, util.If(cond, util.If(cond2, new2, new), old)
def sys_map_pml4(old, pid, index, perm): cond = z3.And( is_pid_valid(pid), # the pid is either current or an embryo belonging to current z3.Or(pid == old.current, z3.And( old.procs[pid].ppid == old.current, old.procs[pid].state == dt.proc_state.PROC_EMBRYO)), # Index is a valid page index z3.ULT(index, 512), # perm has no unsafe bits on it and it is present and non-writable perm & (dt.MAX_INT64 ^ dt.PTE_PERM_MASK) == 0, perm & dt.PTE_P != 0, perm & dt.PTE_W == 0, # index does not have the P bit in the page table root at that index old.pages[old.procs[pid].page_table_root].data( index) & dt.PTE_P == 0, ) new = old.copy() frm = old.procs[pid].page_table_root new.pages[frm].data[index] = ( (z3.UDiv(new.pages_ptr_to_int, util.i64(dt.PAGE_SIZE)) + frm) << dt.PTE_PFN_SHIFT) | perm # maintain the "shadow" pgtable new.pages[frm].pgtable_pn[index] = frm new.pages[frm].pgtable_perm[index] = perm new.pages[frm].pgtable_type[index] = dt.PGTYPE_PAGE new.pages[frm].pgtable_reverse_pn = frm new.pages[frm].pgtable_reverse_idx = index new.flush_tlb(pid) return cond, util.If(cond, new, old)
def sys_map_file(old, pid, frm, index, n, perm): cond = z3.And( z3.ULT(n, dt.NPAGES_FILE_TABLE), is_pid_valid(pid), # the pid is either current or an embryo belonging to current z3.Or(pid == old.current, z3.And( old.procs[pid].ppid == old.current, old.procs[pid].state == dt.proc_state.PROC_EMBRYO)), # frm is a valid pn of type PT whose owner is pid is_pn_valid(frm), old.pages[frm].type == dt.page_type.PAGE_TYPE_X86_PT, old.pages[frm].owner == pid, # Index is a valid page index z3.ULT(index, 512), # perm has no unsafe bits on it and it is present and non-writable perm & (dt.MAX_INT64 ^ dt.PTE_PERM_MASK) == 0, perm & dt.PTE_P != 0, perm & dt.PTE_W == 0, # index does not have the P bit in the from page old.pages[frm].data(index) & dt.PTE_P == 0, ) new = old.copy() new.pages[frm].data[index] = ( (z3.UDiv(new.file_table_ptr_to_int, util.i64(dt.PAGE_SIZE)) + n) << dt.PTE_PFN_SHIFT) | perm # maintain the "shadow" pgtable new.pages[frm].pgtable_pn[index] = n new.pages[frm].pgtable_perm[index] = perm new.pages[frm].pgtable_type[index] = dt.PGTYPE_FILE_TABLE new.flush_tlb(pid) return cond, util.If(cond, new, old)