Beispiel #1
0
def check_model_and_resolve_inner(constraints, sha_constraints, second_try=False):
    # logging.debug('-' * 32)
    extra_constraints = []
    s = z3.SolverFor("QF_ABV")
    z3.set_option(model_compress=False)
    s.add(constraints)
    if s.check() != z3.sat:
        raise IntractablePath("CHECK", "MODEL")
    else:
        if not sha_constraints:
            return s.model()

    while True:
        ne_constraints = []
        for a, b in itertools.combinations(sha_constraints.keys(), 2):
            if (not isinstance(sha_constraints[a], SymRead) and not isinstance(sha_constraints[b], SymRead) and
                    sha_constraints[a].size() != sha_constraints[b].size()):
                ne_constraints.append(a != b)
                continue
            s = z3.SolverFor("QF_ABV")
            z3.set_option(model_compress=False)
            s.add(constraints + ne_constraints + extra_constraints + [a != b, symread_neq(sha_constraints[a],
                                                                                          sha_constraints[b])])
            check_result = s.check()
            # logging.debug("Checking hashes %s and %s: %s", a, b, check_result)
            if check_result == z3.unsat:
                # logging.debug("Hashes MUST be equal: %s and %s", a, b)
                subst = [(a, b)]
                extra_constraints = [z3.simplify(z3.substitute(c, subst)) for c in extra_constraints]
                extra_constraints.append(symread_eq(symread_substitute(sha_constraints[a], subst),
                                                    symread_substitute(sha_constraints[b], subst)))
                constraints = [z3.simplify(z3.substitute(c, subst)) for c in constraints]
                b_val = symread_substitute(sha_constraints[b], subst)
                sha_constraints = {z3.substitute(sha, subst): symread_substitute(sha_value, subst) for
                                   sha, sha_value in
                                   sha_constraints.items() if not sha is a or sha is b}
                sha_constraints[b] = b_val
                break
            else:
                # logging.debug("Hashes COULD be equal: %s and %s", a, b)
                pass
        else:
            break

    return check_and_model(constraints + extra_constraints, sha_constraints, ne_constraints, second_try=second_try)
Beispiel #2
0
def simulates_forwards(topo, a, b, field="vlan", edge_policy={}):
    """Determine if b simulates a up to field on one hop."""
    p, pp = Consts("p pp", Packet)
    v, vv = Ints("v vv")
    # Z3 emits a warning about not finding a pattern for our quantification.
    # This is fine, so ignore it.
    set_option("WARNING", False)

    solv = Solver()
    solv.add(on_valid_port(topo, p))

    # b doesn't need to forward packets on external links that don't satisfy the
    # ingress predicate
    edge_option = And(external_link(edge_policy, p), Not(edges_ingress(edge_policy, p)))

    solv.add(
        And(
            forwards(a, p, pp),
            ForAll([v, vv], Not(Or(forwards_with(b, p, {field: v}, pp, {field: vv}), edge_option)), patterns=[]),
        )
    )
    if solv.check() == unsat:
        set_option("WARNING", True)
        return None
    else:
        set_option("WARNING", True)
        return solv.model(), (p, pp), HEADER_INDEX
Beispiel #3
0
def simulates_forwards2(topo, a, b, field="vlan", edge_policy={}):
    """Determine if b simulates a up to field on two hop on topo."""
    p, pp, q, qq = Consts("p pp q qq", Packet)
    v, vv, vvv = Ints("v vv, vvv")
    # Z3 emits a warning about not finding a pattern for our quantification.
    # This is fine, so ignore it.
    set_option("WARNING", False)

    solv = Solver()

    solv.add(on_valid_port(topo, p))

    # b doesn't need to forward packets on external links that don't satisfy the
    # ingress predicate, but we only care about the first hop
    edge_option = And(external_link(edge_policy, p), Not(edges_ingress(edge_policy, p)))

    # This case breaks the And inside the ForAll because they're both False and
    # z3 can't handle that.
    # However, it does mean that they simulate each other, because neither
    # forwards packets, so just short-circuit.
    if forwards(b, p, pp) is False and forwards(b, q, qq) is False:
        return None
    c = And(
        forwards(a, p, pp),
        transfer(topo, pp, q),
        forwards(a, q, qq),
        ForAll(
            [v, vv, vvv],
            Not(
                Or(
                    And(
                        forwards_with(b, p, {field: v}, pp, {field: vv}),
                        forwards_with(b, q, {field: vv}, qq, {field: vvv}),
                    ),
                    edge_option,
                )
            ),
        ),
    )

    solv.add(c)
    if solv.check() == unsat:
        set_option("WARNING", True)
        return None
    else:
        set_option("WARNING", True)
        return solv.model(), (p, pp), HEADER_INDEX
