All of lore.kernel.org
 help / color / mirror / Atom feed
* [PULL 00/10] Misc next patches
@ 2022-02-17 11:57 Daniel P. Berrangé
  2022-02-17 11:57 ` [PULL 01/10] block: better document SSH host key fingerprint checking Daniel P. Berrangé
                   ` (10 more replies)
  0 siblings, 11 replies; 14+ messages in thread
From: Daniel P. Berrangé @ 2022-02-17 11:57 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Daniel P. Berrangé,
	qemu-block, Kashyap Chamarthy, Richard W.M. Jones,
	Philippe Mathieu-Daudé,
	Hanna Reitz

The following changes since commit ad38520bdeb2b1e0b487db317f29119e94c1c88d:

  Merge remote-tracking branch 'remotes/stefanha-gitlab/tags/block-pull-request' into staging (2022-02-15 19:30:33 +0000)

are available in the Git repository at:

  https://gitlab.com/berrange/qemu tags/misc-next-pull-request

for you to fetch changes up to 2720ceda0521bc43139cfdf45e3e470559e11ce3:

  docs: expand firmware descriptor to allow flash without NVRAM (2022-02-16 18:53:26 +0000)

----------------------------------------------------------------
This misc series of changes:

 - Improves documentation of SSH fingerprint checking
 - Fixes SHA256 fingerprints with non-blockdev usage
 - Blocks the clone3, setns, unshare & execveat syscalls
   with seccomp
 - Blocks process spawning via clone syscall, but allows
   threads, with seccomp
 - Takes over seccomp maintainer role
 - Expands firmware descriptor spec to allow flash
   without NVRAM

----------------------------------------------------------------

Daniel P. Berrangé (10):
  block: better document SSH host key fingerprint checking
  block: support sha256 fingerprint with pre-blockdev options
  block: print the server key type and fingerprint on failure
  seccomp: allow action to be customized per syscall
  seccomp: add unit test for seccomp filtering
  seccomp: fix blocking of process spawning
  seccomp: block use of clone3 syscall
  seccomp: block setns, unshare and execveat syscalls
  MAINTAINERS: take over seccomp from Eduardo Otubo
  docs: expand firmware descriptor to allow flash without NVRAM

 MAINTAINERS                            |   5 +-
 block/ssh.c                            |  42 +++-
 docs/interop/firmware.json             |  54 ++++-
 docs/system/qemu-block-drivers.rst.inc |  30 ++-
 softmmu/qemu-seccomp.c                 | 282 +++++++++++++++++++------
 tests/unit/meson.build                 |   4 +
 tests/unit/test-seccomp.c              | 269 +++++++++++++++++++++++
 7 files changed, 599 insertions(+), 87 deletions(-)
 create mode 100644 tests/unit/test-seccomp.c

-- 
2.34.1




^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PULL 01/10] block: better document SSH host key fingerprint checking
  2022-02-17 11:57 [PULL 00/10] Misc next patches Daniel P. Berrangé
@ 2022-02-17 11:57 ` Daniel P. Berrangé
  2022-02-17 11:57 ` [PULL 02/10] block: support sha256 fingerprint with pre-blockdev options Daniel P. Berrangé
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 14+ messages in thread
From: Daniel P. Berrangé @ 2022-02-17 11:57 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Daniel P. Berrangé,
	qemu-block, Kashyap Chamarthy, Richard W.M. Jones,
	Philippe Mathieu-Daudé,
	Hanna Reitz

The docs still illustrate host key fingerprint checking using the old
md5 hashes which are considered insecure and obsolete. Change it to
illustrate using a sha256 hash. Also show how to extract the hash
value from the known_hosts file.

Reviewed-by: Hanna Reitz <hreitz@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
 docs/system/qemu-block-drivers.rst.inc | 30 ++++++++++++++++++++++----
 1 file changed, 26 insertions(+), 4 deletions(-)

diff --git a/docs/system/qemu-block-drivers.rst.inc b/docs/system/qemu-block-drivers.rst.inc
index e313784426..dfe5d2293d 100644
--- a/docs/system/qemu-block-drivers.rst.inc
+++ b/docs/system/qemu-block-drivers.rst.inc
@@ -778,10 +778,32 @@ The optional *HOST_KEY_CHECK* parameter controls how the remote
 host's key is checked.  The default is ``yes`` which means to use
 the local ``.ssh/known_hosts`` file.  Setting this to ``no``
 turns off known-hosts checking.  Or you can check that the host key
