-
Notifications
You must be signed in to change notification settings - Fork 56
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: seccomp userspace notification (follow-up to #50) #59
Conversation
thanks for addressing all the comments. LGTM |
@pcmoore @drakenclimber should the commits be squashed into logical commits or would you do squash in a single commit when merging? @rodnymolina @ctalledo some of the initial commits from #50 don't have the "Signed-off-by" line. Are you ok with adding it? |
@alban, thanks for picking this one up and addressing all the review comments, haven't had cycles to do it myself. Do you want us to add the signed-off to our original commits and re-submit them again? Or there's another (quicker) way to do this? |
I could just edit your commits in this PR with the following if you give your ok
|
Oh sure, please go ahead. Thanks! |
I forced-pushed the branch with the following changes:
With the changes above, I am able to use this libseccomp-golang branch successfully in runc (tested with Travis in CentOS 7, Ubuntu Bionic, Fedora 32). |
seccomp_test.go
Outdated
// Lock this goroutine to it's current kernel thread; otherwise the go runtime may | ||
// switch us to a different OS thread, bypassing the seccomp notification filter. | ||
runtime.LockOSThread() | ||
defer runtime.UnlockOSThread() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Documentation of UnlockOSThread
says:
// Before calling UnlockOSThread, the caller must ensure that the OS
// thread is suitable for running other goroutines. If the caller made
// any permanent changes to the state of the thread that would affect
// other goroutines, it should not call this function and thus leave
// the goroutine locked to the OS thread until the goroutine (and
// hence the thread) exits.
Since we don't unload this filter (because it's not possible), I assume it would be correct to not call UnlockOSThread() here. Otherwise it could happen that by random choice this thread is re-used. In this test this seems improable but if it's true then it would be good to give the right example here. I'm not an expert and just reasoning from the docs, I have no proof of this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, that's a good catch. I had missed that description of UnlockOSThread(), and I agree with your reasoning that we should not unlock the goroutine from the OS thread given that the seccomp filter is already acting on it and can't be unloaded.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@yvesf Thanks for testing. I have the same error when trying -count 2
like you did. I tried to remove the call to UnlockOSThread
but it didn't help.
I observed the following with the command:
strace -f -s 256 -e chdir,seccomp go test -v . -count 2 -v -run 'TestNotif$'
- First iteration of the test:
[pid 1901155] seccomp(SECCOMP_SET_MODE_FILTER, SECCOMP_FILTER_FLAG_NEW_LISTENER, {len=9, filter=0x1a70580}) = 6
[pid 1901155] chdir("/non-existent-path" <unfinished ...>
[pid 1901155] <... chdir resumed>) = -1 ENOENT (No such file or directory)
-> seccomp() returns the file descriptor correctly
-> chdir() returned ENOENT as expected
- Second iteration of the test:
[pid 1901157] seccomp(SECCOMP_SET_MODE_FILTER, 0, {len=9, filter=0x7f6948001b50}) = 0
[pid 1901157] chdir("/non-existent-path") = -1 ENOSYS (Function not implemented)
-> The pid is different, so removing UnlockOSThread
worked
-> seccomp() is not passed the flag SECCOMP_FILTER_FLAG_NEW_LISTENER as expected (why?)
-> seccomp() fails to return the file descriptor
-> chdir() does not return ENOENT but ENOSYS.
I am continuing to investigate...
Maybe someone else could verify if this affects only me: |
@yvesf I found the root cause: this is because From seccomp_reset(3):
I could fix the issue in libseccomp-golang with the following patch: diff --git a/seccomp.go b/seccomp.go
index 2c12662..68e7690 100644
--- a/seccomp.go
+++ b/seccomp.go
@@ -682,6 +682,14 @@ func (f *ScmpFilter) Reset(defaultAction ScmpAction) error {
return nil
}
+func GlobalReset() error {
+ if retCode := C.seccomp_reset(nil, 0); retCode != 0 {
+ return errRc(retCode)
+ }
+
+ return nil
+}
+
// Release releases a filter context, freeing its memory. Should be called after
// loading into the kernel, when the filter is no longer needed.
// After calling this function, the given filter is no longer valid and cannot
diff --git a/seccomp_test.go b/seccomp_test.go
index 2b82835..5ca9781 100644
--- a/seccomp_test.go
+++ b/seccomp_test.go
@@ -743,6 +743,8 @@ func notifHandler(ch chan error, fd ScmpFd, tests []notifTest) {
}
func TestNotif(t *testing.T) {
+ GlobalReset()
+
// seccomp notification requires API level >= 5
api, err := GetAPI()
if err != nil {
@@ -857,7 +859,9 @@ func TestNotif(t *testing.T) {
// Lock this goroutine to it's current kernel thread; otherwise the go runtime may
// switch us to a different OS thread, bypassing the seccomp notification filter.
runtime.LockOSThread()
- defer runtime.UnlockOSThread()
+
+ // Don't call runtime.UnlockOSThread() to ensure that the thread with the
+ // seccomp filter applied will not be reused in another test.
err = filter.Load()
if err != nil { I think libseccomp API is not ideal with this global state. Although it can make sense in single-threaded programs, it could cause difficulties if a multi-threaded program ever wants to setup different filters for different threads. I would like if libseccomp API could be improved, but in order for libseccomp-golang to support libseccomp-2.5.0, I would add this GlobalReset() in the Go API. What do you think? |
Even with the fix from above, we can't run some tests with
This can reproduce with:
For this, the tests using tsync and the tests not using tsync should be executed separately (in different processes). |
Not sure if it's too much of a hack but we could execute the test in subprocesses, go's func TestLogAct(t *testing.T) {
execInSubprocess(t, func(t *testing.T) {
expectedPid := syscall.Getpid() execInSubprocess(t, func)// execInSubprocess calls the go test binary again for the same test.
// This must be only top-level statment in the test function. Do not nest this.
// It will slightly defect the test log output as the test is entered twice
func execInSubprocess(t *testing.T, f func(t *testing.T)) {
const subprocessEnvKey = `GO_SUBPROCESS_KEY`
if testIDString, ok := os.LookupEnv(subprocessEnvKey); ok && testIDString == "1" {
t.Run(`subprocess`, f)
return
}
cmd := exec.Command(os.Args[0])
cmd.Args = []string{os.Args[0], "-test.run=" + t.Name() + "$", "-test.v=true"}
for _, arg := range os.Args {
if strings.HasPrefix(arg, `-test.testlogfile=`) {
cmd.Args = append(cmd.Args, arg)
}
}
cmd.Env = []string{subprocessEnvKey + "=1"}
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err := cmd.Start()
if err != nil {
t.Error("failed to spawn test in sub-process", err)
t.FailNow()
}
err = cmd.Wait()
if err != nil {
if err, ok := err.(*exec.ExitError); ok {
t.Errorf("Test failed with status %d", err.ExitCode())
}
t.Error(`test failed`)
t.FailNow()
}
} |
@yvesf Thanks, it works for me! I pushed a new commit using your |
It's not the same pattern, just similar. TestLinuxDeathSignal for instance calls itself with |
Gentle reminder about this PR. Thanks! |
Wow, 27 patches ... that's something. Especially considering I think you could count the associated main library patches to do enable userspace notification on one hand :) I'm not sure yet if it is the case with this PR, but for future submissions please take the approach of simply updating flawed patches in the PR if the PR is still open and not merged. I generally dislike merging commits which are known to be broken; it both makes bisection difficult and the git log overly noisy. All that said, I'll start taking a look at this now, but given the number of patches it make take some time. |
Yes, thanks to all that made the merge possible! |
The notify support has been merged in libseccomp-golang in this PR: seccomp/libseccomp-golang#59 Also, we update to new API of libseccomp-golang so code doesn't break. Signed-off-by: Alban Crequy <alban@kinvolk.io> Signed-off-by: Rodrigo Campos <rodrigo@kinvolk.io> Co-authored-by: Rodrigo Campos <rodrigo@kinvolk.io>
The notify support has been merged in libseccomp-golang in this PR: seccomp/libseccomp-golang#59 Also, we update to new API of libseccomp-golang so code doesn't break. Signed-off-by: Alban Crequy <alban@kinvolk.io> Signed-off-by: Rodrigo Campos <rodrigo@kinvolk.io> Co-authored-by: Rodrigo Campos <rodrigo@kinvolk.io>
The notify support has been merged in libseccomp-golang in this PR: seccomp/libseccomp-golang#59 Also, we update to new API of libseccomp-golang so code doesn't break. Signed-off-by: Alban Crequy <alban@kinvolk.io> Signed-off-by: Rodrigo Campos <rodrigo@kinvolk.io> Co-authored-by: Rodrigo Campos <rodrigo@kinvolk.io>
The notify support has been merged in libseccomp-golang in this PR: seccomp/libseccomp-golang#59 Also, we update to new API of libseccomp-golang so code doesn't break. Signed-off-by: Alban Crequy <alban@kinvolk.io> Signed-off-by: Rodrigo Campos <rodrigo@kinvolk.io> Co-authored-by: Rodrigo Campos <rodrigo@kinvolk.io>
The notify support has been merged in libseccomp-golang in this PR: seccomp/libseccomp-golang#59 Also, we update to new API of libseccomp-golang so code doesn't break. Signed-off-by: Alban Crequy <alban@kinvolk.io> Signed-off-by: Rodrigo Campos <rodrigo@kinvolk.io> Co-authored-by: Rodrigo Campos <rodrigo@kinvolk.io>
The notify support has been merged in libseccomp-golang in this PR: seccomp/libseccomp-golang#59 Also, we update to new API of libseccomp-golang so code doesn't break. Signed-off-by: Alban Crequy <alban@kinvolk.io> Signed-off-by: Rodrigo Campos <rodrigo@kinvolk.io> Co-authored-by: Rodrigo Campos <rodrigo@kinvolk.io>
The notify support has been merged in libseccomp-golang in this PR: seccomp/libseccomp-golang#59 Also, we update to new API of libseccomp-golang so code doesn't break. Signed-off-by: Alban Crequy <alban@kinvolk.io> Signed-off-by: Rodrigo Campos <rodrigo@kinvolk.io> Co-authored-by: Rodrigo Campos <rodrigo@kinvolk.io>
The notify support has been merged in libseccomp-golang in this PR: seccomp/libseccomp-golang#59 Also, we update to new API of libseccomp-golang so code doesn't break. Signed-off-by: Alban Crequy <alban@kinvolk.io> Signed-off-by: Rodrigo Campos <rodrigo@kinvolk.io> Co-authored-by: Rodrigo Campos <rodrigo@kinvolk.io>
The notify support has been merged in libseccomp-golang in this PR: seccomp/libseccomp-golang#59 Also, we update to new API of libseccomp-golang so code doesn't break. Signed-off-by: Alban Crequy <alban@kinvolk.io> Signed-off-by: Rodrigo Campos <rodrigo@kinvolk.io> Co-authored-by: Rodrigo Campos <rodrigo@kinvolk.io>
Can we have v0.9.2 with this soon? |
The notify support has been merged in libseccomp-golang in this PR: seccomp/libseccomp-golang#59 Also, we update to new API of libseccomp-golang so code doesn't break. Signed-off-by: Alban Crequy <alban@kinvolk.io> Signed-off-by: Rodrigo Campos <rodrigo@kinvolk.io> Co-authored-by: Rodrigo Campos <rodrigo@kinvolk.io>
The notify support has been merged in libseccomp-golang in this PR: seccomp/libseccomp-golang#59 Also, we update to new API of libseccomp-golang so code doesn't break. Signed-off-by: Alban Crequy <alban@kinvolk.io> Signed-off-by: Rodrigo Campos <rodrigo@kinvolk.io> Co-authored-by: Rodrigo Campos <rodrigo@kinvolk.io>
@AkihiroSuda maybe you can create an issue for this? I see the 0.9.2 milestone exists and has more things to do, but will be great if a new release is out and other stuff are moved to 0.9.3 :) |
Two quick comments:
|
The notify support has been merged in libseccomp-golang in this PR: seccomp/libseccomp-golang#59 Also, we update to new API of libseccomp-golang so code doesn't break. Signed-off-by: Alban Crequy <alban@kinvolk.io> Signed-off-by: Rodrigo Campos <rodrigo@kinvolk.io> Co-authored-by: Rodrigo Campos <rodrigo@kinvolk.io>
The notify support has been merged in libseccomp-golang in this PR: seccomp/libseccomp-golang#59 Also, we update to new API of libseccomp-golang so code doesn't break. Signed-off-by: Alban Crequy <alban@kinvolk.io> Signed-off-by: Rodrigo Campos <rodrigo@kinvolk.io> Co-authored-by: Rodrigo Campos <rodrigo@kinvolk.io>
Our patches have been merged upstream in this PR: seccomp/libseccomp-golang#59 This patch just adjusts the go.mod file and vendoring to use upstream libseccomp-golang on that commit.
Our patches have been merged upstream in this PR: seccomp/libseccomp-golang#59 This patch just adjusts the go.mod file and vendoring to use upstream libseccomp-golang on that commit.
The notify support has been merged in libseccomp-golang in this PR: seccomp/libseccomp-golang#59 Also, we update to new API of libseccomp-golang so code doesn't break. Signed-off-by: Alban Crequy <alban@kinvolk.io> Signed-off-by: Rodrigo Campos <rodrigo@kinvolk.io> Co-authored-by: Rodrigo Campos <rodrigo@kinvolk.io>
The notify support has been merged in libseccomp-golang in this PR: seccomp/libseccomp-golang#59 Also, we update to new API of libseccomp-golang so code doesn't break. Signed-off-by: Alban Crequy <alban@kinvolk.io> Signed-off-by: Rodrigo Campos <rodrigo@kinvolk.io> Co-authored-by: Rodrigo Campos <rodrigo@kinvolk.io>
The notify support has been merged in libseccomp-golang in this PR: seccomp/libseccomp-golang#59 Also, we update to new API of libseccomp-golang so code doesn't break. Signed-off-by: Alban Crequy <alban@kinvolk.io> Signed-off-by: Rodrigo Campos <rodrigo@kinvolk.io> Co-authored-by: Rodrigo Campos <rodrigo@kinvolk.io>
The notify support has been merged in libseccomp-golang in this PR: seccomp/libseccomp-golang#59 Also, we update to new API of libseccomp-golang so code doesn't break. Signed-off-by: Alban Crequy <alban@kinvolk.io> Signed-off-by: Rodrigo Campos <rodrigo@kinvolk.io> Co-authored-by: Rodrigo Campos <rodrigo@kinvolk.io>
The notify support has been merged in libseccomp-golang in this PR: seccomp/libseccomp-golang#59 Also, we update to new API of libseccomp-golang so code doesn't break. Signed-off-by: Alban Crequy <alban@kinvolk.io> Signed-off-by: Rodrigo Campos <rodrigo@kinvolk.io> Co-authored-by: Rodrigo Campos <rodrigo@kinvolk.io>
The notify support has been merged in libseccomp-golang in this PR: seccomp/libseccomp-golang#59 Also, we update to new API of libseccomp-golang so code doesn't break. Signed-off-by: Alban Crequy <alban@kinvolk.io> Signed-off-by: Rodrigo Campos <rodrigo@kinvolk.io> Co-authored-by: Rodrigo Campos <rodrigo@kinvolk.io>
The notify support has been merged in libseccomp-golang in this PR: seccomp/libseccomp-golang#59 Also, we update to new API of libseccomp-golang so code doesn't break. Signed-off-by: Alban Crequy <alban@kinvolk.io> Signed-off-by: Rodrigo Campos <rodrigo@kinvolk.io> Co-authored-by: Rodrigo Campos <rodrigo@kinvolk.io>
The notify support has been merged in libseccomp-golang in this PR: seccomp/libseccomp-golang#59 Also, we update to new API of libseccomp-golang so code doesn't break. Signed-off-by: Alban Crequy <alban@kinvolk.io> Signed-off-by: Rodrigo Campos <rodrigo@kinvolk.io> Co-authored-by: Rodrigo Campos <rodrigo@kinvolk.io>
This PR is based on @rodnymolina's work from #50 and adds the following:
cc @giuseppe