Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFE: support for SCMP_FLTATR_CTL_OPTIMIZE, SCMP_FLTATR_API_SYSRAWRC #75

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions seccomp.go
Original file line number Diff line number Diff line change
Expand Up @@ -901,6 +901,42 @@ func (f *ScmpFilter) GetSSB() (bool, error) {
return true, nil
}

// GetOptimize returns the current optimization level of the filter,
// or an error if an issue was encountered retrieving the value.
// See SetOptimize for more details.
func (f *ScmpFilter) GetOptimize() (int, error) {
level, err := f.getFilterAttr(filterAttrOptimize)
if err != nil {
if e := checkAPI("GetOptimize", 4, 2, 5, 0); e != nil {
err = e
}

return 0, err
}

return int(level), nil
}

// GetRawRC returns the current state of RawRC flag, or an error
// if an issue was encountered retrieving the value.
// See SetRawRC for more details.
func (f *ScmpFilter) GetRawRC() (bool, error) {
rawrc, err := f.getFilterAttr(filterAttrRawRC)
if err != nil {
if e := checkAPI("GetRawRC", 4, 2, 5, 0); e != nil {
err = e
}

return false, err
}

if rawrc == 0 {
return false, nil
}

return true, nil
}

// SetBadArchAction sets the default action taken on a syscall for an
// architecture not in the filter, or an error if an issue was encountered
// setting the value.
Expand Down Expand Up @@ -969,6 +1005,50 @@ func (f *ScmpFilter) SetSSB(state bool) error {
return err
}

// SetOptimize sets optimization level of the seccomp filter. By default
// libseccomp generates a set of sequential "if" statements for each rule in
// the filter. SetSyscallPriority can be used to prioritize the order for the
// default cause. The binary tree optimization sorts by syscall numbers and
// generates consistent O(log n) filter traversal for every rule in the filter.
// The binary tree may be advantageous for large filters. Note that
// SetSyscallPriority is ignored when level == 2.
//
// The different optimization levels are:
// 0: Reserved value, not currently used.
// 1: Rules sorted by priority and complexity (DEFAULT).
// 2: Binary tree sorted by syscall number.
func (f *ScmpFilter) SetOptimize(level int) error {
cLevel := C.uint32_t(level)

err := f.setFilterAttr(filterAttrOptimize, cLevel)
if err != nil {
if e := checkAPI("SetOptimize", 4, 2, 5, 0); e != nil {
err = e
}
}

return err
}

// SetRawRC sets whether libseccomp should pass system error codes back to the
// caller, instead of the default ECANCELED. Defaults to false.
func (f *ScmpFilter) SetRawRC(state bool) error {
var toSet C.uint32_t = 0x0

if state {
toSet = 0x1
}

err := f.setFilterAttr(filterAttrRawRC, toSet)
if err != nil {
if e := checkAPI("SetRawRC", 4, 2, 5, 0); e != nil {
err = e
}
}

return err
}

// SetSyscallPriority sets a syscall's priority.
// This provides a hint to the filter generator in libseccomp about the
// importance of this syscall. High-priority syscalls are placed
Expand Down
26 changes: 19 additions & 7 deletions seccomp_internal.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,16 +119,22 @@ const uint32_t C_ACT_NOTIFY = SCMP_ACT_NOTIFY;
#if SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR < 4
#define SCMP_FLTATR_CTL_LOG _SCMP_FLTATR_MIN
#endif

// The following SCMP_FLTATR_* were added in libseccomp v2.5.0.
#if SCMP_VER_MAJOR == 2 && SCMP_VER_MINOR < 5
#define SCMP_FLTATR_CTL_SSB _SCMP_FLTATR_MIN
#define SCMP_FLTATR_CTL_SSB _SCMP_FLTATR_MIN
#define SCMP_FLTATR_CTL_OPTIMIZE _SCMP_FLTATR_MIN
#define SCMP_FLTATR_API_SYSRAWRC _SCMP_FLTATR_MIN
#endif