-matches a specific fingerprint:
-``host_key_check=md5:78:45:8e:14:57:4f:d5:45:83:0a:0e:f3:49:82:c9:c8``
-(``sha1:`` can also be used as a prefix, but note that OpenSSH
-tools only use MD5 to print fingerprints).
+matches a specific fingerprint. The fingerprint can be provided in
+``md5``, ``sha1``, or ``sha256`` format, however, it is strongly
+recommended to only use ``sha256``, since the other options are
+considered insecure by modern standards. The fingerprint value
+must be given as a hex encoded string::
+
+  host_key_check=sha256:04ce2ae89ff4295a6b9c4111640bdcb3297858ee55cb434d9dd88796e93aa795
+
+The key string may optionally contain ":" separators between
+each pair of hex digits.
+
+The ``$HOME/.ssh/known_hosts`` file contains the base64 encoded
+host keys. These can be converted into the format needed for
+QEMU using a command such as::
+
+   $ for key in `grep 10.33.8.112 known_hosts | awk '{print $3}'`
+     do
+       echo $key | base64 -d | sha256sum
+     done
+     6c3aa525beda9dc83eadfbd7e5ba7d976ecb59575d1633c87cd06ed2ed6e366f  -
+     12214fd9ea5b408086f98ecccd9958609bd9ac7c0ea316734006bc7818b45dc8  -
+     d36420137bcbd101209ef70c3b15dc07362fbe0fa53c5b135eba6e6afa82f0ce  -
+
+Note that there can be multiple keys present per host, each with
+different key ciphers. Care is needed to pick the key fingerprint
+that matches the cipher QEMU will negotiate with the remote server.
 
 Currently authentication must be done using ssh-agent.  Other
 authentication methods may be supported in future.
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PULL 02/10] block: support sha256 fingerprint with pre-blockdev options
  2022-02-17 11:57 [PULL 00/10] Misc next patches Daniel P. Berrangé
  2022-02-17 11:57 ` [PULL 01/10] block: better document SSH host key fingerprint checking Daniel P. Berrangé
@ 2022-02-17 11:57 ` Daniel P. Berrangé
  2022-02-17 11:57 ` [PULL 03/10] block: print the server key type and fingerprint on failure Daniel P. Berrangé
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 14+ messages in thread
From: Daniel P. Berrangé @ 2022-02-17 11:57 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Daniel P. Berrangé,
	qemu-block, Kashyap Chamarthy, Richard W.M. Jones,
	Philippe Mathieu-Daudé,
	Hanna Reitz

When support for sha256 fingerprint checking was aded in

  commit bf783261f0aee6e81af3916bff7606d71ccdc153
  Author: Daniel P. Berrangé <berrange@redhat.com>
  Date:   Tue Jun 22 12:51:56 2021 +0100

    block/ssh: add support for sha256 host key fingerprints

it was only made to work with -blockdev. Getting it working with
-drive requires some extra custom parsing.

Reviewed-by: Hanna Reitz <hreitz@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
 block/ssh.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/block/ssh.c b/block/ssh.c
index 3b5bf34031..ac01301409 100644
--- a/block/ssh.c
+++ b/block/ssh.c
@@ -556,6 +556,11 @@ static bool ssh_process_legacy_options(QDict *output_opts,
             qdict_put_str(output_opts, "host-key-check.type", "sha1");
             qdict_put_str(output_opts, "host-key-check.hash",
                           &host_key_check[5]);
+        } else if (strncmp(host_key_check, "sha256:", 7) == 0) {
+            qdict_put_str(output_opts, "host-key-check.mode", "hash");
+            qdict_put_str(output_opts, "host-key-check.type", "sha256");
+            qdict_put_str(output_opts, "host-key-check.hash",
+                          &host_key_check[7]);
         } else if (strcmp(host_key_check, "yes") == 0) {
             qdict_put_str(output_opts, "host-key-check.mode", "known_hosts");
         } else {
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PULL 03/10] block: print the server key type and fingerprint on failure
  2022-02-17 11:57 [PULL 00/10] Misc next patches Daniel P. Berrangé
  2022-02-17 11:57 ` [PULL 01/10] block: better document SSH host key fingerprint checking Daniel P. Berrangé
  2022-02-17 11:57 ` [PULL 02/10] block: support sha256 fingerprint with pre-blockdev options Daniel P. Berrangé
@ 2022-02-17 11:57 ` Daniel P. Berrangé
  2022-02-17 11:57 ` [PULL 04/10] seccomp: allow action to be customized per syscall Daniel P. Berrangé
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 14+ messages in thread
From: Daniel P. Berrangé @ 2022-02-17 11:57 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Daniel P. Berrangé,
	qemu-block, Kashyap Chamarthy, Richard W.M. Jones,
	Philippe Mathieu-Daudé,
	Hanna Reitz, Philippe Mathieu-Daudé

When validating the server key fingerprint fails, it is difficult for
the user to know what they got wrong. The fingerprint accepted by QEMU
is received in a different format than OpenSSH displays. There can also
be keys for multiple different ciphers in known_hosts. It may not be
obvious which cipher QEMU will use and whether it will be the same
as OpenSSH. Address this by printing the server key type and its
corresponding fingerprint in the format QEMU accepts.

Reviewed-by: Hanna Reitz <hreitz@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
 block/ssh.c | 37 ++++++++++++++++++++++++++++++-------
 1 file changed, 30 insertions(+), 7 deletions(-)

diff --git a/block/ssh.c b/block/ssh.c
index ac01301409..a64db146db 100644
--- a/block/ssh.c
+++ b/block/ssh.c
@@ -386,14 +386,28 @@ static int compare_fingerprint(const unsigned char *fingerprint, size_t len,
     return *host_key_check - '\0';
 }
 
+static char *format_fingerprint(const unsigned char *fingerprint, size_t len)
+{
+    static const char *hex = "0123456789abcdef";
+    char *ret = g_new0(char, (len * 2) + 1);
+    for (size_t i = 0; i < len; i++) {
+        ret[i * 2] = hex[((fingerprint[i] >> 4) & 0xf)];
+        ret[(i * 2) + 1] = hex[(fingerprint[i] & 0xf)];
+    }
+    ret[len * 2] = '\0';
+    return ret;
+}
+
 static int
 check_host_key_hash(BDRVSSHState *s, const char *hash,
-                    enum ssh_publickey_hash_type type, Error **errp)
+                    enum ssh_publickey_hash_type type, const char *typestr,
+                    Error **errp)
 {
     int r;
     ssh_key pubkey;
     unsigned char *server_hash;
     size_t server_hash_len;
+    const char *keytype;
 
     r = ssh_get_server_publickey(s->session, &pubkey);
     if (r != SSH_OK) {
@@ -401,6 +415,8 @@ check_host_key_hash(BDRVSSHState *s, const char *hash,
         return -EINVAL;
     }
 
+    keytype = ssh_key_type_to_char(ssh_key_type(pubkey));
+
     r = ssh_get_publickey_hash(pubkey, type, &server_hash, &server_hash_len);
     ssh_key_free(pubkey);
     if (r != 0) {
@@ -410,12 +426,16 @@ check_host_key_hash(BDRVSSHState *s, const char *hash,
     }
 
     r = compare_fingerprint(server_hash, server_hash_len, hash);
-    ssh_clean_pubkey_hash(&server_hash);
     if (r != 0) {
-        error_setg(errp, "remote host key does not match host_key_check '%s'",
-                   hash);
+        g_autofree char *server_fp = format_fingerprint(server_hash,
+                                                        server_hash_len);
+        error_setg(errp, "remote host %s key fingerprint '%s:%s' "
+                   "does not match host_key_check '%s:%s'",
+                   keytype, typestr, server_fp, typestr, hash);
+        ssh_clean_pubkey_hash(&server_hash);
         return -EPERM;
     }
+    ssh_clean_pubkey_hash(&server_hash);
 
     return 0;
 }
@@ -436,13 +456,16 @@ static int check_host_key(BDRVSSHState *s, SshHostKeyCheck *hkc, Error **errp)
     case SSH_HOST_KEY_CHECK_MODE_HASH:
         if (hkc->u.hash.type == SSH_HOST_KEY_CHECK_HASH_TYPE_MD5) {
             return check_host_key_hash(s, hkc->u.hash.hash,
-                                       SSH_PUBLICKEY_HASH_MD5, errp);
+                                       SSH_PUBLICKEY_HASH_MD5, "md5",
+                                       errp);
         } else if (hkc->u.hash.type == SSH_HOST_KEY_CHECK_HASH_TYPE_SHA1) {
             return check_host_key_hash(s, hkc->u.hash.hash,
-                                       SSH_PUBLICKEY_HASH_SHA1, errp);
+                                       SSH_PUBLICKEY_HASH_SHA1, "sha1",
+                                       errp);
         } else if (hkc->u.hash.type == SSH_HOST_KEY_CHECK_HASH_TYPE_SHA256) {
             return check_host_key_hash(s, hkc->u.hash.hash,
-                                       SSH_PUBLICKEY_HASH_SHA256, errp);
+                                       SSH_PUBLICKEY_HASH_SHA256, "sha256",
+                                       errp);
         }
         g_assert_not_reached();
         break;
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PULL 04/10] seccomp: allow action to be customized per syscall
  2022-02-17 11:57 [PULL 00/10] Misc next patches Daniel P. Berrangé
                   ` (2 preceding siblings ...)
  2022-02-17 11:57 ` [PULL 03/10] block: print the server key type and fingerprint on failure Daniel P. Berrangé
@ 2022-02-17 11:57 ` Daniel P. Berrangé
  2022-02-17 11:57 ` [PULL 05/10] seccomp: add unit test for seccomp filtering Daniel P. Berrangé
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 14+ messages in thread
From: Daniel P. Berrangé @ 2022-02-17 11:57 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Eduardo Otubo, Daniel P. Berrangé,
	qemu-block, Kashyap Chamarthy, Richard W.M. Jones,
	Philippe Mathieu-Daudé,
	Hanna Reitz

We're currently tailoring whether to use kill process or return EPERM
based on the syscall set. This is not flexible enough for future
requirements where we also need to be able to return a variety of
actions on a per-syscall granularity.

Acked-by: Eduardo Otubo <otubo@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
 softmmu/qemu-seccomp.c | 172 +++++++++++++++++++++++++----------------
 1 file changed, 106 insertions(+), 66 deletions(-)

diff --git a/softmmu/qemu-seccomp.c b/softmmu/qemu-seccomp.c
index f50026778c..9f6df8d033 100644
--- a/softmmu/qemu-seccomp.c
+++ b/softmmu/qemu-seccomp.c
@@ -38,6 +38,7 @@ struct QemuSeccompSyscall {
     uint8_t set;
     uint8_t narg;
     const struct scmp_arg_cmp *arg_cmp;
+    uint32_t action;
 };
 
 const struct scmp_arg_cmp sched_setscheduler_arg[] = {
@@ -47,61 +48,111 @@ const struct scmp_arg_cmp sched_setscheduler_arg[] = {
 
 static const struct QemuSeccompSyscall denylist[] = {
     /* default set of syscalls that should get blocked */
-    { SCMP_SYS(reboot),                 QEMU_SECCOMP_SET_DEFAULT },
-    { SCMP_SYS(swapon),                 QEMU_SECCOMP_SET_DEFAULT },
-    { SCMP_SYS(swapoff),                QEMU_SECCOMP_SET_DEFAULT },
-    { SCMP_SYS(syslog),                 QEMU_SECCOMP_SET_DEFAULT },
-    { SCMP_SYS(mount),                  QEMU_SECCOMP_SET_DEFAULT },
-    { SCMP_SYS(umount),                 QEMU_SECCOMP_SET_DEFAULT },
-    { SCMP_SYS(kexec_load),             QEMU_SECCOMP_SET_DEFAULT },
-    { SCMP_SYS(afs_syscall),            QEMU_SECCOMP_SET_DEFAULT },
-    { SCMP_SYS(break),                  QEMU_SECCOMP_SET_DEFAULT },
-    { SCMP_SYS(ftime),                  QEMU_SECCOMP_SET_DEFAULT },
-    { SCMP_SYS(getpmsg),                QEMU_SECCOMP_SET_DEFAULT },
-    { SCMP_SYS(gtty),                   QEMU_SECCOMP_SET_DEFAULT },
-    { SCMP_SYS(lock),                   QEMU_SECCOMP_SET_DEFAULT },
-    { SCMP_SYS(mpx),                    QEMU_SECCOMP_SET_DEFAULT },
-    { SCMP_SYS(prof),                   QEMU_SECCOMP_SET_DEFAULT },
-    { SCMP_SYS(profil),                 QEMU_SECCOMP_SET_DEFAULT },
-    { SCMP_SYS(putpmsg),                QEMU_SECCOMP_SET_DEFAULT },
-    { SCMP_SYS(security),               QEMU_SECCOMP_SET_DEFAULT },
-    { SCMP_SYS(stty),                   QEMU_SECCOMP_SET_DEFAULT },
-    { SCMP_SYS(tuxcall),                QEMU_SECCOMP_SET_DEFAULT },
-    { SCMP_SYS(ulimit),                 QEMU_SECCOMP_SET_DEFAULT },
-    { SCMP_SYS(vserver),                QEMU_SECCOMP_SET_DEFAULT },
+    { SCMP_SYS(reboot),                 QEMU_SECCOMP_SET_DEFAULT,
+      0, NULL, SCMP_ACT_TRAP },
+    { SCMP_SYS(swapon),                 QEMU_SECCOMP_SET_DEFAULT,
+      0, NULL, SCMP_ACT_TRAP },
+    { SCMP_SYS(swapoff),                QEMU_SECCOMP_SET_DEFAULT,
+      0, NULL, SCMP_ACT_TRAP },
+    { SCMP_SYS(syslog),                 QEMU_SECCOMP_SET_DEFAULT,
+      0, NULL, SCMP_ACT_TRAP },
+    { SCMP_SYS(mount),                  QEMU_SECCOMP_SET_DEFAULT,
+      0, NULL, SCMP_ACT_TRAP },
+    { SCMP_SYS(umount),                 QEMU_SECCOMP_SET_DEFAULT,
+      0, NULL, SCMP_ACT_TRAP },
+    { SCMP_SYS(kexec_load),             QEMU_SECCOMP_SET_DEFAULT,
+      0, NULL, SCMP_ACT_TRAP },
+    { SCMP_SYS(afs_syscall),            QEMU_SECCOMP_SET_DEFAULT,
+      0, NULL, SCMP_ACT_TRAP },
+    { SCMP_SYS(break),                  QEMU_SECCOMP_SET_DEFAULT,
+      0, NULL, SCMP_ACT_TRAP },
+    { SCMP_SYS(ftime),                  QEMU_SECCOMP_SET_DEFAULT,
+      0, NULL, SCMP_ACT_TRAP },
+    { SCMP_SYS(getpmsg),                QEMU_SECCOMP_SET_DEFAULT,
+      0, NULL, SCMP_ACT_TRAP },
+    { SCMP_SYS(gtty),                   QEMU_SECCOMP_SET_DEFAULT,
+      0, NULL, SCMP_ACT_TRAP },
+    { SCMP_SYS(lock),                   QEMU_SECCOMP_SET_DEFAULT,
+      0, NULL, SCMP_ACT_TRAP },
+    { SCMP_SYS(mpx),                    QEMU_SECCOMP_SET_DEFAULT,
+      0, NULL, SCMP_ACT_TRAP },
+    { SCMP_SYS(prof),                   QEMU_SECCOMP_SET_DEFAULT,
+      0, NULL, SCMP_ACT_TRAP },
+    { SCMP_SYS(profil),                 QEMU_SECCOMP_SET_DEFAULT,
+      0, NULL, SCMP_ACT_TRAP },
+    { SCMP_SYS(putpmsg),                QEMU_SECCOMP_SET_DEFAULT,
+      0, NULL, SCMP_ACT_TRAP },
+    { SCMP_SYS(security),               QEMU_SECCOMP_SET_DEFAULT,
+      0, NULL, SCMP_ACT_TRAP },
+    { SCMP_SYS(stty),                   QEMU_SECCOMP_SET_DEFAULT,
+      0, NULL, SCMP_ACT_TRAP },
+    { SCMP_SYS(tuxcall),                QEMU_SECCOMP_SET_DEFAULT,
+      0, NULL, SCMP_ACT_TRAP },
+    { SCMP_SYS(ulimit),                 QEMU_SECCOMP_SET_DEFAULT,
+      0, NULL, SCMP_ACT_TRAP },
+    { SCMP_SYS(vserver),                QEMU_SECCOMP_SET_DEFAULT,
+      0, NULL, SCMP_ACT_TRAP },
     /* obsolete */
-    { SCMP_SYS(readdir),                QEMU_SECCOMP_SET_OBSOLETE },
-    { SCMP_SYS(_sysctl),                QEMU_SECCOMP_SET_OBSOLETE },
-    { SCMP_SYS(bdflush),                QEMU_SECCOMP_SET_OBSOLETE },
-    { SCMP_SYS(create_module),          QEMU_SECCOMP_SET_OBSOLETE },
-    { SCMP_SYS(get_kernel_syms),        QEMU_SECCOMP_SET_OBSOLETE },
-    { SCMP_SYS(query_module),           QEMU_SECCOMP_SET_OBSOLETE },
-    { SCMP_SYS(sgetmask),               QEMU_SECCOMP_SET_OBSOLETE },
-    { SCMP_SYS(ssetmask),               QEMU_SECCOMP_SET_OBSOLETE },
-    { SCMP_SYS(sysfs),                  QEMU_SECCOMP_SET_OBSOLETE },
-    { SCMP_SYS(uselib),                 QEMU_SECCOMP_SET_OBSOLETE },
-    { SCMP_SYS(ustat),                  QEMU_SECCOMP_SET_OBSOLETE },
+    { SCMP_SYS(readdir),                QEMU_SECCOMP_SET_OBSOLETE,
+      0, NULL, SCMP_ACT_TRAP },
+    { SCMP_SYS(_sysctl),                QEMU_SECCOMP_SET_OBSOLETE,
+      0, NULL, SCMP_ACT_TRAP },
+    { SCMP_SYS(bdflush),                QEMU_SECCOMP_SET_OBSOLETE,
+      0, NULL, SCMP_ACT_TRAP },
+    { SCMP_SYS(create_module),          QEMU_SECCOMP_SET_OBSOLETE,
+      0, NULL, SCMP_ACT_TRAP },
+    { SCMP_SYS(get_kernel_syms),        QEMU_SECCOMP_SET_OBSOLETE,
+      0, NULL, SCMP_ACT_TRAP },
+    { SCMP_SYS(query_module),           QEMU_SECCOMP_SET_OBSOLETE,
+      0, NULL, SCMP_ACT_TRAP },
+    { SCMP_SYS(sgetmask),               QEMU_SECCOMP_SET_OBSOLETE,
+      0, NULL, SCMP_ACT_TRAP },
+    { SCMP_SYS(ssetmask),               QEMU_SECCOMP_SET_OBSOLETE,
+      0, NULL, SCMP_ACT_TRAP },
+    { SCMP_SYS(sysfs),                  QEMU_SECCOMP_SET_OBSOLETE,
+      0, NULL, SCMP_ACT_TRAP },
+    { SCMP_SYS(uselib),                 QEMU_SECCOMP_SET_OBSOLETE,
+      0, NULL, SCMP_ACT_TRAP },
+    { SCMP_SYS(ustat),                  QEMU_SECCOMP_SET_OBSOLETE,
+      0, NULL, SCMP_ACT_TRAP },
     /* privileged */
-    { SCMP_SYS(setuid),                 QEMU_SECCOMP_SET_PRIVILEGED },
-    { SCMP_SYS(setgid),                 QEMU_SECCOMP_SET_PRIVILEGED },
-    { SCMP_SYS(setpgid),                QEMU_SECCOMP_SET_PRIVILEGED },
-    { SCMP_SYS(setsid),                 QEMU_SECCOMP_SET_PRIVILEGED },
-    { SCMP_SYS(setreuid),               QEMU_SECCOMP_SET_PRIVILEGED },
-    { SCMP_SYS(setregid),               QEMU_SECCOMP_SET_PRIVILEGED },
-    { SCMP_SYS(setresuid),              QEMU_SECCOMP_SET_PRIVILEGED },
-    { SCMP_SYS(setresgid),              QEMU_SECCOMP_SET_PRIVILEGED },
-    { SCMP_SYS(setfsuid),               QEMU_SECCOMP_SET_PRIVILEGED },
-    { SCMP_SYS(setfsgid),               QEMU_SECCOMP_SET_PRIVILEGED },
+    { SCMP_SYS(setuid),                 QEMU_SECCOMP_SET_PRIVILEGED,
+      0, NULL, SCMP_ACT_TRAP },
+    { SCMP_SYS(setgid),                 QEMU_SECCOMP_SET_PRIVILEGED,
+      0, NULL, SCMP_ACT_TRAP },
+    { SCMP_SYS(setpgid),                QEMU_SECCOMP_SET_PRIVILEGED,
+      0, NULL, SCMP_ACT_TRAP },
+    { SCMP_SYS(setsid),                 QEMU_SECCOMP_SET_PRIVILEGED,
+      0, NULL, SCMP_ACT_TRAP },
+    { SCMP_SYS(setreuid),               QEMU_SECCOMP_SET_PRIVILEGED,
+      0, NULL, SCMP_ACT_TRAP },
+    { SCMP_SYS(setregid),               QEMU_SECCOMP_SET_PRIVILEGED,
+      0, NULL, SCMP_ACT_TRAP },
+    { SCMP_SYS(setresuid),              QEMU_SECCOMP_SET_PRIVILEGED,
+      0, NULL, SCMP_ACT_TRAP },
+    { SCMP_SYS(setresgid),              QEMU_SECCOMP_SET_PRIVILEGED,
+      0, NULL, SCMP_ACT_TRAP },
+    { SCMP_SYS(setfsuid),               QEMU_SECCOMP_SET_PRIVILEGED,
+      0, NULL, SCMP_ACT_TRAP },
+    { SCMP_SYS(setfsgid),               QEMU_SECCOMP_SET_PRIVILEGED,
+      0, NULL, SCMP_ACT_TRAP },
     /* spawn */
-    { SCMP_SYS(fork),                   QEMU_SECCOMP_SET_SPAWN },
-    { SCMP_SYS(vfork),                  QEMU_SECCOMP_SET_SPAWN },
-    { SCMP_SYS(execve),                 QEMU_SECCOMP_SET_SPAWN },
+    { SCMP_SYS(fork),                   QEMU_SECCOMP_SET_SPAWN,
+      0, NULL, SCMP_ACT_TRAP },
+    { SCMP_SYS(vfork),                  QEMU_SECCOMP_SET_SPAWN,
+      0, NULL, SCMP_ACT_TRAP },
+    { SCMP_SYS(execve),                 QEMU_SECCOMP_SET_SPAWN,
+      0, NULL, SCMP_ACT_TRAP },
     /* resource control */
-    { SCMP_SYS(setpriority),            QEMU_SECCOMP_SET_RESOURCECTL },
-    { SCMP_SYS(sched_setparam),         QEMU_SECCOMP_SET_RESOURCECTL },
+    { SCMP_SYS(setpriority),            QEMU_SECCOMP_SET_RESOURCECTL,
+      0, NULL, SCMP_ACT_ERRNO(EPERM) },
+    { SCMP_SYS(sched_setparam),         QEMU_SECCOMP_SET_RESOURCECTL,
+      0, NULL, SCMP_ACT_ERRNO(EPERM) },
     { SCMP_SYS(sched_setscheduler),     QEMU_SECCOMP_SET_RESOURCECTL,
-      ARRAY_SIZE(sched_setscheduler_arg), sched_setscheduler_arg },
-    { SCMP_SYS(sched_setaffinity),      QEMU_SECCOMP_SET_RESOURCECTL },
+      ARRAY_SIZE(sched_setscheduler_arg), sched_setscheduler_arg,
+      SCMP_ACT_ERRNO(EPERM) },
+    { SCMP_SYS(sched_setaffinity),      QEMU_SECCOMP_SET_RESOURCECTL,
+      0, NULL, SCMP_ACT_ERRNO(EPERM) },
 };
 
 static inline __attribute__((unused)) int
@@ -115,15 +166,11 @@ qemu_seccomp(unsigned int operation, unsigned int flags, void *args)
 #endif
 }
 
-static uint32_t qemu_seccomp_get_action(int set)
+static uint32_t qemu_seccomp_update_action(uint32_t action)
 {
-    switch (set) {
-    case QEMU_SECCOMP_SET_DEFAULT:
-    case QEMU_SECCOMP_SET_OBSOLETE:
-    case QEMU_SECCOMP_SET_PRIVILEGED:
-    case QEMU_SECCOMP_SET_SPAWN: {
 #if defined(SECCOMP_GET_ACTION_AVAIL) && defined(SCMP_ACT_KILL_PROCESS) && \
     defined(SECCOMP_RET_KILL_PROCESS)
+    if (action == SCMP_ACT_TRAP) {
         static int kill_process = -1;
         if (kill_process == -1) {
             uint32_t action = SECCOMP_RET_KILL_PROCESS;
@@ -137,16 +184,9 @@ static uint32_t qemu_seccomp_get_action(int set)
         if (kill_process == 1) {
             return SCMP_ACT_KILL_PROCESS;
         }
-#endif
-        return SCMP_ACT_TRAP;
-    }
-
-    case QEMU_SECCOMP_SET_RESOURCECTL:
-        return SCMP_ACT_ERRNO(EPERM);
-
-    default:
-        g_assert_not_reached();
     }
+#endif
+    return action;
 }
 
 
@@ -175,7 +215,7 @@ static int seccomp_start(uint32_t seccomp_opts, Error **errp)
             continue;
         }
 
-        action = qemu_seccomp_get_action(denylist[i].set);
+        action = qemu_seccomp_update_action(denylist[i].action);
         rc = seccomp_rule_add_array(ctx, action, denylist[i].num,
                                     denylist[i].narg, denylist[i].arg_cmp);
         if (rc < 0) {
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PULL 05/10] seccomp: add unit test for seccomp filtering
  2022-02-17 11:57 [PULL 00/10] Misc next patches Daniel P. Berrangé
                   ` (3 preceding siblings ...)
  2022-02-17 11:57 ` [PULL 04/10] seccomp: allow action to be customized per syscall Daniel P. Berrangé
@ 2022-02-17 11:57 ` Daniel P. Berrangé
  2022-02-17 11:57 ` [PULL 06/10] seccomp: fix blocking of process spawning Daniel P. Berrangé
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 14+ messages in thread
From: Daniel P. Berrangé @ 2022-02-17 11:57 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Eduardo Otubo, Daniel P. Berrangé,
	qemu-block, Kashyap Chamarthy, Richard W.M. Jones,
	Philippe Mathieu-Daudé,
	Hanna Reitz

The handling of some syscalls / libc function is quite subtle. For
example, 'fork' at a libc level doesn't always correspond to 'fork'
at a syscall level, since the 'clone' syscall is preferred usually.

The unit test will help to detect these kind of problems. A point of
difficulty in writing a test though is that the QEMU build process may
already be confined by seccomp. For example, if running inside a
container. Since we can't predict what filtering might have been applied
already, we are quite conservative and skip all tests if we see any kind
of seccomp filter active.

Acked-by: Eduardo Otubo <otubo@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
 MAINTAINERS               |   1 +
 tests/unit/meson.build    |   4 +
 tests/unit/test-seccomp.c | 270 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 275 insertions(+)
 create mode 100644 tests/unit/test-seccomp.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 4b3ae2ab08..1fe647eb08 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2982,6 +2982,7 @@ M: Eduardo Otubo <otubo@redhat.com>
 S: Supported
 F: softmmu/qemu-seccomp.c
 F: include/sysemu/seccomp.h
+F: tests/unit/test-seccomp.c
 
 Cryptography
 M: Daniel P. Berrange <berrange@redhat.com>
diff --git a/tests/unit/meson.build b/tests/unit/meson.build
index 64a5e7bfde..cd06f0eaf5 100644
--- a/tests/unit/meson.build
+++ b/tests/unit/meson.build
@@ -53,6 +53,10 @@ if have_system or have_tools
   tests += {
     'test-qmp-event': [testqapi],
   }
+
+  if seccomp.found()
+    tests += {'test-seccomp': ['../../softmmu/qemu-seccomp.c', seccomp]}
+  endif
 endif
 
 if have_block
diff --git a/tests/unit/test-seccomp.c b/tests/unit/test-seccomp.c
new file mode 100644
index 0000000000..10ab3e8fe5
--- /dev/null
+++ b/tests/unit/test-seccomp.c
@@ -0,0 +1,270 @@
+/*
+ * QEMU seccomp test suite
+ *
+ * Copyright (c) 2021 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/config-file.h"
+#include "qemu/option.h"
+#include "sysemu/seccomp.h"
+#include "qapi/error.h"
+#include "qemu/module.h"
+
+#include <unistd.h>
+#include <sys/syscall.h>
+
+static void test_seccomp_helper(const char *args, bool killed,
+                                int errnum, int (*doit)(void))
+{
+    if (g_test_subprocess()) {
+        QemuOptsList *olist;
+        QemuOpts *opts;
+        int ret;
+
+        module_call_init(MODULE_INIT_OPTS);
+        olist = qemu_find_opts("sandbox");
+        g_assert(olist != NULL);
+
+        opts = qemu_opts_parse_noisily(olist, args, true);
+        g_assert(opts != NULL);
+
+        parse_sandbox(NULL, opts, &error_abort);
+
+        /* Running in a child process */
+        ret = doit();
+
+        if (errnum != 0) {
+            g_assert(ret != 0);
+            g_assert(errno == errnum);
+        } else {
+            g_assert(ret == 0);
+        }
+
+        _exit(0);
+    } else {
+        /* Running in main test process, spawning the child */
+        g_test_trap_subprocess(NULL, 0, 0);
+        if (killed) {
+            g_test_trap_assert_failed();
+        } else {
+            g_test_trap_assert_passed();
+        }
+    }
+}
+
+
+static void test_seccomp_killed(const char *args, int (*doit)(void))
+{
+    test_seccomp_helper(args, true, 0, doit);
+}
+
+static void test_seccomp_errno(const char *args, int errnum, int (*doit)(void))
+{
+    test_seccomp_helper(args, false, errnum, doit);
+}
+
+static void test_seccomp_passed(const char *args, int (*doit)(void))
+{
+    test_seccomp_helper(args, false, 0, doit);
+}
+
+#ifdef SYS_fork
+static int doit_sys_fork(void)
+{
+    int ret = syscall(SYS_fork);
+    if (ret < 0) {
+        return ret;
+    }
+    if (ret == 0) {
+        _exit(0);
+    }
+    return 0;
+}
+
+static void test_seccomp_sys_fork_on_nospawn(void)
+{
+    test_seccomp_killed("on,spawn=deny", doit_sys_fork);
+}
+
+static void test_seccomp_sys_fork_on(void)
+{
+    test_seccomp_passed("on", doit_sys_fork);
+}
+
+static void test_seccomp_sys_fork_off(void)
+{
+    test_seccomp_passed("off", doit_sys_fork);
+}
+#endif
+
+static int doit_fork(void)
+{
+    int ret = fork();
+    if (ret < 0) {
+        return ret;
+    }
+    if (ret == 0) {
+        _exit(0);
+    }
+    return 0;
+}
+
+static void test_seccomp_fork_on_nospawn(void)
+{
+    /* XXX fixme - should be killed */
+    test_seccomp_passed("on,spawn=deny", doit_fork);
+}
+
+static void test_seccomp_fork_on(void)
+{
+    test_seccomp_passed("on", doit_fork);
+}
+
+static void test_seccomp_fork_off(void)
+{
+    test_seccomp_passed("off", doit_fork);
+}
+
+static void *noop(void *arg)
+{
+    return arg;
+}
+
+static int doit_thread(void)
+{
+    pthread_t th;
+    int ret = pthread_create(&th, NULL, noop, NULL);
+    if (ret != 0) {
+        errno = ret;
+        return -1;
+    } else {
+        pthread_join(th, NULL);
+        return 0;
+    }
+}
+
+static void test_seccomp_thread_on(void)
+{
+    test_seccomp_passed("on", doit_thread);
+}
+
+static void test_seccomp_thread_on_nospawn(void)
+{
+    test_seccomp_passed("on,spawn=deny", doit_thread);
+}
+
+static void test_seccomp_thread_off(void)
+{
+    test_seccomp_passed("off", doit_thread);
+}
+
+static int doit_sched(void)
+{
+    struct sched_param param = { .sched_priority = 0 };
+    return sched_setscheduler(getpid(), SCHED_OTHER, &param);
+}
+
+static void test_seccomp_sched_on_nores(void)
+{
+    test_seccomp_errno("on,resourcecontrol=deny", EPERM, doit_sched);
+}
+
+static void test_seccomp_sched_on(void)
+{
+    test_seccomp_passed("on", doit_sched);
+}
+
+static void test_seccomp_sched_off(void)
+{
+    test_seccomp_passed("off", doit_sched);
+}
+
+static bool can_play_with_seccomp(void)
+{
+    g_autofree char *status = NULL;
+    g_auto(GStrv) lines = NULL;
+    size_t i;
+
+    if (!g_file_get_contents("/proc/self/status", &status, NULL, NULL)) {
+        return false;
+    }
+
+    lines = g_strsplit(status, "\n", 0);
+
+    for (i = 0; lines[i] != NULL; i++) {
+        if (g_str_has_prefix(lines[i], "Seccomp:")) {
+            /*
+             * "Seccomp: 1" or "Seccomp: 2" indicate we're already
+             * confined, probably as we're inside a container. In
+             * this case our tests might get unexpected results,
+             * so we can't run reliably
+             */
+            if (!strchr(lines[i], '0')) {
+                return false;
+            }
+
+            return true;
+        }
+    }
+
+    /* Doesn't look like seccomp is enabled in the kernel */
+    return false;
+}
+
+int main(int argc, char **argv)
+{
+    g_test_init(&argc, &argv, NULL);
+    if (can_play_with_seccomp()) {
+#ifdef SYS_fork
+        g_test_add_func("/softmmu/seccomp/sys-fork/on",
+                        test_seccomp_sys_fork_on);
+        g_test_add_func("/softmmu/seccomp/sys-fork/on-nospawn",
+                        test_seccomp_sys_fork_on_nospawn);
+        g_test_add_func("/softmmu/seccomp/sys-fork/off",
+                        test_seccomp_sys_fork_off);
+#endif
+
+        g_test_add_func("/softmmu/seccomp/fork/on",
+                        test_seccomp_fork_on);
+        g_test_add_func("/softmmu/seccomp/fork/on-nospawn",
+                        test_seccomp_fork_on_nospawn);
+        g_test_add_func("/softmmu/seccomp/fork/off",
+                        test_seccomp_fork_off);
+
+        g_test_add_func("/softmmu/seccomp/thread/on",
+                        test_seccomp_thread_on);
+        g_test_add_func("/softmmu/seccomp/thread/on-nospawn",
+                        test_seccomp_thread_on_nospawn);
+        g_test_add_func("/softmmu/seccomp/thread/off",
+                        test_seccomp_thread_off);
+
+        if (doit_sched() == 0) {
+            /*
+             * musl doesn't impl sched_setscheduler, hence
+             * we check above if it works first
+             */
+            g_test_add_func("/softmmu/seccomp/sched/on",
+                            test_seccomp_sched_on);
+            g_test_add_func("/softmmu/seccomp/sched/on-nores",
+                            test_seccomp_sched_on_nores);
+            g_test_add_func("/softmmu/seccomp/sched/off",
+                            test_seccomp_sched_off);
+        }
+    }
+    return g_test_run();
+}
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PULL 06/10] seccomp: fix blocking of process spawning
  2022-02-17 11:57 [PULL 00/10] Misc next patches Daniel P. Berrangé
                   ` (4 preceding siblings ...)
  2022-02-17 11:57 ` [PULL 05/10] seccomp: add unit test for seccomp filtering Daniel P. Berrangé
@ 2022-02-17 11:57 ` Daniel P. Berrangé
  2022-02-17 11:57 ` [PULL 07/10] seccomp: block use of clone3 syscall Daniel P. Berrangé
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 14+ messages in thread
From: Daniel P. Berrangé @ 2022-02-17 11:57 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Eduardo Otubo, Daniel P. Berrangé,
	qemu-block, Kashyap Chamarthy, Richard W.M. Jones,
	Philippe Mathieu-Daudé,
	Hanna Reitz

When '-sandbox on,spawn=deny' is given, we are supposed to block the
ability to spawn processes. We naively blocked the 'fork' syscall,
forgetting that any modern libc will use the 'clone' syscall instead.

We can't simply block the 'clone' syscall though, as that will break
thread creation. We thus list the set of flags used to create threads
and block anything that doesn't match this exactly.

Acked-by: Eduardo Otubo <otubo@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
 softmmu/qemu-seccomp.c    | 101 ++++++++++++++++++++++++++++++++++++++
 tests/unit/test-seccomp.c |   3 +-
 2 files changed, 102 insertions(+), 2 deletions(-)

diff --git a/softmmu/qemu-seccomp.c b/softmmu/qemu-seccomp.c
index 9f6df8d033..57139cc9ce 100644
--- a/softmmu/qemu-seccomp.c
+++ b/softmmu/qemu-seccomp.c
@@ -46,6 +46,82 @@ const struct scmp_arg_cmp sched_setscheduler_arg[] = {
     { .arg = 1, .op = SCMP_CMP_NE, .datum_a = SCHED_IDLE }
 };
 
+/*
+ * See 'NOTES' in 'man 2 clone' - s390 & cross have 'flags' in
+ *  different position to other architectures
+ */
+#if defined(HOST_S390X) || defined(HOST_S390) || defined(HOST_CRIS)
+#define CLONE_FLAGS_ARG 1
+#else
+#define CLONE_FLAGS_ARG 0
+#endif
+
+#ifndef CLONE_PIDFD
+# define CLONE_PIDFD 0x00001000
+#endif
+
+#define REQUIRE_CLONE_FLAG(flag) \
+    const struct scmp_arg_cmp clone_arg ## flag[] = { \
+    { .arg = CLONE_FLAGS_ARG, \
+      .op = SCMP_CMP_MASKED_EQ, \
+      .datum_a = flag, .datum_b = 0 } }
+
+#define FORBID_CLONE_FLAG(flag) \
+    const struct scmp_arg_cmp clone_arg ## flag[] = { \
+    { .arg = CLONE_FLAGS_ARG, \
+      .op = SCMP_CMP_MASKED_EQ, \
+      .datum_a = flag, .datum_b = flag } }
+
+#define RULE_CLONE_FLAG(flag) \
+    { SCMP_SYS(clone),                  QEMU_SECCOMP_SET_SPAWN, \
+      ARRAY_SIZE(clone_arg ## flag), clone_arg ## flag, SCMP_ACT_TRAP }
+
+/* If no CLONE_* flags are set, except CSIGNAL, deny */
+const struct scmp_arg_cmp clone_arg_none[] = {
+    { .arg = CLONE_FLAGS_ARG,
+      .op = SCMP_CMP_MASKED_EQ,
+      .datum_a = ~(CSIGNAL), .datum_b = 0 }
+};
+
+/*
+ * pthread_create should always set all of these.
+ */
+REQUIRE_CLONE_FLAG(CLONE_VM);
+REQUIRE_CLONE_FLAG(CLONE_FS);
+REQUIRE_CLONE_FLAG(CLONE_FILES);
+REQUIRE_CLONE_FLAG(CLONE_SIGHAND);
+REQUIRE_CLONE_FLAG(CLONE_THREAD);
+REQUIRE_CLONE_FLAG(CLONE_SYSVSEM);
+REQUIRE_CLONE_FLAG(CLONE_SETTLS);
+REQUIRE_CLONE_FLAG(CLONE_PARENT_SETTID);
+REQUIRE_CLONE_FLAG(CLONE_CHILD_CLEARTID);
+/*
+ * Musl sets this in pthread_create too, but it is
+ * obsolete and harmless since its behaviour is
+ * subsumed under CLONE_THREAD
+ */
+/*REQUIRE_CLONE_FLAG(CLONE_DETACHED);*/
+
+
+/*
+ * These all indicate an attempt to spawn a process
+ * instead of a thread, or other undesirable scenarios
+ */
+FORBID_CLONE_FLAG(CLONE_PIDFD);
+FORBID_CLONE_FLAG(CLONE_PTRACE);
+FORBID_CLONE_FLAG(CLONE_VFORK);
+FORBID_CLONE_FLAG(CLONE_PARENT);
+FORBID_CLONE_FLAG(CLONE_NEWNS);
+FORBID_CLONE_FLAG(CLONE_UNTRACED);
+FORBID_CLONE_FLAG(CLONE_NEWCGROUP);
+FORBID_CLONE_FLAG(CLONE_NEWUTS);
+FORBID_CLONE_FLAG(CLONE_NEWIPC);
+FORBID_CLONE_FLAG(CLONE_NEWUSER);
+FORBID_CLONE_FLAG(CLONE_NEWPID);
+FORBID_CLONE_FLAG(CLONE_NEWNET);
+FORBID_CLONE_FLAG(CLONE_IO);
+
+
 static const struct QemuSeccompSyscall denylist[] = {
     /* default set of syscalls that should get blocked */
     { SCMP_SYS(reboot),                 QEMU_SECCOMP_SET_DEFAULT,
@@ -143,6 +219,31 @@ static const struct QemuSeccompSyscall denylist[] = {
       0, NULL, SCMP_ACT_TRAP },
     { SCMP_SYS(execve),                 QEMU_SECCOMP_SET_SPAWN,
       0, NULL, SCMP_ACT_TRAP },
+    { SCMP_SYS(clone),                  QEMU_SECCOMP_SET_SPAWN,
+      ARRAY_SIZE(clone_arg_none), clone_arg_none, SCMP_ACT_TRAP },
+    RULE_CLONE_FLAG(CLONE_VM),
+    RULE_CLONE_FLAG(CLONE_FS),
+    RULE_CLONE_FLAG(CLONE_FILES),
+    RULE_CLONE_FLAG(CLONE_SIGHAND),
+    RULE_CLONE_FLAG(CLONE_THREAD),
+    RULE_CLONE_FLAG(CLONE_SYSVSEM),
+    RULE_CLONE_FLAG(CLONE_SETTLS),
+    RULE_CLONE_FLAG(CLONE_PARENT_SETTID),
+    RULE_CLONE_FLAG(CLONE_CHILD_CLEARTID),
+    /*RULE_CLONE_FLAG(CLONE_DETACHED),*/
+    RULE_CLONE_FLAG(CLONE_PIDFD),
+    RULE_CLONE_FLAG(CLONE_PTRACE),
+    RULE_CLONE_FLAG(CLONE_VFORK),
+    RULE_CLONE_FLAG(CLONE_PARENT),
+    RULE_CLONE_FLAG(CLONE_NEWNS),
+    RULE_CLONE_FLAG(CLONE_UNTRACED),
+    RULE_CLONE_FLAG(CLONE_NEWCGROUP),
+    RULE_CLONE_FLAG(CLONE_NEWUTS),
+    RULE_CLONE_FLAG(CLONE_NEWIPC),
+    RULE_CLONE_FLAG(CLONE_NEWUSER),
+    RULE_CLONE_FLAG(CLONE_NEWPID),
+    RULE_CLONE_FLAG(CLONE_NEWNET),
+    RULE_CLONE_FLAG(CLONE_IO),
     /* resource control */
     { SCMP_SYS(setpriority),            QEMU_SECCOMP_SET_RESOURCECTL,
       0, NULL, SCMP_ACT_ERRNO(EPERM) },
diff --git a/tests/unit/test-seccomp.c b/tests/unit/test-seccomp.c
index 10ab3e8fe5..3d7771e46c 100644
--- a/tests/unit/test-seccomp.c
+++ b/tests/unit/test-seccomp.c
@@ -126,8 +126,7 @@ static int doit_fork(void)
 
 static void test_seccomp_fork_on_nospawn(void)
 {
-    /* XXX fixme - should be killed */
-    test_seccomp_passed("on,spawn=deny", doit_fork);
+    test_seccomp_killed("on,spawn=deny", doit_fork);
 }
 
 static void test_seccomp_fork_on(void)
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PULL 07/10] seccomp: block use of clone3 syscall
  2022-02-17 11:57 [PULL 00/10] Misc next patches Daniel P. Berrangé
                   ` (5 preceding siblings ...)
  2022-02-17 11:57 ` [PULL 06/10] seccomp: fix blocking of process spawning Daniel P. Berrangé
@ 2022-02-17 11:57 ` Daniel P. Berrangé
  2022-02-17 11:57 ` [PULL 08/10] seccomp: block setns, unshare and execveat syscalls Daniel P. Berrangé
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 14+ messages in thread
From: Daniel P. Berrangé @ 2022-02-17 11:57 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Eduardo Otubo, Daniel P. Berrangé,
	qemu-block, Kashyap Chamarthy, Richard W.M. Jones,
	Philippe Mathieu-Daudé,
	Hanna Reitz

Modern glibc will use clone3 instead of clone, when it detects that it
is available. We need to compare flags in order to decide whether to
allow clone (thread create vs process fork), but in clone3 the flags
are hidden inside a struct. Seccomp can't currently match on data inside
a struct, so our only option is to block clone3 entirely. If we use
ENOSYS to block it, then glibc transparently falls back to clone.

This may need to be revisited if Linux adds a new architecture in
future and only provides clone3, without clone.

Acked-by: Eduardo Otubo <otubo@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
 softmmu/qemu-seccomp.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/softmmu/qemu-seccomp.c b/softmmu/qemu-seccomp.c
index 57139cc9ce..a7bb5c350f 100644
--- a/softmmu/qemu-seccomp.c
+++ b/softmmu/qemu-seccomp.c
@@ -244,6 +244,10 @@ static const struct QemuSeccompSyscall denylist[] = {
     RULE_CLONE_FLAG(CLONE_NEWPID),
     RULE_CLONE_FLAG(CLONE_NEWNET),
     RULE_CLONE_FLAG(CLONE_IO),
+#ifdef __SNR_clone3
+    { SCMP_SYS(clone3),                 QEMU_SECCOMP_SET_SPAWN,
+      0, NULL, SCMP_ACT_ERRNO(ENOSYS) },
+#endif
     /* resource control */
     { SCMP_SYS(setpriority),            QEMU_SECCOMP_SET_RESOURCECTL,
       0, NULL, SCMP_ACT_ERRNO(EPERM) },
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PULL 08/10] seccomp: block setns, unshare and execveat syscalls
  2022-02-17 11:57 [PULL 00/10] Misc next patches Daniel P. Berrangé
                   ` (6 preceding siblings ...)
  2022-02-17 11:57 ` [PULL 07/10] seccomp: block use of clone3 syscall Daniel P. Berrangé
@ 2022-02-17 11:57 ` Daniel P. Berrangé
  2022-02-17 11:57 ` [PULL 09/10] MAINTAINERS: take over seccomp from Eduardo Otubo Daniel P. Berrangé
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 14+ messages in thread
From: Daniel P. Berrangé @ 2022-02-17 11:57 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Eduardo Otubo, Daniel P. Berrangé,
	qemu-block, Kashyap Chamarthy, Richard W.M. Jones,
	Philippe Mathieu-Daudé,
	Hanna Reitz

setns/unshare are used to change namespaces which is not something QEMU
needs to be able todo.

execveat is a new variant of execve so should be blocked just like
execve already is.

Acked-by: Eduardo Otubo <otubo@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
 softmmu/qemu-seccomp.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/softmmu/qemu-seccomp.c b/softmmu/qemu-seccomp.c
index a7bb5c350f..deaf8a4ef5 100644
--- a/softmmu/qemu-seccomp.c
+++ b/softmmu/qemu-seccomp.c
@@ -248,6 +248,11 @@ static const struct QemuSeccompSyscall denylist[] = {
     { SCMP_SYS(clone3),                 QEMU_SECCOMP_SET_SPAWN,
       0, NULL, SCMP_ACT_ERRNO(ENOSYS) },
 #endif
+#ifdef __SNR_execveat
+    { SCMP_SYS(execveat),               QEMU_SECCOMP_SET_SPAWN },
+#endif
+    { SCMP_SYS(setns),                  QEMU_SECCOMP_SET_SPAWN },
+    { SCMP_SYS(unshare),                QEMU_SECCOMP_SET_SPAWN },
     /* resource control */
     { SCMP_SYS(setpriority),            QEMU_SECCOMP_SET_RESOURCECTL,
       0, NULL, SCMP_ACT_ERRNO(EPERM) },
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PULL 09/10] MAINTAINERS: take over seccomp from Eduardo Otubo
  2022-02-17 11:57 [PULL 00/10] Misc next patches Daniel P. Berrangé
                   ` (7 preceding siblings ...)
  2022-02-17 11:57 ` [PULL 08/10] seccomp: block setns, unshare and execveat syscalls Daniel P. Berrangé
@ 2022-02-17 11:57 ` Daniel P. Berrangé
  2022-02-17 11:57 ` [PULL 10/10] docs: expand firmware descriptor to allow flash without NVRAM Daniel P. Berrangé
  2022-02-18 20:05 ` [PULL 00/10] Misc next patches Peter Maydell
  10 siblings, 0 replies; 14+ messages in thread
