Comment 5 for bug 1830859

Revision history for this message
Christian Ehrhardt  (paelzer) wrote :

Two Disco containers (one per PPA)

$ sudo add-apt-repository ppa:paelzer/bug-1830859-with-proposed-seccomp
or
$ sudo add-apt-repository ppa:paelzer/bug-1830859-without-proposed-seccomp
# add main/debug and enable the deb-src in the PPA sources

$ sudo apt install gdb qemu-system-x86 qemu-system-x86-dbgsym dpkg-dev
$ apt source qemu
$ cd qemu-3.1+dfsg/

break on qemu_seccomp

Hrm ??
equal qemu source
Good:
Breakpoint 1 at 0x4d63f4: file ./qemu-seccomp.c, line 293.
Bad:
Breakpoint 1 at 0x4d63f4: qemu_seccomp. (2 location
(gdb) info b
Num Type Disp Enb Address What
1 breakpoint keep y <MULTIPLE>
1.1 y 0x00000000004d63f4 in qemu_seccomp at ./qemu-seccomp.c:293
1.2 y 0x00000000004d656e in qemu_seccomp at ./qemu-seccomp.c:244

Now the second hit isn't an actual qemu_seccomp call, but it is very close to the error that we get reported.

(gdb) l qemu-seccomp.c:293
288
289 #if defined(SECCOMP_FILTER_FLAG_TSYNC)
290 int check;
291
292 /* check host TSYNC capability, it returns errno == ENOSYS if unavailable */
293 check = qemu_seccomp(SECCOMP_SET_MODE_FILTER,
294 SECCOMP_FILTER_FLAG_TSYNC, NULL);
295 if (check < 0 && errno == EFAULT) {
296 add = true;
297 }
(gdb) l qemu-seccomp.c:244
239 error_setg(errp, "invalid argument for resourcecontrol");
240 return -1;
241 }
242 }
243
244 if (seccomp_start(seccomp_opts) < 0) {
245 error_setg(errp, "failed to install seccomp syscall filter "
246 "in the kernel");
247 return -1;
248 }

Well maybe with seccomp 2.4 development headers something changed and this now gets inlined?
That is not an error, but suspicious.

qemu_seccomp should ALWAYS be inlined

static inline __attribute__((unused)) int
qemu_seccomp(unsigned int operation, unsigned int flags, void *args)

The one at line 293 is at seccomp_register and depends on #if defined(SECCOMP_FILTER_FLAG_TSYNC).
This one is active in both cases.

But the one at line 244 is part of qemu_seccomp_get_kill_action
That has some checks as well being:
#if defined(SECCOMP_GET_ACTION_AVAIL) && \
    defined(SCMP_ACT_KILL_PROCESS) && \
    defined(SECCOMP_RET_KILL_PROCESS)

There is no other way to "avoid" the path of
  parse_sandbox -> seccomp_start -> qemu_seccomp_get_kill_action -> qemu_seccomp
in terms of precompiler.
Both have CONFIG_SECCOMP set, so it might really come down to the three checks above.

Reading the commit [1] that added this to qemu seems to match the current theories.

Lets see what happens when it tries to use things buildt with 2.4 but without 2.4 being installed at runtime.

The returned value for action is matching expected /usr/include/seccomp.h numbers:
- good case => 196608 ==> SCMP_ACT_TRAP = 0x00030000U
- bad case => 2147483648 ==> SCMP_ACT_KILL_PROCESS = 0x80000000U

As a summary:
- the libseccomp-dev 2.4 headers being installed at build time
- code can detect now the availability of SCMP_ACT_KILL_PROCESS
- code might decide to use SCMP_ACT_KILL_PROCESS
- if code runs without libseccomp2 2.4 installed it breaks

For qemu I could patch out the usage of SCMP_ACT_KILL_PROCESS, but:
- that is stupid as it is preferred if available
- the question is either
  - how can we make such rebuilds pick up the dependency correctly
  - could we runtime (instead of compile time) detect if SCMP_ACT_KILL_PROCESS is available

[1]: https://git.qemu.org/?p=qemu.git;a=commit;h=bda08a5764d