Beispiel #4
0
def simulates_observes(topo, a, b, field="vlan", edge_policy={}):
    p = Const("p", Packet)
    o, v = Ints("o v")
    # Z3 emits a warning about not finding a pattern for our quantification.
    # This is fine, so ignore it.
    set_option("WARNING", False)

    solv = Solver()

    solv.add(on_valid_port(topo, p))

    # b doesn't need to observe packets on external links that don't satisfy the
    # ingress predicate
    edge_option = And(external_link(edge_policy, p), Not(edges_ingress(edge_policy, p)))

    solv.add(And(observes(a, p, o), ForAll([v], Not(Or(observes_with(b, p, {field: v}, o), edge_option)), patterns=[])))

    if solv.check() == unsat:
        set_option("WARNING", True)
        return None
    else:
        set_option("WARNING", True)
        return solv.model(), (p), HEADER_INDEX
Beispiel #5
0
def check_and_model(constraints,
                    sha_constraints,
                    ne_constraints,
                    second_try=False):
    # logging.debug(' ' * 16 + '-' * 16)

    unresolved = set(sha_constraints.keys())
    sol = z3.SolverFor("QF_ABV")
    z3.set_option(model_compress=False)
    sol.add(ne_constraints)
    todo = constraints
    progress = True
    all_vars = dict()
    while progress:
        new_todo = []
        progress = False
        for c in todo:
            all_vars[c] = get_vars_non_recursive(c,
                                                 include_select=True,
                                                 include_indices=False)
            if any(x in unresolved for x in all_vars[c]):
                new_todo.append(c)
            else:
                progress = True
                sol.add(c)
        unresolved_vars = set(v.get_id() for c in new_todo
                              for v in all_vars[c]) | set(v.get_id()
                                                          for v in unresolved)
        # logging.debug("Unresolved vars: %s", ','.join(map(str, unresolved_vars)))
        if sol.check() != z3.sat:
            raise IntractablePath()
        m = sol.model()
        unresolved_todo = list(set(unresolved))
        while unresolved_todo:
            u = unresolved_todo.pop()
            c = sha_constraints[u]
            if isinstance(c, SymRead):
                vars = set()
                if not concrete(c.start):
                    vars |= get_vars_non_recursive(c.start,
                                                   include_select=True)
                if not concrete(c.size):
                    vars |= get_vars_non_recursive(c.size, include_select=True)
                # logging.debug("Trying to resolve %s, start and size vars: %s", u, ','.join(map(str, vars)))
                if any(x.get_id() in unresolved_vars for x in vars):
                    continue
                start = c.start
                if not concrete(c.start):
                    tmp = m.eval(c.start)
                    if not z3util.is_expr_val(tmp):
                        continue
                    start = tmp.as_long()
                    sol.add(c.start == start)
                size = c.size
                if not concrete(c.size):
                    tmp = m.eval(c.size)
                    if not z3util.is_expr_val(tmp):
                        continue
                    size = tmp.as_long()
                    sol.add(c.size == size)

                data = c.memory.read(start, size)
                if isinstance(data, list):
                    if len(data) > 1:
                        data = z3.Concat(*data)
                    elif len(data) == 1:
                        data = data[0]
                    else:
                        raise IntractablePath()
                sha_constraints = dict(sha_constraints)
                sha_constraints[u] = data
                unresolved_todo.append(u)
            else:
                vars = get_vars_non_recursive(c, include_select=True)
                # logging.debug("Trying to resolve %s, vars: %s", u, ','.join(map(str, vars)))
                if any(x.get_id() in unresolved_vars for x in vars):
                    continue
                v = m.eval(c)
                if z3util.is_expr_val(v):
                    sha = big_endian_to_int(sha3(to_bytes(v)))
                    sol.add(c == v)
                    sol.add(u == sha)
                    unresolved.remove(u)
                    progress = True
        todo = new_todo
    if sol.check() != z3.sat:
        raise IntractablePath()
    if todo:
        if second_try:
            raise IntractablePath()
        raise UnresolvedConstraints(unresolved)
    return sol.model()
Beispiel #6
0
################################################################################
"""Sat conversion and solving for netcore.

ONLY CHECK FOR UNSAT UNLESS YOU'RE MARK

No observations yet.
"""

from z3.z3 import And, Or, Not, Implies, Function, ForAll
from z3.z3 import Const, Consts, Solver, unsat, set_option, Int, Ints
from netcore import HEADERS
import netcore as nc

from util import fields_of_policy

set_option(pull_nested_quantifiers=True)

from sat_core import nary_or, nary_and
from sat_core import HEADER_INDEX, Packet, switch, port, vlan
from sat_core import forwards, forwards_with, observes, observes_with
from sat_core import input, output, ingress, egress
from sat_core import external_link, edges_ingress, on_valid_port
from verification import disjoint_observations


def transfer(topo, p_out, p_in):
    """Build constraint for moving p_out to p_in across an edge."""
    options = []
    for s1, s2 in topo.edges():
        p1 = topo.node[s1]["ports"][s2]
        p2 = topo.node[s2]["ports"][s1]