From: Daniel P. Berrangé @ 2022-02-17 11:57 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Eduardo Otubo, Daniel P. Berrangé,
	qemu-block, Kashyap Chamarthy, Richard W.M. Jones,
	Philippe Mathieu-Daudé,
	Hanna Reitz

Eduardo has indicated that he no longer has time to be involved in
a QEMU maintainership role. As one of the more frequent contributors
of patches and design ideas to seccomp, I'll take over in an "Odd
Fixes" role.

Acked-by: Eduardo Otubo <otubo@redhat.com>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
 MAINTAINERS | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index 1fe647eb08..7f345e30eb 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2978,8 +2978,8 @@ F: docs/sphinx/fakedbusdoc.py
 F: tests/qtest/dbus*
 
 Seccomp
-M: Eduardo Otubo <otubo@redhat.com>
-S: Supported
+M: Daniel P. Berrange <berrange@redhat.com>
+S: Odd Fixes
 F: softmmu/qemu-seccomp.c
 F: include/sysemu/seccomp.h
 F: tests/unit/test-seccomp.c
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PULL 10/10] docs: expand firmware descriptor to allow flash without NVRAM
  2022-02-17 11:57 [PULL 00/10] Misc next patches Daniel P. Berrangé
                   ` (8 preceding siblings ...)
  2022-02-17 11:57 ` [PULL 09/10] MAINTAINERS: take over seccomp from Eduardo Otubo Daniel P. Berrangé
@ 2022-02-17 11:57 ` Daniel P. Berrangé
  2022-02-18 20:05 ` [PULL 00/10] Misc next patches Peter Maydell
  10 siblings, 0 replies; 14+ messages in thread
From: Daniel P. Berrangé @ 2022-02-17 11:57 UTC (permalink / raw)
  To: qemu-devel
  Cc: Kevin Wolf, Daniel P. Berrangé,
	qemu-block, Kashyap Chamarthy, Richard W.M. Jones,
	Philippe Mathieu-Daudé,
	Hanna Reitz

The current firmware descriptor schema for flash requires that both the
executable to NVRAM template paths be provided. This is fine for the
most common usage of EDK2 builds in virtualization where the separate
_CODE and _VARS files are provided.

With confidential computing technology like AMD SEV, persistent storage
of variables may be completely disabled because the firmware requires a
known clean state on every cold boot. There is no way to express this
in the firmware descriptor today.

Even with regular EDK2 builds it is possible to create a firmware that
has both executable code and variable persistence in a single file. This
hasn't been commonly used, since it would mean every guest bootup would
need to clone the full firmware file, leading to redundant duplicate
storage of the code portion. In some scenarios this may not matter and
might even be beneficial. For example if a public cloud allows users to
bring their own firmware, such that the user can pre-enroll their own
secure boot keys, you're going to have this copied on disk for each
tenant already. At this point the it can be simpler to just deal with
a single file rather than split builds. The firmware descriptor ought
to be able to express this combined firmware model too.

This all points towards expanding the schema for flash with a 'mode'
concept:

 - "split" - the current implicit behaviour with separate files
   for code and variables.

 - "combined" - the alternate behaviour where a single file contains
   both code and variables.

 - "stateless" - the confidential computing use case where storage
   of variables is completely disable, leaving only the code.

Reviewed-by: Kashyap Chamarthy <kchamart@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
Signed-off-by: Daniel P. Berrangé <berrange@redhat.com>
---
 docs/interop/firmware.json | 54 ++++++++++++++++++++++++++++++++------
 1 file changed, 46 insertions(+), 8 deletions(-)

diff --git a/docs/interop/firmware.json b/docs/interop/firmware.json
index 8d8b0be030..4e049b1c7c 100644
--- a/docs/interop/firmware.json
+++ b/docs/interop/firmware.json
@@ -210,24 +210,61 @@
   'data'   : { 'filename' : 'str',
                'format'   : 'BlockdevDriver' } }
 
+
+##
+# @FirmwareFlashType:
+#
+# Describes how the firmware build handles code versus variable
+# persistence.
+#
+# @split: the executable file contains code while the NVRAM
+#         template provides variable storage. The executable
+#         must be configured read-only and can be shared between
+#         multiple guests. The NVRAM template must be cloned
+#         for each new guest and configured read-write.
+#
+# @combined: the executable file contains both code and
+#            variable storage. The executable must be cloned
+#            for each new guest and configured read-write.
+#            No NVRAM template will be specified.
+#
+# @stateless: the executable file contains code and variable
+#             storage is not persisted. The executable must
+#             be configured read-only and can be shared
+#             between multiple guests. No NVRAM template
+#             will be specified.
+#
+# Since: 7.0.0
+##
+{ 'enum': 'FirmwareFlashMode',
+  'data': [ 'split', 'combined', 'stateless' ] }
+
 ##
 # @FirmwareMappingFlash:
 #
 # Describes loading and mapping properties for the firmware executable
 # and its accompanying NVRAM file, when @FirmwareDevice is @flash.
 #
-# @executable: Identifies the firmware executable. The firmware
-#              executable may be shared by multiple virtual machine
-#              definitions. The preferred corresponding QEMU command
-#              line options are
+# @mode: Describes how the firmware build handles code versus variable
+#        storage. If not present, it must be treated as if it was
+#        configured with value ``split``. Since: 7.0.0
+#
+# @executable: Identifies the firmware executable. The @mode
+#              indicates whether there will be an associated
+#              NVRAM template present. The preferred
+#              corresponding QEMU command line options are
 #                  -drive if=none,id=pflash0,readonly=on,file=@executable.@filename,format=@executable.@format
 #                  -machine pflash0=pflash0
-#              or equivalent -blockdev instead of -drive.
+#              or equivalent -blockdev instead of -drive. When
+#              @mode is ``combined`` the executable must be
+#              cloned before use and configured with readonly=off.
 #              With QEMU versions older than 4.0, you have to use
 #                  -drive if=pflash,unit=0,readonly=on,file=@executable.@filename,format=@executable.@format
 #
 # @nvram-template: Identifies the NVRAM template compatible with
-#                  @executable. Management software instantiates an
+#                  @executable, when @mode is set to ``split``,
+#                  otherwise it should not be present.
+#                  Management software instantiates an
 #                  individual copy -- a specific NVRAM file -- from
 #                  @nvram-template.@filename for each new virtual
 #                  machine definition created. @nvram-template.@filename
