Commit 1ccb7c6f authored by mdempsky@chromium.org's avatar mdempsky@chromium.org

Add SandboxBPFPolicy::InvalidSyscall() to simplify writing policies

Instead of requiring every BPF policy to check IsValidSyscallNumber()
and return a fixed value when it's true, provide an alternative entry
point and guarantee that EvaluateSyscall() will only be called for
valid syscall numbers.

Review URL: https://codereview.chromium.org/293463002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@271256 0039d316-1c4b-4281-b951-d872f2087c98
parent 4e6c96e8
...@@ -129,6 +129,7 @@ ...@@ -129,6 +129,7 @@
'seccomp-bpf/sandbox_bpf.cc', 'seccomp-bpf/sandbox_bpf.cc',
'seccomp-bpf/sandbox_bpf.h', 'seccomp-bpf/sandbox_bpf.h',
'seccomp-bpf/sandbox_bpf_compatibility_policy.h', 'seccomp-bpf/sandbox_bpf_compatibility_policy.h',
'seccomp-bpf/sandbox_bpf_policy.cc',
'seccomp-bpf/sandbox_bpf_policy.h', 'seccomp-bpf/sandbox_bpf_policy.h',
'seccomp-bpf/syscall.cc', 'seccomp-bpf/syscall.cc',
'seccomp-bpf/syscall.h', 'seccomp-bpf/syscall.h',
......
...@@ -79,9 +79,7 @@ void ProbeProcess(void) { ...@@ -79,9 +79,7 @@ void ProbeProcess(void) {
} }
ErrorCode AllowAllEvaluator(SandboxBPF*, int sysnum, void*) { ErrorCode AllowAllEvaluator(SandboxBPF*, int sysnum, void*) {
if (!SandboxBPF::IsValidSyscallNumber(sysnum)) { DCHECK(SandboxBPF::IsValidSyscallNumber(sysnum));
return ErrorCode(ENOSYS);
}
return ErrorCode(ErrorCode::ERR_ALLOWED); return ErrorCode(ErrorCode::ERR_ALLOWED);
} }
...@@ -188,13 +186,21 @@ class RedirectToUserSpacePolicyWrapper : public SandboxBPFPolicy { ...@@ -188,13 +186,21 @@ class RedirectToUserSpacePolicyWrapper : public SandboxBPFPolicy {
ErrorCode err = ErrorCode err =
wrapped_policy_->EvaluateSyscall(sandbox_compiler, system_call_number); wrapped_policy_->EvaluateSyscall(sandbox_compiler, system_call_number);
if ((err.err() & SECCOMP_RET_ACTION) == SECCOMP_RET_ERRNO) { if ((err.err() & SECCOMP_RET_ACTION) == SECCOMP_RET_ERRNO) {
return sandbox_compiler->Trap( return ReturnErrnoViaTrap(sandbox_compiler, err.err() & SECCOMP_RET_DATA);
ReturnErrno, reinterpret_cast<void*>(err.err() & SECCOMP_RET_DATA));
} }
return err; return err;
} }
virtual ErrorCode InvalidSyscall(
SandboxBPF* sandbox_compiler) const OVERRIDE {
return ReturnErrnoViaTrap(sandbox_compiler, ENOSYS);
}
private: private:
ErrorCode ReturnErrnoViaTrap(SandboxBPF* sandbox_compiler, int err) const {
return sandbox_compiler->Trap(ReturnErrno, reinterpret_cast<void*>(err));
}
const SandboxBPFPolicy* wrapped_policy_; const SandboxBPFPolicy* wrapped_policy_;
DISALLOW_COPY_AND_ASSIGN(RedirectToUserSpacePolicyWrapper); DISALLOW_COPY_AND_ASSIGN(RedirectToUserSpacePolicyWrapper);
}; };
...@@ -463,13 +469,8 @@ bool SandboxBPF::StartSandbox(SandboxThreadState thread_state) { ...@@ -463,13 +469,8 @@ bool SandboxBPF::StartSandbox(SandboxThreadState thread_state) {
} }
void SandboxBPF::PolicySanityChecks(SandboxBPFPolicy* policy) { void SandboxBPF::PolicySanityChecks(SandboxBPFPolicy* policy) {
for (SyscallIterator iter(true); !iter.Done();) { if (!IsDenied(policy->InvalidSyscall(this))) {
uint32_t sysnum = iter.Next(); SANDBOX_DIE("Policies should deny invalid system calls.");
if (!IsDenied(policy->EvaluateSyscall(this, sysnum))) {
SANDBOX_DIE(
"Policies should deny system calls that are outside the "
"expected range (typically MIN_SYSCALL..MAX_SYSCALL)");
}
} }
return; return;
} }
...@@ -745,20 +746,18 @@ void SandboxBPF::FindRanges(Ranges* ranges) { ...@@ -745,20 +746,18 @@ void SandboxBPF::FindRanges(Ranges* ranges) {
// deal with this disparity by enumerating from MIN_SYSCALL to MAX_SYSCALL, // deal with this disparity by enumerating from MIN_SYSCALL to MAX_SYSCALL,
// and then verifying that the rest of the number range (both positive and // and then verifying that the rest of the number range (both positive and
// negative) all return the same ErrorCode. // negative) all return the same ErrorCode.
const ErrorCode invalid_err = policy_->InvalidSyscall(this);
uint32_t old_sysnum = 0; uint32_t old_sysnum = 0;
ErrorCode old_err = policy_->EvaluateSyscall(this, old_sysnum); ErrorCode old_err = IsValidSyscallNumber(old_sysnum)
ErrorCode invalid_err = policy_->EvaluateSyscall(this, MIN_SYSCALL - 1); ? policy_->EvaluateSyscall(this, old_sysnum)
: invalid_err;
for (SyscallIterator iter(false); !iter.Done();) { for (SyscallIterator iter(false); !iter.Done();) {
uint32_t sysnum = iter.Next(); uint32_t sysnum = iter.Next();
ErrorCode err = policy_->EvaluateSyscall(this, static_cast<int>(sysnum)); ErrorCode err =
if (!iter.IsValid(sysnum) && !invalid_err.Equals(err)) { IsValidSyscallNumber(sysnum)
// A proper sandbox policy should always treat system calls outside of ? policy_->EvaluateSyscall(this, static_cast<int>(sysnum))
// the range MIN_SYSCALL..MAX_SYSCALL (i.e. anything that returns : invalid_err;
// "false" for SyscallIterator::IsValid()) identically. Typically, all
// of these system calls would be denied with the same ErrorCode.
SANDBOX_DIE("Invalid seccomp policy");
}
if (!err.Equals(old_err) || iter.Done()) { if (!err.Equals(old_err) || iter.Done()) {
ranges->push_back(Range(old_sysnum, sysnum - 1, old_err)); ranges->push_back(Range(old_sysnum, sysnum - 1, old_err));
old_sysnum = sysnum; old_sysnum = sysnum;
......
...@@ -28,6 +28,7 @@ class CompatibilityPolicy : public SandboxBPFPolicy { ...@@ -28,6 +28,7 @@ class CompatibilityPolicy : public SandboxBPFPolicy {
virtual ErrorCode EvaluateSyscall(SandboxBPF* sandbox_compiler, virtual ErrorCode EvaluateSyscall(SandboxBPF* sandbox_compiler,
int system_call_number) const OVERRIDE { int system_call_number) const OVERRIDE {
DCHECK(SandboxBPF::IsValidSyscallNumber(system_call_number));
return syscall_evaluator_(sandbox_compiler, system_call_number, aux_); return syscall_evaluator_(sandbox_compiler, system_call_number, aux_);
} }
......
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "sandbox/linux/seccomp-bpf/sandbox_bpf_policy.h"
#include <errno.h>
#include "sandbox/linux/seccomp-bpf/errorcode.h"
namespace sandbox {
ErrorCode SandboxBPFPolicy::InvalidSyscall(SandboxBPF* sandbox_compiler) const {
return ErrorCode(ENOSYS);
}
} // namespace sandbox
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#define SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_POLICY_H_ #define SANDBOX_LINUX_SECCOMP_BPF_SANDBOX_BPF_POLICY_H_
#include "base/basictypes.h" #include "base/basictypes.h"
#include "sandbox/sandbox_export.h"
namespace sandbox { namespace sandbox {
...@@ -13,7 +14,7 @@ class ErrorCode; ...@@ -13,7 +14,7 @@ class ErrorCode;
class SandboxBPF; class SandboxBPF;
// This is the interface to implement to define a BPF sandbox policy. // This is the interface to implement to define a BPF sandbox policy.
class SandboxBPFPolicy { class SANDBOX_EXPORT SandboxBPFPolicy {
public: public:
SandboxBPFPolicy() {} SandboxBPFPolicy() {}
virtual ~SandboxBPFPolicy() {} virtual ~SandboxBPFPolicy() {}
...@@ -23,9 +24,14 @@ class SandboxBPFPolicy { ...@@ -23,9 +24,14 @@ class SandboxBPFPolicy {
// it can deny the system call unconditionally by returning an appropriate // it can deny the system call unconditionally by returning an appropriate
// "errno" value; or it can request inspection of system call argument(s) by // "errno" value; or it can request inspection of system call argument(s) by
// returning a suitable ErrorCode. // returning a suitable ErrorCode.
// Will only be called for valid system call numbers.
virtual ErrorCode EvaluateSyscall(SandboxBPF* sandbox_compiler, virtual ErrorCode EvaluateSyscall(SandboxBPF* sandbox_compiler,
int system_call_number) const = 0; int system_call_number) const = 0;
// The InvalidSyscall method specifies the behavior used for invalid
// system calls. The default implementation is to return ENOSYS.
virtual ErrorCode InvalidSyscall(SandboxBPF* sandbox_compiler) const;
private: private:
DISALLOW_COPY_AND_ASSIGN(SandboxBPFPolicy); DISALLOW_COPY_AND_ASSIGN(SandboxBPFPolicy);
}; };
......
...@@ -387,7 +387,9 @@ bool Verifier::VerifyBPF(SandboxBPF* sandbox, ...@@ -387,7 +387,9 @@ bool Verifier::VerifyBPF(SandboxBPF* sandbox,
} }
#endif #endif
#endif #endif
ErrorCode code = policy.EvaluateSyscall(sandbox, sysnum); ErrorCode code = iter.IsValid(sysnum)
? policy.EvaluateSyscall(sandbox, sysnum)
: policy.InvalidSyscall(sandbox);
if (!VerifyErrorCode(sandbox, program, &data, code, code, err)) { if (!VerifyErrorCode(sandbox, program, &data, code, code, err)) {
return false; return false;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment