An Application Sandbox for Netbsd
Total Page:16
File Type:pdf, Size:1020Kb
secmodel sandbox : An application sandbox for NetBSD Stephen Herwig University of Maryland, College Park Abtract POSIX interface into categories, and allows processes to whitelist or pledge their use of certain categories; an at- We introduce a new security model for NetBSD – sec- tempt to perform an operation from a non-pledged cate- model sandbox – that allows per-process policies for re- gory kills the process. stricting privileges. Privileges correspond to kauth au- We implement an application sandbox for NetBSD, thorization requests, such as a request to create a socket secmodel sandbox, that allows per-process restriction or read a file, and policies specify the sandbox’s deci- of privileges. secmodel sandbox plugs into the kauth sion: deny, defer, or allow. Processes may apply mul- framework, and uses NetBSD’s support for in-kernel Lua tiple sandbox policies to themselves, in which case the [7] to both specify and evaluate sandbox policies. We policies stack, and child processes inherit their parent’s are developing several facilities with secmodel sandbox, sandbox. Sandbox policies are expressed in Lua, and the such as a secure chroot and a partial emulation of evaluation of policies uses NetBSD 7’s experimental in- OpenBSD’s pledge system call. kernel Lua interpreter. As such, policies may express static authorization decisions, or may register Lua func- tions that secmodel sandbox invokes for a decision. 2 NetBSD Overview 2.1 kauth 1 Introduction NetBSD 4.0 introduced the kauth kernel subsystem [3] A process sandbox is a mechanism for limiting the privi- – a clean room implementation of Apple’s kauth frame- leges of a process, as in restricting the operations the pro- work [6] for OS X – to handle authorization requests for cess may perform, the resources it may use, or its view of privileged operations. Privileged operations are repre- of the system. Sandboxes address the dual problems of sented as triples of the form (scope, action, optional sub- limiting the potential damage caused by running an un- action). The predefined scopes are system, process, trusted binary, and mitigating the effects of exploitation network, machdep, device, and vnode, each forming of a trusted binary. In either case, the goal is to restrict a a namespace that is further refined by the action and sub- process to only the necessary privileges for the purported action components. For instance, the operation to create task, and, in the latter case, to also drop privileges when a socket is identified by the triple (network, socket, they are no longer needed. open), and the operation to read a file by (vnode, Although NetBSD currently lacks a sandbox mech- read data). anism, sandbox implementations exist for various op- Some authorizations, such as (process, nice), are erating systems. systrace [5], a multi-platform mecha- triggered by a single system call (setpriority); some, such nism used in earlier versions of NetBSD, and seccomp as (system, mount, update), are triggered when a [2], a Linux-specific implementation, exemplify the ap- system call (mount) is called with specific arguments proach of specifying a per-process system call policy, (the MNT UPDATE flag); and others, such as (system, and use system call interposition to enforce the policy filehandle) may be triggered by more than one sys- filter. For systrace, the policy format is systrace-specific, tem call (fhopen and fhstat). Many system calls do not whereas seccomp specifies the policy as a BPF program. trigger a kauth request. OpenBSD’s pledge system call [4] offers a simplified kauth uses an observer pattern whereby listeners reg- interface for dropping privileges: OpenBSD groups the ister for operation requests for a given scope; when a re- quest occurs, each listener is called. module. The sandbox Lua module allows a script to set Each listener receives as arguments the operation policy rules via the following interface: triple, the credentials of the object (typically, the pro- cess) that triggered the authorization request, as well as sandbox.default(result) additional context specific to the request. sandbox.allow(req) Each listener returns a decision: either allow, deny, sandbox.deny(req) or defer. If any listener returns deny, the request sandbox.on(req, func) is denied. If at least one listener returns allow and The sandbox.default function specifies a result of none returns deny, the request is allowed. If all listen- either `allow', `deny', or `defer'. The result is the ers return defer, the decision is scope-dependent. For sandbox’s decision for any kauth request for which the all scopes other than the vnode scope, the result is to script does not specify a more specific rule. deny the authorization. For the vnode scope, the autho- The sandbox.allow and sandbox.deny specify al- rization request contains a “fall-back” decision, which low and deny rules, respectively, for the kauth request nearly always specifies a decision conforming to tradi- given as req. tional BSD4.4 file access permissions. The sandbox Lua module uses strings of the form `scope.action.subaction' to represent the requests; 2.2 secmodel hence, a request to open a socket corresponds to the string `network.socket.open', and a request to read While the NetBSD kernel source contains many listen- a file to `vnode.read data'. A script may specify a ers (typically in accordance with kernel configuration complete request name, or a prefix. When the process options), the secmodel framework offers a lightweight triggers an authorization request, secmodel sandbox will convention for developing and managing a set of lis- select the policy rule that has the longest prefix match teners that represents a larger security model. By with the given request. As an example, a sandbox policy default, NetBSD uses secmodel bsd44, which imple- script of: ments the traditional security model based on 4.4BSD, and which itself is composed of three separate mod- sandbox.default(`deny') els: secmodel suser, secmodel securelevel, and sec- sandbox.allow(`network') model extensions. would allow any request in the network scope, but would An important, subtle point with the default security deny requests from all other scopes. model is that many authorization requests are deferred, The sandbox.on Lua function registers a Lua func- relying on kauth’s default behavior when all listeners re- tion func to be called for the given kauth request. The turn defer to fully implement the policy. signature for func is: func(req, cred, arg0, arg1, arg2, arg3) 3 Design where req is the kauth request that generated the call- We developed secmodel sandbox as a loadable kernel back, cred is a Lua table that represents the credentials module with companion user-space library libsandbox. of the requesting object or process, and the remaining ar- By convention, we install the device file for sec- guments are request-specific. All parameters for func model sandbox at /dev/sandbox. exist only in the Lua environment; manipulating the val- A process interacts with secmodel sandbox via the ues does not affect the underlying C objects that they rep- sandbox(const char *script, int flags) func- resent. tion of libsandbox. The argument script is a Lua For many requests, the values for arg0 through arg3 script that specifies the sandbox policy. The flag argu- are nil, as the kauth request carries no additional con- ment specifies the action to take when a process attempts text. For the requests that do contain context, we trans- a denied operation: a value of 0 means that the oper- late the context into appropriate Lua values. For exam- ation returns an appropriate errno as dictated by kauth ple, for the request `network.socket.open', the ar- (typically EACCES for kauth’s vnode scope and EPERM guments are Lua integers representing the arguments to for all other scopes); a value of SANDBOX ON DENY KILL the socket system call that triggered the request. For specifies the pledge behavior of killing the process. The clarity in script writing, we pre-populate the sandbox sandbox function packages these arguments into a struct Lua module with symbols for common constants, such and, via an ioctl call, passes the struct to /dev/sandbox. as sandbox.AF INET and sandbox.SOCK STREAM. For secmodel sandbox evaluates the Lua script in a Lua requests in the process scope, arg0 is a Lua table that environment that is pre-populated with a sandbox Lua represents a subset of the fields of the struct proc that 2 is the target of the request, such as the pid, ppid, comm struct sandbox. A sandbox contains two main items: (program name), and nice value. Callback functions for a Lua state and a ruleset. The Lua state is the Lua en- the vnode scope receive as arg0 a Lua table that con- vironment in which secmodel sandbox evaluates all Lua tains the pathname and file status information of the tar- code for that particluar sandbox. The ruleset is a pre- get vnode. Completely representing the context with Lua fix tree that secmodel sandbox searches during a kauth values is an ongoing effort. request to find the sandbox’s matching rule. Before secmodel sandbox evaluates the policy script 4 Sandbox Implementation in the newly created Lua state, secmodel sandbox adds the sandbox Lua functions (e.g., sandbox.allow) and Our design and implementation of secmodel sandbox constants (e.g., sandbox.AF INET) to the state. Each considered several important requirements and features. sandbox Lua function is a closure that contains a pointer First, while expressing rules in Lua is elegant, having to to the struct sandbox. In Lua terminology, the call into Lua to find a matching rule for each request is struct sandbox is a light userdata upvalue. not. Thus, we implemented secmodel sandbox so that- When the script calls a sandbox Lua function, the evaluating the policy script “compiles” the rules into a function – which is implemented in C code – performs prefix tree, mimicking the natural hierarchy provided by argument checking, retrieves the ruleset from the struct the (scope, action, subaction) format of requests.