@@ -246,8 +283,9 @@
 # Since: 3.0
 ##
 { 'struct' : 'FirmwareMappingFlash',
-  'data'   : { 'executable'     : 'FirmwareFlashFile',
-               'nvram-template' : 'FirmwareFlashFile' } }
+  'data'   : { '*mode': 'FirmwareFlashMode',
+               'executable'     : 'FirmwareFlashFile',
+               '*nvram-template' : 'FirmwareFlashFile' } }
 
 ##
 # @FirmwareMappingKernel:
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [PULL 00/10] Misc next patches
  2022-02-17 11:57 [PULL 00/10] Misc next patches Daniel P. Berrangé
                   ` (9 preceding siblings ...)
  2022-02-17 11:57 ` [PULL 10/10] docs: expand firmware descriptor to allow flash without NVRAM Daniel P. Berrangé
@ 2022-02-18 20:05 ` Peter Maydell
  2022-02-21 19:17   ` Daniel P. Berrangé
  10 siblings, 1 reply; 14+ messages in thread
From: Peter Maydell @ 2022-02-18 20:05 UTC (permalink / raw)
  To: Daniel P. Berrangé
  Cc: Kevin Wolf, qemu-block, Kashyap Chamarthy, qemu-devel,
	Richard W.M. Jones, Philippe Mathieu-Daudé,
	Hanna Reitz

