def execve(self, file_obj=None, new_sid=None): import copy new = Cred() new.uid = self.uid new.gid = self.gid new.groups = copy.deepcopy(self.groups) if new_sid: assert isinstance(new_sid, SELinuxContext) new.sid = copy.deepcopy(new_sid) else: new.sid = copy.deepcopy(self.sid) # TODO: check file if set-user-id and for file capabilities # TODO: handle capability(7) assignment semantics # TODO: file system capabilities /vendor/bin/pm-service # Drop by default, when transitioning to a non-privileged process if new.uid != 0: new.cap = Capabilities() else: new.cap = copy.deepcopy(self.cap) return new
def _emit_facts(self): G = self.graph log.info("Emitting prolog facts...") node_objs = nx.get_node_attributes(G, 'obj') proc_to_drop =[] obj_to_drop = [] total_proc = 0 total_obj = 0 # Prune the graph of any nodes we can't get DAC/MAC information for for node in list(G.nodes()): obj = node_objs[node] ty = obj.get_obj_type() if ty == "process" or ty == "subject": total_proc += 1 uid = obj.cred.uid gid = obj.cred.gid groups = obj.cred.groups if None in [uid, gid, groups]: log.warning("Dropping Process %s as no cred %s", node, str([uid, gid, groups])) proc_to_drop += [node] continue elif ty == "ipc": total_obj += 1 if not obj.owner: log.warning("Dropping IPC %s as no owner", node) obj_to_drop += [node] continue if None in [obj.owner.cred.uid, obj.owner.cred.gid]: log.warning("Dropping IPC %s as owner has no cred", node) obj_to_drop += [node] continue elif ty == "file": total_obj += 1 uid = obj.uid gid = obj.gid if None in [uid, gid]: log.warning("Dropping File %s as no DAC info", node) obj_to_drop += [node] continue else: assert 0 G.remove_nodes_from(obj_to_drop) G.remove_nodes_from(proc_to_drop) if len(proc_to_drop) or len(obj_to_drop): log.warning("Dropping %d proc (%.1f), %d obj (%.1f)", len(proc_to_drop), len(proc_to_drop)/total_proc*100.0, len(obj_to_drop), len(obj_to_drop)/total_obj*100.0) if len(G.nodes()) == 0: log.error("Dropped all nodes") return False node_id = 0 sub_db = [] obj_db = [] self.node_id_map = {} facts = "" def get_node_type(n): return node_objs[n].get_obj_type() all_processes = filter(lambda n: get_node_type(n) in ["process", "subject"], G.nodes()) all_objects = filter(lambda n: get_node_type(n) not in ["process", "subject"], G.nodes()) # Sort by PID for node in sorted(all_processes, key=lambda n: node_objs[n].pid): obj = node_objs[node] ty = obj.get_obj_type() assert obj not in self.node_id_map node_name = "s%d" % node_id uid = obj.cred.uid gid = obj.cred.gid groups = list(obj.cred.groups) caps = obj.cred.cap.effective caps = [Capabilities.name_to_bit(x) for x in caps] caps = sorted(caps) caps = str(caps) groups = str(sorted([gid] + groups)).replace('\'', '') line = "sub(%s, %d, %s, 7, 7, 7, %s)." % ( node_name, uid, groups, caps) sub_db += [node_name] if obj.trusted: self.sub_trusted.append(node) self.node_id_map[node] = node_name node_id += 1 facts += "% " + node + "\n" facts += line + "\n" node_id = 0 for node in sorted(all_objects): extra_comment = "" obj = node_objs[node] ty = obj.get_obj_type() assert obj not in self.node_id_map node_name = "o%d" % node_id if ty == "ipc": uid = obj.owner.cred.uid gid = obj.owner.cred.gid # TODO: not really correct for all IPCs uperm = 7 gperm = 7 operm = 7 tags = ["all"] perty = "[" + ",".join(map(str, map(self.special_file_map.get, tags))) +"]" line = "obj(%s, %d, %d, %d, %d, %d, %s)." % ( node_name, uid, gid, uperm, gperm, operm, perty) obj_db += [node_name] elif ty == "file": (fn, fo), = obj.backing_files.items() uid = obj.uid gid = obj.gid mode = fo["perms"] & 0o777 uperm = (mode & 0o700) >> 6 gperm = (mode & 0o070) >> 3 operm = (mode & 0o007) >> 0 tags = sorted(list(fo.get("tags", []))) if len(tags): log.info("SPECIAL OBJECT %s %s", fn, tags) self.special_files[node] = (obj, fn, tags) extra_comment = " SPECIAL " + str(tags) tags = ["all"] + tags perty = "[" + ",".join(map(str, map(self.special_file_map.get, tags))) +"]" line = "obj(%s, %d, %d, %d, %d, %d, %s)." % ( node_name, uid, gid, uperm, gperm, operm, perty) obj_db += [node_name] else: assert 0 self.node_id_map[node] = node_name node_id += 1 comment = node + extra_comment facts += "% " + comment + "\n" facts += line + "\n" facts += "\nsub_db(all, %s).\n" % str(sub_db).replace('\'', '') obj_db_str = "[" for i, o in enumerate(obj_db): last = i+1 == len(obj_db) if last: obj_db_str += "%s]" % str(o) break if i > 0 and i % 10 == 0: obj_db_str += "%s,\n" % str(o) else: obj_db_str += "%s, " % str(o) facts += "obj_db(all, %s).\n\n" % obj_db_str # Emit edges for edge in sorted(list(G.edges())): u = self.node_id_map[edge[0]] v = self.node_id_map[edge[1]] facts += "edge(%s, %s).\n" % (u, v) # Sort all special files self.sort_special_files() log.info("Prolog facts emitted") return facts
def __init__(self): self.uid = None self.gid = None self.groups = set() self.sid = None self.cap = Capabilities()