libseccomp icon indicating copy to clipboard operation
libseccomp copied to clipboard

RFE: add runtime autodetection

Open fsateler opened this issue 9 years ago • 8 comments

This should be useful eg, for https://github.com/systemd/systemd/issues/3882 .

I did a tentative patch for systemd that reads if Seccomp is mentioned in /proc/self/status:

bool is_seccomp_enabled() {
        _cleanup_free_ char* field = NULL;
        return get_proc_field("/proc/self/status", "Seccomp", "\n", &field) == 0;
}

But I think it is best if libseccomp provides a canonical way to test for the availability of seccomp.

fsateler avatar Aug 03 '16 20:08 fsateler

Is get_proc_field() a systemd specific function? If not, what/who provides the implementation? Not that it matters too much, I think we can all figure out what it does from the name/args, but just for the sake of clarity it might be nice to see the implementation.

One thing to keep in mind with respect to checking on entries in /proc is that if there is a seccomp filter already loaded it may block the open() and/or read() fields which could lead to confusing results. Kees also did a quick write up on detecting seccomp state at runtime (link below); taking the approach he describes (carefully inspecting the return values when loading a filter) seems to be a better approach.

  • https://outflux.net/teach-seccomp/autodetect.html

pcmoore avatar Aug 07 '16 10:08 pcmoore

Yes, get_proc_field is a a systemd function: https://github.com/systemd/systemd/blob/master/src/basic/fileio.c#L866-L929 . For our purposes, the check basically consists in a line in /proc/self/status starting with Seccomp: (we ignore the field value).

You are correct that this function may fail if there is already a SECCOMP filter. For systemd's purposes I think it is fine, as there are no filters loaded for PID1, but for a general purpose library it may not be appropiate.

With respect to the PR_GET_SECCOMP approach, I considered it, but the following warning in the prctl man page made use the /proc way:

If the caller is in filter mode, and this system call is allowed by the seccomp filters, it returns 2; otherwise, the process is killed with a SIGKILL signal.

Since Linux 3.8, the Seccomp field of the /proc/[pid]/status file provides a method of obtaining the same information, without the risk that the process is killed; see proc(5).

I am definitely no expert in SECCOMP, so I don't know if this warning may be misleading and PR_GET_SECCOMP is indeed a better option.

fsateler avatar Aug 07 '16 17:08 fsateler

There are always going to be risks in trying to detect if seccomp is supported and enabled as the existing filter could always block the process, or even worse kill the process. This is one of the reasons why we don't have a supported API in libseccomp for runtime detection; making this work is going to require a careful/clever solution.

pcmoore avatar Aug 07 '16 18:08 pcmoore

I realized that libseccomp already does a partial check like this (https://github.com/seccomp/libseccomp/blob/bbf23ba4beae9a23148c6845a3037b1a4a8589e7/src/system.c#L54) .

Could it be possible to extend this check to use the PR_GET_SECCOMP approach and return a tristate value (unsupported, prctl only, seccomp syscall). It appears users already rely on being able to query the existence of seccomp.

What do you think?

fsateler avatar Aug 20 '16 04:08 fsateler

A couple of comments:

First, I haven't closed this issue because I think it is a reasonable request, although I haven't thought through this enough just yet to decide if it is something I want to be stuck supporting for the rest of the libseccomp-2.x life cycle.

Second, the problem isn't that we don't already do some checking inside libseccomp, the problem is providing this functionality to calling applications without any guarantee that it will work correctly.

pcmoore avatar Aug 20 '16 13:08 pcmoore

Now that libseccomp has the concept of API levels, it seems like most of this issue is already addressed; the one missing piece is the total lack of seccomp-bpf in the running process (either due to kernel limitations or pre-existing filters).

Currently we list API level zero as a reserved value, but we could use this to indicate a total lack of seccomp-bpf in seccomp_api_get(). I think we would still want to block it's use as a value in seccomp_api_set() for obvious reasons. What do you think @drakenclimber?

pcmoore avatar Jul 21 '20 14:07 pcmoore

Currently we list API level zero as a reserved value, but we could use this to indicate a total lack of seccomp-bpf in seccomp_api_get(). I think we would still want to block it's use as a value in seccomp_api_set() for obvious reasons. What do you think @drakenclimber?

Just to make sure I understand - you're proposing that users like systemd can make a seccomp_api_get() call. If for some reason, libseccomp can't interact with the seccomp kernel interfaces (either because they're not supported or because we're blocked by a seccomp filter), then libseccomp will return 0 as the currently supported API. If so, that's a clever and creative solution, and I think that sounds really good.

drakenclimber avatar Jul 22 '20 14:07 drakenclimber

Just to make sure I understand - you're proposing that users like systemd can make a seccomp_api_get() call. If for some reason, libseccomp can't interact with the seccomp kernel interfaces (either because they're not supported or because we're blocked by a seccomp filter), then libseccomp will return 0 as the currently supported API.

Yep, that's pretty much it. We've basically already implemented a runtime detection mechanism with the API levels, the only thing that is missing is that we assume a base level of support; this change would no longer assume that base level but instead test for it. Famous last words, but this shouldn't be too difficult ;)

pcmoore avatar Jul 23 '20 01:07 pcmoore