On Thu, 17 Feb 2022 at 12:01, Daniel P. Berrangé <berrange@redhat.com> wrote:
>
> The following changes since commit ad38520bdeb2b1e0b487db317f29119e94c1c88d:
>
>   Merge remote-tracking branch 'remotes/stefanha-gitlab/tags/block-pull-request' into staging (2022-02-15 19:30:33 +0000)
>
> are available in the Git repository at:
>
>   https://gitlab.com/berrange/qemu tags/misc-next-pull-request
>
> for you to fetch changes up to 2720ceda0521bc43139cfdf45e3e470559e11ce3:
>
>   docs: expand firmware descriptor to allow flash without NVRAM (2022-02-16 18:53:26 +0000)
>
> ----------------------------------------------------------------
> This misc series of changes:
>
>  - Improves documentation of SSH fingerprint checking
>  - Fixes SHA256 fingerprints with non-blockdev usage
>  - Blocks the clone3, setns, unshare & execveat syscalls
>    with seccomp
>  - Blocks process spawning via clone syscall, but allows
>    threads, with seccomp
>  - Takes over seccomp maintainer role
>  - Expands firmware descriptor spec to allow flash
>    without NVRAM

Hi; this series seems to cause the x64-freebsd-13-build to fail:
https://gitlab.com/qemu-project/qemu/-/jobs/2112237501

1/1 qemu:block / qemu-iotests qcow2 ERROR 155.99s exit status 1
▶ 469/707 /or1k/qmp/x-query-opcount OK
▶ 493/707 /ppc64/pnv-xscom/cfam_id/POWER8NVL OK
Summary of Failures:
1/1 qemu:block / qemu-iotests qcow2 ERROR 155.99s exit status 1
Ok: 0
Expected Fail: 0
Fail: 1
Unexpected Pass: 0
Skipped: 0
Timeout: 0
Full log written to /tmp/cirrus-ci-build/build/meson-logs/iotestslog.txt

This is an allowed-to-fail job, so I could in theory allow the
merge, but OTOH the job was passing previously and the failure
is block-related and this is a block-related pullreq...

thanks
-- PMM


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PULL 00/10] Misc next patches
  2022-02-18 20:05 ` [PULL 00/10] Misc next patches Peter Maydell
@ 2022-02-21 19:17   ` Daniel P. Berrangé
  2022-02-24 12:48     ` Peter Maydell
  0 siblings, 1 reply; 14+ messages in thread
From: Daniel P. Berrangé @ 2022-02-21 19:17 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Kevin Wolf, qemu-block, Kashyap Chamarthy, qemu-devel,
	Richard W.M. Jones, Philippe Mathieu-Daudé,
	Hanna Reitz

On Fri, Feb 18, 2022 at 08:05:12PM +0000, Peter Maydell wrote:
> On Thu, 17 Feb 2022 at 12:01, Daniel P. Berrangé <berrange@redhat.com> wrote:
> >
> > The following changes since commit ad38520bdeb2b1e0b487db317f29119e94c1c88d:
> >
> >   Merge remote-tracking branch 'remotes/stefanha-gitlab/tags/block-pull-request' into staging (2022-02-15 19:30:33 +0000)
> >
> > are available in the Git repository at:
> >
> >   https://gitlab.com/berrange/qemu tags/misc-next-pull-request
> >
> > for you to fetch changes up to 2720ceda0521bc43139cfdf45e3e470559e11ce3:
> >
> >   docs: expand firmware descriptor to allow flash without NVRAM (2022-02-16 18:53:26 +0000)
> >
> > ----------------------------------------------------------------
> > This misc series of changes:
> >
> >  - Improves documentation of SSH fingerprint checking
> >  - Fixes SHA256 fingerprints with non-blockdev usage
> >  - Blocks the clone3, setns, unshare & execveat syscalls
> >    with seccomp
> >  - Blocks process spawning via clone syscall, but allows
> >    threads, with seccomp
> >  - Takes over seccomp maintainer role
> >  - Expands firmware descriptor spec to allow flash
> >    without NVRAM
> 
> Hi; this series seems to cause the x64-freebsd-13-build to fail:
> https://gitlab.com/qemu-project/qemu/-/jobs/2112237501
> 
> 1/1 qemu:block / qemu-iotests qcow2 ERROR 155.99s exit status 1
> ▶ 469/707 /or1k/qmp/x-query-opcount OK
> ▶ 493/707 /ppc64/pnv-xscom/cfam_id/POWER8NVL OK
> Summary of Failures:
> 1/1 qemu:block / qemu-iotests qcow2 ERROR 155.99s exit status 1
> Ok: 0
> Expected Fail: 0
> Fail: 1
> Unexpected Pass: 0
> Skipped: 0
> Timeout: 0
> Full log written to /tmp/cirrus-ci-build/build/meson-logs/iotestslog.txt
> 
> This is an allowed-to-fail job, so I could in theory allow the
> merge, but OTOH the job was passing previously and the failure
> is block-related and this is a block-related pullreq...

AFAIK, the block jobs run in CI don't cover the SSH driver at all.

I had a CI pipeline before submitting, which covered Free BSD 13
which passed. To be sure I just rebased to git master and tried
another pipeline which passed too:

  https://gitlab.com/berrange/qemu/-/jobs/2119118096

so I'm thinking the failure you got is a transient. Could you retry
this PULL

With regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|



^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PULL 00/10] Misc next patches
  2022-02-21 19:17   ` Daniel P. Berrangé
@ 2022-02-24 12:48     ` Peter Maydell
  0 siblings, 0 replies; 14+ messages in thread
From: Peter Maydell @ 2022-02-24 12:48 UTC (permalink / raw)
  To: Daniel P. Berrangé
  Cc: Kevin Wolf, qemu-block, Kashyap Chamarthy, qemu-devel,
	Richard W.M. Jones, Philippe Mathieu-Daudé,
	Hanna Reitz

On Mon, 21 Feb 2022 at 19:18, Daniel P. Berrangé <berrange@redhat.com> wrote:
> AFAIK, the block jobs run in CI don't cover the SSH driver at all.
>
> I had a CI pipeline before submitting, which covered Free BSD 13
> which passed. To be sure I just rebased to git master and tried
> another pipeline which passed too:
>
>   https://gitlab.com/berrange/qemu/-/jobs/2119118096
>
> so I'm thinking the failure you got is a transient. Could you retry
> this PULL

Does seem to have been a transient. (We have way too many of those
at the moment for a variety of reasons.)


Applied, thanks.

Please update the changelog at https://wiki.qemu.org/ChangeLog/7.0
for any user-visible changes.

-- PMM


^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2022-02-24 12:55 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-02-17 11:57 [PULL 00/10] Misc next patches Daniel P. Berrangé
2022-02-17 11:57 ` [PULL 01/10] block: better document SSH host key fingerprint checking Daniel P. Berrangé
2022-02-17 11:57 ` [PULL 02/10] block: support sha256 fingerprint with pre-blockdev options Daniel P. Berrangé
2022-02-17 11:57 ` [PULL 03/10] block: print the server key type and fingerprint on failure Daniel P. Berrangé
2022-02-17 11:57 ` [PULL 04/10] seccomp: allow action to be customized per syscall Daniel P. Berrangé
2022-02-17 11:57 ` [PULL 05/10] seccomp: add unit test for seccomp filtering Daniel P. Berrangé
2022-02-17 11:57 ` [PULL 06/10] seccomp: fix blocking of process spawning Daniel P. Berrangé
2022-02-17 11:57 ` [PULL 07/10] seccomp: block use of clone3 syscall Daniel P. Berrangé
2022-02-17 11:57 ` [PULL 08/10] seccomp: block setns, unshare and execveat syscalls Daniel P. Berrangé
2022-02-17 11:57 ` [PULL 09/10] MAINTAINERS: take over seccomp from Eduardo Otubo Daniel P. Berrangé
2022-02-17 11:57 ` [PULL 10/10] docs: expand firmware descriptor to allow flash without NVRAM Daniel P. Berrangé
2022-02-18 20:05 ` [PULL 00/10] Misc next patches Peter Maydell
2022-02-21 19:17   ` Daniel P. Berrangé
2022-02-24 12:48     ` Peter Maydell

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.