const uint32_t C_ATTRIBUTE_DEFAULT = (uint32_t)SCMP_FLTATR_ACT_DEFAULT;
const uint32_t C_ATTRIBUTE_BADARCH = (uint32_t)SCMP_FLTATR_ACT_BADARCH;
const uint32_t C_ATTRIBUTE_NNP = (uint32_t)SCMP_FLTATR_CTL_NNP;
const uint32_t C_ATTRIBUTE_TSYNC = (uint32_t)SCMP_FLTATR_CTL_TSYNC;
const uint32_t C_ATTRIBUTE_LOG = (uint32_t)SCMP_FLTATR_CTL_LOG;
const uint32_t C_ATTRIBUTE_SSB = (uint32_t)SCMP_FLTATR_CTL_SSB;
const uint32_t C_ATTRIBUTE_DEFAULT = (uint32_t)SCMP_FLTATR_ACT_DEFAULT;
const uint32_t C_ATTRIBUTE_BADARCH = (uint32_t)SCMP_FLTATR_ACT_BADARCH;
const uint32_t C_ATTRIBUTE_NNP = (uint32_t)SCMP_FLTATR_CTL_NNP;
const uint32_t C_ATTRIBUTE_TSYNC = (uint32_t)SCMP_FLTATR_CTL_TSYNC;
const uint32_t C_ATTRIBUTE_LOG = (uint32_t)SCMP_FLTATR_CTL_LOG;
const uint32_t C_ATTRIBUTE_SSB = (uint32_t)SCMP_FLTATR_CTL_SSB;
const uint32_t C_ATTRIBUTE_OPTIMIZE = (uint32_t)SCMP_FLTATR_CTL_OPTIMIZE;
const uint32_t C_ATTRIBUTE_SYSRAWRC = (uint32_t)SCMP_FLTATR_API_SYSRAWRC;

const int C_CMP_NE = (int)SCMP_CMP_NE;
const int C_CMP_LT = (int)SCMP_CMP_LT;
Expand Down Expand Up @@ -275,6 +281,8 @@ const (
filterAttrTsync
filterAttrLog
filterAttrSSB
filterAttrOptimize
filterAttrRawRC
)

