Esempio n. 1
0
    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
Esempio n. 2
0
    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
Esempio n. 3
0
 def __init__(self):
     self.uid = None
     self.gid = None
     self.groups = set()
     self.sid = None
     self.cap = Capabilities()