Android is a popular mobile operating system (OS) that has been used in a range of mobile devices such as smartphones and tablet computers. It uses Linux as the kernel, which is extended with an application framework (middleware). Most applications of Android are written to run on top of this middleware, and most of Android-specific security mechanisms are enforced at this level.
Android treats each application as a distinct user with a unique user ID. At the kernel level, access control is enforced via the standard Unix permission mechanism based on the user id (and group id) of the app. At the middleware level, each application is sandboxed, i.e., it is running in its own instance of Dalvik virtual machine, and communication and sharing between apps are allowed only through an inter-process communication (IPC) mechanism. Android middleware provides a list of resources and services such as sending SMS, access to contacts, or internet access. Android enforces access control to these services via its permission mechanism: each service/resource is associated with a certain unique permission tag, and each app must request permissions to the services it needs at installation time. Everytime an app requests access to a specific service/resource, Android runtime security monitor checks whether the app has the required permission tags for that particular service/resource. A more detailed discussion of Android security architecture can be found in [Enck09].
One problem with Android security mechanism is the problem of privilege escalation, that is, the possibility of an app to gain access to services or resources that it does not have permissions to access. Obviously privilege escalation is a common problem of every OS, e.g., when a kernel bug is exploited to gain root access. However, in Android, privilege escalation is possible even when apps are running in the confine of Android sandboxes [defcon18, Davi10, LastPE]. There are two types of attacks that can lead to privilege escalation [LastPE]: the confused deputy attack and the collusion attack. In the confused deputy attack, a legitimate app (the deputy) has permissions to certain services, e.g., sending SMS, and exposes an interface to this functionality without any guards. This interface can then be exploited by a malicious app to send SMS, even though the malicious app does not have the permission. Recent studies [defcon18, Grace12NDSS, DroidChecker] show some system and consumer apps expose critical functionalities that can be exploited to launch confused deputy attacks. The collusion attack requires two or more malicious apps to collaborate. We have yet to encounter such a malware, either in the Google Play market or in the third party markets, although a proof-of-concept malware with such properties, called SoundComber [Soundcomber], has been constructed.
Several security extensions to Android have been proposed to deal with privilege escalation attacks [QUIRE, IPCInspection, LastPE]. Unlike these works, we aim at designing a high-level policy language that is expressive enough to capture privilege escalation attacks, but is also able to express more refined policies (see Section 4). Moreover, we aim at designing a lightweight monitoring framework, where policy specifications can be modified easily and enforced efficiently. Thus we aim at an automated generation of security monitors that can efficiently enforce policies written in our specification language.
On the specific problem of detecting privilege escalation, it is essentially a problem of tracking (runtime) control flow, which is in general a difficult problem and would require a certain amount static analysis [Denning, TaintDroid]
. So we adopt a ‘lightweight’ heuristic to ascertain causal dependency between IPC calls: we consider two successive calls, say from A to B, followed by a call from B to C, as causally dependent if they happen within a certain reasonably short time frame. This heuristic seems sensible in the presence of confused deputy attacks, but can be of course circumvented by colluding attacks. For the latter there is probably not a general solution that can be effective in all cases, e.g., when covert channels are involved[Soundcomber], so we shall restrict to addressing the former.
The core of our policy language, called RMTL, is essentially a past-fragment of metric linear temporal logic (MTL) [Alur90lics, Thati05MTL, Basin08FSTTCS]. We consider only the fragment of MTL with past-time operators, as this is sufficient for our purpose to enforce history-sensitive access control. This also means that we can only express safety properties [Lichtenstein], but not policies capturing obligations as in, e.g., [Basin08FSTTCS]. Temporal operators are useful in this setting to enforce access control on apps based on histories of their executions; see Section 4. Such a history-dependent policy cannot be expressed in the policy languages used in [QUIRE, IPCInspection, LastPE].
MTL by itelf is, however, insufficient to express transitive closures of relations, which is needed to specify an IPC call chains between apps, among others. To deal with this, we extend MTL with a recursive definitions, e.g., one would be able to write a definition such as:
where denotes the IPC event. This equation defines the reflexive-transitive closure of The metric operator means intuitively holds within time units in the past; we shall see a more precise definition of the operators in Section 2. Readers familiar with modal -calculus [Bradfield07handbook] will note that this is but a syntactic sugar for -expressions for (least) fixed points.
To be practically enforceable in Android, RMTL monitoring algorithm must satisfy an important constraint, i.e., the algorithm must be trace-length independent. This is because the number of events generated by Android can range in the thousands per hour, so if the monitor must keep all the events generated by Android, its performance will degrade significantly overtime. Another practical consideration also motivates a restriction to metric operators that we adopt in RMTL. More specifically, MTL allows a metric version of the ‘since’ operator of the form , where specifies a half-closed (discrete) time interval from to . The monitoring algorithm for MTL in [Thati05MTL] works by first expanding this formula into formulas of the form where is any subinterval of . A similar expansion is also used implicitly in monitoring for first-order MTL in [Basin08FSTTCS], i.e., in their incremental automatic structure extension in their first-order logic encoding for the ‘since’ and ‘until’ operators. In general, if we have nested occurrences of metric operators, each with interval , the number of formulas produced by this expansion is bounded by . In Android, event timestamps are in milliseconds, so this kind of expansion is not practically feasible. For example, suppose we have a policy that monitors three successive IPC calls that happen within 10 seconds between successive calls. This requires two nested metric operators with intervals to specify. The above naive expansion would produce around formulas, and assuming the truth value of each formula is represented with 1 bit, this would require more than GB of storage to store all their truth values, something which is beyond the capacity of most smartphones today. An improvement to this exponential expansion is proposed in [Basin11RV, Reinbacher12RV], where one keeps a sequence of timestamps for each metric temporal operator occuring in the policy. This solution, although avoids the exponential expansion, is strictly speaking not trace-length independent. This solution seems optimal so it is hard to improve it without further restriction to the policy language. We show that, if one restricts the intervals of metric operators to the form , one only needs to keep one timestamp for each metric operator in monitoring; see Section 3.
To summarise, our contributions are as follows:
In terms of results in runtime verification, our contribution is in the design of a new logic-based policy language that extends MTL with recursive definitions, that avoids exponential expansion of metric operators, and for which the policy enforcement is trace-length independent.
In terms of the application domain, ours is the first implementation of a logic-based runtime security monitor for Android that can enforce history-based access control policies, including those that concern privilege escalations. Our monitoring framework can express temporal and metric-based policies not possible in existing works [QUIRE, IPCInspection, LastPE, bauer2013rv].
The rest of the paper is organized as follows. Section 2 introduces our policy language RMTL. Some example policies are described in 4. Section 5 discusses our implementation of the monitors for RMTL, and the required modification of Android OS kernel to integrate our monitor into the OS. In Section 6 we conclude and discuss related and future works.
Some proofs of the lemmas and theorems can be found in the appendix. Details of the implementation of the monitor generator and the binaries of the modified Android OS are available online.111 http://users.cecs.anu.edu.au/~hengunadi/LogicDroid.html.
This work is partly supported by the Australian Research Council Discovery Grant DP110103173.
2 The policy specification language RMTL
Our policy specification language, which we call RMTL, is based on an extension of metric linear temporal logic (MTL) [MTL]. The semantics of LTL [Pnueli77] is defined in terms of models which are sequences of states (or worlds). In our case, we restrict to finite sequences of states. MTL extends LTL models by adding timestamps to each state, and adding temporal operators that incorporate timing constraints, e.g., MTL features temporal operators such as which expresses that holds in some state in the future, and the timestamp of that world is within 0 to 3 time units from the current timestamp. We restrict to a model of MTL that uses discrete time, i.e., timestamps in this case are non-negative integers. We shall also restrict to the past-time fragment of MTL.
We extend MTL with two additional features: first-order quantifiers and recursive definitions. Our first-order language is a multi-sorted language. For this paper, we consider only two sorts, which we call (for ‘properties’) and (for denoting applications). Sorts are ranged over by . We first fix a signature for our first-order language, which is used to express terms and predicates of the language. We shall consider only constant symbols and predicate symbols, but no function symbols. We distinguish two types of predicate symbols: defined predicates and undefined ones. The defined predicate symbols are used to write recursive definitions and to each of such symbols we associate a formula as its definition. We shall come back to this shortly.
Constant symbols are ranged over by , and , undefined predicate symbols are ranged over by , and , and defined predicate symbols are ranged over by , and We assume an infinite set of sorted variables , whose elements are ranged over by , and We sometimes write to say that is the sort of variable A -term is either a constant symbol or a variable . We use , and to range over terms. To each symbol in we associate a sort information. We shall write when is a constant symbol of sort A predicate symbol of arity has sort of the form , and such a predicate can only be applied to terms of sorts
Constant symbols are used to express things like permissions in the Android OS, e.g., reading contacts, sending SMS, etc., and user ids of apps. Predicate symbols are used express events such as IPC calls between apps, and properties of an app, such as whether it is a system app, a trusted app (as determined by the user). As standard in first-order logic (see e.g. [fitting]), the semantics of terms and predicates are given in terms of a first-order structure, i.e., a set , called a domain, for each sort , and an interpretation function assigning each constant symbol an element of and each predicate symbol an -ary relation We shall assume constant domains in our model, i.e., every world has the same domain.
The formulas of RMTL is defined via the following grammar:
where and are natural numbers. The existential quantifier is annotated with a sort information . For most of our examples and applications, we only quantify only over variables of sort . The operators indexed by are metric temporal operators. The here denotes the interval , so these are special cases of the more general MTL operators in [MTL], where intervals can take the form , for We use , and to range over formulas. We assume that unary operators bind stronger than the binary operators, so means . We write to denote a formula whose free variables are among . Given such a formula, we write to denote the formula obtained by replacing with for every .
To each defined predicate symbol , we associate a formula , which we call the definition of . Notationally, we write We require that is guarded, i.e., every occurrence of any recursive predicate in is prefixed by either , , or . This guardedness condition is important to guarantee termination of recursion in model checking.
Given the above logical operators, we can define additional operators via their negation, e.g., is defined as , is defined as , is defined as , and is defined as , etc.
Before proceeding to the semantics of RMTL, we first define a well-founded ordering on formulae of RMTL, which will be used later.
We define a relation on the set RMTL formulae as the smallest relation satisfying the following conditions:
For any formula of the form , , , , and , there is no such that .
For every recursive definition , we have for every terms
, , , and .
, and , for
We denote with the reflexive and transitive closure of
The relation on RMTL formulas is a well-founded partial order.
For our application, we shall restrict to finite domains. Moreover, we shall restrict to an interpretation which is injective, i.e., mapping every constant to a unique element of In effect we shall be working in the term model, so elements of are just constant symbols from So we shall use a constant symbol, say , to mean both and . With this fix interpretation, the definition of the semantics (i.e., the satisfiability relation) can be much simplified, e.g., we do not need to consider valuations of variables. A state is a set of undefined atomic formulas of the form . Given a sequence , we write to denote its length, and we write to denote the -th element of when it is defined, i.e., when A model is a pair of a sequence of states and a sequence timestamps, which are natural numbers, such that and whenever .
Let denote the total order on natural numbers. Then we can define a well-order on pairs of natural numbers and formulas by taking the lexicographical ordering . The satisfiability relation between a model , a world (which is a natural number) and a closed formula (i.e., contains no free variables), written , is defined by induction on the pair as follows, where we write when is false.
iff or .
iff there exists s.t. .
iff and there exists s.t.
iff there exists such that and for every s.t.
iff , and
iff there exists s.t. and .
iff and there exists s.t. and
iff there exists such that , for every s.t. , and
iff there exists s.t.
Note that due to the guardedness condition in recursive definitions, our semantics for recursive predicates is much simpler than the usual definition as in -calculus, which typically involves the construction of a (semantic) fixed point operator. Note also that some operators are redundant, e.g., can be defined as , and can be defined as This holds for some metric operators, e.g., and can be defined as, respectively, and
This operator will be used to specify an active call chain, as we shall see later, so it is convenient to include it in our policy language.
In the next section, we shall assume that , , as derived connectives. Since we consider only finite domains, can be reduced to a big disjunction , so we shall not treat -quantifier explicitly. This can be problematic if the domain of quantification is big, as it suffers the same kind of exponential explosion as with the expansion of metric operators in MTL [Thati05MTL]. We shall defer the explicit treatment of quantifiers to future work.
3 Trace-length independent monitoring
The problem of monitoring is essentially a problem of model checking, i.e., to decide whether , for any given , and In the context of Android runtime monitoring, a state in can be any events of interest that one would like to capture, e.g., the IPC call events, queries related to location information or contacts, etc. To simplify discussions, and because our main interest is in privilege escalation through IPC, the only type of event we consider in is the IPC event, which we model with the predicate .
Given a policy specification , a naive monitoring algorithm that enforces this policy would store the entire event history and every time a new event arrives at time , it would check This is easily shown decidable, but is of course rather inefficient. In general, the model checking problem for RMTL (with finite domains) can be shown PSPACE hard following the same argument as in [FOTL]. A design criteria of RMTL is that enforcement of policies does not depend on the length of history of events, i.e., at any time the monitor only needs to keep track of a fixed number of states. Following [bauer2013rv], we call a monitoring algorithm that satisfies this property trace-length independent.
For PTLTL, trace-length independent monitoring algorithm exists, e.g., the algorithm by Havelund and Rosu [DYNAMICLTL], which depends only on two states in a history. That is, satisfiability of is a boolean function of satisfiability of , for every strict subformula of , and satisfiability of , for every subformula of This works for PTLTL because the semantics of temporal operators in PTLTL can be expressed in a recursive form, e.g., the semantics of can be equally expressed as [DYNAMICLTL]: iff , or and This is not the case for MTL. For example, satisfiability of the unrestricted ‘since’ operator can be equivalently expressed as:
where and Since can vary, the value of and can vary, depending on the history We avoid the expansion of metric operators in monitoring by restricting the intervals in the metric operators to the form We show that clause (3) can be brought back to a purely recursive form. The key to this is the following lemma:
Lemma 2 (Minimality)
If () then there exists an such that (resp. ) and such that for every such that , we have (resp., ).
Given , and , we define a function as follows:
Theorem 3.1 (Recursive forms)
For every model , every , , and , and every , the following hold:
iff , or and and
iff and , or and
Given Theorem 3.1, the monitoring algorithm for PTLTL in [DYNAMICLTL] can be adapted, but with an added data structure to keep track of the function In the following, given a formula , we assume that , and have been replaced with its equivalent form as mentioned in Section 2.
Given a formula , let be the set of subformulas of . We define a closure set of as follows: Let , and let
and define Since is finite, is finite, although its size is exponential in the arities of recursive predicates. For our specific applications, the predicates used in our sample policies have at most arity of two (for tracking transitive calls), so this is still tractable. In future work, we plan to investigate ways of avoiding this explicit expansion of recursive predicates.
We now describe how monitoring can be done for , given and We assume implicitly a preprocessing step where we compute ; we do not describe this step here but it is quite straightforward. Let be an enumeration of respecting the partial order , i.e., if then Then we can assign to each an index , s.t., in this enumeration. We refer to this index as We maintain two boolean arrays and The intention is that given and , the value of corresponds to the truth value of the judgment and the truth value of corresponds to the truth value of the judgment We also maintain two integer arrays and to store the value of the function The value of corresponds to , and corresponds to Note that this preprocessing step only needs to be done once, i.e., when generating the monitor codes for a particular policy, which is done offline, prior to inserting the monitor into the operating system kernel.
The main monitoring algorithm is divided into two subprocedures: the initialisation procedure (Algorithm 2) and the iterative procedure (Algorithm 3). The monitoring procedure (Algorithm 1) is then a simple combination of these two. We overload some logical symbols to denote operators on boolean values. In the actual implementation, we do not actually implement the loop in Algorithm 1; rather it is implemented as an event-triggered procedure, to process each event as they arrive using .
iff returns true.
The function only depends on two worlds: and , so the algorithm is trace-length independent. In principle there is no upperbound to its space complexity, as the timestamp can grow arbitrarily large, as is the case in [Basin11RV]. Practically, however, the timestamps in Android are stored in a fixed size data structure, so in such a case, when the policy is fixed, the space complexity is constant (i.e., independent of the length of history ).
We provide some basic policies as an example of how we can use this logic to specify security policies. From now on, we shall only quantify over the domain , so in the following we shall omit the sort annotation in the existential quantifier. The predicate is the recursive predicate defined in Equation (1) in the introduction. The constant denotes a service or resource that an unprivileged application tries to access via privilege escalation e.g. send SMS, or access to internet. The constant denotes the Contact provider app in Android. We also assume the following “static” predicates (i.e., their truth values do not vary over time):
: is a system app or process.
: has permission to access the sink.
: is an app that the user trusts. This is not a feature of Android, rather, it is a specific feature of our implementation. We build into our implementation a ‘trust’ management app to allow the user a limited control over apps that he/she trusts.
The following policies refer to access patterns that are forbidden. So given a policy , the monitor at each state make sure that holds. Assuming that , where , holds, then whenever a new event (i.e., the IPC call) is registered at time , the monitor checks that holds. If it does, then the call is allowed to proceed. Otherwise, it will be terminated.
This is a simple policy where we block a direct call from any untrusted application to the sink. This policy can serve as a privilege manager where we dynamically revoke permission for application to access the sink regardless of the static permission it asked during installation.
This policy says that transitive calls to a sink from non-system apps are forbidden, unless the source of the calls already has permission to the sink. This is then a simple privilege escalation detection (for non-system apps).
This is further refinement to the policy in that we also give the user privilege to decide for themselves dynamically whether or not to trust an application. Untrusted apps can not make transitive call to the sink, but trusted apps are allowed, regardless of their permissions.
This policy allows privilege escalation by non-trusted apps as long as there is no potential for data leakage through the sink. That is, as soon as a non-system and untrusted app accesses contact, it will be barred from accessing the internet. Note that the use of non-metric operator ensures that the information that a particular app has accessed contact is persistent.
We have implemented the monitoring algorithm presented in the previous section in Android 4.1. Some modifications to the application framework and the underlying Linux kernel in Android are neccessary to ensure our monitor can effectively monitor and stop unwanted behaviours. We have tested our implementation in both Android emulator and an actual device (Samsung Galaxy Nexus phone). We give a brief overview of our implementation; details of the monitor code generators and the modified Android kernel images are available from the authors’ website.
Our implementation consists of two parts: the codes that generate a monitor given a policy specification, and the modifications of Android framework and its Linux kernel to hook our monitor and to intercepts IPCs and access to Android resources. To improve runtime performance, the monitor generation is done outside Android; it produces C codes that are then compiled into a kernel module, and inserted into Android boot image.
The monitor generator takes an input policy, encoded in an XML format extending that of RuleML. The monitor generator works by following the logic of the monitoring algorithm presented in Section 3. It takes a policy formula , and generates the required data structures and determine an ordering between elements of as described earlier, and produces the codes illustrated in Algorithm 2, 3 and 1.
The main body of our monitor lies in the Linux kernel space as a kernel module. The reason for this is that there are some cases where Android leaves the permission checking to the Linux kernel layer e.g., for opening network socket. However, to monitor the IPC events between Android components and apps, we need to place a hook inside the application framework. The IPC between apps is done through passing a data structure called Intent, which gets broken down into parcels before they are passed down to the kernel level to be delivered. So intercepting these parcels and reconstructing the original Intent object in the kernel space would be more difficult and error prone. The events generated by apps or components will be passed down to the monitor in the kernel, along with the application’s user id. If the event is a call to the sink, then depending on the policy that is implemented in the monitor, it will decide to whether block or allow the call to proceed. We do this through our custom additional system calls to the Linux kernel which goes to this monitor.
Our implementation places hooks in four services, namely accessing internet, sending SMS, accessing location, and accessing contact database. For each of this sink, we add a virtual UID in the monitor and treat it as a component of Android. We currently track only IPC calls through the Intent passing mechanism. This is obviously not enough to detect all possible communications between apps, e.g., those that are done through file systems, or side channels, such as vibration setting (e.g., as implemented in SoundComber [Soundcomber]), so our implementation is currently more of a proof of concept. In the case of SoundComber, our monitor can actually intercepts the calls between colluding apps, due to the fact that they utilise intent broadcast through IPC to synchronize data transfer.
We have implemented some apps to test policies we mentioned in Section 4. In Table 1 and Figure 1, we provide some measurement of the timing of the calls between applications. The policy numbers in Table 1 refer to the policies in Section 4. To measure the average time for each IPC call, we construct a chain of ten apps, making successive calls between them, and measure the time needed for one end to reach the other. We measure two different average timings in miliseconds (ms) for different scenarios, based on whether the apps are in the background cache (i.e., suspended) or not. We also measure time spent on the monitor actually processing the event, which are around 1 ms for policy 1, and around 10 ms for the other three policies. This shows that the time spent in processing the event is quite low, but more overhead comes from the space required to process the event (there is a big jump in overall timing from simple rules with at most 2 free variables to more complex one with 3 free variables). Figure 1 shows that the timing of calls over time for each policy are roughly the same. This backs our claim that even though our monitor implements history-based access control, its performance does not depend on the size of the history.
6 Conclusion, related and future work
We have shown a policy language design based on MTL that can effectively describe various scenarios of privilege escalation in Android. Moreover, any policy written in our language can be effectively enforced. The key to the latter is the fact that our enforcement procedure is trace-length independent. We have also given a proof-of-concept implementation on actual Android devices and show that our implementation can effectively enforce RMTL policies.
We have already discussed related work in runtime monitoring based on LTL in the introduction. We now discuss briefly related work in Android security. There is a large body of works in this area, more than what can be reasonably surveyed here, so we shall focus on the most relevant ones to our work, i.e., those that deal with privilege escalation. For a more comprehensive survey on other security extensions or analysis, the interested reader can consult [LastPE]. QUIRE [QUIRE] is an application centric approach to privilege escalation, done by tagging the intent objects with the caller’s UID. Thus, the recipient application can check the permission of the source of the call chain. IPC Inspection [IPCInspection] is another application centric solution that works by reducing the privilege of the recipient application when it receives a communication from a less privileged application. XManDroid [LastPE] is a system centric solution, just like ours. Its security monitor maintains a call graph between apps. It is the closest to our solution, except that we are using temporal logic to specify a policy, and our policy can be modified modularly. Our policy language is also more expressive as we can specify both temporal and metric propertes. TaintDroid [TaintDroid] is another system-centric solution, but it is designed to track data flow, rather than control flow, via taint analysis, so privilege escalation can be inferred from leakage of data.
We currently do not deal with quantifiers directly in our algorithm. Such quantifiers are expanded into purely propositional connectives (when the domain is finite), which is exponential in the number of variables in the policy. As an immediate future work, we plan to investigate whether techniques using spawning automata [bauer2013rv] can be adapted to our setting to allow a “lazy” expansion of quantifiers as needed. It is not possible to design trace-length-independent monitoring algorithms in the unrestricted first-order LTL [bauer2013rv], so the challenge here is to find a suitable restriction that can be enforced efficiently.
Appendix 0.A Proofs
Lemma 1. The relation on RMTL formulas is a well-founded partial order.
We first show that is well-founded. Suppose otherwise: then there is an infinite descending chain of formulas:
Obviously, none of ’s can be a bottom element (i.e., those that take the form as specified in clause (1) of Definition 1). Furthermore, there must be an such that and where is a recursive predicate defined by If no such exists then all the instances of the relation in the chain must be instances of clause (3) and (4) in Definition 1, and the chain would be finite as those two clauses relate only strict subformulas. So without loss of generality, let us assume that . We claim that for every , every occurrence of any recursive predicate in is guarded. We prove this by induction on . If then we have . In this case, must be , and by the guardedness condition, all recursive predicates in are guarded. If , then we have . By induction hypothesis, all recursive predicates in are guarded. In this case, the relation must be an instance of either clause (3) or clause (4) of Definition 1, and therefore also satisfies the guardedness condition.
So now we have that none of ’s are recursive predicates. This means that all instances of in the chain must be instances of clause (3) and (4) in Definition 1, and consequently the size of the formulas in the chain must be strictly decreasing. Thus the chain cannot be infinite, contrary to the assumption.
Anti-symmetry follows immediately from well-foundedness. Suppose is not anti-symmetric. Then we have a chain
where We can repeat this chain to form an infinite descending chain, which contradicts the well-foundedness of ∎
Lemma 2 (Minimality). If () then there exists an such that (resp. ) and such that for every such that , we have (resp., ).
We show a case for ; the other case is straightforward. We prove this by induction on
Base case: Since , it must be the case that . In this case, let Obviously and is minimal.
Inductive case: We have . By the definition of , there exists such that and for every s.t. and If , then we have In this case, let If , then it must be the case that . It is not difficult to see that in this case we must have
By the induction hypothesis, we have there is an such that
and for every s.t. , we have In this case, we let It is straightforward to check that
Now, we claim that this is minimal. Suppose otherwise, i.e., there exists s.t. Since , we must have . But , so this contradicts the minimality of
Lemma 3 (Monotonicity)
If (resp., and ) then for every , we have (resp., and ).
Straightforward from the definition of ∎
Theorem 3.1 (Recursive forms). For every model , every , , and , and every , the following hold:
iff , or and and
iff and , or and
We show the case for ; the other case is similar.
Suppose . By definition, there exists such that
and for every s.t. we have
Suppose that the right-hand side of iff doesn’t hold, i.e., we have , and that one of the following hold:
The first case contradicts our assumption in (6), so it cannot hold. Note that since , it must be the case that , so (4), (5), and (6) above entail that , so the second case can’t hold either. For the third case: from (5) we have so