const (
Expand Down Expand Up @@ -681,6 +689,10 @@ func (a scmpFilterAttr) toNative() uint32 {
return uint32(C.C_ATTRIBUTE_LOG)
case filterAttrSSB:
return uint32(C.C_ATTRIBUTE_SSB)
case filterAttrOptimize:
return uint32(C.C_ATTRIBUTE_OPTIMIZE)
case filterAttrRawRC:
return uint32(C.C_ATTRIBUTE_SYSRAWRC)
default:
return 0x0
}
Expand Down
114 changes: 49 additions & 65 deletions seccomp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,11 @@ func TestFilterAttributeGettersAndSetters(t *testing.T) {
t.Errorf("Bad arch action was not set correctly!")
}

err = filter.SetBadArchAction(ActInvalid)
if err == nil {
t.Errorf("Setting bad arch action to an invalid action should error")
}

err = filter.SetNoNewPrivsBit(false)
if err != nil {
t.Errorf("Error setting no new privileges bit")
Expand All @@ -439,73 +444,64 @@ func TestFilterAttributeGettersAndSetters(t *testing.T) {
t.Errorf("No new privileges bit was not set correctly")
}

if APILevelIsSupported() {
api, err := GetAPI()
if err != nil {
t.Errorf("Error getting API level: %s", err)
} else if api < 3 {
err = SetAPI(3)
if err != nil {
t.Errorf("Error setting API level: %s", err)
}
}
// Checks that require API level >= 3 and libseccomp >= 2.4.0.
if err := checkAPI(t.Name(), 3, 2, 4, 0); err != nil {
t.Logf("Skipping the rest of the test: %v", err)
return
}

err = filter.SetLogBit(true)
if err != nil {
if !APILevelIsSupported() {
t.Logf("Ignoring failure: %s\n", err)
} else {
t.Errorf("Error setting log bit")
}
t.Errorf("Error setting log bit: %v", err)
}

log, err := filter.GetLogBit()
if err != nil {
if !APILevelIsSupported() {
t.Logf("Ignoring failure: %s\n", err)
} else {
t.Errorf("Error getting log bit")
}
t.Errorf("Error getting log bit: %v", err)
} else if log != true {
t.Errorf("Log bit was not set correctly")
t.Error("Log bit was not set correctly")
}

if APILevelIsSupported() {
api, err := GetAPI()
if err != nil {
t.Errorf("Error getting API level: %s", err)
} else if api < 4 {
err = SetAPI(4)
if err != nil {
t.Skipf("Skipping test: API level %d is less than 4", api)
}
}
// Checks that require API level >= 4 and libseccomp >= 2.5.0.
if err := checkAPI(t.Name(), 4, 2, 5, 0); err != nil {
t.Logf("Skipping the rest of the test: %v", err)
return
}

err = filter.SetSSB(true)
if err != nil {
if !APILevelIsSupported() {
t.Logf("Ignoring failure: %s\n", err)
} else {
t.Errorf("Error setting SSB bit")
}
t.Errorf("Error setting SSB bit: %v", err)
}

ssb, err := filter.GetSSB()
if err != nil {
if !APILevelIsSupported() {
t.Logf("Ignoring failure: %s\n", err)
} else {
t.Errorf("Error getting SSB bit")
}
t.Errorf("Error getting SSB bit: %v", err)
} else if ssb != true {
t.Errorf("SSB bit was not set correctly")
t.Error("SSB bit was not set correctly")
}

err = filter.SetBadArchAction(ActInvalid)
if err == nil {
t.Errorf("Setting bad arch action to an invalid action should error")
err = filter.SetOptimize(2)
if err != nil {
t.Errorf("Error setting optimize level: %v", err)
}

level, err := filter.GetOptimize()
if err != nil {
t.Errorf("Error getting optimize level: %v", err)
} else if level != 2 {
t.Error("Optimize level was not set correctly")
}

err = filter.SetRawRC(true)
if err != nil {
t.Errorf("Error setting RawRC flag: %v", err)
}

rawrc, err := filter.GetRawRC()
if err != nil {
t.Errorf("Error getting RawRC flag: %v", err)
} else if rawrc != true {
t.Error("RawRC flag was not set correctly")
}
}

Expand Down Expand Up @@ -645,19 +641,13 @@ func TestLogAct(t *testing.T) {
}

func subprocessLogAct(t *testing.T) {
expectedPid := syscall.Getpid()

api, err := GetAPI()
if err != nil {
if !APILevelIsSupported() {
t.Skipf("Skipping test: %s", err)
}

t.Errorf("Error getting API level: %s", err)
} else if api < 3 {
t.Skipf("Skipping test: API level %d is less than 3", api)
// ActLog requires API >=3 and libseccomp >= 2.4.0.
if err := checkAPI(t.Name(), 3, 2, 4, 0); err != nil {
t.Skip(err)
}

expectedPid := syscall.Getpid()

filter, err := NewFilter(ActAllow)
if err != nil {
t.Errorf("Error creating filter: %s", err)
Expand Down Expand Up @@ -706,15 +696,9 @@ func TestCreateActKillProcessFilter(t *testing.T) {
}

func subprocessCreateActKillProcessFilter(t *testing.T) {
api, err := GetAPI()
if err != nil {
if !APILevelIsSupported() {
t.Skipf("Skipping test: %s", err)
}

t.Errorf("Error getting API level: %s", err)
} else if api < 3 {
t.Skipf("Skipping test: API level %d is less than 3", api)
// Requires API level >= 3 and libseccomp >= 2.4.0
if err := checkAPI(t.Name(), 3, 2, 4, 0); err != nil {
t.Skip(err)
}

filter, err := NewFilter(ActKillThread)
Expand Down