All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH  00/19] vhost-user-rpmb (Replay Protected Memory Block)
@ 2020-09-25 12:51 ` Alex Bennée
  0 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2020-09-25 12:51 UTC (permalink / raw)
  To: qemu-devel, maxim.uvarov, joakim.bech, ilias.apalodimas,
	tomas.winkler, yang.huang, bing.zhu, Matti.Moell, hmo
  Cc: jean-philippe, takahiro.akashi, virtualization, Alex Bennée,
	arnd, stratos-dev

Hi,

This is an initial implementation of a vhost-user backend for the
VirtIO RPMB device. The device is currently in the draft of the next
VirtIO specification and describes block device which uses combination
of a key, nonce, hashing and a persistent write counter to prevent
replay attacks (hence Replay Protected Memory Block).

It is implemented as a vhost-user device because we want to experiment
in making portable backends that can be used with multiple
hypervisors. We also want to support backends isolated in their own
separate service VMs with limited memory cross-sections with the
principle guest. This is part of a wider initiative called project
Stratos for which you can find information here:

  https://collaborate.linaro.org/display/STR/Stratos

I mention this to explain the decision to duplicate some of the
utility functions (specifically iov and hmac handling) and write the
daemon as a fairly pure glib application that just depends on
libvhost-user. As it happens I ended up having to include libqemuutil
as libvhost-user requires qemu_memfd_alloc. Whether this is an
oversight for libvhost-user or it means we should split these daemons
into a separate repository is a discussion I would like to have with
the community. Now I have a working reference implementation I also
want to explore how easy it is to write a Rust version of the backend
which raises similar questions about where such a project should live.

The current Linux kernel doesn't support RPMB devices in the vanilla
tree so if you want to test you will need to look at my testing tree
which is based on Thomas Winkler's original patches although somewhat
cut down and pared back to just support the JDEC style frames of the
upstream spec and the simple chardev based userspace interface. You
can find my kernel testing tree here:

  https://git.linaro.org/people/alex.bennee/linux.git/log/?h=testing/virtio-rpmb   

The above branch includes a simple test script with the rpmb userspace
tool which I've used to exercise the various features. I'm unsure if
there will ever be a push to upstream support for RPMB to the kernel
as access to these sorts of devices are usually the preserve of
firmware living in the secure world. There is currently work underway
to support this device in uboot and I suspect eventually there will be
support for OPTEE as well.

Any review comments gratefully received as well as discussion about if
we should consider creating some new projects for housing these sort
of vhost-user backends. 

Alex Bennée (19):
  tools/virtiofsd: add support for --socket-group
  hw/block: add boilerplate for vhost-user-rpmb device
  hw/virtio: move virtio-pci.h into shared include space
  hw/block: add vhost-user-rpmb-pci boilerplate
  virtio-pci: add notification trace points
  tools/vhost-user-rpmb: add boilerplate and initial main
  tools/vhost-user-rpmb: implement --print-capabilities
  tools/vhost-user-rpmb: connect to fd and instantiate basic run loop
  tools/vhost-user-rpmb: add a --verbose/debug flags for logging
  tools/vhost-user-rpmb: handle shutdown and SIGINT/SIGHUP cleanly
  tools/vhost-user-rpmb: add --flash-path for backing store
  tools/vhost-user-rpmb: import hmac_sha256 functions
  tools/vhost-user-rpmb: implement the PROGRAM_KEY handshake
  tools/vhost-user-rpmb: implement VIRTIO_RPMB_REQ_GET_WRITE_COUNTER
  tools/vhost-user-rpmb: implement VIRTIO_RPMB_REQ_DATA_WRITE
  tools/vhost-user-rpmb: implement VIRTIO_RPMB_REQ_DATA_READ
  tools/vhost-user-rpmb: add key persistence
  tools/vhost-user-rpmb: allow setting of the write_count
  docs: add a man page for vhost-user-rpmb

 docs/tools/index.rst                       |   1 +
 docs/tools/vhost-user-rpmb.rst             | 102 +++
 docs/tools/virtiofsd.rst                   |   4 +
 include/hw/virtio/vhost-user-rpmb.h        |  46 ++
 {hw => include/hw}/virtio/virtio-pci.h     |   0
 tools/vhost-user-rpmb/hmac_sha256.h        |  87 ++
 tools/virtiofsd/fuse_i.h                   |   1 +
 hw/block/vhost-user-rpmb-pci.c             |  82 ++
 hw/block/vhost-user-rpmb.c                 | 333 ++++++++
 hw/virtio/vhost-scsi-pci.c                 |   2 +-
 hw/virtio/vhost-user-blk-pci.c             |   2 +-
 hw/virtio/vhost-user-fs-pci.c              |   2 +-
 hw/virtio/vhost-user-input-pci.c           |   2 +-
 hw/virtio/vhost-user-scsi-pci.c            |   2 +-
 hw/virtio/vhost-user-vsock-pci.c           |   2 +-
 hw/virtio/vhost-vsock-pci.c                |   2 +-
 hw/virtio/virtio-9p-pci.c                  |   2 +-
 hw/virtio/virtio-balloon-pci.c             |   2 +-
 hw/virtio/virtio-blk-pci.c                 |   2 +-
 hw/virtio/virtio-input-host-pci.c          |   2 +-
 hw/virtio/virtio-input-pci.c               |   2 +-
 hw/virtio/virtio-iommu-pci.c               |   2 +-
 hw/virtio/virtio-net-pci.c                 |   2 +-
 hw/virtio/virtio-pci.c                     |   5 +-
 hw/virtio/virtio-rng-pci.c                 |   2 +-
 hw/virtio/virtio-scsi-pci.c                |   2 +-
 hw/virtio/virtio-serial-pci.c              |   2 +-
 tools/vhost-user-rpmb/hmac_sha256.c        | 331 ++++++++
 tools/vhost-user-rpmb/main.c               | 880 +++++++++++++++++++++
 tools/virtiofsd/fuse_lowlevel.c            |   6 +
 tools/virtiofsd/fuse_virtio.c              |  20 +-
 MAINTAINERS                                |   5 +
 hw/block/Kconfig                           |   5 +
 hw/block/meson.build                       |   3 +
 hw/virtio/trace-events                     |   7 +-
 tools/meson.build                          |   8 +
 tools/vhost-user-rpmb/50-qemu-rpmb.json.in |   5 +
 tools/vhost-user-rpmb/meson.build          |  12 +
 38 files changed, 1956 insertions(+), 21 deletions(-)
 create mode 100644 docs/tools/vhost-user-rpmb.rst
 create mode 100644 include/hw/virtio/vhost-user-rpmb.h
 rename {hw => include/hw}/virtio/virtio-pci.h (100%)
 create mode 100644 tools/vhost-user-rpmb/hmac_sha256.h
 create mode 100644 hw/block/vhost-user-rpmb-pci.c
 create mode 100644 hw/block/vhost-user-rpmb.c
 create mode 100644 tools/vhost-user-rpmb/hmac_sha256.c
 create mode 100644 tools/vhost-user-rpmb/main.c
 create mode 100644 tools/vhost-user-rpmb/50-qemu-rpmb.json.in
 create mode 100644 tools/vhost-user-rpmb/meson.build

-- 
2.20.1



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

* [RFC PATCH  00/19] vhost-user-rpmb (Replay Protected Memory Block)
@ 2020-09-25 12:51 ` Alex Bennée
  0 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2020-09-25 12:51 UTC (permalink / raw)
  To: qemu-devel, maxim.uvarov, joakim.bech, ilias.apalodimas,
	tomas.winkler, yang.huang, bing.zhu, Matti.Moell, hmo
  Cc: jean-philippe, takahiro.akashi, virtualization, arnd, stratos-dev

Hi,

This is an initial implementation of a vhost-user backend for the
VirtIO RPMB device. The device is currently in the draft of the next
VirtIO specification and describes block device which uses combination
of a key, nonce, hashing and a persistent write counter to prevent
replay attacks (hence Replay Protected Memory Block).

It is implemented as a vhost-user device because we want to experiment
in making portable backends that can be used with multiple
hypervisors. We also want to support backends isolated in their own
separate service VMs with limited memory cross-sections with the
principle guest. This is part of a wider initiative called project
Stratos for which you can find information here:

  https://collaborate.linaro.org/display/STR/Stratos

I mention this to explain the decision to duplicate some of the
utility functions (specifically iov and hmac handling) and write the
daemon as a fairly pure glib application that just depends on
libvhost-user. As it happens I ended up having to include libqemuutil
as libvhost-user requires qemu_memfd_alloc. Whether this is an
oversight for libvhost-user or it means we should split these daemons
into a separate repository is a discussion I would like to have with
the community. Now I have a working reference implementation I also
want to explore how easy it is to write a Rust version of the backend
which raises similar questions about where such a project should live.

The current Linux kernel doesn't support RPMB devices in the vanilla
tree so if you want to test you will need to look at my testing tree
which is based on Thomas Winkler's original patches although somewhat
cut down and pared back to just support the JDEC style frames of the
upstream spec and the simple chardev based userspace interface. You
can find my kernel testing tree here:

  https://git.linaro.org/people/alex.bennee/linux.git/log/?h=testing/virtio-rpmb   

The above branch includes a simple test script with the rpmb userspace
tool which I've used to exercise the various features. I'm unsure if
there will ever be a push to upstream support for RPMB to the kernel
as access to these sorts of devices are usually the preserve of
firmware living in the secure world. There is currently work underway
to support this device in uboot and I suspect eventually there will be
support for OPTEE as well.

Any review comments gratefully received as well as discussion about if
we should consider creating some new projects for housing these sort
of vhost-user backends. 

Alex Bennée (19):
  tools/virtiofsd: add support for --socket-group
  hw/block: add boilerplate for vhost-user-rpmb device
  hw/virtio: move virtio-pci.h into shared include space
  hw/block: add vhost-user-rpmb-pci boilerplate
  virtio-pci: add notification trace points
  tools/vhost-user-rpmb: add boilerplate and initial main
  tools/vhost-user-rpmb: implement --print-capabilities
  tools/vhost-user-rpmb: connect to fd and instantiate basic run loop
  tools/vhost-user-rpmb: add a --verbose/debug flags for logging
  tools/vhost-user-rpmb: handle shutdown and SIGINT/SIGHUP cleanly
  tools/vhost-user-rpmb: add --flash-path for backing store
  tools/vhost-user-rpmb: import hmac_sha256 functions
  tools/vhost-user-rpmb: implement the PROGRAM_KEY handshake
  tools/vhost-user-rpmb: implement VIRTIO_RPMB_REQ_GET_WRITE_COUNTER
  tools/vhost-user-rpmb: implement VIRTIO_RPMB_REQ_DATA_WRITE
  tools/vhost-user-rpmb: implement VIRTIO_RPMB_REQ_DATA_READ
  tools/vhost-user-rpmb: add key persistence
  tools/vhost-user-rpmb: allow setting of the write_count
  docs: add a man page for vhost-user-rpmb

 docs/tools/index.rst                       |   1 +
 docs/tools/vhost-user-rpmb.rst             | 102 +++
 docs/tools/virtiofsd.rst                   |   4 +
 include/hw/virtio/vhost-user-rpmb.h        |  46 ++
 {hw => include/hw}/virtio/virtio-pci.h     |   0
 tools/vhost-user-rpmb/hmac_sha256.h        |  87 ++
 tools/virtiofsd/fuse_i.h                   |   1 +
 hw/block/vhost-user-rpmb-pci.c             |  82 ++
 hw/block/vhost-user-rpmb.c                 | 333 ++++++++
 hw/virtio/vhost-scsi-pci.c                 |   2 +-
 hw/virtio/vhost-user-blk-pci.c             |   2 +-
 hw/virtio/vhost-user-fs-pci.c              |   2 +-
 hw/virtio/vhost-user-input-pci.c           |   2 +-
 hw/virtio/vhost-user-scsi-pci.c            |   2 +-
 hw/virtio/vhost-user-vsock-pci.c           |   2 +-
 hw/virtio/vhost-vsock-pci.c                |   2 +-
 hw/virtio/virtio-9p-pci.c                  |   2 +-
 hw/virtio/virtio-balloon-pci.c             |   2 +-
 hw/virtio/virtio-blk-pci.c                 |   2 +-
 hw/virtio/virtio-input-host-pci.c          |   2 +-
 hw/virtio/virtio-input-pci.c               |   2 +-
 hw/virtio/virtio-iommu-pci.c               |   2 +-
 hw/virtio/virtio-net-pci.c                 |   2 +-
 hw/virtio/virtio-pci.c                     |   5 +-
 hw/virtio/virtio-rng-pci.c                 |   2 +-
 hw/virtio/virtio-scsi-pci.c                |   2 +-
 hw/virtio/virtio-serial-pci.c              |   2 +-
 tools/vhost-user-rpmb/hmac_sha256.c        | 331 ++++++++
 tools/vhost-user-rpmb/main.c               | 880 +++++++++++++++++++++
 tools/virtiofsd/fuse_lowlevel.c            |   6 +
 tools/virtiofsd/fuse_virtio.c              |  20 +-
 MAINTAINERS                                |   5 +
 hw/block/Kconfig                           |   5 +
 hw/block/meson.build                       |   3 +
 hw/virtio/trace-events                     |   7 +-
 tools/meson.build                          |   8 +
 tools/vhost-user-rpmb/50-qemu-rpmb.json.in |   5 +
 tools/vhost-user-rpmb/meson.build          |  12 +
 38 files changed, 1956 insertions(+), 21 deletions(-)
 create mode 100644 docs/tools/vhost-user-rpmb.rst
 create mode 100644 include/hw/virtio/vhost-user-rpmb.h
 rename {hw => include/hw}/virtio/virtio-pci.h (100%)
 create mode 100644 tools/vhost-user-rpmb/hmac_sha256.h
 create mode 100644 hw/block/vhost-user-rpmb-pci.c
 create mode 100644 hw/block/vhost-user-rpmb.c
 create mode 100644 tools/vhost-user-rpmb/hmac_sha256.c
 create mode 100644 tools/vhost-user-rpmb/main.c
 create mode 100644 tools/vhost-user-rpmb/50-qemu-rpmb.json.in
 create mode 100644 tools/vhost-user-rpmb/meson.build

-- 
2.20.1

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

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

* [RFC PATCH  01/19] tools/virtiofsd: add support for --socket-group
  2020-09-25 12:51 ` Alex Bennée
@ 2020-09-25 12:51   ` Alex Bennée
  -1 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2020-09-25 12:51 UTC (permalink / raw)
  To: qemu-devel, maxim.uvarov, joakim.bech, ilias.apalodimas,
	tomas.winkler, yang.huang, bing.zhu, Matti.Moell, hmo
  Cc: jean-philippe, Dr. David Alan Gilbert, takahiro.akashi,
	Stefan Hajnoczi, virtualization, Alex Bennée, arnd,
	stratos-dev

If you like running QEMU as a normal user (very common for TCG runs)
but you have to run virtiofsd as a root user you run into connection
problems. Adding support for an optional --socket-group allows the
users to keep using the command line.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>

---
v1
  - tweak documentation and commentary
---
 docs/tools/virtiofsd.rst        |  4 ++++
 tools/virtiofsd/fuse_i.h        |  1 +
 tools/virtiofsd/fuse_lowlevel.c |  6 ++++++
 tools/virtiofsd/fuse_virtio.c   | 20 ++++++++++++++++++--
 4 files changed, 29 insertions(+), 2 deletions(-)

diff --git a/docs/tools/virtiofsd.rst b/docs/tools/virtiofsd.rst
index e33c81ed41f1..085f9b12a6a3 100644
--- a/docs/tools/virtiofsd.rst
+++ b/docs/tools/virtiofsd.rst
@@ -87,6 +87,10 @@ Options
 
   Listen on vhost-user UNIX domain socket at PATH.
 
+.. option:: --socket-group=GROUP
+
+  Set the vhost-user UNIX domain socket gid to GROUP.
+
 .. option:: --fd=FDNUM
 
   Accept connections from vhost-user UNIX domain socket file descriptor FDNUM.
diff --git a/tools/virtiofsd/fuse_i.h b/tools/virtiofsd/fuse_i.h
index 1240828208ab..492e002181e2 100644
--- a/tools/virtiofsd/fuse_i.h
+++ b/tools/virtiofsd/fuse_i.h
@@ -68,6 +68,7 @@ struct fuse_session {
     size_t bufsize;
     int error;
     char *vu_socket_path;
+    char *vu_socket_group;
     int   vu_listen_fd;
     int   vu_socketfd;
     struct fv_VuDev *virtio_dev;
diff --git a/tools/virtiofsd/fuse_lowlevel.c b/tools/virtiofsd/fuse_lowlevel.c
index 2dd36ec03b6e..4d1ba2925d1b 100644
--- a/tools/virtiofsd/fuse_lowlevel.c
+++ b/tools/virtiofsd/fuse_lowlevel.c
@@ -2523,6 +2523,7 @@ static const struct fuse_opt fuse_ll_opts[] = {
     LL_OPTION("--debug", debug, 1),
     LL_OPTION("allow_root", deny_others, 1),
     LL_OPTION("--socket-path=%s", vu_socket_path, 0),
+    LL_OPTION("--socket-group=%s", vu_socket_group, 0),
     LL_OPTION("--fd=%d", vu_listen_fd, 0),
     LL_OPTION("--thread-pool-size=%d", thread_pool_size, 0),
     FUSE_OPT_END
@@ -2630,6 +2631,11 @@ struct fuse_session *fuse_session_new(struct fuse_args *args,
                  "fuse: --socket-path and --fd cannot be given together\n");
         goto out4;
     }
+    if (se->vu_socket_group && !se->vu_socket_path) {
+        fuse_log(FUSE_LOG_ERR,
+                 "fuse: --socket-group can only be used with --socket-path\n");
+        goto out4;
+    }
 
     se->bufsize = FUSE_MAX_MAX_PAGES * getpagesize() + FUSE_BUFFER_HEADER_SIZE;
 
diff --git a/tools/virtiofsd/fuse_virtio.c b/tools/virtiofsd/fuse_virtio.c
index 9e5537506c16..7942d3d11a87 100644
--- a/tools/virtiofsd/fuse_virtio.c
+++ b/tools/virtiofsd/fuse_virtio.c
@@ -31,6 +31,8 @@
 #include <sys/socket.h>
 #include <sys/types.h>
 #include <sys/un.h>
+#include <sys/types.h>
+#include <grp.h>
 #include <unistd.h>
 
 #include "contrib/libvhost-user/libvhost-user.h"
@@ -924,15 +926,29 @@ static int fv_create_listen_socket(struct fuse_session *se)
 
     /*
      * Unfortunately bind doesn't let you set the mask on the socket,
-     * so set umask to 077 and restore it later.
+     * so set umask appropriately and restore it later.
      */
-    old_umask = umask(0077);
+    if (se->vu_socket_group) {
+        old_umask = umask(S_IROTH | S_IWOTH | S_IXOTH);
+    } else {
+        old_umask = umask(S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH);
+    }
     if (bind(listen_sock, (struct sockaddr *)&un, addr_len) == -1) {
         fuse_log(FUSE_LOG_ERR, "vhost socket bind: %m\n");
         close(listen_sock);
         umask(old_umask);
         return -1;
     }
+    if (se->vu_socket_group) {
+        struct group *g = getgrnam(se->vu_socket_group);
+        if (g) {
+            if (!chown(se->vu_socket_path, -1, g->gr_gid)) {
+                fuse_log(FUSE_LOG_WARNING,
+                         "vhost socket failed to set group to %s (%d)\n",
+                         se->vu_socket_group, g->gr_gid);
+            }
+        }
+    }
     umask(old_umask);
 
     if (listen(listen_sock, 1) == -1) {
-- 
2.20.1



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

* [RFC PATCH  01/19] tools/virtiofsd: add support for --socket-group
@ 2020-09-25 12:51   ` Alex Bennée
  0 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2020-09-25 12:51 UTC (permalink / raw)
  To: qemu-devel, maxim.uvarov, joakim.bech, ilias.apalodimas,
	tomas.winkler, yang.huang, bing.zhu, Matti.Moell, hmo
  Cc: jean-philippe, Dr. David Alan Gilbert, takahiro.akashi,
	Stefan Hajnoczi, virtualization, arnd, stratos-dev

If you like running QEMU as a normal user (very common for TCG runs)
but you have to run virtiofsd as a root user you run into connection
problems. Adding support for an optional --socket-group allows the
users to keep using the command line.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>

---
v1
  - tweak documentation and commentary
---
 docs/tools/virtiofsd.rst        |  4 ++++
 tools/virtiofsd/fuse_i.h        |  1 +
 tools/virtiofsd/fuse_lowlevel.c |  6 ++++++
 tools/virtiofsd/fuse_virtio.c   | 20 ++++++++++++++++++--
 4 files changed, 29 insertions(+), 2 deletions(-)

diff --git a/docs/tools/virtiofsd.rst b/docs/tools/virtiofsd.rst
index e33c81ed41f1..085f9b12a6a3 100644
--- a/docs/tools/virtiofsd.rst
+++ b/docs/tools/virtiofsd.rst
@@ -87,6 +87,10 @@ Options
 
   Listen on vhost-user UNIX domain socket at PATH.
 
+.. option:: --socket-group=GROUP
+
+  Set the vhost-user UNIX domain socket gid to GROUP.
+
 .. option:: --fd=FDNUM
 
   Accept connections from vhost-user UNIX domain socket file descriptor FDNUM.
diff --git a/tools/virtiofsd/fuse_i.h b/tools/virtiofsd/fuse_i.h
index 1240828208ab..492e002181e2 100644
--- a/tools/virtiofsd/fuse_i.h
+++ b/tools/virtiofsd/fuse_i.h
@@ -68,6 +68,7 @@ struct fuse_session {
     size_t bufsize;
     int error;
     char *vu_socket_path;
+    char *vu_socket_group;
     int   vu_listen_fd;
     int   vu_socketfd;
     struct fv_VuDev *virtio_dev;
diff --git a/tools/virtiofsd/fuse_lowlevel.c b/tools/virtiofsd/fuse_lowlevel.c
index 2dd36ec03b6e..4d1ba2925d1b 100644
--- a/tools/virtiofsd/fuse_lowlevel.c
+++ b/tools/virtiofsd/fuse_lowlevel.c
@@ -2523,6 +2523,7 @@ static const struct fuse_opt fuse_ll_opts[] = {
     LL_OPTION("--debug", debug, 1),
     LL_OPTION("allow_root", deny_others, 1),
     LL_OPTION("--socket-path=%s", vu_socket_path, 0),
+    LL_OPTION("--socket-group=%s", vu_socket_group, 0),
     LL_OPTION("--fd=%d", vu_listen_fd, 0),
     LL_OPTION("--thread-pool-size=%d", thread_pool_size, 0),
     FUSE_OPT_END
@@ -2630,6 +2631,11 @@ struct fuse_session *fuse_session_new(struct fuse_args *args,
                  "fuse: --socket-path and --fd cannot be given together\n");
         goto out4;
     }
+    if (se->vu_socket_group && !se->vu_socket_path) {
+        fuse_log(FUSE_LOG_ERR,
+                 "fuse: --socket-group can only be used with --socket-path\n");
+        goto out4;
+    }
 
     se->bufsize = FUSE_MAX_MAX_PAGES * getpagesize() + FUSE_BUFFER_HEADER_SIZE;
 
diff --git a/tools/virtiofsd/fuse_virtio.c b/tools/virtiofsd/fuse_virtio.c
index 9e5537506c16..7942d3d11a87 100644
--- a/tools/virtiofsd/fuse_virtio.c
+++ b/tools/virtiofsd/fuse_virtio.c
@@ -31,6 +31,8 @@
 #include <sys/socket.h>
 #include <sys/types.h>
 #include <sys/un.h>
+#include <sys/types.h>
+#include <grp.h>
 #include <unistd.h>
 
 #include "contrib/libvhost-user/libvhost-user.h"
@@ -924,15 +926,29 @@ static int fv_create_listen_socket(struct fuse_session *se)
 
     /*
      * Unfortunately bind doesn't let you set the mask on the socket,
-     * so set umask to 077 and restore it later.
+     * so set umask appropriately and restore it later.
      */
-    old_umask = umask(0077);
+    if (se->vu_socket_group) {
+        old_umask = umask(S_IROTH | S_IWOTH | S_IXOTH);
+    } else {
+        old_umask = umask(S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH);
+    }
     if (bind(listen_sock, (struct sockaddr *)&un, addr_len) == -1) {
         fuse_log(FUSE_LOG_ERR, "vhost socket bind: %m\n");
         close(listen_sock);
         umask(old_umask);
         return -1;
     }
+    if (se->vu_socket_group) {
+        struct group *g = getgrnam(se->vu_socket_group);
+        if (g) {
+            if (!chown(se->vu_socket_path, -1, g->gr_gid)) {
+                fuse_log(FUSE_LOG_WARNING,
+                         "vhost socket failed to set group to %s (%d)\n",
+                         se->vu_socket_group, g->gr_gid);
+            }
+        }
+    }
     umask(old_umask);
 
     if (listen(listen_sock, 1) == -1) {
-- 
2.20.1

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

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

* [RFC PATCH 02/19] hw/block: add boilerplate for vhost-user-rpmb device
  2020-09-25 12:51 ` Alex Bennée
@ 2020-09-25 12:51   ` Alex Bennée
  -1 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2020-09-25 12:51 UTC (permalink / raw)
  To: qemu-devel, maxim.uvarov, joakim.bech, ilias.apalodimas,
	tomas.winkler, yang.huang, bing.zhu, Matti.Moell, hmo
  Cc: Kevin Wolf, jean-philippe, open list:Block layer core,
	Michael S. Tsirkin, Max Reitz, takahiro.akashi, virtualization,
	Alex Bennée, arnd, stratos-dev

This creates the QEMU side of the vhost-user-rpmb device which
connects to the remote daemon. It is based of the reasonably modern
vhost-user-fs code with bits from vhost-user-blk as we want the
virtio-config itself to be sourced from the daemon.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 include/hw/virtio/vhost-user-rpmb.h |  46 ++++
 hw/block/vhost-user-rpmb.c          | 333 ++++++++++++++++++++++++++++
 hw/block/Kconfig                    |   5 +
 hw/block/meson.build                |   1 +
 4 files changed, 385 insertions(+)
 create mode 100644 include/hw/virtio/vhost-user-rpmb.h
 create mode 100644 hw/block/vhost-user-rpmb.c

diff --git a/include/hw/virtio/vhost-user-rpmb.h b/include/hw/virtio/vhost-user-rpmb.h
new file mode 100644
index 000000000000..7e5988127dc2
--- /dev/null
+++ b/include/hw/virtio/vhost-user-rpmb.h
@@ -0,0 +1,46 @@
+/*
+ * vhost-user-rpmb virtio device
+ *
+ * Copyright (c) 2020 Linaro Ltd
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef _VHOST_USER_RPMB_H_
+#define _VHOST_USER_RPMB_H_
+
+#include "hw/virtio/virtio.h"
+#include "hw/virtio/vhost.h"
+#include "hw/virtio/vhost-user.h"
+#include "chardev/char-fe.h"
+
+#define TYPE_VHOST_USER_RPMB "vhost-user-rpmb-device"
+#define VHOST_USER_RPMB(obj) \
+        OBJECT_CHECK(VHostUserRPMB, (obj), TYPE_VHOST_USER_RPMB)
+
+/* This is defined in the VIRTIO spec */
+struct virtio_rpmb_config {
+    uint8_t capacity;
+    uint8_t max_wr_cnt;
+    uint8_t max_rd_cnt;
+};
+
+typedef struct {
+    CharBackend chardev;
+    struct virtio_rpmb_config config;
+} VHostUserRPMBConf;
+
+typedef struct {
+    /*< private >*/
+    VirtIODevice parent;
+    VHostUserRPMBConf conf;
+    struct vhost_virtqueue *vhost_vq;
+    struct vhost_dev vhost_dev;
+    VhostUserState vhost_user;
+    VirtQueue *req_vq;
+    bool connected;
+    /*< public >*/
+} VHostUserRPMB;
+
+
+#endif /* _VHOST_USER_RPMB_H_ */
diff --git a/hw/block/vhost-user-rpmb.c b/hw/block/vhost-user-rpmb.c
new file mode 100644
index 000000000000..de243e7a53a0
--- /dev/null
+++ b/hw/block/vhost-user-rpmb.c
@@ -0,0 +1,333 @@
+/*
+ * Vhost-user RPMB virtio device
+ *
+ * This is the boilerplate for instantiating a vhost-user device
+ * implementing a Replay Protected Memory Block (RPMB) device. This is
+ * a type of flash chip that is protected from replay attacks and used
+ * for tamper resistant storage. The actual back-end for this driver
+ * is the vhost-user-rpmb daemon. The code here just connects up the
+ * device in QEMU and allows it to be instantiated.
+ *
+ * Copyright (c) 2020 Linaro Ltd
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/qdev-properties.h"
+#include "hw/virtio/virtio-bus.h"
+#include "hw/virtio/vhost-user-rpmb.h"
+#include "qemu/error-report.h"
+
+/* currently there is no RPMB driver in Linux */
+#define VIRTIO_ID_RPMB         28 /* virtio RPMB */
+
+static void vurpmb_get_config(VirtIODevice *vdev, uint8_t *config)
+{
+    /* this somehow needs to come from the vhost-user daemon */
+}
+
+static void vurpmb_start(VirtIODevice *vdev)
+{
+    VHostUserRPMB *rpmb = VHOST_USER_RPMB(vdev);
+    BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
+    VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
+    int ret;
+    int i;
+
+    if (!k->set_guest_notifiers) {
+        error_report("binding does not support guest notifiers");
+        return;
+    }
+
+    ret = vhost_dev_enable_notifiers(&rpmb->vhost_dev, vdev);
+    if (ret < 0) {
+        error_report("Error enabling host notifiers: %d", -ret);
+        return;
+    }
+
+    ret = k->set_guest_notifiers(qbus->parent, rpmb->vhost_dev.nvqs, true);
+    if (ret < 0) {
+        error_report("Error binding guest notifier: %d", -ret);
+        goto err_host_notifiers;
+    }
+
+    rpmb->vhost_dev.acked_features = vdev->guest_features;
+    ret = vhost_dev_start(&rpmb->vhost_dev, vdev);
+    if (ret < 0) {
+        error_report("Error starting vhost-user-rpmb: %d", -ret);
+        goto err_guest_notifiers;
+    }
+
+    /*
+     * guest_notifier_mask/pending not used yet, so just unmask
+     * everything here.  virtio-pci will do the right thing by
+     * enabling/disabling irqfd.
+     */
+    for (i = 0; i < rpmb->vhost_dev.nvqs; i++) {
+        vhost_virtqueue_mask(&rpmb->vhost_dev, vdev, i, false);
+    }
+
+    return;
+
+err_guest_notifiers:
+    k->set_guest_notifiers(qbus->parent, rpmb->vhost_dev.nvqs, false);
+err_host_notifiers:
+    vhost_dev_disable_notifiers(&rpmb->vhost_dev, vdev);
+}
+
+static void vurpmb_stop(VirtIODevice *vdev)
+{
+    VHostUserRPMB *rpmb = VHOST_USER_RPMB(vdev);
+    BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
+    VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
+    int ret;
+
+    if (!k->set_guest_notifiers) {
+        return;
+    }
+
+    vhost_dev_stop(&rpmb->vhost_dev, vdev);
+
+    ret = k->set_guest_notifiers(qbus->parent, rpmb->vhost_dev.nvqs, false);
+    if (ret < 0) {
+        error_report("vhost guest notifier cleanup failed: %d", ret);
+        return;
+    }
+
+    vhost_dev_disable_notifiers(&rpmb->vhost_dev, vdev);
+}
+
+static void vurpmb_set_status(VirtIODevice *vdev, uint8_t status)
+{
+    VHostUserRPMB *rpmb = VHOST_USER_RPMB(vdev);
+    bool should_start = status & VIRTIO_CONFIG_S_DRIVER_OK;
+
+    if (!vdev->vm_running) {
+        should_start = false;
+    }
+
+    if (rpmb->vhost_dev.started == should_start) {
+        return;
+    }
+
+    if (should_start) {
+        vurpmb_start(vdev);
+    } else {
+        vurpmb_stop(vdev);
+    }
+}
+
+static uint64_t vurpmb_get_features(VirtIODevice *vdev,
+                                      uint64_t requested_features,
+                                      Error **errp)
+{
+    /* No feature bits used yet */
+    return requested_features;
+}
+
+static void vurpmb_handle_output(VirtIODevice *vdev, VirtQueue *vq)
+{
+    /*
+     * Not normally called; it's the daemon that handles the queue;
+     * however virtio's cleanup path can call this.
+     */
+}
+
+static void vurpmb_guest_notifier_mask(VirtIODevice *vdev, int idx,
+                                            bool mask)
+{
+    VHostUserRPMB *rpmb = VHOST_USER_RPMB(vdev);
+    vhost_virtqueue_mask(&rpmb->vhost_dev, vdev, idx, mask);
+}
+
+static bool vurpmb_guest_notifier_pending(VirtIODevice *vdev, int idx)
+{
+    VHostUserRPMB *rpmb = VHOST_USER_RPMB(vdev);
+    return vhost_virtqueue_pending(&rpmb->vhost_dev, idx);
+}
+
+/*
+ * Chardev connect/disconnect events
+ */
+
+static int vurpmb_handle_config_change(struct vhost_dev *dev)
+{
+    int ret;
+    VHostUserRPMB *rpmb = VHOST_USER_RPMB(dev->vdev);
+
+    ret = vhost_dev_get_config(dev, (uint8_t *)&rpmb->conf.config,
+                               sizeof(struct virtio_rpmb_config));
+    if (ret < 0) {
+        error_report("get config space failed");
+        return -1;
+    }
+
+    return 0;
+}
+
+const VhostDevConfigOps rpmb_ops = {
+    .vhost_dev_config_notifier = vurpmb_handle_config_change,
+};
+
+static int vurpmb_connect(DeviceState *dev)
+{
+    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+    VHostUserRPMB *rpmb = VHOST_USER_RPMB(vdev);
+
+    if (rpmb->connected) {
+        return 0;
+    }
+    rpmb->connected = true;
+
+    /* restore vhost state */
+    if (virtio_device_started(vdev, vdev->status)) {
+        vurpmb_start(vdev);
+    }
+
+    return 0;
+}
+
+static void vurpmb_disconnect(DeviceState *dev)
+{
+    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+    VHostUserRPMB *rpmb = VHOST_USER_RPMB(vdev);
+
+    if (!rpmb->connected) {
+        return;
+    }
+    rpmb->connected = false;
+
+    if (rpmb->vhost_dev.started) {
+        vurpmb_stop(vdev);
+    }
+
+    vhost_dev_cleanup(&rpmb->vhost_dev);
+}
+
+static void vurpmb_event(void *opaque, QEMUChrEvent event)
+{
+    DeviceState *dev = opaque;
+    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+    VHostUserRPMB *rpmb = VHOST_USER_RPMB(vdev);
+
+    switch (event) {
+    case CHR_EVENT_OPENED:
+        if (vurpmb_connect(dev) < 0) {
+            qemu_chr_fe_disconnect(&rpmb->conf.chardev);
+            return;
+        }
+        break;
+    case CHR_EVENT_CLOSED:
+        vurpmb_disconnect(dev);
+        break;
+    case CHR_EVENT_BREAK:
+    case CHR_EVENT_MUX_IN:
+    case CHR_EVENT_MUX_OUT:
+        /* Ignore */
+        break;
+    }
+}
+
+static void do_vhost_user_cleanup(VirtIODevice *vdev, VHostUserRPMB *rpmb)
+{
+    vhost_user_cleanup(&rpmb->vhost_user);
+    virtio_delete_queue(rpmb->req_vq);
+    virtio_cleanup(vdev);
+    g_free(rpmb->vhost_dev.vqs);
+    rpmb->vhost_dev.vqs = NULL;
+}
+
+
+static void vurpmb_device_realize(DeviceState *dev, Error **errp)
+{
+    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+    VHostUserRPMB *rpmb = VHOST_USER_RPMB(dev);
+    int ret;
+
+    if (!rpmb->conf.chardev.chr) {
+        error_setg(errp, "missing chardev");
+        return;
+    }
+
+    if (!vhost_user_init(&rpmb->vhost_user, &rpmb->conf.chardev, errp)) {
+        return;
+    }
+
+    virtio_init(vdev, "vhost-user-rpmb", VIRTIO_ID_RPMB,
+                sizeof(struct virtio_rpmb_config));
+
+    /* One request queue, 4 elements in case we don't do indirect */
+    rpmb->req_vq = virtio_add_queue(vdev, 4, vurpmb_handle_output);
+    rpmb->vhost_dev.nvqs = 1;
+    rpmb->vhost_dev.vqs = g_new0(struct vhost_virtqueue, rpmb->vhost_dev.nvqs);
+    ret = vhost_dev_init(&rpmb->vhost_dev, &rpmb->vhost_user,
+                         VHOST_BACKEND_TYPE_USER, 0);
+    if (ret < 0) {
+        error_setg_errno(errp, -ret, "vhost_dev_init failed");
+        do_vhost_user_cleanup(vdev, rpmb);
+    }
+
+    /*
+     * At this point the next event we will get is a connection from
+     * the daemon on the control socket.
+     */
+
+    qemu_chr_fe_set_handlers(&rpmb->conf.chardev,  NULL, NULL, vurpmb_event,
+                             NULL, (void *)dev, NULL, true);
+
+    return;
+}
+
+static void vurpmb_device_unrealize(DeviceState *dev)
+{
+    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+    VHostUserRPMB *rpmb = VHOST_USER_RPMB(dev);
+
+    /* This will stop vhost backend if appropriate. */
+    vurpmb_set_status(vdev, 0);
+
+    do_vhost_user_cleanup(vdev, rpmb);
+}
+
+static const VMStateDescription vurpmb_vmstate = {
+    .name = "vhost-user-rpmb",
+    .unmigratable = 1,
+};
+
+static Property vurpmb_properties[] = {
+    DEFINE_PROP_CHR("chardev", VHostUserRPMB, conf.chardev),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void vurpmb_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
+
+    device_class_set_props(dc, vurpmb_properties);
+    dc->vmsd = &vurpmb_vmstate;
+    set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
+    vdc->realize = vurpmb_device_realize;
+    vdc->unrealize = vurpmb_device_unrealize;
+    vdc->get_features = vurpmb_get_features;
+    vdc->get_config = vurpmb_get_config;
+    vdc->set_status = vurpmb_set_status;
+    vdc->guest_notifier_mask = vurpmb_guest_notifier_mask;
+    vdc->guest_notifier_pending = vurpmb_guest_notifier_pending;
+}
+
+static const TypeInfo vurpmb_info = {
+    .name = TYPE_VHOST_USER_RPMB,
+    .parent = TYPE_VIRTIO_DEVICE,
+    .instance_size = sizeof(VHostUserRPMB),
+    .class_init = vurpmb_class_init,
+};
+
+static void vurpmb_register_types(void)
+{
+    type_register_static(&vurpmb_info);
+}
+
+type_init(vurpmb_register_types)
diff --git a/hw/block/Kconfig b/hw/block/Kconfig
index 2d17f481adc6..12e21870847a 100644
--- a/hw/block/Kconfig
+++ b/hw/block/Kconfig
@@ -38,5 +38,10 @@ config VHOST_USER_BLK
     default y if VIRTIO_PCI
     depends on VIRTIO && VHOST_USER && LINUX
 
+config VHOST_USER_RPMB
+    bool
+    default y
+    depends on VIRTIO && VHOST_USER
+
 config SWIM
     bool
diff --git a/hw/block/meson.build b/hw/block/meson.build
index 78cad8f7cba1..114222f18424 100644
--- a/hw/block/meson.build
+++ b/hw/block/meson.build
@@ -17,5 +17,6 @@ softmmu_ss.add(when: 'CONFIG_NVME_PCI', if_true: files('nvme.c'))
 
 specific_ss.add(when: 'CONFIG_VIRTIO_BLK', if_true: files('virtio-blk.c'))
 specific_ss.add(when: 'CONFIG_VHOST_USER_BLK', if_true: files('vhost-user-blk.c'))
+specific_ss.add(when: 'CONFIG_VHOST_USER_RPMB', if_true: files('vhost-user-rpmb.c'))
 
 subdir('dataplane')
-- 
2.20.1



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

* [RFC PATCH 02/19] hw/block: add boilerplate for vhost-user-rpmb device
@ 2020-09-25 12:51   ` Alex Bennée
  0 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2020-09-25 12:51 UTC (permalink / raw)
  To: qemu-devel, maxim.uvarov, joakim.bech, ilias.apalodimas,
	tomas.winkler, yang.huang, bing.zhu, Matti.Moell, hmo
  Cc: jean-philippe, open list:Block layer core, Michael S. Tsirkin,
	Max Reitz, takahiro.akashi, virtualization, arnd, stratos-dev

This creates the QEMU side of the vhost-user-rpmb device which
connects to the remote daemon. It is based of the reasonably modern
vhost-user-fs code with bits from vhost-user-blk as we want the
virtio-config itself to be sourced from the daemon.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 include/hw/virtio/vhost-user-rpmb.h |  46 ++++
 hw/block/vhost-user-rpmb.c          | 333 ++++++++++++++++++++++++++++
 hw/block/Kconfig                    |   5 +
 hw/block/meson.build                |   1 +
 4 files changed, 385 insertions(+)
 create mode 100644 include/hw/virtio/vhost-user-rpmb.h
 create mode 100644 hw/block/vhost-user-rpmb.c

diff --git a/include/hw/virtio/vhost-user-rpmb.h b/include/hw/virtio/vhost-user-rpmb.h
new file mode 100644
index 000000000000..7e5988127dc2
--- /dev/null
+++ b/include/hw/virtio/vhost-user-rpmb.h
@@ -0,0 +1,46 @@
+/*
+ * vhost-user-rpmb virtio device
+ *
+ * Copyright (c) 2020 Linaro Ltd
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef _VHOST_USER_RPMB_H_
+#define _VHOST_USER_RPMB_H_
+
+#include "hw/virtio/virtio.h"
+#include "hw/virtio/vhost.h"
+#include "hw/virtio/vhost-user.h"
+#include "chardev/char-fe.h"
+
+#define TYPE_VHOST_USER_RPMB "vhost-user-rpmb-device"
+#define VHOST_USER_RPMB(obj) \
+        OBJECT_CHECK(VHostUserRPMB, (obj), TYPE_VHOST_USER_RPMB)
+
+/* This is defined in the VIRTIO spec */
+struct virtio_rpmb_config {
+    uint8_t capacity;
+    uint8_t max_wr_cnt;
+    uint8_t max_rd_cnt;
+};
+
+typedef struct {
+    CharBackend chardev;
+    struct virtio_rpmb_config config;
+} VHostUserRPMBConf;
+
+typedef struct {
+    /*< private >*/
+    VirtIODevice parent;
+    VHostUserRPMBConf conf;
+    struct vhost_virtqueue *vhost_vq;
+    struct vhost_dev vhost_dev;
+    VhostUserState vhost_user;
+    VirtQueue *req_vq;
+    bool connected;
+    /*< public >*/
+} VHostUserRPMB;
+
+
+#endif /* _VHOST_USER_RPMB_H_ */
diff --git a/hw/block/vhost-user-rpmb.c b/hw/block/vhost-user-rpmb.c
new file mode 100644
index 000000000000..de243e7a53a0
--- /dev/null
+++ b/hw/block/vhost-user-rpmb.c
@@ -0,0 +1,333 @@
+/*
+ * Vhost-user RPMB virtio device
+ *
+ * This is the boilerplate for instantiating a vhost-user device
+ * implementing a Replay Protected Memory Block (RPMB) device. This is
+ * a type of flash chip that is protected from replay attacks and used
+ * for tamper resistant storage. The actual back-end for this driver
+ * is the vhost-user-rpmb daemon. The code here just connects up the
+ * device in QEMU and allows it to be instantiated.
+ *
+ * Copyright (c) 2020 Linaro Ltd
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "hw/qdev-properties.h"
+#include "hw/virtio/virtio-bus.h"
+#include "hw/virtio/vhost-user-rpmb.h"
+#include "qemu/error-report.h"
+
+/* currently there is no RPMB driver in Linux */
+#define VIRTIO_ID_RPMB         28 /* virtio RPMB */
+
+static void vurpmb_get_config(VirtIODevice *vdev, uint8_t *config)
+{
+    /* this somehow needs to come from the vhost-user daemon */
+}
+
+static void vurpmb_start(VirtIODevice *vdev)
+{
+    VHostUserRPMB *rpmb = VHOST_USER_RPMB(vdev);
+    BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
+    VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
+    int ret;
+    int i;
+
+    if (!k->set_guest_notifiers) {
+        error_report("binding does not support guest notifiers");
+        return;
+    }
+
+    ret = vhost_dev_enable_notifiers(&rpmb->vhost_dev, vdev);
+    if (ret < 0) {
+        error_report("Error enabling host notifiers: %d", -ret);
+        return;
+    }
+
+    ret = k->set_guest_notifiers(qbus->parent, rpmb->vhost_dev.nvqs, true);
+    if (ret < 0) {
+        error_report("Error binding guest notifier: %d", -ret);
+        goto err_host_notifiers;
+    }
+
+    rpmb->vhost_dev.acked_features = vdev->guest_features;
+    ret = vhost_dev_start(&rpmb->vhost_dev, vdev);
+    if (ret < 0) {
+        error_report("Error starting vhost-user-rpmb: %d", -ret);
+        goto err_guest_notifiers;
+    }
+
+    /*
+     * guest_notifier_mask/pending not used yet, so just unmask
+     * everything here.  virtio-pci will do the right thing by
+     * enabling/disabling irqfd.
+     */
+    for (i = 0; i < rpmb->vhost_dev.nvqs; i++) {
+        vhost_virtqueue_mask(&rpmb->vhost_dev, vdev, i, false);
+    }
+
+    return;
+
+err_guest_notifiers:
+    k->set_guest_notifiers(qbus->parent, rpmb->vhost_dev.nvqs, false);
+err_host_notifiers:
+    vhost_dev_disable_notifiers(&rpmb->vhost_dev, vdev);
+}
+
+static void vurpmb_stop(VirtIODevice *vdev)
+{
+    VHostUserRPMB *rpmb = VHOST_USER_RPMB(vdev);
+    BusState *qbus = BUS(qdev_get_parent_bus(DEVICE(vdev)));
+    VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(qbus);
+    int ret;
+
+    if (!k->set_guest_notifiers) {
+        return;
+    }
+
+    vhost_dev_stop(&rpmb->vhost_dev, vdev);
+
+    ret = k->set_guest_notifiers(qbus->parent, rpmb->vhost_dev.nvqs, false);
+    if (ret < 0) {
+        error_report("vhost guest notifier cleanup failed: %d", ret);
+        return;
+    }
+
+    vhost_dev_disable_notifiers(&rpmb->vhost_dev, vdev);
+}
+
+static void vurpmb_set_status(VirtIODevice *vdev, uint8_t status)
+{
+    VHostUserRPMB *rpmb = VHOST_USER_RPMB(vdev);
+    bool should_start = status & VIRTIO_CONFIG_S_DRIVER_OK;
+
+    if (!vdev->vm_running) {
+        should_start = false;
+    }
+
+    if (rpmb->vhost_dev.started == should_start) {
+        return;
+    }
+
+    if (should_start) {
+        vurpmb_start(vdev);
+    } else {
+        vurpmb_stop(vdev);
+    }
+}
+
+static uint64_t vurpmb_get_features(VirtIODevice *vdev,
+                                      uint64_t requested_features,
+                                      Error **errp)
+{
+    /* No feature bits used yet */
+    return requested_features;
+}
+
+static void vurpmb_handle_output(VirtIODevice *vdev, VirtQueue *vq)
+{
+    /*
+     * Not normally called; it's the daemon that handles the queue;
+     * however virtio's cleanup path can call this.
+     */
+}
+
+static void vurpmb_guest_notifier_mask(VirtIODevice *vdev, int idx,
+                                            bool mask)
+{
+    VHostUserRPMB *rpmb = VHOST_USER_RPMB(vdev);
+    vhost_virtqueue_mask(&rpmb->vhost_dev, vdev, idx, mask);
+}
+
+static bool vurpmb_guest_notifier_pending(VirtIODevice *vdev, int idx)
+{
+    VHostUserRPMB *rpmb = VHOST_USER_RPMB(vdev);
+    return vhost_virtqueue_pending(&rpmb->vhost_dev, idx);
+}
+
+/*
+ * Chardev connect/disconnect events
+ */
+
+static int vurpmb_handle_config_change(struct vhost_dev *dev)
+{
+    int ret;
+    VHostUserRPMB *rpmb = VHOST_USER_RPMB(dev->vdev);
+
+    ret = vhost_dev_get_config(dev, (uint8_t *)&rpmb->conf.config,
+                               sizeof(struct virtio_rpmb_config));
+    if (ret < 0) {
+        error_report("get config space failed");
+        return -1;
+    }
+
+    return 0;
+}
+
+const VhostDevConfigOps rpmb_ops = {
+    .vhost_dev_config_notifier = vurpmb_handle_config_change,
+};
+
+static int vurpmb_connect(DeviceState *dev)
+{
+    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+    VHostUserRPMB *rpmb = VHOST_USER_RPMB(vdev);
+
+    if (rpmb->connected) {
+        return 0;
+    }
+    rpmb->connected = true;
+
+    /* restore vhost state */
+    if (virtio_device_started(vdev, vdev->status)) {
+        vurpmb_start(vdev);
+    }
+
+    return 0;
+}
+
+static void vurpmb_disconnect(DeviceState *dev)
+{
+    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+    VHostUserRPMB *rpmb = VHOST_USER_RPMB(vdev);
+
+    if (!rpmb->connected) {
+        return;
+    }
+    rpmb->connected = false;
+
+    if (rpmb->vhost_dev.started) {
+        vurpmb_stop(vdev);
+    }
+
+    vhost_dev_cleanup(&rpmb->vhost_dev);
+}
+
+static void vurpmb_event(void *opaque, QEMUChrEvent event)
+{
+    DeviceState *dev = opaque;
+    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+    VHostUserRPMB *rpmb = VHOST_USER_RPMB(vdev);
+
+    switch (event) {
+    case CHR_EVENT_OPENED:
+        if (vurpmb_connect(dev) < 0) {
+            qemu_chr_fe_disconnect(&rpmb->conf.chardev);
+            return;
+        }
+        break;
+    case CHR_EVENT_CLOSED:
+        vurpmb_disconnect(dev);
+        break;
+    case CHR_EVENT_BREAK:
+    case CHR_EVENT_MUX_IN:
+    case CHR_EVENT_MUX_OUT:
+        /* Ignore */
+        break;
+    }
+}
+
+static void do_vhost_user_cleanup(VirtIODevice *vdev, VHostUserRPMB *rpmb)
+{
+    vhost_user_cleanup(&rpmb->vhost_user);
+    virtio_delete_queue(rpmb->req_vq);
+    virtio_cleanup(vdev);
+    g_free(rpmb->vhost_dev.vqs);
+    rpmb->vhost_dev.vqs = NULL;
+}
+
+
+static void vurpmb_device_realize(DeviceState *dev, Error **errp)
+{
+    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+    VHostUserRPMB *rpmb = VHOST_USER_RPMB(dev);
+    int ret;
+
+    if (!rpmb->conf.chardev.chr) {
+        error_setg(errp, "missing chardev");
+        return;
+    }
+
+    if (!vhost_user_init(&rpmb->vhost_user, &rpmb->conf.chardev, errp)) {
+        return;
+    }
+
+    virtio_init(vdev, "vhost-user-rpmb", VIRTIO_ID_RPMB,
+                sizeof(struct virtio_rpmb_config));
+
+    /* One request queue, 4 elements in case we don't do indirect */
+    rpmb->req_vq = virtio_add_queue(vdev, 4, vurpmb_handle_output);
+    rpmb->vhost_dev.nvqs = 1;
+    rpmb->vhost_dev.vqs = g_new0(struct vhost_virtqueue, rpmb->vhost_dev.nvqs);
+    ret = vhost_dev_init(&rpmb->vhost_dev, &rpmb->vhost_user,
+                         VHOST_BACKEND_TYPE_USER, 0);
+    if (ret < 0) {
+        error_setg_errno(errp, -ret, "vhost_dev_init failed");
+        do_vhost_user_cleanup(vdev, rpmb);
+    }
+
+    /*
+     * At this point the next event we will get is a connection from
+     * the daemon on the control socket.
+     */
+
+    qemu_chr_fe_set_handlers(&rpmb->conf.chardev,  NULL, NULL, vurpmb_event,
+                             NULL, (void *)dev, NULL, true);
+
+    return;
+}
+
+static void vurpmb_device_unrealize(DeviceState *dev)
+{
+    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+    VHostUserRPMB *rpmb = VHOST_USER_RPMB(dev);
+
+    /* This will stop vhost backend if appropriate. */
+    vurpmb_set_status(vdev, 0);
+
+    do_vhost_user_cleanup(vdev, rpmb);
+}
+
+static const VMStateDescription vurpmb_vmstate = {
+    .name = "vhost-user-rpmb",
+    .unmigratable = 1,
+};
+
+static Property vurpmb_properties[] = {
+    DEFINE_PROP_CHR("chardev", VHostUserRPMB, conf.chardev),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void vurpmb_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
+
+    device_class_set_props(dc, vurpmb_properties);
+    dc->vmsd = &vurpmb_vmstate;
+    set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
+    vdc->realize = vurpmb_device_realize;
+    vdc->unrealize = vurpmb_device_unrealize;
+    vdc->get_features = vurpmb_get_features;
+    vdc->get_config = vurpmb_get_config;
+    vdc->set_status = vurpmb_set_status;
+    vdc->guest_notifier_mask = vurpmb_guest_notifier_mask;
+    vdc->guest_notifier_pending = vurpmb_guest_notifier_pending;
+}
+
+static const TypeInfo vurpmb_info = {
+    .name = TYPE_VHOST_USER_RPMB,
+    .parent = TYPE_VIRTIO_DEVICE,
+    .instance_size = sizeof(VHostUserRPMB),
+    .class_init = vurpmb_class_init,
+};
+
+static void vurpmb_register_types(void)
+{
+    type_register_static(&vurpmb_info);
+}
+
+type_init(vurpmb_register_types)
diff --git a/hw/block/Kconfig b/hw/block/Kconfig
index 2d17f481adc6..12e21870847a 100644
--- a/hw/block/Kconfig
+++ b/hw/block/Kconfig
@@ -38,5 +38,10 @@ config VHOST_USER_BLK
     default y if VIRTIO_PCI
     depends on VIRTIO && VHOST_USER && LINUX
 
+config VHOST_USER_RPMB
+    bool
+    default y
+    depends on VIRTIO && VHOST_USER
+
 config SWIM
     bool
diff --git a/hw/block/meson.build b/hw/block/meson.build
index 78cad8f7cba1..114222f18424 100644
--- a/hw/block/meson.build
+++ b/hw/block/meson.build
@@ -17,5 +17,6 @@ softmmu_ss.add(when: 'CONFIG_NVME_PCI', if_true: files('nvme.c'))
 
 specific_ss.add(when: 'CONFIG_VIRTIO_BLK', if_true: files('virtio-blk.c'))
 specific_ss.add(when: 'CONFIG_VHOST_USER_BLK', if_true: files('vhost-user-blk.c'))
+specific_ss.add(when: 'CONFIG_VHOST_USER_RPMB', if_true: files('vhost-user-rpmb.c'))
 
 subdir('dataplane')
-- 
2.20.1

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

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

* [RFC PATCH 03/19] hw/virtio: move virtio-pci.h into shared include space
  2020-09-25 12:51 ` Alex Bennée
@ 2020-09-25 12:51   ` Alex Bennée
  -1 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2020-09-25 12:51 UTC (permalink / raw)
  To: qemu-devel, maxim.uvarov, joakim.bech, ilias.apalodimas,
	tomas.winkler, yang.huang, bing.zhu, Matti.Moell, hmo
  Cc: jean-philippe, Michael S. Tsirkin, David Hildenbrand,
	Dr. David Alan Gilbert, Raphael Norwitz, takahiro.akashi,
	Stefan Hajnoczi, Eric Auger, virtualization, Alex Bennée,
	arnd, stratos-dev

This allows other device classes that will be exposed via PCI to be
able to do so in the appropriate hw/ directory. I resisted the
temptation to re-order headers to be more aesthetically pleasing.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 {hw => include/hw}/virtio/virtio-pci.h | 0
 hw/virtio/vhost-scsi-pci.c             | 2 +-
 hw/virtio/vhost-user-blk-pci.c         | 2 +-
 hw/virtio/vhost-user-fs-pci.c          | 2 +-
 hw/virtio/vhost-user-input-pci.c       | 2 +-
 hw/virtio/vhost-user-scsi-pci.c        | 2 +-
 hw/virtio/vhost-user-vsock-pci.c       | 2 +-
 hw/virtio/vhost-vsock-pci.c            | 2 +-
 hw/virtio/virtio-9p-pci.c              | 2 +-
 hw/virtio/virtio-balloon-pci.c         | 2 +-
 hw/virtio/virtio-blk-pci.c             | 2 +-
 hw/virtio/virtio-input-host-pci.c      | 2 +-
 hw/virtio/virtio-input-pci.c           | 2 +-
 hw/virtio/virtio-iommu-pci.c           | 2 +-
 hw/virtio/virtio-net-pci.c             | 2 +-
 hw/virtio/virtio-pci.c                 | 2 +-
 hw/virtio/virtio-rng-pci.c             | 2 +-
 hw/virtio/virtio-scsi-pci.c            | 2 +-
 hw/virtio/virtio-serial-pci.c          | 2 +-
 19 files changed, 18 insertions(+), 18 deletions(-)
 rename {hw => include/hw}/virtio/virtio-pci.h (100%)

diff --git a/hw/virtio/virtio-pci.h b/include/hw/virtio/virtio-pci.h
similarity index 100%
rename from hw/virtio/virtio-pci.h
rename to include/hw/virtio/virtio-pci.h
diff --git a/hw/virtio/vhost-scsi-pci.c b/hw/virtio/vhost-scsi-pci.c
index cb71a294faaf..08980bc23bdb 100644
--- a/hw/virtio/vhost-scsi-pci.c
+++ b/hw/virtio/vhost-scsi-pci.c
@@ -21,7 +21,7 @@
 #include "hw/virtio/vhost-scsi.h"
 #include "qapi/error.h"
 #include "qemu/module.h"
-#include "virtio-pci.h"
+#include "hw/virtio/virtio-pci.h"
 #include "qom/object.h"
 
 typedef struct VHostSCSIPCI VHostSCSIPCI;
diff --git a/hw/virtio/vhost-user-blk-pci.c b/hw/virtio/vhost-user-blk-pci.c
index 33b404d8a225..eef8641a9891 100644
--- a/hw/virtio/vhost-user-blk-pci.c
+++ b/hw/virtio/vhost-user-blk-pci.c
@@ -26,7 +26,7 @@
 #include "qapi/error.h"
 #include "qemu/error-report.h"
 #include "qemu/module.h"
-#include "virtio-pci.h"
+#include "hw/virtio/virtio-pci.h"
 #include "qom/object.h"
 
 typedef struct VHostUserBlkPCI VHostUserBlkPCI;
diff --git a/hw/virtio/vhost-user-fs-pci.c b/hw/virtio/vhost-user-fs-pci.c
index 8bb389bd282a..777249e8bc4d 100644
--- a/hw/virtio/vhost-user-fs-pci.c
+++ b/hw/virtio/vhost-user-fs-pci.c
@@ -14,7 +14,7 @@
 #include "qemu/osdep.h"
 #include "hw/qdev-properties.h"
 #include "hw/virtio/vhost-user-fs.h"
-#include "virtio-pci.h"
+#include "hw/virtio/virtio-pci.h"
 #include "qom/object.h"
 
 struct VHostUserFSPCI {
diff --git a/hw/virtio/vhost-user-input-pci.c b/hw/virtio/vhost-user-input-pci.c
index c9d3e9113a5e..b858898a3630 100644
--- a/hw/virtio/vhost-user-input-pci.c
+++ b/hw/virtio/vhost-user-input-pci.c
@@ -9,7 +9,7 @@
 #include "hw/virtio/virtio-input.h"
 #include "qapi/error.h"
 #include "qemu/error-report.h"
-#include "virtio-pci.h"
+#include "hw/virtio/virtio-pci.h"
 #include "qom/object.h"
 
 typedef struct VHostUserInputPCI VHostUserInputPCI;
diff --git a/hw/virtio/vhost-user-scsi-pci.c b/hw/virtio/vhost-user-scsi-pci.c
index d5343412a11c..75882e3cf943 100644
--- a/hw/virtio/vhost-user-scsi-pci.c
+++ b/hw/virtio/vhost-user-scsi-pci.c
@@ -30,7 +30,7 @@
 #include "hw/pci/msix.h"
 #include "hw/loader.h"
 #include "sysemu/kvm.h"
-#include "virtio-pci.h"
+#include "hw/virtio/virtio-pci.h"
 #include "qom/object.h"
 
 typedef struct VHostUserSCSIPCI VHostUserSCSIPCI;
diff --git a/hw/virtio/vhost-user-vsock-pci.c b/hw/virtio/vhost-user-vsock-pci.c
index 763f89984e91..a50845ea87a3 100644
--- a/hw/virtio/vhost-user-vsock-pci.c
+++ b/hw/virtio/vhost-user-vsock-pci.c
@@ -10,7 +10,7 @@
 
 #include "qemu/osdep.h"
 
-#include "virtio-pci.h"
+#include "hw/virtio/virtio-pci.h"
 #include "hw/qdev-properties.h"
 #include "hw/virtio/vhost-user-vsock.h"
 #include "qom/object.h"
diff --git a/hw/virtio/vhost-vsock-pci.c b/hw/virtio/vhost-vsock-pci.c
index e56067b42781..35773fbcb3b0 100644
--- a/hw/virtio/vhost-vsock-pci.c
+++ b/hw/virtio/vhost-vsock-pci.c
@@ -13,7 +13,7 @@
 
 #include "qemu/osdep.h"
 
-#include "virtio-pci.h"
+#include "hw/virtio/virtio-pci.h"
 #include "hw/qdev-properties.h"
 #include "hw/virtio/vhost-vsock.h"
 #include "qemu/module.h"
diff --git a/hw/virtio/virtio-9p-pci.c b/hw/virtio/virtio-9p-pci.c
index e07adcd9ea78..94c14f0b98c9 100644
--- a/hw/virtio/virtio-9p-pci.c
+++ b/hw/virtio/virtio-9p-pci.c
@@ -15,7 +15,7 @@
 
 #include "qemu/osdep.h"
 
-#include "virtio-pci.h"
+#include "hw/virtio/virtio-pci.h"
 #include "hw/9pfs/virtio-9p.h"
 #include "hw/qdev-properties.h"
 #include "qemu/module.h"
diff --git a/hw/virtio/virtio-balloon-pci.c b/hw/virtio/virtio-balloon-pci.c
index a2c5cc7207a9..8d5a212b94cd 100644
--- a/hw/virtio/virtio-balloon-pci.c
+++ b/hw/virtio/virtio-balloon-pci.c
@@ -14,7 +14,7 @@
 
 #include "qemu/osdep.h"
 
-#include "virtio-pci.h"
+#include "hw/virtio/virtio-pci.h"
 #include "hw/qdev-properties.h"
 #include "hw/virtio/virtio-balloon.h"
 #include "qapi/error.h"
diff --git a/hw/virtio/virtio-blk-pci.c b/hw/virtio/virtio-blk-pci.c
index 9d5795810c36..9743bee965af 100644
--- a/hw/virtio/virtio-blk-pci.c
+++ b/hw/virtio/virtio-blk-pci.c
@@ -19,7 +19,7 @@
 
 #include "hw/qdev-properties.h"
 #include "hw/virtio/virtio-blk.h"
-#include "virtio-pci.h"
+#include "hw/virtio/virtio-pci.h"
 #include "qapi/error.h"
 #include "qemu/module.h"
 #include "qom/object.h"
diff --git a/hw/virtio/virtio-input-host-pci.c b/hw/virtio/virtio-input-host-pci.c
index 0ac360de4f34..cf8a9cf9e8db 100644
--- a/hw/virtio/virtio-input-host-pci.c
+++ b/hw/virtio/virtio-input-host-pci.c
@@ -8,7 +8,7 @@
 
 #include "qemu/osdep.h"
 
-#include "virtio-pci.h"
+#include "hw/virtio/virtio-pci.h"
 #include "hw/virtio/virtio-input.h"
 #include "qemu/module.h"
 #include "qom/object.h"
diff --git a/hw/virtio/virtio-input-pci.c b/hw/virtio/virtio-input-pci.c
index 85acd3d2ebb4..d208df68af5f 100644
--- a/hw/virtio/virtio-input-pci.c
+++ b/hw/virtio/virtio-input-pci.c
@@ -8,7 +8,7 @@
 
 #include "qemu/osdep.h"
 
-#include "virtio-pci.h"
+#include "hw/virtio/virtio-pci.h"
 #include "hw/qdev-properties.h"
 #include "hw/virtio/virtio-input.h"
 #include "qemu/module.h"
diff --git a/hw/virtio/virtio-iommu-pci.c b/hw/virtio/virtio-iommu-pci.c
index 76540e57b104..022447b5a469 100644
--- a/hw/virtio/virtio-iommu-pci.c
+++ b/hw/virtio/virtio-iommu-pci.c
@@ -11,7 +11,7 @@
 
 #include "qemu/osdep.h"
 
-#include "virtio-pci.h"
+#include "hw/virtio/virtio-pci.h"
 #include "hw/virtio/virtio-iommu.h"
 #include "hw/qdev-properties.h"
 #include "qapi/error.h"
diff --git a/hw/virtio/virtio-net-pci.c b/hw/virtio/virtio-net-pci.c
index 292d13d27815..954b6fbf2d58 100644
--- a/hw/virtio/virtio-net-pci.c
+++ b/hw/virtio/virtio-net-pci.c
@@ -19,7 +19,7 @@
 
 #include "hw/qdev-properties.h"
 #include "hw/virtio/virtio-net.h"
-#include "virtio-pci.h"
+#include "hw/virtio/virtio-pci.h"
 #include "qapi/error.h"
 #include "qemu/module.h"
 #include "qom/object.h"
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index 5bc769f685ce..507cb57c410f 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -32,7 +32,7 @@
 #include "hw/pci/msix.h"
 #include "hw/loader.h"
 #include "sysemu/kvm.h"
-#include "virtio-pci.h"
+#include "hw/virtio/virtio-pci.h"
 #include "qemu/range.h"
 #include "hw/virtio/virtio-bus.h"
 #include "qapi/visitor.h"
diff --git a/hw/virtio/virtio-rng-pci.c b/hw/virtio/virtio-rng-pci.c
index c1f916268be7..151ece6f946a 100644
--- a/hw/virtio/virtio-rng-pci.c
+++ b/hw/virtio/virtio-rng-pci.c
@@ -11,7 +11,7 @@
 
 #include "qemu/osdep.h"
 
-#include "virtio-pci.h"
+#include "hw/virtio/virtio-pci.h"
 #include "hw/virtio/virtio-rng.h"
 #include "qapi/error.h"
 #include "qemu/module.h"
diff --git a/hw/virtio/virtio-scsi-pci.c b/hw/virtio/virtio-scsi-pci.c
index 97fab742368a..e8e3442f3828 100644
--- a/hw/virtio/virtio-scsi-pci.c
+++ b/hw/virtio/virtio-scsi-pci.c
@@ -18,7 +18,7 @@
 #include "hw/qdev-properties.h"
 #include "hw/virtio/virtio-scsi.h"
 #include "qemu/module.h"
-#include "virtio-pci.h"
+#include "hw/virtio/virtio-pci.h"
 #include "qom/object.h"
 
 typedef struct VirtIOSCSIPCI VirtIOSCSIPCI;
diff --git a/hw/virtio/virtio-serial-pci.c b/hw/virtio/virtio-serial-pci.c
index 35bcd961c988..cea31adcc4c6 100644
--- a/hw/virtio/virtio-serial-pci.c
+++ b/hw/virtio/virtio-serial-pci.c
@@ -20,7 +20,7 @@
 #include "hw/qdev-properties.h"
 #include "hw/virtio/virtio-serial.h"
 #include "qemu/module.h"
-#include "virtio-pci.h"
+#include "hw/virtio/virtio-pci.h"
 #include "qom/object.h"
 
 typedef struct VirtIOSerialPCI VirtIOSerialPCI;
-- 
2.20.1



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

* [RFC PATCH 03/19] hw/virtio: move virtio-pci.h into shared include space
@ 2020-09-25 12:51   ` Alex Bennée
  0 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2020-09-25 12:51 UTC (permalink / raw)
  To: qemu-devel, maxim.uvarov, joakim.bech, ilias.apalodimas,
	tomas.winkler, yang.huang, bing.zhu, Matti.Moell, hmo
  Cc: jean-philippe, Michael S. Tsirkin, Dr. David Alan Gilbert,
	Raphael Norwitz, takahiro.akashi, Stefan Hajnoczi, Eric Auger,
	virtualization, arnd, stratos-dev

This allows other device classes that will be exposed via PCI to be
able to do so in the appropriate hw/ directory. I resisted the
temptation to re-order headers to be more aesthetically pleasing.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 {hw => include/hw}/virtio/virtio-pci.h | 0
 hw/virtio/vhost-scsi-pci.c             | 2 +-
 hw/virtio/vhost-user-blk-pci.c         | 2 +-
 hw/virtio/vhost-user-fs-pci.c          | 2 +-
 hw/virtio/vhost-user-input-pci.c       | 2 +-
 hw/virtio/vhost-user-scsi-pci.c        | 2 +-
 hw/virtio/vhost-user-vsock-pci.c       | 2 +-
 hw/virtio/vhost-vsock-pci.c            | 2 +-
 hw/virtio/virtio-9p-pci.c              | 2 +-
 hw/virtio/virtio-balloon-pci.c         | 2 +-
 hw/virtio/virtio-blk-pci.c             | 2 +-
 hw/virtio/virtio-input-host-pci.c      | 2 +-
 hw/virtio/virtio-input-pci.c           | 2 +-
 hw/virtio/virtio-iommu-pci.c           | 2 +-
 hw/virtio/virtio-net-pci.c             | 2 +-
 hw/virtio/virtio-pci.c                 | 2 +-
 hw/virtio/virtio-rng-pci.c             | 2 +-
 hw/virtio/virtio-scsi-pci.c            | 2 +-
 hw/virtio/virtio-serial-pci.c          | 2 +-
 19 files changed, 18 insertions(+), 18 deletions(-)
 rename {hw => include/hw}/virtio/virtio-pci.h (100%)

diff --git a/hw/virtio/virtio-pci.h b/include/hw/virtio/virtio-pci.h
similarity index 100%
rename from hw/virtio/virtio-pci.h
rename to include/hw/virtio/virtio-pci.h
diff --git a/hw/virtio/vhost-scsi-pci.c b/hw/virtio/vhost-scsi-pci.c
index cb71a294faaf..08980bc23bdb 100644
--- a/hw/virtio/vhost-scsi-pci.c
+++ b/hw/virtio/vhost-scsi-pci.c
@@ -21,7 +21,7 @@
 #include "hw/virtio/vhost-scsi.h"
 #include "qapi/error.h"
 #include "qemu/module.h"
-#include "virtio-pci.h"
+#include "hw/virtio/virtio-pci.h"
 #include "qom/object.h"
 
 typedef struct VHostSCSIPCI VHostSCSIPCI;
diff --git a/hw/virtio/vhost-user-blk-pci.c b/hw/virtio/vhost-user-blk-pci.c
index 33b404d8a225..eef8641a9891 100644
--- a/hw/virtio/vhost-user-blk-pci.c
+++ b/hw/virtio/vhost-user-blk-pci.c
@@ -26,7 +26,7 @@
 #include "qapi/error.h"
 #include "qemu/error-report.h"
 #include "qemu/module.h"
-#include "virtio-pci.h"
+#include "hw/virtio/virtio-pci.h"
 #include "qom/object.h"
 
 typedef struct VHostUserBlkPCI VHostUserBlkPCI;
diff --git a/hw/virtio/vhost-user-fs-pci.c b/hw/virtio/vhost-user-fs-pci.c
index 8bb389bd282a..777249e8bc4d 100644
--- a/hw/virtio/vhost-user-fs-pci.c
+++ b/hw/virtio/vhost-user-fs-pci.c
@@ -14,7 +14,7 @@
 #include "qemu/osdep.h"
 #include "hw/qdev-properties.h"
 #include "hw/virtio/vhost-user-fs.h"
-#include "virtio-pci.h"
+#include "hw/virtio/virtio-pci.h"
 #include "qom/object.h"
 
 struct VHostUserFSPCI {
diff --git a/hw/virtio/vhost-user-input-pci.c b/hw/virtio/vhost-user-input-pci.c
index c9d3e9113a5e..b858898a3630 100644
--- a/hw/virtio/vhost-user-input-pci.c
+++ b/hw/virtio/vhost-user-input-pci.c
@@ -9,7 +9,7 @@
 #include "hw/virtio/virtio-input.h"
 #include "qapi/error.h"
 #include "qemu/error-report.h"
-#include "virtio-pci.h"
+#include "hw/virtio/virtio-pci.h"
 #include "qom/object.h"
 
 typedef struct VHostUserInputPCI VHostUserInputPCI;
diff --git a/hw/virtio/vhost-user-scsi-pci.c b/hw/virtio/vhost-user-scsi-pci.c
index d5343412a11c..75882e3cf943 100644
--- a/hw/virtio/vhost-user-scsi-pci.c
+++ b/hw/virtio/vhost-user-scsi-pci.c
@@ -30,7 +30,7 @@
 #include "hw/pci/msix.h"
 #include "hw/loader.h"
 #include "sysemu/kvm.h"
-#include "virtio-pci.h"
+#include "hw/virtio/virtio-pci.h"
 #include "qom/object.h"
 
 typedef struct VHostUserSCSIPCI VHostUserSCSIPCI;
diff --git a/hw/virtio/vhost-user-vsock-pci.c b/hw/virtio/vhost-user-vsock-pci.c
index 763f89984e91..a50845ea87a3 100644
--- a/hw/virtio/vhost-user-vsock-pci.c
+++ b/hw/virtio/vhost-user-vsock-pci.c
@@ -10,7 +10,7 @@
 
 #include "qemu/osdep.h"
 
-#include "virtio-pci.h"
+#include "hw/virtio/virtio-pci.h"
 #include "hw/qdev-properties.h"
 #include "hw/virtio/vhost-user-vsock.h"
 #include "qom/object.h"
diff --git a/hw/virtio/vhost-vsock-pci.c b/hw/virtio/vhost-vsock-pci.c
index e56067b42781..35773fbcb3b0 100644
--- a/hw/virtio/vhost-vsock-pci.c
+++ b/hw/virtio/vhost-vsock-pci.c
@@ -13,7 +13,7 @@
 
 #include "qemu/osdep.h"
 
-#include "virtio-pci.h"
+#include "hw/virtio/virtio-pci.h"
 #include "hw/qdev-properties.h"
 #include "hw/virtio/vhost-vsock.h"
 #include "qemu/module.h"
diff --git a/hw/virtio/virtio-9p-pci.c b/hw/virtio/virtio-9p-pci.c
index e07adcd9ea78..94c14f0b98c9 100644
--- a/hw/virtio/virtio-9p-pci.c
+++ b/hw/virtio/virtio-9p-pci.c
@@ -15,7 +15,7 @@
 
 #include "qemu/osdep.h"
 
-#include "virtio-pci.h"
+#include "hw/virtio/virtio-pci.h"
 #include "hw/9pfs/virtio-9p.h"
 #include "hw/qdev-properties.h"
 #include "qemu/module.h"
diff --git a/hw/virtio/virtio-balloon-pci.c b/hw/virtio/virtio-balloon-pci.c
index a2c5cc7207a9..8d5a212b94cd 100644
--- a/hw/virtio/virtio-balloon-pci.c
+++ b/hw/virtio/virtio-balloon-pci.c
@@ -14,7 +14,7 @@
 
 #include "qemu/osdep.h"
 
-#include "virtio-pci.h"
+#include "hw/virtio/virtio-pci.h"
 #include "hw/qdev-properties.h"
 #include "hw/virtio/virtio-balloon.h"
 #include "qapi/error.h"
diff --git a/hw/virtio/virtio-blk-pci.c b/hw/virtio/virtio-blk-pci.c
index 9d5795810c36..9743bee965af 100644
--- a/hw/virtio/virtio-blk-pci.c
+++ b/hw/virtio/virtio-blk-pci.c
@@ -19,7 +19,7 @@
 
 #include "hw/qdev-properties.h"
 #include "hw/virtio/virtio-blk.h"
-#include "virtio-pci.h"
+#include "hw/virtio/virtio-pci.h"
 #include "qapi/error.h"
 #include "qemu/module.h"
 #include "qom/object.h"
diff --git a/hw/virtio/virtio-input-host-pci.c b/hw/virtio/virtio-input-host-pci.c
index 0ac360de4f34..cf8a9cf9e8db 100644
--- a/hw/virtio/virtio-input-host-pci.c
+++ b/hw/virtio/virtio-input-host-pci.c
@@ -8,7 +8,7 @@
 
 #include "qemu/osdep.h"
 
-#include "virtio-pci.h"
+#include "hw/virtio/virtio-pci.h"
 #include "hw/virtio/virtio-input.h"
 #include "qemu/module.h"
 #include "qom/object.h"
diff --git a/hw/virtio/virtio-input-pci.c b/hw/virtio/virtio-input-pci.c
index 85acd3d2ebb4..d208df68af5f 100644
--- a/hw/virtio/virtio-input-pci.c
+++ b/hw/virtio/virtio-input-pci.c
@@ -8,7 +8,7 @@
 
 #include "qemu/osdep.h"
 
-#include "virtio-pci.h"
+#include "hw/virtio/virtio-pci.h"
 #include "hw/qdev-properties.h"
 #include "hw/virtio/virtio-input.h"
 #include "qemu/module.h"
diff --git a/hw/virtio/virtio-iommu-pci.c b/hw/virtio/virtio-iommu-pci.c
index 76540e57b104..022447b5a469 100644
--- a/hw/virtio/virtio-iommu-pci.c
+++ b/hw/virtio/virtio-iommu-pci.c
@@ -11,7 +11,7 @@
 
 #include "qemu/osdep.h"
 
-#include "virtio-pci.h"
+#include "hw/virtio/virtio-pci.h"
 #include "hw/virtio/virtio-iommu.h"
 #include "hw/qdev-properties.h"
 #include "qapi/error.h"
diff --git a/hw/virtio/virtio-net-pci.c b/hw/virtio/virtio-net-pci.c
index 292d13d27815..954b6fbf2d58 100644
--- a/hw/virtio/virtio-net-pci.c
+++ b/hw/virtio/virtio-net-pci.c
@@ -19,7 +19,7 @@
 
 #include "hw/qdev-properties.h"
 #include "hw/virtio/virtio-net.h"
-#include "virtio-pci.h"
+#include "hw/virtio/virtio-pci.h"
 #include "qapi/error.h"
 #include "qemu/module.h"
 #include "qom/object.h"
diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index 5bc769f685ce..507cb57c410f 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -32,7 +32,7 @@
 #include "hw/pci/msix.h"
 #include "hw/loader.h"
 #include "sysemu/kvm.h"
-#include "virtio-pci.h"
+#include "hw/virtio/virtio-pci.h"
 #include "qemu/range.h"
 #include "hw/virtio/virtio-bus.h"
 #include "qapi/visitor.h"
diff --git a/hw/virtio/virtio-rng-pci.c b/hw/virtio/virtio-rng-pci.c
index c1f916268be7..151ece6f946a 100644
--- a/hw/virtio/virtio-rng-pci.c
+++ b/hw/virtio/virtio-rng-pci.c
@@ -11,7 +11,7 @@
 
 #include "qemu/osdep.h"
 
-#include "virtio-pci.h"
+#include "hw/virtio/virtio-pci.h"
 #include "hw/virtio/virtio-rng.h"
 #include "qapi/error.h"
 #include "qemu/module.h"
diff --git a/hw/virtio/virtio-scsi-pci.c b/hw/virtio/virtio-scsi-pci.c
index 97fab742368a..e8e3442f3828 100644
--- a/hw/virtio/virtio-scsi-pci.c
+++ b/hw/virtio/virtio-scsi-pci.c
@@ -18,7 +18,7 @@
 #include "hw/qdev-properties.h"
 #include "hw/virtio/virtio-scsi.h"
 #include "qemu/module.h"
-#include "virtio-pci.h"
+#include "hw/virtio/virtio-pci.h"
 #include "qom/object.h"
 
 typedef struct VirtIOSCSIPCI VirtIOSCSIPCI;
diff --git a/hw/virtio/virtio-serial-pci.c b/hw/virtio/virtio-serial-pci.c
index 35bcd961c988..cea31adcc4c6 100644
--- a/hw/virtio/virtio-serial-pci.c
+++ b/hw/virtio/virtio-serial-pci.c
@@ -20,7 +20,7 @@
 #include "hw/qdev-properties.h"
 #include "hw/virtio/virtio-serial.h"
 #include "qemu/module.h"
-#include "virtio-pci.h"
+#include "hw/virtio/virtio-pci.h"
 #include "qom/object.h"
 
 typedef struct VirtIOSerialPCI VirtIOSerialPCI;
-- 
2.20.1

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

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

* [RFC PATCH  04/19] hw/block: add vhost-user-rpmb-pci boilerplate
  2020-09-25 12:51 ` Alex Bennée
@ 2020-09-25 12:51   ` Alex Bennée
  -1 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2020-09-25 12:51 UTC (permalink / raw)
  To: qemu-devel, maxim.uvarov, joakim.bech, ilias.apalodimas,
	tomas.winkler, yang.huang, bing.zhu, Matti.Moell, hmo
  Cc: Kevin Wolf, jean-philippe, open list:Block layer core,
	Michael S. Tsirkin, Max Reitz, takahiro.akashi, virtualization,
	Alex Bennée, arnd, stratos-dev

This allows is to instantiate a vhost-user-rpmb device as part of a
PCI bus. It is mostly boilerplate which looks pretty similar to the
vhost-user-fs-pci device if you squint.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>

---
  - enable use IOEVENTFD flag
  - swap obj set bool args
---
 hw/block/vhost-user-rpmb-pci.c | 82 ++++++++++++++++++++++++++++++++++
 hw/block/meson.build           |  2 +
 2 files changed, 84 insertions(+)
 create mode 100644 hw/block/vhost-user-rpmb-pci.c

diff --git a/hw/block/vhost-user-rpmb-pci.c b/hw/block/vhost-user-rpmb-pci.c
new file mode 100644
index 000000000000..f0518305a1d9
--- /dev/null
+++ b/hw/block/vhost-user-rpmb-pci.c
@@ -0,0 +1,82 @@
+/*
+ * Vhost-user RPMB virtio device PCI glue
+ *
+ * Copyright (c) 2020 Linaro Ltd
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "hw/qdev-properties.h"
+#include "hw/virtio/vhost-user-rpmb.h"
+#include "hw/virtio/virtio-pci.h"
+
+struct VHostUserRPMBPCI {
+    VirtIOPCIProxy parent_obj;
+    VHostUserRPMB vdev;
+};
+
+typedef struct VHostUserRPMBPCI VHostUserRPMBPCI;
+
+#define TYPE_VHOST_USER_RPMB_PCI "vhost-user-rpmb-pci-base"
+
+#define VHOST_USER_RPMB_PCI(obj) \
+        OBJECT_CHECK(VHostUserRPMBPCI, (obj), TYPE_VHOST_USER_RPMB_PCI)
+
+static Property vurpmb_pci_properties[] = {
+    DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
+                    VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
+    DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
+                       DEV_NVECTORS_UNSPECIFIED),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void vurpmb_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
+{
+    VHostUserRPMBPCI *dev = VHOST_USER_RPMB_PCI(vpci_dev);
+    DeviceState *vdev = DEVICE(&dev->vdev);
+
+    if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
+        vpci_dev->nvectors = 1;
+    }
+
+    qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
+    object_property_set_bool(OBJECT(vdev), "realized", true, errp);
+}
+
+static void vurpmb_pci_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
+    PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
+    k->realize = vurpmb_pci_realize;
+    set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
+    device_class_set_props(dc, vurpmb_pci_properties);
+    pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+    pcidev_k->device_id = 0; /* Set by virtio-pci based on virtio id */
+    pcidev_k->revision = 0x00;
+    pcidev_k->class_id = PCI_CLASS_STORAGE_OTHER;
+}
+
+static void vurpmb_pci_instance_init(Object *obj)
+{
+    VHostUserRPMBPCI *dev = VHOST_USER_RPMB_PCI(obj);
+
+    virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
+                                TYPE_VHOST_USER_RPMB);
+}
+
+static const VirtioPCIDeviceTypeInfo vurpmb_pci_info = {
+    .base_name             = TYPE_VHOST_USER_RPMB_PCI,
+    .non_transitional_name = "vhost-user-rpmb-pci",
+    .instance_size = sizeof(VHostUserRPMBPCI),
+    .instance_init = vurpmb_pci_instance_init,
+    .class_init    = vurpmb_pci_class_init,
+};
+
+static void vurpmb_pci_register(void)
+{
+    virtio_pci_types_register(&vurpmb_pci_info);
+}
+
+type_init(vurpmb_pci_register);
diff --git a/hw/block/meson.build b/hw/block/meson.build
index 114222f18424..0b2d10201e28 100644
--- a/hw/block/meson.build
+++ b/hw/block/meson.build
@@ -18,5 +18,7 @@ softmmu_ss.add(when: 'CONFIG_NVME_PCI', if_true: files('nvme.c'))
 specific_ss.add(when: 'CONFIG_VIRTIO_BLK', if_true: files('virtio-blk.c'))
 specific_ss.add(when: 'CONFIG_VHOST_USER_BLK', if_true: files('vhost-user-blk.c'))
 specific_ss.add(when: 'CONFIG_VHOST_USER_RPMB', if_true: files('vhost-user-rpmb.c'))
+specific_ss.add(when: ['CONFIG_VHOST_USER_RPMB', 'CONFIG_VIRTIO_PCI' ],
+                if_true: files('vhost-user-rpmb-pci.c'))
 
 subdir('dataplane')
-- 
2.20.1



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

* [RFC PATCH  04/19] hw/block: add vhost-user-rpmb-pci boilerplate
@ 2020-09-25 12:51   ` Alex Bennée
  0 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2020-09-25 12:51 UTC (permalink / raw)
  To: qemu-devel, maxim.uvarov, joakim.bech, ilias.apalodimas,
	tomas.winkler, yang.huang, bing.zhu, Matti.Moell, hmo
  Cc: jean-philippe, open list:Block layer core, Michael S. Tsirkin,
	Max Reitz, takahiro.akashi, virtualization, arnd, stratos-dev

This allows is to instantiate a vhost-user-rpmb device as part of a
PCI bus. It is mostly boilerplate which looks pretty similar to the
vhost-user-fs-pci device if you squint.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>

---
  - enable use IOEVENTFD flag
  - swap obj set bool args
---
 hw/block/vhost-user-rpmb-pci.c | 82 ++++++++++++++++++++++++++++++++++
 hw/block/meson.build           |  2 +
 2 files changed, 84 insertions(+)
 create mode 100644 hw/block/vhost-user-rpmb-pci.c

diff --git a/hw/block/vhost-user-rpmb-pci.c b/hw/block/vhost-user-rpmb-pci.c
new file mode 100644
index 000000000000..f0518305a1d9
--- /dev/null
+++ b/hw/block/vhost-user-rpmb-pci.c
@@ -0,0 +1,82 @@
+/*
+ * Vhost-user RPMB virtio device PCI glue
+ *
+ * Copyright (c) 2020 Linaro Ltd
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "hw/qdev-properties.h"
+#include "hw/virtio/vhost-user-rpmb.h"
+#include "hw/virtio/virtio-pci.h"
+
+struct VHostUserRPMBPCI {
+    VirtIOPCIProxy parent_obj;
+    VHostUserRPMB vdev;
+};
+
+typedef struct VHostUserRPMBPCI VHostUserRPMBPCI;
+
+#define TYPE_VHOST_USER_RPMB_PCI "vhost-user-rpmb-pci-base"
+
+#define VHOST_USER_RPMB_PCI(obj) \
+        OBJECT_CHECK(VHostUserRPMBPCI, (obj), TYPE_VHOST_USER_RPMB_PCI)
+
+static Property vurpmb_pci_properties[] = {
+    DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags,
+                    VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true),
+    DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors,
+                       DEV_NVECTORS_UNSPECIFIED),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void vurpmb_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
+{
+    VHostUserRPMBPCI *dev = VHOST_USER_RPMB_PCI(vpci_dev);
+    DeviceState *vdev = DEVICE(&dev->vdev);
+
+    if (vpci_dev->nvectors == DEV_NVECTORS_UNSPECIFIED) {
+        vpci_dev->nvectors = 1;
+    }
+
+    qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
+    object_property_set_bool(OBJECT(vdev), "realized", true, errp);
+}
+
+static void vurpmb_pci_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+    VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
+    PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
+    k->realize = vurpmb_pci_realize;
+    set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
+    device_class_set_props(dc, vurpmb_pci_properties);
+    pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+    pcidev_k->device_id = 0; /* Set by virtio-pci based on virtio id */
+    pcidev_k->revision = 0x00;
+    pcidev_k->class_id = PCI_CLASS_STORAGE_OTHER;
+}
+
+static void vurpmb_pci_instance_init(Object *obj)
+{
+    VHostUserRPMBPCI *dev = VHOST_USER_RPMB_PCI(obj);
+
+    virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
+                                TYPE_VHOST_USER_RPMB);
+}
+
+static const VirtioPCIDeviceTypeInfo vurpmb_pci_info = {
+    .base_name             = TYPE_VHOST_USER_RPMB_PCI,
+    .non_transitional_name = "vhost-user-rpmb-pci",
+    .instance_size = sizeof(VHostUserRPMBPCI),
+    .instance_init = vurpmb_pci_instance_init,
+    .class_init    = vurpmb_pci_class_init,
+};
+
+static void vurpmb_pci_register(void)
+{
+    virtio_pci_types_register(&vurpmb_pci_info);
+}
+
+type_init(vurpmb_pci_register);
diff --git a/hw/block/meson.build b/hw/block/meson.build
index 114222f18424..0b2d10201e28 100644
--- a/hw/block/meson.build
+++ b/hw/block/meson.build
@@ -18,5 +18,7 @@ softmmu_ss.add(when: 'CONFIG_NVME_PCI', if_true: files('nvme.c'))
 specific_ss.add(when: 'CONFIG_VIRTIO_BLK', if_true: files('virtio-blk.c'))
 specific_ss.add(when: 'CONFIG_VHOST_USER_BLK', if_true: files('vhost-user-blk.c'))
 specific_ss.add(when: 'CONFIG_VHOST_USER_RPMB', if_true: files('vhost-user-rpmb.c'))
+specific_ss.add(when: ['CONFIG_VHOST_USER_RPMB', 'CONFIG_VIRTIO_PCI' ],
+                if_true: files('vhost-user-rpmb-pci.c'))
 
 subdir('dataplane')
-- 
2.20.1

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

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

* [RFC PATCH  05/19] virtio-pci: add notification trace points
  2020-09-25 12:51 ` Alex Bennée
@ 2020-09-25 12:51   ` Alex Bennée
  -1 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2020-09-25 12:51 UTC (permalink / raw)
  To: qemu-devel, maxim.uvarov, joakim.bech, ilias.apalodimas,
	tomas.winkler, yang.huang, bing.zhu, Matti.Moell, hmo
  Cc: jean-philippe, Michael S. Tsirkin, takahiro.akashi,
	virtualization, Alex Bennée, arnd, stratos-dev

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 hw/virtio/virtio-pci.c | 3 +++
 hw/virtio/trace-events | 7 ++++++-
 2 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index 507cb57c410f..33a40e31d955 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -36,6 +36,7 @@
 #include "qemu/range.h"
 #include "hw/virtio/virtio-bus.h"
 #include "qapi/visitor.h"
+#include "trace.h"
 
 #define VIRTIO_PCI_REGION_SIZE(dev)     VIRTIO_PCI_CONFIG_OFF(msix_present(dev))
 
@@ -1340,6 +1341,7 @@ static void virtio_pci_notify_write(void *opaque, hwaddr addr,
     unsigned queue = addr / virtio_pci_queue_mem_mult(proxy);
 
     if (vdev != NULL && queue < VIRTIO_QUEUE_MAX) {
+        trace_virtio_pci_notify_write(addr, val, size);
         virtio_queue_notify(vdev, queue);
     }
 }
@@ -1353,6 +1355,7 @@ static void virtio_pci_notify_write_pio(void *opaque, hwaddr addr,
     unsigned queue = val;
 
     if (vdev != NULL && queue < VIRTIO_QUEUE_MAX) {
+        trace_virtio_pci_notify_write_pio(addr, val, size);
         virtio_queue_notify(vdev, queue);
     }
 }
diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events
index 845200bf109d..189972b9213a 100644
--- a/hw/virtio/trace-events
+++ b/hw/virtio/trace-events
@@ -55,7 +55,12 @@ virtio_mmio_guest_page(uint64_t size, int shift) "guest page size 0x%" PRIx64 "
 virtio_mmio_queue_write(uint64_t value, int max_size) "mmio_queue write 0x%" PRIx64 " max %d"
 virtio_mmio_setting_irq(int level) "virtio_mmio setting IRQ %d"
 
-# virtio-iommu.c
+# virtio-pci.c
+virtio_pci_notify(uint16_t vector) "virtio_pci_notify vec 0x%x"
+virtio_pci_notify_write(uint64_t addr, uint64_t val, unsigned int size) "0x%" PRIx64" = 0x%" PRIx64 " (%d)"
+virtio_pci_notify_write_pio(uint64_t addr, uint64_t val, unsigned int size) "0x%" PRIx64" = 0x%" PRIx64 " (%d)"
+
+# hw/virtio/virtio-iommu.c
 virtio_iommu_device_reset(void) "reset!"
 virtio_iommu_get_features(uint64_t features) "device supports features=0x%"PRIx64
 virtio_iommu_device_status(uint8_t status) "driver status = %d"
-- 
2.20.1



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

* [RFC PATCH  05/19] virtio-pci: add notification trace points
@ 2020-09-25 12:51   ` Alex Bennée
  0 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2020-09-25 12:51 UTC (permalink / raw)
  To: qemu-devel, maxim.uvarov, joakim.bech, ilias.apalodimas,
	tomas.winkler, yang.huang, bing.zhu, Matti.Moell, hmo
  Cc: jean-philippe, Michael S. Tsirkin, takahiro.akashi,
	virtualization, arnd, stratos-dev

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 hw/virtio/virtio-pci.c | 3 +++
 hw/virtio/trace-events | 7 ++++++-
 2 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
index 507cb57c410f..33a40e31d955 100644
--- a/hw/virtio/virtio-pci.c
+++ b/hw/virtio/virtio-pci.c
@@ -36,6 +36,7 @@
 #include "qemu/range.h"
 #include "hw/virtio/virtio-bus.h"
 #include "qapi/visitor.h"
+#include "trace.h"
 
 #define VIRTIO_PCI_REGION_SIZE(dev)     VIRTIO_PCI_CONFIG_OFF(msix_present(dev))
 
@@ -1340,6 +1341,7 @@ static void virtio_pci_notify_write(void *opaque, hwaddr addr,
     unsigned queue = addr / virtio_pci_queue_mem_mult(proxy);
 
     if (vdev != NULL && queue < VIRTIO_QUEUE_MAX) {
+        trace_virtio_pci_notify_write(addr, val, size);
         virtio_queue_notify(vdev, queue);
     }
 }
@@ -1353,6 +1355,7 @@ static void virtio_pci_notify_write_pio(void *opaque, hwaddr addr,
     unsigned queue = val;
 
     if (vdev != NULL && queue < VIRTIO_QUEUE_MAX) {
+        trace_virtio_pci_notify_write_pio(addr, val, size);
         virtio_queue_notify(vdev, queue);
     }
 }
diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events
index 845200bf109d..189972b9213a 100644
--- a/hw/virtio/trace-events
+++ b/hw/virtio/trace-events
@@ -55,7 +55,12 @@ virtio_mmio_guest_page(uint64_t size, int shift) "guest page size 0x%" PRIx64 "
 virtio_mmio_queue_write(uint64_t value, int max_size) "mmio_queue write 0x%" PRIx64 " max %d"
 virtio_mmio_setting_irq(int level) "virtio_mmio setting IRQ %d"
 
-# virtio-iommu.c
+# virtio-pci.c
+virtio_pci_notify(uint16_t vector) "virtio_pci_notify vec 0x%x"
+virtio_pci_notify_write(uint64_t addr, uint64_t val, unsigned int size) "0x%" PRIx64" = 0x%" PRIx64 " (%d)"
+virtio_pci_notify_write_pio(uint64_t addr, uint64_t val, unsigned int size) "0x%" PRIx64" = 0x%" PRIx64 " (%d)"
+
+# hw/virtio/virtio-iommu.c
 virtio_iommu_device_reset(void) "reset!"
 virtio_iommu_get_features(uint64_t features) "device supports features=0x%"PRIx64
 virtio_iommu_device_status(uint8_t status) "driver status = %d"
-- 
2.20.1

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

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

* [RFC PATCH 06/19] tools/vhost-user-rpmb: add boilerplate and initial main
  2020-09-25 12:51 ` Alex Bennée
@ 2020-09-25 12:51   ` Alex Bennée
  -1 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2020-09-25 12:51 UTC (permalink / raw)
  To: qemu-devel, maxim.uvarov, joakim.bech, ilias.apalodimas,
	tomas.winkler, yang.huang, bing.zhu, Matti.Moell, hmo
  Cc: jean-philippe, takahiro.akashi, virtualization, Alex Bennée,
	arnd, stratos-dev

This adds the boilerplate files for a new vhost-user helper called
vhost-user-rpmb which will support virtio based RPMB (Replay Protected
Memory Block) devices.

This commit just adds the initial boilerplate for building the binary
with the common vhost-user options. As of this commit the only useful
output you get is when running:

  vhost-user-rpmb --help

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 tools/vhost-user-rpmb/main.c               | 37 ++++++++++++++++++++++
 MAINTAINERS                                |  5 +++
 tools/meson.build                          |  8 +++++
 tools/vhost-user-rpmb/50-qemu-rpmb.json.in |  5 +++
 tools/vhost-user-rpmb/meson.build          | 11 +++++++
 5 files changed, 66 insertions(+)
 create mode 100644 tools/vhost-user-rpmb/main.c
 create mode 100644 tools/vhost-user-rpmb/50-qemu-rpmb.json.in
 create mode 100644 tools/vhost-user-rpmb/meson.build

diff --git a/tools/vhost-user-rpmb/main.c b/tools/vhost-user-rpmb/main.c
new file mode 100644
index 000000000000..a40a680a74ca
--- /dev/null
+++ b/tools/vhost-user-rpmb/main.c
@@ -0,0 +1,37 @@
+/*
+ * VIRTIO RPMB Emulation via vhost-user
+ *
+ * Copyright (c) 2020 Linaro Ltd
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <glib.h>
+
+static gchar *socket_path;
+static gint socket_fd;
+static gboolean print_cap;
+
+static GOptionEntry options[] =
+{
+    { "socket-path", 0, 0, G_OPTION_ARG_FILENAME, &socket_path, "Location of vhost-user Unix domain socket, incompatible with --fd", "PATH" },
+    { "fd", 0, 0, G_OPTION_ARG_INT, &socket_fd, "Specify the file-descriptor of the backend, incompatible with --socket-path", "FD" },
+    { "print-capabilities", 0, 0, G_OPTION_ARG_NONE, &print_cap, "Output to stdout the backend capabilities in JSON format and exit", NULL},
+    { NULL }
+};
+
+int main (int argc, char *argv[])
+{
+    GError *error = NULL;
+    GOptionContext *context;
+
+    context = g_option_context_new ("vhost-user-rpmb - vhost-user emulation of RPBM device");
+    g_option_context_add_main_entries (context, options, "vhost-user-rpmb");
+    if (!g_option_context_parse (context, &argc, &argv, &error))
+    {
+        g_print ("option parsing failed: %s\n", error->message);
+        exit (1);
+    }
+
+
+}
diff --git a/MAINTAINERS b/MAINTAINERS
index 3d17cad19aa0..e325c1024a33 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1873,6 +1873,11 @@ F: hw/virtio/virtio-mem-pci.h
 F: hw/virtio/virtio-mem-pci.c
 F: include/hw/virtio/virtio-mem.h
 
+virtio-rpmb
+M: Alex Bennée <alex.bennee@linaro.org>
+S: Supported
+F: tools/vhost-user-rpmb/*
+
 nvme
 M: Keith Busch <kbusch@kernel.org>
 M: Klaus Jensen <its@irrelevant.dk>
diff --git a/tools/meson.build b/tools/meson.build
index 513bd2ff4fd2..408048c6357c 100644
--- a/tools/meson.build
+++ b/tools/meson.build
@@ -8,3 +8,11 @@ have_virtiofsd = (have_system and
 if have_virtiofsd
   subdir('virtiofsd')
 endif
+
+have_virtiorpmb = (have_system and
+    have_tools and
+    'CONFIG_LINUX' in config_host)
+
+if have_virtiorpmb
+  subdir('vhost-user-rpmb')
+endif
diff --git a/tools/vhost-user-rpmb/50-qemu-rpmb.json.in b/tools/vhost-user-rpmb/50-qemu-rpmb.json.in
new file mode 100644
index 000000000000..2b033cda567c
--- /dev/null
+++ b/tools/vhost-user-rpmb/50-qemu-rpmb.json.in
@@ -0,0 +1,5 @@
+{
+  "description": "QEMU vhost-user-rpmb",
+  "type": "block",
+  "binary": "@libexecdir@/vhost-user-rpmb"
+}
diff --git a/tools/vhost-user-rpmb/meson.build b/tools/vhost-user-rpmb/meson.build
new file mode 100644
index 000000000000..e0df1b69a3fb
--- /dev/null
+++ b/tools/vhost-user-rpmb/meson.build
@@ -0,0 +1,11 @@
+executable('vhost-user-rpmb', files(
+  'main.c'),
+  dependencies: [glib],
+  link_with: [libvhost_user],
+  install: true,
+  install_dir: get_option('libexecdir'))
+
+configure_file(input: '50-qemu-rpmb.json.in',
+               output: '50-qemu-rpmb.json',
+               configuration: config_host,
+               install_dir: qemu_datadir / 'vhost-user')
-- 
2.20.1



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

* [RFC PATCH 06/19] tools/vhost-user-rpmb: add boilerplate and initial main
@ 2020-09-25 12:51   ` Alex Bennée
  0 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2020-09-25 12:51 UTC (permalink / raw)
  To: qemu-devel, maxim.uvarov, joakim.bech, ilias.apalodimas,
	tomas.winkler, yang.huang, bing.zhu, Matti.Moell, hmo
  Cc: jean-philippe, takahiro.akashi, virtualization, arnd, stratos-dev

This adds the boilerplate files for a new vhost-user helper called
vhost-user-rpmb which will support virtio based RPMB (Replay Protected
Memory Block) devices.

This commit just adds the initial boilerplate for building the binary
with the common vhost-user options. As of this commit the only useful
output you get is when running:

  vhost-user-rpmb --help

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 tools/vhost-user-rpmb/main.c               | 37 ++++++++++++++++++++++
 MAINTAINERS                                |  5 +++
 tools/meson.build                          |  8 +++++
 tools/vhost-user-rpmb/50-qemu-rpmb.json.in |  5 +++
 tools/vhost-user-rpmb/meson.build          | 11 +++++++
 5 files changed, 66 insertions(+)
 create mode 100644 tools/vhost-user-rpmb/main.c
 create mode 100644 tools/vhost-user-rpmb/50-qemu-rpmb.json.in
 create mode 100644 tools/vhost-user-rpmb/meson.build

diff --git a/tools/vhost-user-rpmb/main.c b/tools/vhost-user-rpmb/main.c
new file mode 100644
index 000000000000..a40a680a74ca
--- /dev/null
+++ b/tools/vhost-user-rpmb/main.c
@@ -0,0 +1,37 @@
+/*
+ * VIRTIO RPMB Emulation via vhost-user
+ *
+ * Copyright (c) 2020 Linaro Ltd
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include <glib.h>
+
+static gchar *socket_path;
+static gint socket_fd;
+static gboolean print_cap;
+
+static GOptionEntry options[] =
+{
+    { "socket-path", 0, 0, G_OPTION_ARG_FILENAME, &socket_path, "Location of vhost-user Unix domain socket, incompatible with --fd", "PATH" },
+    { "fd", 0, 0, G_OPTION_ARG_INT, &socket_fd, "Specify the file-descriptor of the backend, incompatible with --socket-path", "FD" },
+    { "print-capabilities", 0, 0, G_OPTION_ARG_NONE, &print_cap, "Output to stdout the backend capabilities in JSON format and exit", NULL},
+    { NULL }
+};
+
+int main (int argc, char *argv[])
+{
+    GError *error = NULL;
+    GOptionContext *context;
+
+    context = g_option_context_new ("vhost-user-rpmb - vhost-user emulation of RPBM device");
+    g_option_context_add_main_entries (context, options, "vhost-user-rpmb");
+    if (!g_option_context_parse (context, &argc, &argv, &error))
+    {
+        g_print ("option parsing failed: %s\n", error->message);
+        exit (1);
+    }
+
+
+}
diff --git a/MAINTAINERS b/MAINTAINERS
index 3d17cad19aa0..e325c1024a33 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1873,6 +1873,11 @@ F: hw/virtio/virtio-mem-pci.h
 F: hw/virtio/virtio-mem-pci.c
 F: include/hw/virtio/virtio-mem.h
 
+virtio-rpmb
+M: Alex Bennée <alex.bennee@linaro.org>
+S: Supported
+F: tools/vhost-user-rpmb/*
+
 nvme
 M: Keith Busch <kbusch@kernel.org>
 M: Klaus Jensen <its@irrelevant.dk>
diff --git a/tools/meson.build b/tools/meson.build
index 513bd2ff4fd2..408048c6357c 100644
--- a/tools/meson.build
+++ b/tools/meson.build
@@ -8,3 +8,11 @@ have_virtiofsd = (have_system and
 if have_virtiofsd
   subdir('virtiofsd')
 endif
+
+have_virtiorpmb = (have_system and
+    have_tools and
+    'CONFIG_LINUX' in config_host)
+
+if have_virtiorpmb
+  subdir('vhost-user-rpmb')
+endif
diff --git a/tools/vhost-user-rpmb/50-qemu-rpmb.json.in b/tools/vhost-user-rpmb/50-qemu-rpmb.json.in
new file mode 100644
index 000000000000..2b033cda567c
--- /dev/null
+++ b/tools/vhost-user-rpmb/50-qemu-rpmb.json.in
@@ -0,0 +1,5 @@
+{
+  "description": "QEMU vhost-user-rpmb",
+  "type": "block",
+  "binary": "@libexecdir@/vhost-user-rpmb"
+}
diff --git a/tools/vhost-user-rpmb/meson.build b/tools/vhost-user-rpmb/meson.build
new file mode 100644
index 000000000000..e0df1b69a3fb
--- /dev/null
+++ b/tools/vhost-user-rpmb/meson.build
@@ -0,0 +1,11 @@
+executable('vhost-user-rpmb', files(
+  'main.c'),
+  dependencies: [glib],
+  link_with: [libvhost_user],
+  install: true,
+  install_dir: get_option('libexecdir'))
+
+configure_file(input: '50-qemu-rpmb.json.in',
+               output: '50-qemu-rpmb.json',
+               configuration: config_host,
+               install_dir: qemu_datadir / 'vhost-user')
-- 
2.20.1

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

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

* [RFC PATCH 07/19] tools/vhost-user-rpmb: implement --print-capabilities
  2020-09-25 12:51 ` Alex Bennée
@ 2020-09-25 12:51   ` Alex Bennée
  -1 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2020-09-25 12:51 UTC (permalink / raw)
  To: qemu-devel, maxim.uvarov, joakim.bech, ilias.apalodimas,
	tomas.winkler, yang.huang, bing.zhu, Matti.Moell, hmo
  Cc: jean-philippe, takahiro.akashi, virtualization, Alex Bennée,
	arnd, stratos-dev

A very simple capabilities dump.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 tools/vhost-user-rpmb/main.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/tools/vhost-user-rpmb/main.c b/tools/vhost-user-rpmb/main.c
index a40a680a74ca..6b1989125bd6 100644
--- a/tools/vhost-user-rpmb/main.c
+++ b/tools/vhost-user-rpmb/main.c
@@ -7,6 +7,7 @@
  */
 
 #include <glib.h>
+#include <stdio.h>
 
 static gchar *socket_path;
 static gint socket_fd;
@@ -20,6 +21,14 @@ static GOptionEntry options[] =
     { NULL }
 };
 
+/* Print vhost-user.json backend program capabilities */
+static void print_capabilities(void)
+{
+    printf("{\n");
+    printf("  \"type\": \"block\"\n");
+    printf("}\n");
+}
+
 int main (int argc, char *argv[])
 {
     GError *error = NULL;
@@ -33,5 +42,9 @@ int main (int argc, char *argv[])
         exit (1);
     }
 
+    if (print_cap) {
+        print_capabilities();
+        exit(0);
+    }
 
 }
-- 
2.20.1



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

* [RFC PATCH 07/19] tools/vhost-user-rpmb: implement --print-capabilities
@ 2020-09-25 12:51   ` Alex Bennée
  0 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2020-09-25 12:51 UTC (permalink / raw)
  To: qemu-devel, maxim.uvarov, joakim.bech, ilias.apalodimas,
	tomas.winkler, yang.huang, bing.zhu, Matti.Moell, hmo
  Cc: jean-philippe, takahiro.akashi, virtualization, arnd, stratos-dev

A very simple capabilities dump.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 tools/vhost-user-rpmb/main.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/tools/vhost-user-rpmb/main.c b/tools/vhost-user-rpmb/main.c
index a40a680a74ca..6b1989125bd6 100644
--- a/tools/vhost-user-rpmb/main.c
+++ b/tools/vhost-user-rpmb/main.c
@@ -7,6 +7,7 @@
  */
 
 #include <glib.h>
+#include <stdio.h>
 
 static gchar *socket_path;
 static gint socket_fd;
@@ -20,6 +21,14 @@ static GOptionEntry options[] =
     { NULL }
 };
 
+/* Print vhost-user.json backend program capabilities */
+static void print_capabilities(void)
+{
+    printf("{\n");
+    printf("  \"type\": \"block\"\n");
+    printf("}\n");
+}
+
 int main (int argc, char *argv[])
 {
     GError *error = NULL;
@@ -33,5 +42,9 @@ int main (int argc, char *argv[])
         exit (1);
     }
 
+    if (print_cap) {
+        print_capabilities();
+        exit(0);
+    }
 
 }
-- 
2.20.1

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

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

* [RFC PATCH 08/19] tools/vhost-user-rpmb: connect to fd and instantiate basic run loop
  2020-09-25 12:51 ` Alex Bennée
@ 2020-09-25 12:51   ` Alex Bennée
  -1 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2020-09-25 12:51 UTC (permalink / raw)
  To: qemu-devel, maxim.uvarov, joakim.bech, ilias.apalodimas,
	tomas.winkler, yang.huang, bing.zhu, Matti.Moell, hmo
  Cc: jean-philippe, takahiro.akashi, virtualization, Alex Bennée,
	arnd, stratos-dev

Again doesn't do much on it's own but will create a socket and wait on
messages coming in from the vhost-user message socket.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 tools/vhost-user-rpmb/main.c      | 211 +++++++++++++++++++++++++++++-
 tools/vhost-user-rpmb/meson.build |   2 +-
 2 files changed, 210 insertions(+), 3 deletions(-)

diff --git a/tools/vhost-user-rpmb/main.c b/tools/vhost-user-rpmb/main.c
index 6b1989125bd6..269c86cbb633 100644
--- a/tools/vhost-user-rpmb/main.c
+++ b/tools/vhost-user-rpmb/main.c
@@ -7,10 +7,23 @@
  */
 
 #include <glib.h>
+#include <gio/gio.h>
+#include <gio/gunixsocketaddress.h>
 #include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "contrib/libvhost-user/libvhost-user-glib.h"
+#include "contrib/libvhost-user/libvhost-user.h"
+
+#ifndef container_of
+#define container_of(ptr, type, member) ({                      \
+        const typeof(((type *) 0)->member) *__mptr = (ptr);     \
+        (type *) ((char *) __mptr - offsetof(type, member));})
+#endif
 
 static gchar *socket_path;
-static gint socket_fd;
+static gint socket_fd = -1;
 static gboolean print_cap;
 
 static GOptionEntry options[] =
@@ -21,6 +34,147 @@ static GOptionEntry options[] =
     { NULL }
 };
 
+enum {
+    VHOST_USER_RPMB_MAX_QUEUES = 1,
+};
+
+/* These structures are defined in the specification */
+
+struct virtio_rpmb_config {
+    uint8_t capacity;
+    uint8_t max_wr_cnt;
+    uint8_t max_rd_cnt;
+};
+
+struct virtio_rpmb_frame {
+    uint8_t stuff[196];
+    uint8_t key_mac[32];
+    uint8_t data[256];
+    uint8_t nonce[16];
+    /* remaining fields are big-endian */
+    uint32_t write_counter;
+    uint16_t address;
+    uint16_t block_count;
+    uint16_t result;
+    uint16_t req_resp;
+};
+
+/*
+ * Structure to track internal state of RPMB Device
+ */
+
+typedef struct VuRpmb {
+    VugDev dev;
+    struct virtio_rpmb_config virtio_config;
+} VuRpmb;
+
+struct virtio_rpmb_ctrl_command {
+    VuVirtqElement elem;
+    VuVirtq *vq;
+    struct virtio_rpmb_frame frame;
+    uint32_t error;
+    bool finished;
+};
+
+static void vrpmb_panic(VuDev *dev, const char *msg)
+{
+    g_critical("%s\n", msg);
+    exit(EXIT_FAILURE);
+}
+
+static uint64_t vrpmb_get_features(VuDev *dev)
+{
+    return 0;
+}
+
+static void vrpmb_set_features(VuDev *dev, uint64_t features)
+{
+    if (features) {
+        g_autoptr(GString) s = g_string_new("Requested un-handled feature");
+        g_string_append_printf(s, " 0x%" PRIx64 "", features);
+        g_info("%s: %s", __func__, s->str);
+    }
+}
+
+/*
+ * The configuration of the device is static and set when we start the
+ * daemon.
+ */
+static int
+vrpmb_get_config(VuDev *dev, uint8_t *config, uint32_t len)
+{
+    VuRpmb *r = container_of(dev, VuRpmb, dev.parent);
+    g_return_val_if_fail(len <= sizeof(struct virtio_rpmb_config), -1);
+    memcpy(config, &r->virtio_config, len);
+    return 0;
+}
+
+static int
+vrpmb_set_config(VuDev *dev, const uint8_t *data,
+                 uint32_t offset, uint32_t size,
+                 uint32_t flags)
+{
+    /* ignore */
+    return 0;
+}
+
+static void
+vrpmb_handle_ctrl(VuDev *dev, int qidx)
+{
+    VuVirtq *vq = vu_get_queue(dev, qidx);
+    struct virtio_rpmb_ctrl_command *cmd = NULL;
+
+    for (;;) {
+        cmd = vu_queue_pop(dev, vq, sizeof(struct virtio_rpmb_ctrl_command));
+        if (!cmd) {
+            break;
+        }
+
+        g_debug("un-handled cmd: %p", cmd);
+    }
+}
+
+static void
+vrpmb_queue_set_started(VuDev *dev, int qidx, bool started)
+{
+    VuVirtq *vq = vu_get_queue(dev, qidx);
+
+    g_debug("queue started %d:%d\n", qidx, started);
+
+    switch (qidx) {
+    case 0:
+        vu_set_queue_handler(dev, vq, started ? vrpmb_handle_ctrl : NULL);
+        break;
+    default:
+        break;
+    }
+}
+
+static int
+vrpmb_process_msg(VuDev *dev, VhostUserMsg *msg, int *do_reply)
+{
+    switch (msg->request) {
+    default:
+        return 0;
+    }
+
+    return 0;
+}
+
+static const VuDevIface vuiface = {
+    .set_features = vrpmb_set_features,
+    .get_features = vrpmb_get_features,
+    .queue_set_started = vrpmb_queue_set_started,
+    .process_msg = vrpmb_process_msg,
+    .get_config = vrpmb_get_config,
+    .set_config = vrpmb_set_config,
+};
+
+static void vrpmb_destroy(VuRpmb *r)
+{
+    vug_deinit(&r->dev);
+}
+
 /* Print vhost-user.json backend program capabilities */
 static void print_capabilities(void)
 {
@@ -33,8 +187,11 @@ int main (int argc, char *argv[])
 {
     GError *error = NULL;
     GOptionContext *context;
+    g_autoptr(GMainLoop) loop = NULL;
+    g_autoptr(GSocket) socket = NULL;
+    VuRpmb rpmb = {  };
 
-    context = g_option_context_new ("vhost-user-rpmb - vhost-user emulation of RPBM device");
+    context = g_option_context_new ("vhost-user emulation of RPBM device");
     g_option_context_add_main_entries (context, options, "vhost-user-rpmb");
     if (!g_option_context_parse (context, &argc, &argv, &error))
     {
@@ -47,4 +204,54 @@ int main (int argc, char *argv[])
         exit(0);
     }
 
+    if (!socket_path && socket_fd < 0) {
+        g_printerr("Please specify either --fd or --socket-path\n");
+        exit(EXIT_FAILURE);
+    }
+
+    /*
+     * Now create a vhost-user socket that we will receive messages
+     * on. Once we have our handler set up we can enter the glib main
+     * loop.
+     */
+    if (socket_path) {
+        g_autoptr(GSocketAddress) addr = g_unix_socket_address_new(socket_path);
+        g_autoptr(GSocket) bind_socket = g_socket_new(G_SOCKET_FAMILY_UNIX, G_SOCKET_TYPE_STREAM,
+                                                      G_SOCKET_PROTOCOL_DEFAULT, &error);
+
+        if (!g_socket_bind(bind_socket, addr, false, &error)) {
+            g_printerr("Failed to bind to socket at %s (%s).\n",
+                       socket_path, error->message);
+            exit(EXIT_FAILURE);
+        }
+        if (!g_socket_listen(bind_socket, &error)) {
+            g_printerr("Failed to listen on socket %s (%s).\n",
+                       socket_path, error->message);
+        }
+        g_message("awaiting connection to %s", socket_path);
+        socket = g_socket_accept(bind_socket, NULL, &error);
+        if (!socket) {
+            g_printerr("Failed to accept on socket %s (%s).\n",
+                       socket_path, error->message);
+        }
+    } else {
+        socket = g_socket_new_from_fd(socket_fd, &error);
+        if (!socket) {
+            g_printerr("Failed to connect to FD %d (%s).\n",
+                       socket_fd, error->message);
+            exit(EXIT_FAILURE);
+        }
+    }
+
+    if (!vug_init(&rpmb.dev, VHOST_USER_RPMB_MAX_QUEUES, g_socket_get_fd(socket),
+                  vrpmb_panic, &vuiface)) {
+        g_printerr("Failed to initialize libvhost-user-glib.\n");
+        exit(EXIT_FAILURE);
+    }
+
+    loop = g_main_loop_new(NULL, FALSE);
+    g_main_loop_run(loop);
+    g_main_loop_unref(loop);
+
+    vrpmb_destroy(&rpmb);
 }
diff --git a/tools/vhost-user-rpmb/meson.build b/tools/vhost-user-rpmb/meson.build
index e0df1b69a3fb..cf80bedd99ac 100644
--- a/tools/vhost-user-rpmb/meson.build
+++ b/tools/vhost-user-rpmb/meson.build
@@ -1,6 +1,6 @@
 executable('vhost-user-rpmb', files(
   'main.c'),
-  dependencies: [glib],
+  dependencies: [qemuutil, glib, gio],
   link_with: [libvhost_user],
   install: true,
   install_dir: get_option('libexecdir'))
-- 
2.20.1



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

* [RFC PATCH 08/19] tools/vhost-user-rpmb: connect to fd and instantiate basic run loop
@ 2020-09-25 12:51   ` Alex Bennée
  0 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2020-09-25 12:51 UTC (permalink / raw)
  To: qemu-devel, maxim.uvarov, joakim.bech, ilias.apalodimas,
	tomas.winkler, yang.huang, bing.zhu, Matti.Moell, hmo
  Cc: jean-philippe, takahiro.akashi, virtualization, arnd, stratos-dev

Again doesn't do much on it's own but will create a socket and wait on
messages coming in from the vhost-user message socket.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 tools/vhost-user-rpmb/main.c      | 211 +++++++++++++++++++++++++++++-
 tools/vhost-user-rpmb/meson.build |   2 +-
 2 files changed, 210 insertions(+), 3 deletions(-)

diff --git a/tools/vhost-user-rpmb/main.c b/tools/vhost-user-rpmb/main.c
index 6b1989125bd6..269c86cbb633 100644
--- a/tools/vhost-user-rpmb/main.c
+++ b/tools/vhost-user-rpmb/main.c
@@ -7,10 +7,23 @@
  */
 
 #include <glib.h>
+#include <gio/gio.h>
+#include <gio/gunixsocketaddress.h>
 #include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "contrib/libvhost-user/libvhost-user-glib.h"
+#include "contrib/libvhost-user/libvhost-user.h"
+
+#ifndef container_of
+#define container_of(ptr, type, member) ({                      \
+        const typeof(((type *) 0)->member) *__mptr = (ptr);     \
+        (type *) ((char *) __mptr - offsetof(type, member));})
+#endif
 
 static gchar *socket_path;
-static gint socket_fd;
+static gint socket_fd = -1;
 static gboolean print_cap;
 
 static GOptionEntry options[] =
@@ -21,6 +34,147 @@ static GOptionEntry options[] =
     { NULL }
 };
 
+enum {
+    VHOST_USER_RPMB_MAX_QUEUES = 1,
+};
+
+/* These structures are defined in the specification */
+
+struct virtio_rpmb_config {
+    uint8_t capacity;
+    uint8_t max_wr_cnt;
+    uint8_t max_rd_cnt;
+};
+
+struct virtio_rpmb_frame {
+    uint8_t stuff[196];
+    uint8_t key_mac[32];
+    uint8_t data[256];
+    uint8_t nonce[16];
+    /* remaining fields are big-endian */
+    uint32_t write_counter;
+    uint16_t address;
+    uint16_t block_count;
+    uint16_t result;
+    uint16_t req_resp;
+};
+
+/*
+ * Structure to track internal state of RPMB Device
+ */
+
+typedef struct VuRpmb {
+    VugDev dev;
+    struct virtio_rpmb_config virtio_config;
+} VuRpmb;
+
+struct virtio_rpmb_ctrl_command {
+    VuVirtqElement elem;
+    VuVirtq *vq;
+    struct virtio_rpmb_frame frame;
+    uint32_t error;
+    bool finished;
+};
+
+static void vrpmb_panic(VuDev *dev, const char *msg)
+{
+    g_critical("%s\n", msg);
+    exit(EXIT_FAILURE);
+}
+
+static uint64_t vrpmb_get_features(VuDev *dev)
+{
+    return 0;
+}
+
+static void vrpmb_set_features(VuDev *dev, uint64_t features)
+{
+    if (features) {
+        g_autoptr(GString) s = g_string_new("Requested un-handled feature");
+        g_string_append_printf(s, " 0x%" PRIx64 "", features);
+        g_info("%s: %s", __func__, s->str);
+    }
+}
+
+/*
+ * The configuration of the device is static and set when we start the
+ * daemon.
+ */
+static int
+vrpmb_get_config(VuDev *dev, uint8_t *config, uint32_t len)
+{
+    VuRpmb *r = container_of(dev, VuRpmb, dev.parent);
+    g_return_val_if_fail(len <= sizeof(struct virtio_rpmb_config), -1);
+    memcpy(config, &r->virtio_config, len);
+    return 0;
+}
+
+static int
+vrpmb_set_config(VuDev *dev, const uint8_t *data,
+                 uint32_t offset, uint32_t size,
+                 uint32_t flags)
+{
+    /* ignore */
+    return 0;
+}
+
+static void
+vrpmb_handle_ctrl(VuDev *dev, int qidx)
+{
+    VuVirtq *vq = vu_get_queue(dev, qidx);
+    struct virtio_rpmb_ctrl_command *cmd = NULL;
+
+    for (;;) {
+        cmd = vu_queue_pop(dev, vq, sizeof(struct virtio_rpmb_ctrl_command));
+        if (!cmd) {
+            break;
+        }
+
+        g_debug("un-handled cmd: %p", cmd);
+    }
+}
+
+static void
+vrpmb_queue_set_started(VuDev *dev, int qidx, bool started)
+{
+    VuVirtq *vq = vu_get_queue(dev, qidx);
+
+    g_debug("queue started %d:%d\n", qidx, started);
+
+    switch (qidx) {
+    case 0:
+        vu_set_queue_handler(dev, vq, started ? vrpmb_handle_ctrl : NULL);
+        break;
+    default:
+        break;
+    }
+}
+
+static int
+vrpmb_process_msg(VuDev *dev, VhostUserMsg *msg, int *do_reply)
+{
+    switch (msg->request) {
+    default:
+        return 0;
+    }
+
+    return 0;
+}
+
+static const VuDevIface vuiface = {
+    .set_features = vrpmb_set_features,
+    .get_features = vrpmb_get_features,
+    .queue_set_started = vrpmb_queue_set_started,
+    .process_msg = vrpmb_process_msg,
+    .get_config = vrpmb_get_config,
+    .set_config = vrpmb_set_config,
+};
+
+static void vrpmb_destroy(VuRpmb *r)
+{
+    vug_deinit(&r->dev);
+}
+
 /* Print vhost-user.json backend program capabilities */
 static void print_capabilities(void)
 {
@@ -33,8 +187,11 @@ int main (int argc, char *argv[])
 {
     GError *error = NULL;
     GOptionContext *context;
+    g_autoptr(GMainLoop) loop = NULL;
+    g_autoptr(GSocket) socket = NULL;
+    VuRpmb rpmb = {  };
 
-    context = g_option_context_new ("vhost-user-rpmb - vhost-user emulation of RPBM device");
+    context = g_option_context_new ("vhost-user emulation of RPBM device");
     g_option_context_add_main_entries (context, options, "vhost-user-rpmb");
     if (!g_option_context_parse (context, &argc, &argv, &error))
     {
@@ -47,4 +204,54 @@ int main (int argc, char *argv[])
         exit(0);
     }
 
+    if (!socket_path && socket_fd < 0) {
+        g_printerr("Please specify either --fd or --socket-path\n");
+        exit(EXIT_FAILURE);
+    }
+
+    /*
+     * Now create a vhost-user socket that we will receive messages
+     * on. Once we have our handler set up we can enter the glib main
+     * loop.
+     */
+    if (socket_path) {
+        g_autoptr(GSocketAddress) addr = g_unix_socket_address_new(socket_path);
+        g_autoptr(GSocket) bind_socket = g_socket_new(G_SOCKET_FAMILY_UNIX, G_SOCKET_TYPE_STREAM,
+                                                      G_SOCKET_PROTOCOL_DEFAULT, &error);
+
+        if (!g_socket_bind(bind_socket, addr, false, &error)) {
+            g_printerr("Failed to bind to socket at %s (%s).\n",
+                       socket_path, error->message);
+            exit(EXIT_FAILURE);
+        }
+        if (!g_socket_listen(bind_socket, &error)) {
+            g_printerr("Failed to listen on socket %s (%s).\n",
+                       socket_path, error->message);
+        }
+        g_message("awaiting connection to %s", socket_path);
+        socket = g_socket_accept(bind_socket, NULL, &error);
+        if (!socket) {
+            g_printerr("Failed to accept on socket %s (%s).\n",
+                       socket_path, error->message);
+        }
+    } else {
+        socket = g_socket_new_from_fd(socket_fd, &error);
+        if (!socket) {
+            g_printerr("Failed to connect to FD %d (%s).\n",
+                       socket_fd, error->message);
+            exit(EXIT_FAILURE);
+        }
+    }
+
+    if (!vug_init(&rpmb.dev, VHOST_USER_RPMB_MAX_QUEUES, g_socket_get_fd(socket),
+                  vrpmb_panic, &vuiface)) {
+        g_printerr("Failed to initialize libvhost-user-glib.\n");
+        exit(EXIT_FAILURE);
+    }
+
+    loop = g_main_loop_new(NULL, FALSE);
+    g_main_loop_run(loop);
+    g_main_loop_unref(loop);
+
+    vrpmb_destroy(&rpmb);
 }
diff --git a/tools/vhost-user-rpmb/meson.build b/tools/vhost-user-rpmb/meson.build
index e0df1b69a3fb..cf80bedd99ac 100644
--- a/tools/vhost-user-rpmb/meson.build
+++ b/tools/vhost-user-rpmb/meson.build
@@ -1,6 +1,6 @@
 executable('vhost-user-rpmb', files(
   'main.c'),
-  dependencies: [glib],
+  dependencies: [qemuutil, glib, gio],
   link_with: [libvhost_user],
   install: true,
   install_dir: get_option('libexecdir'))
-- 
2.20.1

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

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

* [RFC PATCH 09/19] tools/vhost-user-rpmb: add a --verbose/debug flags for logging
  2020-09-25 12:51 ` Alex Bennée
@ 2020-09-25 12:51   ` Alex Bennée
  -1 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2020-09-25 12:51 UTC (permalink / raw)
  To: qemu-devel, maxim.uvarov, joakim.bech, ilias.apalodimas,
	tomas.winkler, yang.huang, bing.zhu, Matti.Moell, hmo
  Cc: jean-philippe, takahiro.akashi, virtualization, Alex Bennée,
	arnd, stratos-dev

This gives us two levels of informational output when tracing what the
daemon is doing.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 tools/vhost-user-rpmb/main.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/tools/vhost-user-rpmb/main.c b/tools/vhost-user-rpmb/main.c
index 269c86cbb633..1be0d4b8a567 100644
--- a/tools/vhost-user-rpmb/main.c
+++ b/tools/vhost-user-rpmb/main.c
@@ -6,6 +6,9 @@
  * SPDX-License-Identifier: GPL-2.0-or-later
  */
 
+#define G_LOG_DOMAIN "vhost-user-rpmb"
+#define G_LOG_USE_STRUCTURED 1
+
 #include <glib.h>
 #include <gio/gio.h>
 #include <gio/gunixsocketaddress.h>
@@ -25,12 +28,16 @@
 static gchar *socket_path;
 static gint socket_fd = -1;
 static gboolean print_cap;
+static gboolean verbose;
+static gboolean debug;
 
 static GOptionEntry options[] =
 {
     { "socket-path", 0, 0, G_OPTION_ARG_FILENAME, &socket_path, "Location of vhost-user Unix domain socket, incompatible with --fd", "PATH" },
     { "fd", 0, 0, G_OPTION_ARG_INT, &socket_fd, "Specify the file-descriptor of the backend, incompatible with --socket-path", "FD" },
     { "print-capabilities", 0, 0, G_OPTION_ARG_NONE, &print_cap, "Output to stdout the backend capabilities in JSON format and exit", NULL},
+    { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Be more verbose in output", NULL},
+    { "debug", 0, 0, G_OPTION_ARG_NONE, &debug, "Include debug output", NULL},
     { NULL }
 };
 
@@ -84,6 +91,7 @@ static void vrpmb_panic(VuDev *dev, const char *msg)
 
 static uint64_t vrpmb_get_features(VuDev *dev)
 {
+    g_info("%s: replying", __func__);
     return 0;
 }
 
@@ -209,6 +217,17 @@ int main (int argc, char *argv[])
         exit(EXIT_FAILURE);
     }
 
+    if (verbose || debug) {
+        g_log_set_handler(NULL, G_LOG_LEVEL_MASK, g_log_default_handler, NULL);
+        if (debug) {
+            g_setenv("G_MESSAGES_DEBUG", "all", true);
+        }
+    } else {
+        g_log_set_handler(NULL,
+                          G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_ERROR,
+                          g_log_default_handler, NULL);
+    }
+
     /*
      * Now create a vhost-user socket that we will receive messages
      * on. Once we have our handler set up we can enter the glib main
-- 
2.20.1



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

* [RFC PATCH 09/19] tools/vhost-user-rpmb: add a --verbose/debug flags for logging
@ 2020-09-25 12:51   ` Alex Bennée
  0 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2020-09-25 12:51 UTC (permalink / raw)
  To: qemu-devel, maxim.uvarov, joakim.bech, ilias.apalodimas,
	tomas.winkler, yang.huang, bing.zhu, Matti.Moell, hmo
  Cc: jean-philippe, takahiro.akashi, virtualization, arnd, stratos-dev

This gives us two levels of informational output when tracing what the
daemon is doing.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 tools/vhost-user-rpmb/main.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/tools/vhost-user-rpmb/main.c b/tools/vhost-user-rpmb/main.c
index 269c86cbb633..1be0d4b8a567 100644
--- a/tools/vhost-user-rpmb/main.c
+++ b/tools/vhost-user-rpmb/main.c
@@ -6,6 +6,9 @@
  * SPDX-License-Identifier: GPL-2.0-or-later
  */
 
+#define G_LOG_DOMAIN "vhost-user-rpmb"
+#define G_LOG_USE_STRUCTURED 1
+
 #include <glib.h>
 #include <gio/gio.h>
 #include <gio/gunixsocketaddress.h>
@@ -25,12 +28,16 @@
 static gchar *socket_path;
 static gint socket_fd = -1;
 static gboolean print_cap;
+static gboolean verbose;
+static gboolean debug;
 
 static GOptionEntry options[] =
 {
     { "socket-path", 0, 0, G_OPTION_ARG_FILENAME, &socket_path, "Location of vhost-user Unix domain socket, incompatible with --fd", "PATH" },
     { "fd", 0, 0, G_OPTION_ARG_INT, &socket_fd, "Specify the file-descriptor of the backend, incompatible with --socket-path", "FD" },
     { "print-capabilities", 0, 0, G_OPTION_ARG_NONE, &print_cap, "Output to stdout the backend capabilities in JSON format and exit", NULL},
+    { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Be more verbose in output", NULL},
+    { "debug", 0, 0, G_OPTION_ARG_NONE, &debug, "Include debug output", NULL},
     { NULL }
 };
 
@@ -84,6 +91,7 @@ static void vrpmb_panic(VuDev *dev, const char *msg)
 
 static uint64_t vrpmb_get_features(VuDev *dev)
 {
+    g_info("%s: replying", __func__);
     return 0;
 }
 
@@ -209,6 +217,17 @@ int main (int argc, char *argv[])
         exit(EXIT_FAILURE);
     }
 
+    if (verbose || debug) {
+        g_log_set_handler(NULL, G_LOG_LEVEL_MASK, g_log_default_handler, NULL);
+        if (debug) {
+            g_setenv("G_MESSAGES_DEBUG", "all", true);
+        }
+    } else {
+        g_log_set_handler(NULL,
+                          G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_ERROR,
+                          g_log_default_handler, NULL);
+    }
+
     /*
      * Now create a vhost-user socket that we will receive messages
      * on. Once we have our handler set up we can enter the glib main
-- 
2.20.1

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

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

* [RFC PATCH 10/19] tools/vhost-user-rpmb: handle shutdown and SIGINT/SIGHUP cleanly
  2020-09-25 12:51 ` Alex Bennée
@ 2020-09-25 12:51   ` Alex Bennée
  -1 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2020-09-25 12:51 UTC (permalink / raw)
  To: qemu-devel, maxim.uvarov, joakim.bech, ilias.apalodimas,
	tomas.winkler, yang.huang, bing.zhu, Matti.Moell, hmo
  Cc: jean-philippe, takahiro.akashi, virtualization, Alex Bennée,
	arnd, stratos-dev

The libvhost-user library will just exit if it handles the
VHOST_USER_NONE message and we want to ensure we have tidied up after
ourselves. As we need to signal the shutdown of the main loop we need
to move the information into the VuRmb state structure.

We also want to do the same if we catch a SIGINT/SIGHUP termination
signal. While we are at it add some instrumentation so we can follow
the program flow.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 tools/vhost-user-rpmb/main.c | 49 +++++++++++++++++++++++++++++++-----
 1 file changed, 43 insertions(+), 6 deletions(-)

diff --git a/tools/vhost-user-rpmb/main.c b/tools/vhost-user-rpmb/main.c
index 1be0d4b8a567..7b3b29ccfc5b 100644
--- a/tools/vhost-user-rpmb/main.c
+++ b/tools/vhost-user-rpmb/main.c
@@ -12,6 +12,7 @@
 #include <glib.h>
 #include <gio/gio.h>
 #include <gio/gunixsocketaddress.h>
+#include <glib-unix.h>
 #include <stdio.h>
 #include <string.h>
 #include <inttypes.h>
@@ -73,6 +74,7 @@ struct virtio_rpmb_frame {
 typedef struct VuRpmb {
     VugDev dev;
     struct virtio_rpmb_config virtio_config;
+    GMainLoop *loop;
 } VuRpmb;
 
 struct virtio_rpmb_ctrl_command {
@@ -158,10 +160,22 @@ vrpmb_queue_set_started(VuDev *dev, int qidx, bool started)
     }
 }
 
-static int
-vrpmb_process_msg(VuDev *dev, VhostUserMsg *msg, int *do_reply)
+/*
+ * vrpmb_process_msg: process messages of vhost-user interface
+ *
+ * Any that are not handled here are processed by the libvhost library
+ * itself.
+ */
+static int vrpmb_process_msg(VuDev *dev, VhostUserMsg *msg, int *do_reply)
 {
+    VuRpmb *r = container_of(dev, VuRpmb, dev.parent);
+
+    g_info("%s: msg %d", __func__, msg->request);
+
     switch (msg->request) {
+    case VHOST_USER_NONE:
+        g_main_loop_quit(r->loop);
+        return 1;
     default:
         return 0;
     }
@@ -181,6 +195,9 @@ static const VuDevIface vuiface = {
 static void vrpmb_destroy(VuRpmb *r)
 {
     vug_deinit(&r->dev);
+    if (socket_path) {
+        unlink(socket_path);
+    }
 }
 
 /* Print vhost-user.json backend program capabilities */
@@ -191,11 +208,18 @@ static void print_capabilities(void)
     printf("}\n");
 }
 
+static gboolean hangup(gpointer user_data)
+{
+    GMainLoop *loop = (GMainLoop *) user_data;
+    g_info("%s: caught hangup/quit signal, quitting main loop", __func__);
+    g_main_loop_quit(loop);
+    return true;
+}
+
 int main (int argc, char *argv[])
 {
     GError *error = NULL;
     GOptionContext *context;
-    g_autoptr(GMainLoop) loop = NULL;
     g_autoptr(GSocket) socket = NULL;
     VuRpmb rpmb = {  };
 
@@ -262,15 +286,28 @@ int main (int argc, char *argv[])
         }
     }
 
+    /*
+     * Create the main loop first so all the various sources can be
+     * added. As well as catching signals we need to ensure vug_init
+     * can add it's GSource watches.
+     */
+
+    rpmb.loop = g_main_loop_new(NULL, FALSE);
+    /* catch exit signals */
+    g_unix_signal_add(SIGHUP, hangup, rpmb.loop);
+    g_unix_signal_add(SIGINT, hangup, rpmb.loop);
+
     if (!vug_init(&rpmb.dev, VHOST_USER_RPMB_MAX_QUEUES, g_socket_get_fd(socket),
                   vrpmb_panic, &vuiface)) {
         g_printerr("Failed to initialize libvhost-user-glib.\n");
         exit(EXIT_FAILURE);
     }
 
-    loop = g_main_loop_new(NULL, FALSE);
-    g_main_loop_run(loop);
-    g_main_loop_unref(loop);
 
+    g_message("entering main loop, awaiting messages");
+    g_main_loop_run(rpmb.loop);
+    g_message("finished main loop, cleaning up");
+
+    g_main_loop_unref(rpmb.loop);
     vrpmb_destroy(&rpmb);
 }
-- 
2.20.1



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

* [RFC PATCH 10/19] tools/vhost-user-rpmb: handle shutdown and SIGINT/SIGHUP cleanly
@ 2020-09-25 12:51   ` Alex Bennée
  0 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2020-09-25 12:51 UTC (permalink / raw)
  To: qemu-devel, maxim.uvarov, joakim.bech, ilias.apalodimas,
	tomas.winkler, yang.huang, bing.zhu, Matti.Moell, hmo
  Cc: jean-philippe, takahiro.akashi, virtualization, arnd, stratos-dev

The libvhost-user library will just exit if it handles the
VHOST_USER_NONE message and we want to ensure we have tidied up after
ourselves. As we need to signal the shutdown of the main loop we need
to move the information into the VuRmb state structure.

We also want to do the same if we catch a SIGINT/SIGHUP termination
signal. While we are at it add some instrumentation so we can follow
the program flow.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 tools/vhost-user-rpmb/main.c | 49 +++++++++++++++++++++++++++++++-----
 1 file changed, 43 insertions(+), 6 deletions(-)

diff --git a/tools/vhost-user-rpmb/main.c b/tools/vhost-user-rpmb/main.c
index 1be0d4b8a567..7b3b29ccfc5b 100644
--- a/tools/vhost-user-rpmb/main.c
+++ b/tools/vhost-user-rpmb/main.c
@@ -12,6 +12,7 @@
 #include <glib.h>
 #include <gio/gio.h>
 #include <gio/gunixsocketaddress.h>
+#include <glib-unix.h>
 #include <stdio.h>
 #include <string.h>
 #include <inttypes.h>
@@ -73,6 +74,7 @@ struct virtio_rpmb_frame {
 typedef struct VuRpmb {
     VugDev dev;
     struct virtio_rpmb_config virtio_config;
+    GMainLoop *loop;
 } VuRpmb;
 
 struct virtio_rpmb_ctrl_command {
@@ -158,10 +160,22 @@ vrpmb_queue_set_started(VuDev *dev, int qidx, bool started)
     }
 }
 
-static int
-vrpmb_process_msg(VuDev *dev, VhostUserMsg *msg, int *do_reply)
+/*
+ * vrpmb_process_msg: process messages of vhost-user interface
+ *
+ * Any that are not handled here are processed by the libvhost library
+ * itself.
+ */
+static int vrpmb_process_msg(VuDev *dev, VhostUserMsg *msg, int *do_reply)
 {
+    VuRpmb *r = container_of(dev, VuRpmb, dev.parent);
+
+    g_info("%s: msg %d", __func__, msg->request);
+
     switch (msg->request) {
+    case VHOST_USER_NONE:
+        g_main_loop_quit(r->loop);
+        return 1;
     default:
         return 0;
     }
@@ -181,6 +195,9 @@ static const VuDevIface vuiface = {
 static void vrpmb_destroy(VuRpmb *r)
 {
     vug_deinit(&r->dev);
+    if (socket_path) {
+        unlink(socket_path);
+    }
 }
 
 /* Print vhost-user.json backend program capabilities */
@@ -191,11 +208,18 @@ static void print_capabilities(void)
     printf("}\n");
 }
 
+static gboolean hangup(gpointer user_data)
+{
+    GMainLoop *loop = (GMainLoop *) user_data;
+    g_info("%s: caught hangup/quit signal, quitting main loop", __func__);
+    g_main_loop_quit(loop);
+    return true;
+}
+
 int main (int argc, char *argv[])
 {
     GError *error = NULL;
     GOptionContext *context;
-    g_autoptr(GMainLoop) loop = NULL;
     g_autoptr(GSocket) socket = NULL;
     VuRpmb rpmb = {  };
 
@@ -262,15 +286,28 @@ int main (int argc, char *argv[])
         }
     }
 
+    /*
+     * Create the main loop first so all the various sources can be
+     * added. As well as catching signals we need to ensure vug_init
+     * can add it's GSource watches.
+     */
+
+    rpmb.loop = g_main_loop_new(NULL, FALSE);
+    /* catch exit signals */
+    g_unix_signal_add(SIGHUP, hangup, rpmb.loop);
+    g_unix_signal_add(SIGINT, hangup, rpmb.loop);
+
     if (!vug_init(&rpmb.dev, VHOST_USER_RPMB_MAX_QUEUES, g_socket_get_fd(socket),
                   vrpmb_panic, &vuiface)) {
         g_printerr("Failed to initialize libvhost-user-glib.\n");
         exit(EXIT_FAILURE);
     }
 
-    loop = g_main_loop_new(NULL, FALSE);
-    g_main_loop_run(loop);
-    g_main_loop_unref(loop);
 
+    g_message("entering main loop, awaiting messages");
+    g_main_loop_run(rpmb.loop);
+    g_message("finished main loop, cleaning up");
+
+    g_main_loop_unref(rpmb.loop);
     vrpmb_destroy(&rpmb);
 }
-- 
2.20.1

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

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

* [RFC PATCH 11/19] tools/vhost-user-rpmb: add --flash-path for backing store
  2020-09-25 12:51 ` Alex Bennée
@ 2020-09-25 12:51   ` Alex Bennée
  -1 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2020-09-25 12:51 UTC (permalink / raw)
  To: qemu-devel, maxim.uvarov, joakim.bech, ilias.apalodimas,
	tomas.winkler, yang.huang, bing.zhu, Matti.Moell, hmo
  Cc: jean-philippe, takahiro.akashi, virtualization, Alex Bennée,
	arnd, stratos-dev

We will need to store the data somewhere so add the option to point to
the file where we will keep the data.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 tools/vhost-user-rpmb/main.c | 58 +++++++++++++++++++++++++++++++++++-
 1 file changed, 57 insertions(+), 1 deletion(-)

diff --git a/tools/vhost-user-rpmb/main.c b/tools/vhost-user-rpmb/main.c
index 7b3b29ccfc5b..64bd7e79f573 100644
--- a/tools/vhost-user-rpmb/main.c
+++ b/tools/vhost-user-rpmb/main.c
@@ -13,9 +13,15 @@
 #include <gio/gio.h>
 #include <gio/gunixsocketaddress.h>
 #include <glib-unix.h>
+#include <glib/gstdio.h>
 #include <stdio.h>
 #include <string.h>
 #include <inttypes.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <unistd.h>
 
 #include "contrib/libvhost-user/libvhost-user-glib.h"
 #include "contrib/libvhost-user/libvhost-user.h"
@@ -27,6 +33,7 @@
 #endif
 
 static gchar *socket_path;
+static char *flash_path;
 static gint socket_fd = -1;
 static gboolean print_cap;
 static gboolean verbose;
@@ -35,6 +42,7 @@ static gboolean debug;
 static GOptionEntry options[] =
 {
     { "socket-path", 0, 0, G_OPTION_ARG_FILENAME, &socket_path, "Location of vhost-user Unix domain socket, incompatible with --fd", "PATH" },
+    { "flash-path", 0, 0, G_OPTION_ARG_FILENAME, &flash_path, "Location of raw flash image file", "PATH" },
     { "fd", 0, 0, G_OPTION_ARG_INT, &socket_fd, "Specify the file-descriptor of the backend, incompatible with --socket-path", "FD" },
     { "print-capabilities", 0, 0, G_OPTION_ARG_NONE, &print_cap, "Output to stdout the backend capabilities in JSON format and exit", NULL},
     { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Be more verbose in output", NULL},
@@ -47,6 +55,8 @@ enum {
 };
 
 /* These structures are defined in the specification */
+#define KiB     (1UL << 10)
+#define MAX_RPMB_SIZE (KiB * 128 * 256)
 
 struct virtio_rpmb_config {
     uint8_t capacity;
@@ -75,6 +85,8 @@ typedef struct VuRpmb {
     VugDev dev;
     struct virtio_rpmb_config virtio_config;
     GMainLoop *loop;
+    int flash_fd;
+    void *flash_map;
 } VuRpmb;
 
 struct virtio_rpmb_ctrl_command {
@@ -116,6 +128,8 @@ vrpmb_get_config(VuDev *dev, uint8_t *config, uint32_t len)
     VuRpmb *r = container_of(dev, VuRpmb, dev.parent);
     g_return_val_if_fail(len <= sizeof(struct virtio_rpmb_config), -1);
     memcpy(config, &r->virtio_config, len);
+
+    g_info("%s: done", __func__);
     return 0;
 }
 
@@ -192,6 +206,41 @@ static const VuDevIface vuiface = {
     .set_config = vrpmb_set_config,
 };
 
+static bool vrpmb_load_flash_image(VuRpmb *r, char *img_path)
+{
+    GStatBuf statbuf;
+    size_t map_size;
+
+    if (g_stat(img_path, &statbuf) < 0) {
+        g_error("couldn't stat %s", img_path);
+        return false;
+    }
+
+    r->flash_fd = g_open(img_path, O_RDWR, 0);
+    if (r->flash_fd < 0) {
+        g_error("couldn't open %s (%s)", img_path, strerror(errno));
+        return false;
+    }
+
+    if (statbuf.st_size > MAX_RPMB_SIZE) {
+        g_warning("%s larger than maximum size supported", img_path);
+        map_size = MAX_RPMB_SIZE;
+    } else {
+        map_size = statbuf.st_size;
+    }
+    r->virtio_config.capacity = map_size / (128 *KiB);
+    r->virtio_config.max_wr_cnt = 1;
+    r->virtio_config.max_rd_cnt = 1;
+
+    r->flash_map = mmap(NULL, map_size, PROT_READ, MAP_SHARED, r->flash_fd, 0);
+    if (r->flash_map == MAP_FAILED) {
+        g_error("failed to mmap file");
+        return false;
+    }
+
+    return true;
+}
+
 static void vrpmb_destroy(VuRpmb *r)
 {
     vug_deinit(&r->dev);
@@ -216,7 +265,7 @@ static gboolean hangup(gpointer user_data)
     return true;
 }
 
-int main (int argc, char *argv[])
+int main(int argc, char *argv[])
 {
     GError *error = NULL;
     GOptionContext *context;
@@ -236,6 +285,13 @@ int main (int argc, char *argv[])
         exit(0);
     }
 
+    if (!flash_path || !g_file_test(flash_path, G_FILE_TEST_EXISTS)) {
+        g_printerr("Please specify a valid --flash-path for the flash image\n");
+        exit(EXIT_FAILURE);
+    } else {
+        vrpmb_load_flash_image(&rpmb, flash_path);
+    }
+
     if (!socket_path && socket_fd < 0) {
         g_printerr("Please specify either --fd or --socket-path\n");
         exit(EXIT_FAILURE);
-- 
2.20.1



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

* [RFC PATCH 11/19] tools/vhost-user-rpmb: add --flash-path for backing store
@ 2020-09-25 12:51   ` Alex Bennée
  0 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2020-09-25 12:51 UTC (permalink / raw)
  To: qemu-devel, maxim.uvarov, joakim.bech, ilias.apalodimas,
	tomas.winkler, yang.huang, bing.zhu, Matti.Moell, hmo
  Cc: jean-philippe, takahiro.akashi, virtualization, arnd, stratos-dev

We will need to store the data somewhere so add the option to point to
the file where we will keep the data.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 tools/vhost-user-rpmb/main.c | 58 +++++++++++++++++++++++++++++++++++-
 1 file changed, 57 insertions(+), 1 deletion(-)

diff --git a/tools/vhost-user-rpmb/main.c b/tools/vhost-user-rpmb/main.c
index 7b3b29ccfc5b..64bd7e79f573 100644
--- a/tools/vhost-user-rpmb/main.c
+++ b/tools/vhost-user-rpmb/main.c
@@ -13,9 +13,15 @@
 #include <gio/gio.h>
 #include <gio/gunixsocketaddress.h>
 #include <glib-unix.h>
+#include <glib/gstdio.h>
 #include <stdio.h>
 #include <string.h>
 #include <inttypes.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <unistd.h>
 
 #include "contrib/libvhost-user/libvhost-user-glib.h"
 #include "contrib/libvhost-user/libvhost-user.h"
@@ -27,6 +33,7 @@
 #endif
 
 static gchar *socket_path;
+static char *flash_path;
 static gint socket_fd = -1;
 static gboolean print_cap;
 static gboolean verbose;
@@ -35,6 +42,7 @@ static gboolean debug;
 static GOptionEntry options[] =
 {
     { "socket-path", 0, 0, G_OPTION_ARG_FILENAME, &socket_path, "Location of vhost-user Unix domain socket, incompatible with --fd", "PATH" },
+    { "flash-path", 0, 0, G_OPTION_ARG_FILENAME, &flash_path, "Location of raw flash image file", "PATH" },
     { "fd", 0, 0, G_OPTION_ARG_INT, &socket_fd, "Specify the file-descriptor of the backend, incompatible with --socket-path", "FD" },
     { "print-capabilities", 0, 0, G_OPTION_ARG_NONE, &print_cap, "Output to stdout the backend capabilities in JSON format and exit", NULL},
     { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Be more verbose in output", NULL},
@@ -47,6 +55,8 @@ enum {
 };
 
 /* These structures are defined in the specification */
+#define KiB     (1UL << 10)
+#define MAX_RPMB_SIZE (KiB * 128 * 256)
 
 struct virtio_rpmb_config {
     uint8_t capacity;
@@ -75,6 +85,8 @@ typedef struct VuRpmb {
     VugDev dev;
     struct virtio_rpmb_config virtio_config;
     GMainLoop *loop;
+    int flash_fd;
+    void *flash_map;
 } VuRpmb;
 
 struct virtio_rpmb_ctrl_command {
@@ -116,6 +128,8 @@ vrpmb_get_config(VuDev *dev, uint8_t *config, uint32_t len)
     VuRpmb *r = container_of(dev, VuRpmb, dev.parent);
     g_return_val_if_fail(len <= sizeof(struct virtio_rpmb_config), -1);
     memcpy(config, &r->virtio_config, len);
+
+    g_info("%s: done", __func__);
     return 0;
 }
 
@@ -192,6 +206,41 @@ static const VuDevIface vuiface = {
     .set_config = vrpmb_set_config,
 };
 
+static bool vrpmb_load_flash_image(VuRpmb *r, char *img_path)
+{
+    GStatBuf statbuf;
+    size_t map_size;
+
+    if (g_stat(img_path, &statbuf) < 0) {
+        g_error("couldn't stat %s", img_path);
+        return false;
+    }
+
+    r->flash_fd = g_open(img_path, O_RDWR, 0);
+    if (r->flash_fd < 0) {
+        g_error("couldn't open %s (%s)", img_path, strerror(errno));
+        return false;
+    }
+
+    if (statbuf.st_size > MAX_RPMB_SIZE) {
+        g_warning("%s larger than maximum size supported", img_path);
+        map_size = MAX_RPMB_SIZE;
+    } else {
+        map_size = statbuf.st_size;
+    }
+    r->virtio_config.capacity = map_size / (128 *KiB);
+    r->virtio_config.max_wr_cnt = 1;
+    r->virtio_config.max_rd_cnt = 1;
+
+    r->flash_map = mmap(NULL, map_size, PROT_READ, MAP_SHARED, r->flash_fd, 0);
+    if (r->flash_map == MAP_FAILED) {
+        g_error("failed to mmap file");
+        return false;
+    }
+
+    return true;
+}
+
 static void vrpmb_destroy(VuRpmb *r)
 {
     vug_deinit(&r->dev);
@@ -216,7 +265,7 @@ static gboolean hangup(gpointer user_data)
     return true;
 }
 
-int main (int argc, char *argv[])
+int main(int argc, char *argv[])
 {
     GError *error = NULL;
     GOptionContext *context;
@@ -236,6 +285,13 @@ int main (int argc, char *argv[])
         exit(0);
     }
 
+    if (!flash_path || !g_file_test(flash_path, G_FILE_TEST_EXISTS)) {
+        g_printerr("Please specify a valid --flash-path for the flash image\n");
+        exit(EXIT_FAILURE);
+    } else {
+        vrpmb_load_flash_image(&rpmb, flash_path);
+    }
+
     if (!socket_path && socket_fd < 0) {
         g_printerr("Please specify either --fd or --socket-path\n");
         exit(EXIT_FAILURE);
-- 
2.20.1

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

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

* [RFC PATCH 12/19] tools/vhost-user-rpmb: import hmac_sha256 functions
  2020-09-25 12:51 ` Alex Bennée
@ 2020-09-25 12:51   ` Alex Bennée
  -1 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2020-09-25 12:51 UTC (permalink / raw)
  To: qemu-devel, maxim.uvarov, joakim.bech, ilias.apalodimas,
	tomas.winkler, yang.huang, bing.zhu, Matti.Moell, hmo
  Cc: jean-philippe, takahiro.akashi, virtualization, Alex Bennée,
	arnd, stratos-dev

We need to calculate HMAC-256SHA as part of the protocol. To avoid
making the daemon dependent on QEMU's internal crypto library we
import the functions here.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 tools/vhost-user-rpmb/hmac_sha256.h |  87 ++++++++
 tools/vhost-user-rpmb/hmac_sha256.c | 331 ++++++++++++++++++++++++++++
 tools/vhost-user-rpmb/meson.build   |   3 +-
 3 files changed, 420 insertions(+), 1 deletion(-)
 create mode 100644 tools/vhost-user-rpmb/hmac_sha256.h
 create mode 100644 tools/vhost-user-rpmb/hmac_sha256.c

diff --git a/tools/vhost-user-rpmb/hmac_sha256.h b/tools/vhost-user-rpmb/hmac_sha256.h
new file mode 100644
index 000000000000..e67a5baedecd
--- /dev/null
+++ b/tools/vhost-user-rpmb/hmac_sha256.h
@@ -0,0 +1,87 @@
+/*
+ * HMAC-SHA-256 implementation
+ * Last update: 06/15/2005
+ * Issue date:  06/15/2005
+ *
+ * Copyright (C) 2005 Olivier Gay <olivier.gay@a3.epfl.ch>
+ * All rights reserved.
+ *
+ * Copyright (c) 2016, 2020, Linaro Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef HMAC_SHA256_H
+#define HMAC_SHA256_H
+
+#define SHA256_DIGEST_SIZE ( 256 / 8)
+#define SHA256_BLOCK_SIZE  ( 512 / 8)
+
+#ifndef SHA2_TYPES
+#define SHA2_TYPES
+typedef unsigned char uint8;
+typedef unsigned int  uint32;
+typedef unsigned long long uint64;
+#endif
+
+typedef struct {
+    unsigned int tot_len;
+    unsigned int len;
+    unsigned char block[2 * SHA256_BLOCK_SIZE];
+    uint32 h[8];
+} sha256_ctx;
+
+void sha256_init(sha256_ctx * ctx);
+void sha256_update(sha256_ctx *ctx, const unsigned char *message,
+                   unsigned int len);
+void sha256_final(sha256_ctx *ctx, unsigned char *digest);
+void sha256(const unsigned char *message, unsigned int len,
+            unsigned char *digest);
+
+typedef struct {
+    sha256_ctx ctx_inside;
+    sha256_ctx ctx_outside;
+
+    /* for hmac_reinit */
+    sha256_ctx ctx_inside_reinit;
+    sha256_ctx ctx_outside_reinit;
+
+    unsigned char block_ipad[SHA256_BLOCK_SIZE];
+    unsigned char block_opad[SHA256_BLOCK_SIZE];
+} hmac_sha256_ctx;
+
+void hmac_sha256_init(hmac_sha256_ctx *ctx, const unsigned char *key,
+                      unsigned int key_size);
+void hmac_sha256_reinit(hmac_sha256_ctx *ctx);
+void hmac_sha256_update(hmac_sha256_ctx *ctx, const unsigned char *message,
+                        unsigned int message_len);
+void hmac_sha256_final(hmac_sha256_ctx *ctx, unsigned char *mac,
+                       unsigned int mac_size);
+void hmac_sha256(const unsigned char *key, unsigned int key_size,
+                 const unsigned char *message, unsigned int message_len,
+                 unsigned char *mac, unsigned mac_size);
+
+#endif /* !HMAC_SHA256_H */
diff --git a/tools/vhost-user-rpmb/hmac_sha256.c b/tools/vhost-user-rpmb/hmac_sha256.c
new file mode 100644
index 000000000000..f6640a46c616
--- /dev/null
+++ b/tools/vhost-user-rpmb/hmac_sha256.c
@@ -0,0 +1,331 @@
+/*
+ * HMAC-SHA-256 implementation
+ * Last update: 06/15/2005
+ * Issue date:  06/15/2005
+ *
+ * Copyright (C) 2005 Olivier Gay <olivier.gay@a3.epfl.ch>
+ * All rights reserved.
+ *
+ * Copyright (c) 2016, 2020 Linaro Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <string.h>
+
+#include "hmac_sha256.h"
+
+/* SHA256 functions */
+
+#define SHFR(x, n)    (x >> n)
+#define ROTR(x, n)   ((x >> n) | (x << ((sizeof(x) << 3) - n)))
+#define ROTL(x, n)   ((x << n) | (x >> ((sizeof(x) << 3) - n)))
+#define CH(x, y, z)  ((x & y) ^ (~x & z))
+#define MAJ(x, y, z) ((x & y) ^ (x & z) ^ (y & z))
+
+#define SHA256_F1(x) (ROTR(x,  2) ^ ROTR(x, 13) ^ ROTR(x, 22))
+#define SHA256_F2(x) (ROTR(x,  6) ^ ROTR(x, 11) ^ ROTR(x, 25))
+#define SHA256_F3(x) (ROTR(x,  7) ^ ROTR(x, 18) ^ SHFR(x,  3))
+#define SHA256_F4(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHFR(x, 10))
+
+#define UNPACK32(x, str)                      \
+{                                             \
+    *((str) + 3) = (uint8) ((x)      );       \
+    *((str) + 2) = (uint8) ((x) >>  8);       \
+    *((str) + 1) = (uint8) ((x) >> 16);       \
+    *((str) + 0) = (uint8) ((x) >> 24);       \
+}
+
+#define PACK32(str, x)                        \
+{                                             \
+    *(x) =   ((uint32) *((str) + 3)      )    \
+           | ((uint32) *((str) + 2) <<  8)    \
+           | ((uint32) *((str) + 1) << 16)    \
+           | ((uint32) *((str) + 0) << 24);   \
+}
+
+#define UNPACK64(x, str)                      \
+{                                             \
+    *((str) + 7) = (uint8) ((x)      );       \
+    *((str) + 6) = (uint8) ((x) >>  8);       \
+    *((str) + 5) = (uint8) ((x) >> 16);       \
+    *((str) + 4) = (uint8) ((x) >> 24);       \
+    *((str) + 3) = (uint8) ((x) >> 32);       \
+    *((str) + 2) = (uint8) ((x) >> 40);       \
+    *((str) + 1) = (uint8) ((x) >> 48);       \
+    *((str) + 0) = (uint8) ((x) >> 56);       \
+}
+
+#define PACK64(str, x)                        \
+{                                             \
+    *(x) =   ((uint64) *((str) + 7)      )    \
+           | ((uint64) *((str) + 6) <<  8)    \
+           | ((uint64) *((str) + 5) << 16)    \
+           | ((uint64) *((str) + 4) << 24)    \
+           | ((uint64) *((str) + 3) << 32)    \
+           | ((uint64) *((str) + 2) << 40)    \
+           | ((uint64) *((str) + 1) << 48)    \
+           | ((uint64) *((str) + 0) << 56);   \
+}
+
+#define SHA256_SCR(i)                         \
+{                                             \
+    w[i] =  SHA256_F4(w[i -  2]) + w[i -  7]  \
+          + SHA256_F3(w[i - 15]) + w[i - 16]; \
+}
+
+uint32 sha256_h0[8] =
+            {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
+             0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19};
+
+uint32 sha256_k[64] =
+            {0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
+             0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+             0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
+             0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+             0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
+             0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+             0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
+             0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+             0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
+             0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+             0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
+             0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+             0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
+             0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+             0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
+             0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2};
+
+/* SHA-256 functions */
+
+static void sha256_transf(sha256_ctx *ctx, const unsigned char *message,
+                          unsigned int block_nb)
+{
+    uint32 w[64];
+    uint32 wv[8];
+    uint32 t1, t2;
+    const unsigned char *sub_block;
+    int i;
+    int j;
+
+    for (i = 0; i < (int) block_nb; i++) {
+        sub_block = message + (i << 6);
+
+        for (j = 0; j < 16; j++) {
+            PACK32(&sub_block[j << 2], &w[j]);
+        }
+
+        for (j = 16; j < 64; j++) {
+            SHA256_SCR(j);
+        }
+
+        for (j = 0; j < 8; j++) {
+            wv[j] = ctx->h[j];
+        }
+
+        for (j = 0; j < 64; j++) {
+            t1 = wv[7] + SHA256_F2(wv[4]) + CH(wv[4], wv[5], wv[6])
+                + sha256_k[j] + w[j];
+            t2 = SHA256_F1(wv[0]) + MAJ(wv[0], wv[1], wv[2]);
+            wv[7] = wv[6];
+            wv[6] = wv[5];
+            wv[5] = wv[4];
+            wv[4] = wv[3] + t1;
+            wv[3] = wv[2];
+            wv[2] = wv[1];
+            wv[1] = wv[0];
+            wv[0] = t1 + t2;
+        }
+
+        for (j = 0; j < 8; j++) {
+            ctx->h[j] += wv[j];
+        }
+    }
+}
+
+void sha256(const unsigned char *message, unsigned int len, unsigned char *digest)
+{
+    sha256_ctx ctx;
+
+    sha256_init(&ctx);
+    sha256_update(&ctx, message, len);
+    sha256_final(&ctx, digest);
+}
+
+void sha256_init(sha256_ctx *ctx)
+{
+    int i;
+    for (i = 0; i < 8; i++) {
+        ctx->h[i] = sha256_h0[i];
+    }
+
+    ctx->len = 0;
+    ctx->tot_len = 0;
+}
+
+void sha256_update(sha256_ctx *ctx, const unsigned char *message,
+                   unsigned int len)
+{
+    unsigned int block_nb;
+    unsigned int new_len, rem_len, tmp_len;
+    const unsigned char *shifted_message;
+
+    tmp_len = SHA256_BLOCK_SIZE - ctx->len;
+    rem_len = len < tmp_len ? len : tmp_len;
+
+    memcpy(&ctx->block[ctx->len], message, rem_len);
+
+    if (ctx->len + len < SHA256_BLOCK_SIZE) {
+        ctx->len += len;
+        return;
+    }
+
+    new_len = len - rem_len;
+    block_nb = new_len / SHA256_BLOCK_SIZE;
+
+    shifted_message = message + rem_len;
+
+    sha256_transf(ctx, ctx->block, 1);
+    sha256_transf(ctx, shifted_message, block_nb);
+
+    rem_len = new_len % SHA256_BLOCK_SIZE;
+
+    memcpy(ctx->block, &shifted_message[block_nb << 6],
+           rem_len);
+
+    ctx->len = rem_len;
+    ctx->tot_len += (block_nb + 1) << 6;
+}
+
+void sha256_final(sha256_ctx *ctx, unsigned char *digest)
+{
+    unsigned int block_nb;
+    unsigned int pm_len;
+    unsigned int len_b;
+    int i;
+
+    block_nb = (1 + ((SHA256_BLOCK_SIZE - 9)
+                     < (ctx->len % SHA256_BLOCK_SIZE)));
+
+    len_b = (ctx->tot_len + ctx->len) << 3;
+    pm_len = block_nb << 6;
+
+    memset(ctx->block + ctx->len, 0, pm_len - ctx->len);
+    ctx->block[ctx->len] = 0x80;
+    UNPACK32(len_b, ctx->block + pm_len - 4);
+
+    sha256_transf(ctx, ctx->block, block_nb);
+
+    for (i = 0 ; i < 8; i++) {
+        UNPACK32(ctx->h[i], &digest[i << 2]);
+    }
+}
+
+/* HMAC-SHA-256 functions */
+
+void hmac_sha256_init(hmac_sha256_ctx *ctx, const unsigned char *key,
+                      unsigned int key_size)
+{
+    unsigned int fill;
+    unsigned int num;
+
+    const unsigned char *key_used;
+    unsigned char key_temp[SHA256_DIGEST_SIZE];
+    int i;
+
+    if (key_size == SHA256_BLOCK_SIZE) {
+        key_used = key;
+        num = SHA256_BLOCK_SIZE;
+    } else {
+        if (key_size > SHA256_BLOCK_SIZE){
+            num = SHA256_DIGEST_SIZE;
+            sha256(key, key_size, key_temp);
+            key_used = key_temp;
+        } else { /* key_size > SHA256_BLOCK_SIZE */
+            key_used = key;
+            num = key_size;
+        }
+        fill = SHA256_BLOCK_SIZE - num;
+
+        memset(ctx->block_ipad + num, 0x36, fill);
+        memset(ctx->block_opad + num, 0x5c, fill);
+    }
+
+    for (i = 0; i < (int) num; i++) {
+        ctx->block_ipad[i] = key_used[i] ^ 0x36;
+        ctx->block_opad[i] = key_used[i] ^ 0x5c;
+    }
+
+    sha256_init(&ctx->ctx_inside);
+    sha256_update(&ctx->ctx_inside, ctx->block_ipad, SHA256_BLOCK_SIZE);
+
+    sha256_init(&ctx->ctx_outside);
+    sha256_update(&ctx->ctx_outside, ctx->block_opad,
+                  SHA256_BLOCK_SIZE);
+
+    /* for hmac_reinit */
+    memcpy(&ctx->ctx_inside_reinit, &ctx->ctx_inside,
+           sizeof(sha256_ctx));
+    memcpy(&ctx->ctx_outside_reinit, &ctx->ctx_outside,
+           sizeof(sha256_ctx));
+}
+
+void hmac_sha256_reinit(hmac_sha256_ctx *ctx)
+{
+    memcpy(&ctx->ctx_inside, &ctx->ctx_inside_reinit,
+           sizeof(sha256_ctx));
+    memcpy(&ctx->ctx_outside, &ctx->ctx_outside_reinit,
+           sizeof(sha256_ctx));
+}
+
+void hmac_sha256_update(hmac_sha256_ctx *ctx, const unsigned char *message,
+                        unsigned int message_len)
+{
+    sha256_update(&ctx->ctx_inside, message, message_len);
+}
+
+void hmac_sha256_final(hmac_sha256_ctx *ctx, unsigned char *mac,
+                       unsigned int mac_size)
+{
+    unsigned char digest_inside[SHA256_DIGEST_SIZE];
+    unsigned char mac_temp[SHA256_DIGEST_SIZE];
+
+    sha256_final(&ctx->ctx_inside, digest_inside);
+    sha256_update(&ctx->ctx_outside, digest_inside, SHA256_DIGEST_SIZE);
+    sha256_final(&ctx->ctx_outside, mac_temp);
+    memcpy(mac, mac_temp, mac_size);
+}
+
+void hmac_sha256(const unsigned char *key, unsigned int key_size,
+          const unsigned char *message, unsigned int message_len,
+          unsigned char *mac, unsigned mac_size)
+{
+    hmac_sha256_ctx ctx;
+
+    hmac_sha256_init(&ctx, key, key_size);
+    hmac_sha256_update(&ctx, message, message_len);
+    hmac_sha256_final(&ctx, mac, mac_size);
+}
diff --git a/tools/vhost-user-rpmb/meson.build b/tools/vhost-user-rpmb/meson.build
index cf80bedd99ac..f964837d151d 100644
--- a/tools/vhost-user-rpmb/meson.build
+++ b/tools/vhost-user-rpmb/meson.build
@@ -1,5 +1,6 @@
 executable('vhost-user-rpmb', files(
-  'main.c'),
+  'main.c',
+  'hmac_sha256.c'),
   dependencies: [qemuutil, glib, gio],
   link_with: [libvhost_user],
   install: true,
-- 
2.20.1



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

* [RFC PATCH 12/19] tools/vhost-user-rpmb: import hmac_sha256 functions
@ 2020-09-25 12:51   ` Alex Bennée
  0 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2020-09-25 12:51 UTC (permalink / raw)
  To: qemu-devel, maxim.uvarov, joakim.bech, ilias.apalodimas,
	tomas.winkler, yang.huang, bing.zhu, Matti.Moell, hmo
  Cc: jean-philippe, takahiro.akashi, virtualization, arnd, stratos-dev

We need to calculate HMAC-256SHA as part of the protocol. To avoid
making the daemon dependent on QEMU's internal crypto library we
import the functions here.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 tools/vhost-user-rpmb/hmac_sha256.h |  87 ++++++++
 tools/vhost-user-rpmb/hmac_sha256.c | 331 ++++++++++++++++++++++++++++
 tools/vhost-user-rpmb/meson.build   |   3 +-
 3 files changed, 420 insertions(+), 1 deletion(-)
 create mode 100644 tools/vhost-user-rpmb/hmac_sha256.h
 create mode 100644 tools/vhost-user-rpmb/hmac_sha256.c

diff --git a/tools/vhost-user-rpmb/hmac_sha256.h b/tools/vhost-user-rpmb/hmac_sha256.h
new file mode 100644
index 000000000000..e67a5baedecd
--- /dev/null
+++ b/tools/vhost-user-rpmb/hmac_sha256.h
@@ -0,0 +1,87 @@
+/*
+ * HMAC-SHA-256 implementation
+ * Last update: 06/15/2005
+ * Issue date:  06/15/2005
+ *
+ * Copyright (C) 2005 Olivier Gay <olivier.gay@a3.epfl.ch>
+ * All rights reserved.
+ *
+ * Copyright (c) 2016, 2020, Linaro Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef HMAC_SHA256_H
+#define HMAC_SHA256_H
+
+#define SHA256_DIGEST_SIZE ( 256 / 8)
+#define SHA256_BLOCK_SIZE  ( 512 / 8)
+
+#ifndef SHA2_TYPES
+#define SHA2_TYPES
+typedef unsigned char uint8;
+typedef unsigned int  uint32;
+typedef unsigned long long uint64;
+#endif
+
+typedef struct {
+    unsigned int tot_len;
+    unsigned int len;
+    unsigned char block[2 * SHA256_BLOCK_SIZE];
+    uint32 h[8];
+} sha256_ctx;
+
+void sha256_init(sha256_ctx * ctx);
+void sha256_update(sha256_ctx *ctx, const unsigned char *message,
+                   unsigned int len);
+void sha256_final(sha256_ctx *ctx, unsigned char *digest);
+void sha256(const unsigned char *message, unsigned int len,
+            unsigned char *digest);
+
+typedef struct {
+    sha256_ctx ctx_inside;
+    sha256_ctx ctx_outside;
+
+    /* for hmac_reinit */
+    sha256_ctx ctx_inside_reinit;
+    sha256_ctx ctx_outside_reinit;
+
+    unsigned char block_ipad[SHA256_BLOCK_SIZE];
+    unsigned char block_opad[SHA256_BLOCK_SIZE];
+} hmac_sha256_ctx;
+
+void hmac_sha256_init(hmac_sha256_ctx *ctx, const unsigned char *key,
+                      unsigned int key_size);
+void hmac_sha256_reinit(hmac_sha256_ctx *ctx);
+void hmac_sha256_update(hmac_sha256_ctx *ctx, const unsigned char *message,
+                        unsigned int message_len);
+void hmac_sha256_final(hmac_sha256_ctx *ctx, unsigned char *mac,
+                       unsigned int mac_size);
+void hmac_sha256(const unsigned char *key, unsigned int key_size,
+                 const unsigned char *message, unsigned int message_len,
+                 unsigned char *mac, unsigned mac_size);
+
+#endif /* !HMAC_SHA256_H */
diff --git a/tools/vhost-user-rpmb/hmac_sha256.c b/tools/vhost-user-rpmb/hmac_sha256.c
new file mode 100644
index 000000000000..f6640a46c616
--- /dev/null
+++ b/tools/vhost-user-rpmb/hmac_sha256.c
@@ -0,0 +1,331 @@
+/*
+ * HMAC-SHA-256 implementation
+ * Last update: 06/15/2005
+ * Issue date:  06/15/2005
+ *
+ * Copyright (C) 2005 Olivier Gay <olivier.gay@a3.epfl.ch>
+ * All rights reserved.
+ *
+ * Copyright (c) 2016, 2020 Linaro Limited
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <string.h>
+
+#include "hmac_sha256.h"
+
+/* SHA256 functions */
+
+#define SHFR(x, n)    (x >> n)
+#define ROTR(x, n)   ((x >> n) | (x << ((sizeof(x) << 3) - n)))
+#define ROTL(x, n)   ((x << n) | (x >> ((sizeof(x) << 3) - n)))
+#define CH(x, y, z)  ((x & y) ^ (~x & z))
+#define MAJ(x, y, z) ((x & y) ^ (x & z) ^ (y & z))
+
+#define SHA256_F1(x) (ROTR(x,  2) ^ ROTR(x, 13) ^ ROTR(x, 22))
+#define SHA256_F2(x) (ROTR(x,  6) ^ ROTR(x, 11) ^ ROTR(x, 25))
+#define SHA256_F3(x) (ROTR(x,  7) ^ ROTR(x, 18) ^ SHFR(x,  3))
+#define SHA256_F4(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ SHFR(x, 10))
+
+#define UNPACK32(x, str)                      \
+{                                             \
+    *((str) + 3) = (uint8) ((x)      );       \
+    *((str) + 2) = (uint8) ((x) >>  8);       \
+    *((str) + 1) = (uint8) ((x) >> 16);       \
+    *((str) + 0) = (uint8) ((x) >> 24);       \
+}
+
+#define PACK32(str, x)                        \
+{                                             \
+    *(x) =   ((uint32) *((str) + 3)      )    \
+           | ((uint32) *((str) + 2) <<  8)    \
+           | ((uint32) *((str) + 1) << 16)    \
+           | ((uint32) *((str) + 0) << 24);   \
+}
+
+#define UNPACK64(x, str)                      \
+{                                             \
+    *((str) + 7) = (uint8) ((x)      );       \
+    *((str) + 6) = (uint8) ((x) >>  8);       \
+    *((str) + 5) = (uint8) ((x) >> 16);       \
+    *((str) + 4) = (uint8) ((x) >> 24);       \
+    *((str) + 3) = (uint8) ((x) >> 32);       \
+    *((str) + 2) = (uint8) ((x) >> 40);       \
+    *((str) + 1) = (uint8) ((x) >> 48);       \
+    *((str) + 0) = (uint8) ((x) >> 56);       \
+}
+
+#define PACK64(str, x)                        \
+{                                             \
+    *(x) =   ((uint64) *((str) + 7)      )    \
+           | ((uint64) *((str) + 6) <<  8)    \
+           | ((uint64) *((str) + 5) << 16)    \
+           | ((uint64) *((str) + 4) << 24)    \
+           | ((uint64) *((str) + 3) << 32)    \
+           | ((uint64) *((str) + 2) << 40)    \
+           | ((uint64) *((str) + 1) << 48)    \
+           | ((uint64) *((str) + 0) << 56);   \
+}
+
+#define SHA256_SCR(i)                         \
+{                                             \
+    w[i] =  SHA256_F4(w[i -  2]) + w[i -  7]  \
+          + SHA256_F3(w[i - 15]) + w[i - 16]; \
+}
+
+uint32 sha256_h0[8] =
+            {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
+             0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19};
+
+uint32 sha256_k[64] =
+            {0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
+             0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+             0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
+             0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+             0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
+             0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+             0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
+             0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+             0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
+             0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+             0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
+             0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+             0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
+             0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+             0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
+             0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2};
+
+/* SHA-256 functions */
+
+static void sha256_transf(sha256_ctx *ctx, const unsigned char *message,
+                          unsigned int block_nb)
+{
+    uint32 w[64];
+    uint32 wv[8];
+    uint32 t1, t2;
+    const unsigned char *sub_block;
+    int i;
+    int j;
+
+    for (i = 0; i < (int) block_nb; i++) {
+        sub_block = message + (i << 6);
+
+        for (j = 0; j < 16; j++) {
+            PACK32(&sub_block[j << 2], &w[j]);
+        }
+
+        for (j = 16; j < 64; j++) {
+            SHA256_SCR(j);
+        }
+
+        for (j = 0; j < 8; j++) {
+            wv[j] = ctx->h[j];
+        }
+
+        for (j = 0; j < 64; j++) {
+            t1 = wv[7] + SHA256_F2(wv[4]) + CH(wv[4], wv[5], wv[6])
+                + sha256_k[j] + w[j];
+            t2 = SHA256_F1(wv[0]) + MAJ(wv[0], wv[1], wv[2]);
+            wv[7] = wv[6];
+            wv[6] = wv[5];
+            wv[5] = wv[4];
+            wv[4] = wv[3] + t1;
+            wv[3] = wv[2];
+            wv[2] = wv[1];
+            wv[1] = wv[0];
+            wv[0] = t1 + t2;
+        }
+
+        for (j = 0; j < 8; j++) {
+            ctx->h[j] += wv[j];
+        }
+    }
+}
+
+void sha256(const unsigned char *message, unsigned int len, unsigned char *digest)
+{
+    sha256_ctx ctx;
+
+    sha256_init(&ctx);
+    sha256_update(&ctx, message, len);
+    sha256_final(&ctx, digest);
+}
+
+void sha256_init(sha256_ctx *ctx)
+{
+    int i;
+    for (i = 0; i < 8; i++) {
+        ctx->h[i] = sha256_h0[i];
+    }
+
+    ctx->len = 0;
+    ctx->tot_len = 0;
+}
+
+void sha256_update(sha256_ctx *ctx, const unsigned char *message,
+                   unsigned int len)
+{
+    unsigned int block_nb;
+    unsigned int new_len, rem_len, tmp_len;
+    const unsigned char *shifted_message;
+
+    tmp_len = SHA256_BLOCK_SIZE - ctx->len;
+    rem_len = len < tmp_len ? len : tmp_len;
+
+    memcpy(&ctx->block[ctx->len], message, rem_len);
+
+    if (ctx->len + len < SHA256_BLOCK_SIZE) {
+        ctx->len += len;
+        return;
+    }
+
+    new_len = len - rem_len;
+    block_nb = new_len / SHA256_BLOCK_SIZE;
+
+    shifted_message = message + rem_len;
+
+    sha256_transf(ctx, ctx->block, 1);
+    sha256_transf(ctx, shifted_message, block_nb);
+
+    rem_len = new_len % SHA256_BLOCK_SIZE;
+
+    memcpy(ctx->block, &shifted_message[block_nb << 6],
+           rem_len);
+
+    ctx->len = rem_len;
+    ctx->tot_len += (block_nb + 1) << 6;
+}
+
+void sha256_final(sha256_ctx *ctx, unsigned char *digest)
+{
+    unsigned int block_nb;
+    unsigned int pm_len;
+    unsigned int len_b;
+    int i;
+
+    block_nb = (1 + ((SHA256_BLOCK_SIZE - 9)
+                     < (ctx->len % SHA256_BLOCK_SIZE)));
+
+    len_b = (ctx->tot_len + ctx->len) << 3;
+    pm_len = block_nb << 6;
+
+    memset(ctx->block + ctx->len, 0, pm_len - ctx->len);
+    ctx->block[ctx->len] = 0x80;
+    UNPACK32(len_b, ctx->block + pm_len - 4);
+
+    sha256_transf(ctx, ctx->block, block_nb);
+
+    for (i = 0 ; i < 8; i++) {
+        UNPACK32(ctx->h[i], &digest[i << 2]);
+    }
+}
+
+/* HMAC-SHA-256 functions */
+
+void hmac_sha256_init(hmac_sha256_ctx *ctx, const unsigned char *key,
+                      unsigned int key_size)
+{
+    unsigned int fill;
+    unsigned int num;
+
+    const unsigned char *key_used;
+    unsigned char key_temp[SHA256_DIGEST_SIZE];
+    int i;
+
+    if (key_size == SHA256_BLOCK_SIZE) {
+        key_used = key;
+        num = SHA256_BLOCK_SIZE;
+    } else {
+        if (key_size > SHA256_BLOCK_SIZE){
+            num = SHA256_DIGEST_SIZE;
+            sha256(key, key_size, key_temp);
+            key_used = key_temp;
+        } else { /* key_size > SHA256_BLOCK_SIZE */
+            key_used = key;
+            num = key_size;
+        }
+        fill = SHA256_BLOCK_SIZE - num;
+
+        memset(ctx->block_ipad + num, 0x36, fill);
+        memset(ctx->block_opad + num, 0x5c, fill);
+    }
+
+    for (i = 0; i < (int) num; i++) {
+        ctx->block_ipad[i] = key_used[i] ^ 0x36;
+        ctx->block_opad[i] = key_used[i] ^ 0x5c;
+    }
+
+    sha256_init(&ctx->ctx_inside);
+    sha256_update(&ctx->ctx_inside, ctx->block_ipad, SHA256_BLOCK_SIZE);
+
+    sha256_init(&ctx->ctx_outside);
+    sha256_update(&ctx->ctx_outside, ctx->block_opad,
+                  SHA256_BLOCK_SIZE);
+
+    /* for hmac_reinit */
+    memcpy(&ctx->ctx_inside_reinit, &ctx->ctx_inside,
+           sizeof(sha256_ctx));
+    memcpy(&ctx->ctx_outside_reinit, &ctx->ctx_outside,
+           sizeof(sha256_ctx));
+}
+
+void hmac_sha256_reinit(hmac_sha256_ctx *ctx)
+{
+    memcpy(&ctx->ctx_inside, &ctx->ctx_inside_reinit,
+           sizeof(sha256_ctx));
+    memcpy(&ctx->ctx_outside, &ctx->ctx_outside_reinit,
+           sizeof(sha256_ctx));
+}
+
+void hmac_sha256_update(hmac_sha256_ctx *ctx, const unsigned char *message,
+                        unsigned int message_len)
+{
+    sha256_update(&ctx->ctx_inside, message, message_len);
+}
+
+void hmac_sha256_final(hmac_sha256_ctx *ctx, unsigned char *mac,
+                       unsigned int mac_size)
+{
+    unsigned char digest_inside[SHA256_DIGEST_SIZE];
+    unsigned char mac_temp[SHA256_DIGEST_SIZE];
+
+    sha256_final(&ctx->ctx_inside, digest_inside);
+    sha256_update(&ctx->ctx_outside, digest_inside, SHA256_DIGEST_SIZE);
+    sha256_final(&ctx->ctx_outside, mac_temp);
+    memcpy(mac, mac_temp, mac_size);
+}
+
+void hmac_sha256(const unsigned char *key, unsigned int key_size,
+          const unsigned char *message, unsigned int message_len,
+          unsigned char *mac, unsigned mac_size)
+{
+    hmac_sha256_ctx ctx;
+
+    hmac_sha256_init(&ctx, key, key_size);
+    hmac_sha256_update(&ctx, message, message_len);
+    hmac_sha256_final(&ctx, mac, mac_size);
+}
diff --git a/tools/vhost-user-rpmb/meson.build b/tools/vhost-user-rpmb/meson.build
index cf80bedd99ac..f964837d151d 100644
--- a/tools/vhost-user-rpmb/meson.build
+++ b/tools/vhost-user-rpmb/meson.build
@@ -1,5 +1,6 @@
 executable('vhost-user-rpmb', files(
-  'main.c'),
+  'main.c',
+  'hmac_sha256.c'),
   dependencies: [qemuutil, glib, gio],
   link_with: [libvhost_user],
   install: true,
-- 
2.20.1

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

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

* [RFC PATCH 13/19] tools/vhost-user-rpmb: implement the PROGRAM_KEY handshake
  2020-09-25 12:51 ` Alex Bennée
@ 2020-09-25 12:51   ` Alex Bennée
  -1 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2020-09-25 12:51 UTC (permalink / raw)
  To: qemu-devel, maxim.uvarov, joakim.bech, ilias.apalodimas,
	tomas.winkler, yang.huang, bing.zhu, Matti.Moell, hmo
  Cc: jean-philippe, takahiro.akashi, virtualization, Alex Bennée,
	arnd, stratos-dev

This implements the first handshake of the device initialisation which
is the programming of the device key. This can only be done once
per-device.

Currently there is no persistence for the device key and other
metadata such as the write count. This will be added later.

[TODO: clarify the spec if we should respond immediately or on request]

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 tools/vhost-user-rpmb/main.c | 299 +++++++++++++++++++++++++++++++++--
 1 file changed, 286 insertions(+), 13 deletions(-)

diff --git a/tools/vhost-user-rpmb/main.c b/tools/vhost-user-rpmb/main.c
index 64bd7e79f573..9c98f6916f6f 100644
--- a/tools/vhost-user-rpmb/main.c
+++ b/tools/vhost-user-rpmb/main.c
@@ -22,10 +22,14 @@
 #include <sys/stat.h>
 #include <sys/mman.h>
 #include <unistd.h>
+#include <endian.h>
+#include <assert.h>
 
 #include "contrib/libvhost-user/libvhost-user-glib.h"
 #include "contrib/libvhost-user/libvhost-user.h"
 
+#include "hmac_sha256.h"
+
 #ifndef container_of
 #define container_of(ptr, type, member) ({                      \
         const typeof(((type *) 0)->member) *__mptr = (ptr);     \
@@ -57,6 +61,31 @@ enum {
 /* These structures are defined in the specification */
 #define KiB     (1UL << 10)
 #define MAX_RPMB_SIZE (KiB * 128 * 256)
+#define RPMB_KEY_MAC_SIZE 32
+
+/* RPMB Request Types */
+#define VIRTIO_RPMB_REQ_PROGRAM_KEY        0x0001
+#define VIRTIO_RPMB_REQ_GET_WRITE_COUNTER  0x0002
+#define VIRTIO_RPMB_REQ_DATA_WRITE         0x0003
+#define VIRTIO_RPMB_REQ_DATA_READ          0x0004
+#define VIRTIO_RPMB_REQ_RESULT_READ        0x0005
+
+/* RPMB Response Types */
+#define VIRTIO_RPMB_RESP_PROGRAM_KEY       0x0100
+#define VIRTIO_RPMB_RESP_GET_COUNTER       0x0200
+#define VIRTIO_RPMB_RESP_DATA_WRITE        0x0300
+#define VIRTIO_RPMB_RESP_DATA_READ         0x0400
+
+/* RPMB Operation Results */
+#define VIRTIO_RPMB_RES_OK                     0x0000
+#define VIRTIO_RPMB_RES_GENERAL_FAILURE        0x0001
+#define VIRTIO_RPMB_RES_AUTH_FAILURE           0x0002
+#define VIRTIO_RPMB_RES_COUNT_FAILURE          0x0003
+#define VIRTIO_RPMB_RES_ADDR_FAILURE           0x0004
+#define VIRTIO_RPMB_RES_WRITE_FAILURE          0x0005
+#define VIRTIO_RPMB_RES_READ_FAILURE           0x0006
+#define VIRTIO_RPMB_RES_NO_AUTH_KEY            0x0007
+#define VIRTIO_RPMB_RES_WRITE_COUNTER_EXPIRED  0x0080
 
 struct virtio_rpmb_config {
     uint8_t capacity;
@@ -64,9 +93,13 @@ struct virtio_rpmb_config {
     uint8_t max_rd_cnt;
 };
 
+/*
+ * This is based on the JDEC standard and not the currently not
+ * up-streamed NVME standard.
+ */
 struct virtio_rpmb_frame {
     uint8_t stuff[196];
-    uint8_t key_mac[32];
+    uint8_t key_mac[RPMB_KEY_MAC_SIZE];
     uint8_t data[256];
     uint8_t nonce[16];
     /* remaining fields are big-endian */
@@ -75,7 +108,7 @@ struct virtio_rpmb_frame {
     uint16_t block_count;
     uint16_t result;
     uint16_t req_resp;
-};
+} __attribute__((packed));
 
 /*
  * Structure to track internal state of RPMB Device
@@ -87,15 +120,63 @@ typedef struct VuRpmb {
     GMainLoop *loop;
     int flash_fd;
     void *flash_map;
+    uint8_t *key;
+    uint16_t last_result;
+    uint16_t last_reqresp;
 } VuRpmb;
 
-struct virtio_rpmb_ctrl_command {
-    VuVirtqElement elem;
-    VuVirtq *vq;
-    struct virtio_rpmb_frame frame;
-    uint32_t error;
-    bool finished;
-};
+/* refer to util/iov.c */
+static size_t vrpmb_iov_size(const struct iovec *iov,
+                             const unsigned int iov_cnt)
+{
+    size_t len;
+    unsigned int i;
+
+    len = 0;
+    for (i = 0; i < iov_cnt; i++) {
+        len += iov[i].iov_len;
+    }
+    return len;
+}
+
+
+static size_t vrpmb_iov_to_buf(const struct iovec *iov, const unsigned int iov_cnt,
+                               size_t offset, void *buf, size_t bytes)
+{
+    size_t done;
+    unsigned int i;
+    for (i = 0, done = 0; (offset || done < bytes) && i < iov_cnt; i++) {
+        if (offset < iov[i].iov_len) {
+            size_t len = MIN(iov[i].iov_len - offset, bytes - done);
+            memcpy(buf + done, iov[i].iov_base + offset, len);
+            done += len;
+            offset = 0;
+        } else {
+            offset -= iov[i].iov_len;
+        }
+    }
+    assert(offset == 0);
+    return done;
+}
+
+static size_t vrpmb_iov_from_buf(const struct iovec *iov, unsigned int iov_cnt,
+                                 size_t offset, const void *buf, size_t bytes)
+{
+    size_t done;
+    unsigned int i;
+    for (i = 0, done = 0; (offset || done < bytes) && i < iov_cnt; i++) {
+        if (offset < iov[i].iov_len) {
+            size_t len = MIN(iov[i].iov_len - offset, bytes - done);
+            memcpy(iov[i].iov_base + offset, buf + done, len);
+            done += len;
+            offset = 0;
+        } else {
+            offset -= iov[i].iov_len;
+        }
+    }
+    assert(offset == 0);
+    return done;
+}
 
 static void vrpmb_panic(VuDev *dev, const char *msg)
 {
@@ -142,19 +223,211 @@ vrpmb_set_config(VuDev *dev, const uint8_t *data,
     return 0;
 }
 
+/*
+ * vrpmb_update_mac_in_frame:
+ *
+ * From the spec:
+ *   The MAC is calculated using HMAC SHA-256. It takes
+ *   as input a key and a message. The key used for the MAC calculation
+ *   is always the 256-bit RPMB authentication key. The message used as
+ *   input to the MAC calculation is the concatenation of the fields in
+ *   the RPMB frames excluding stuff bytes and the MAC itself.
+ *
+ * The code to do this has been lifted from the optee supplicant code
+ * which itself uses a 3 clause BSD chunk of code.
+ */
+
+static void vrpmb_update_mac_in_frame(VuRpmb *r, struct virtio_rpmb_frame *frm)
+{
+    hmac_sha256_ctx ctx;
+    static const int dlen = (sizeof(struct virtio_rpmb_frame) -
+                             offsetof(struct virtio_rpmb_frame, data));
+
+    hmac_sha256_init(&ctx, r->key, RPMB_KEY_MAC_SIZE);
+    hmac_sha256_update(&ctx, frm->data, dlen);
+    hmac_sha256_final(&ctx, &frm->key_mac[0], 32);
+}
+
+/*
+ * Handlers for individual control messages
+ */
+
+/*
+ * vrpmb_handle_program_key:
+ *
+ * Program the device with our key. The spec is a little hazzy on if
+ * we respond straight away or we wait for the user to send a
+ * VIRTIO_RPMB_REQ_RESULT_READ request.
+ */
+static void vrpmb_handle_program_key(VuDev *dev, struct virtio_rpmb_frame *frame)
+{
+    VuRpmb *r = container_of(dev, VuRpmb, dev.parent);
+
+    /*
+     * Run the checks from:
+     * 5.12.6.1.1 Device Requirements: Device Operation: Program Key
+     */
+    r->last_reqresp = VIRTIO_RPMB_RESP_PROGRAM_KEY;
+
+    /* Fail if already programmed */
+    if (r->key) {
+        g_debug("key already programmed");
+        r->last_result = VIRTIO_RPMB_RES_WRITE_FAILURE;
+    } else if (be16toh(frame->block_count) != 1) {
+        g_debug("weird block counts (%d)", frame->block_count);
+        r->last_result = VIRTIO_RPMB_RES_GENERAL_FAILURE;
+    } else {
+        r->key = g_memdup(&frame->key_mac[0], RPMB_KEY_MAC_SIZE);
+        r->last_result = VIRTIO_RPMB_RES_OK;
+    }
+
+    g_info("%s: req_resp = %x, result = %x", __func__,
+           r->last_reqresp, r->last_result);
+    return;
+}
+
+/*
+ * Return the result of the last message. This is only valid if the
+ * previous message was VIRTIO_RPMB_REQ_PROGRAM_KEY or
+ * VIRTIO_RPMB_REQ_DATA_WRITE.
+ *
+ * The frame should be freed once sent.
+ */
+static struct virtio_rpmb_frame * vrpmb_handle_result_read(VuDev *dev)
+{
+    VuRpmb *r = container_of(dev, VuRpmb, dev.parent);
+    struct virtio_rpmb_frame *resp = g_new0(struct virtio_rpmb_frame, 1);
+
+    if (r->last_reqresp == VIRTIO_RPMB_RESP_PROGRAM_KEY ||
+        r->last_reqresp == VIRTIO_RPMB_REQ_DATA_WRITE) {
+        resp->result = htobe16(r->last_result);
+        resp->req_resp = htobe16(r->last_reqresp);
+    } else {
+        resp->result = htobe16(VIRTIO_RPMB_RES_GENERAL_FAILURE);
+    }
+
+    /* calculate HMAC */
+    if (!r->key) {
+        resp->result = htobe16(VIRTIO_RPMB_RES_GENERAL_FAILURE);
+    } else {
+        vrpmb_update_mac_in_frame(r, resp);
+    }
+
+    g_info("%s: result = %x req_resp = %x", __func__,
+           be16toh(resp->result),
+           be16toh(resp->req_resp));
+    return resp;
+}
+
+static void fmt_bytes(GString *s, uint8_t *bytes, int len)
+{
+    int i;
+    for (i = 0; i < len; i++) {
+        if (i % 16 == 0) {
+            g_string_append_c(s, '\n');
+        }
+        g_string_append_printf(s, "%x ", bytes[i]);
+    }
+}
+
+static void vrpmb_dump_frame(struct virtio_rpmb_frame *frame)
+{
+    g_autoptr(GString) s = g_string_new("frame: ");
+
+    g_string_append_printf(s, " %p\n", frame);
+    g_string_append_printf(s, "key_mac:");
+    fmt_bytes(s, (uint8_t *) &frame->key_mac[0], 32);
+    g_string_append_printf(s, "\ndata:");
+    fmt_bytes(s, (uint8_t *) &frame->data, 256);
+    g_string_append_printf(s, "\nnonce:");
+    fmt_bytes(s, (uint8_t *) &frame->nonce, 16);
+    g_string_append_printf(s, "\nwrite_counter: %d\n",
+                           be32toh(frame->write_counter));
+    g_string_append_printf(s, "address: %#04x\n", be16toh(frame->address));
+    g_string_append_printf(s, "block_count: %d\n", be16toh(frame->block_count));
+    g_string_append_printf(s, "result: %d\n", be16toh(frame->result));
+    g_string_append_printf(s, "req_resp: %d\n", be16toh(frame->req_resp));
+
+    g_debug("%s: %s\n", __func__, s->str);
+}
+
 static void
 vrpmb_handle_ctrl(VuDev *dev, int qidx)
 {
     VuVirtq *vq = vu_get_queue(dev, qidx);
-    struct virtio_rpmb_ctrl_command *cmd = NULL;
+    struct virtio_rpmb_frame *frames = NULL;
 
     for (;;) {
-        cmd = vu_queue_pop(dev, vq, sizeof(struct virtio_rpmb_ctrl_command));
-        if (!cmd) {
+        VuVirtqElement *elem;
+        size_t len, frame_sz = sizeof(struct virtio_rpmb_frame);
+        int n;
+
+        elem = vu_queue_pop(dev, vq, sizeof(VuVirtqElement));
+        if (!elem) {
             break;
         }
+        g_debug("%s: got queue (in %d, out %d)", __func__,
+                elem->in_num, elem->out_num);
 
-        g_debug("un-handled cmd: %p", cmd);
+        len = vrpmb_iov_size(elem->out_sg, elem->out_num);
+        frames = g_realloc(frames, len);
+        vrpmb_iov_to_buf(elem->out_sg, elem->out_num, 0, frames, len);
+
+        if (len % frame_sz != 0) {
+            g_warning("%s: incomplete frames %zu/%zu != 0\n",
+                      __func__, len, frame_sz);
+        }
+
+        for (n = 0; n < len / frame_sz; n++) {
+            struct virtio_rpmb_frame *f = &frames[n];
+            struct virtio_rpmb_frame *resp = NULL;
+            uint16_t req_resp = be16toh(f->req_resp);
+            bool responded = false;
+
+            if (debug) {
+                g_info("req_resp=%x", req_resp);
+                vrpmb_dump_frame(f);
+            }
+
+            switch (req_resp) {
+            case VIRTIO_RPMB_REQ_PROGRAM_KEY:
+                vrpmb_handle_program_key(dev, f);
+                break;
+            case VIRTIO_RPMB_REQ_RESULT_READ:
+                if (!responded) {
+                    resp = vrpmb_handle_result_read(dev);
+                } else {
+                    g_warning("%s: already sent a response in this set of frames",
+                              __func__);
+                }
+                break;
+            default:
+                g_debug("un-handled request: %x", f->req_resp);
+                break;
+            }
+
+            /*
+             * Do we have a frame to send back?
+             */
+            if (resp) {
+                g_debug("sending response frame: %p", resp);
+                if (debug) {
+                    vrpmb_dump_frame(resp);
+                }
+                len = vrpmb_iov_from_buf(elem->in_sg,
+                                         elem->in_num, 0, resp, sizeof(*resp));
+                if (len != sizeof(*resp)) {
+                    g_critical("%s: response size incorrect %zu vs %zu",
+                               __func__, len, sizeof(*resp));
+                } else {
+                    vu_queue_push(dev, vq, elem, len);
+                    vu_queue_notify(dev, vq);
+                    responded = true;
+                }
+
+                g_free(resp);
+            }
+        }
     }
 }
 
-- 
2.20.1



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

* [RFC PATCH 13/19] tools/vhost-user-rpmb: implement the PROGRAM_KEY handshake
@ 2020-09-25 12:51   ` Alex Bennée
  0 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2020-09-25 12:51 UTC (permalink / raw)
  To: qemu-devel, maxim.uvarov, joakim.bech, ilias.apalodimas,
	tomas.winkler, yang.huang, bing.zhu, Matti.Moell, hmo
  Cc: jean-philippe, takahiro.akashi, virtualization, arnd, stratos-dev

This implements the first handshake of the device initialisation which
is the programming of the device key. This can only be done once
per-device.

Currently there is no persistence for the device key and other
metadata such as the write count. This will be added later.

[TODO: clarify the spec if we should respond immediately or on request]

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 tools/vhost-user-rpmb/main.c | 299 +++++++++++++++++++++++++++++++++--
 1 file changed, 286 insertions(+), 13 deletions(-)

diff --git a/tools/vhost-user-rpmb/main.c b/tools/vhost-user-rpmb/main.c
index 64bd7e79f573..9c98f6916f6f 100644
--- a/tools/vhost-user-rpmb/main.c
+++ b/tools/vhost-user-rpmb/main.c
@@ -22,10 +22,14 @@
 #include <sys/stat.h>
 #include <sys/mman.h>
 #include <unistd.h>
+#include <endian.h>
+#include <assert.h>
 
 #include "contrib/libvhost-user/libvhost-user-glib.h"
 #include "contrib/libvhost-user/libvhost-user.h"
 
+#include "hmac_sha256.h"
+
 #ifndef container_of
 #define container_of(ptr, type, member) ({                      \
         const typeof(((type *) 0)->member) *__mptr = (ptr);     \
@@ -57,6 +61,31 @@ enum {
 /* These structures are defined in the specification */
 #define KiB     (1UL << 10)
 #define MAX_RPMB_SIZE (KiB * 128 * 256)
+#define RPMB_KEY_MAC_SIZE 32
+
+/* RPMB Request Types */
+#define VIRTIO_RPMB_REQ_PROGRAM_KEY        0x0001
+#define VIRTIO_RPMB_REQ_GET_WRITE_COUNTER  0x0002
+#define VIRTIO_RPMB_REQ_DATA_WRITE         0x0003
+#define VIRTIO_RPMB_REQ_DATA_READ          0x0004
+#define VIRTIO_RPMB_REQ_RESULT_READ        0x0005
+
+/* RPMB Response Types */
+#define VIRTIO_RPMB_RESP_PROGRAM_KEY       0x0100
+#define VIRTIO_RPMB_RESP_GET_COUNTER       0x0200
+#define VIRTIO_RPMB_RESP_DATA_WRITE        0x0300
+#define VIRTIO_RPMB_RESP_DATA_READ         0x0400
+
+/* RPMB Operation Results */
+#define VIRTIO_RPMB_RES_OK                     0x0000
+#define VIRTIO_RPMB_RES_GENERAL_FAILURE        0x0001
+#define VIRTIO_RPMB_RES_AUTH_FAILURE           0x0002
+#define VIRTIO_RPMB_RES_COUNT_FAILURE          0x0003
+#define VIRTIO_RPMB_RES_ADDR_FAILURE           0x0004
+#define VIRTIO_RPMB_RES_WRITE_FAILURE          0x0005
+#define VIRTIO_RPMB_RES_READ_FAILURE           0x0006
+#define VIRTIO_RPMB_RES_NO_AUTH_KEY            0x0007
+#define VIRTIO_RPMB_RES_WRITE_COUNTER_EXPIRED  0x0080
 
 struct virtio_rpmb_config {
     uint8_t capacity;
@@ -64,9 +93,13 @@ struct virtio_rpmb_config {
     uint8_t max_rd_cnt;
 };
 
+/*
+ * This is based on the JDEC standard and not the currently not
+ * up-streamed NVME standard.
+ */
 struct virtio_rpmb_frame {
     uint8_t stuff[196];
-    uint8_t key_mac[32];
+    uint8_t key_mac[RPMB_KEY_MAC_SIZE];
     uint8_t data[256];
     uint8_t nonce[16];
     /* remaining fields are big-endian */
@@ -75,7 +108,7 @@ struct virtio_rpmb_frame {
     uint16_t block_count;
     uint16_t result;
     uint16_t req_resp;
-};
+} __attribute__((packed));
 
 /*
  * Structure to track internal state of RPMB Device
@@ -87,15 +120,63 @@ typedef struct VuRpmb {
     GMainLoop *loop;
     int flash_fd;
     void *flash_map;
+    uint8_t *key;
+    uint16_t last_result;
+    uint16_t last_reqresp;
 } VuRpmb;
 
-struct virtio_rpmb_ctrl_command {
-    VuVirtqElement elem;
-    VuVirtq *vq;
-    struct virtio_rpmb_frame frame;
-    uint32_t error;
-    bool finished;
-};
+/* refer to util/iov.c */
+static size_t vrpmb_iov_size(const struct iovec *iov,
+                             const unsigned int iov_cnt)
+{
+    size_t len;
+    unsigned int i;
+
+    len = 0;
+    for (i = 0; i < iov_cnt; i++) {
+        len += iov[i].iov_len;
+    }
+    return len;
+}
+
+
+static size_t vrpmb_iov_to_buf(const struct iovec *iov, const unsigned int iov_cnt,
+                               size_t offset, void *buf, size_t bytes)
+{
+    size_t done;
+    unsigned int i;
+    for (i = 0, done = 0; (offset || done < bytes) && i < iov_cnt; i++) {
+        if (offset < iov[i].iov_len) {
+            size_t len = MIN(iov[i].iov_len - offset, bytes - done);
+            memcpy(buf + done, iov[i].iov_base + offset, len);
+            done += len;
+            offset = 0;
+        } else {
+            offset -= iov[i].iov_len;
+        }
+    }
+    assert(offset == 0);
+    return done;
+}
+
+static size_t vrpmb_iov_from_buf(const struct iovec *iov, unsigned int iov_cnt,
+                                 size_t offset, const void *buf, size_t bytes)
+{
+    size_t done;
+    unsigned int i;
+    for (i = 0, done = 0; (offset || done < bytes) && i < iov_cnt; i++) {
+        if (offset < iov[i].iov_len) {
+            size_t len = MIN(iov[i].iov_len - offset, bytes - done);
+            memcpy(iov[i].iov_base + offset, buf + done, len);
+            done += len;
+            offset = 0;
+        } else {
+            offset -= iov[i].iov_len;
+        }
+    }
+    assert(offset == 0);
+    return done;
+}
 
 static void vrpmb_panic(VuDev *dev, const char *msg)
 {
@@ -142,19 +223,211 @@ vrpmb_set_config(VuDev *dev, const uint8_t *data,
     return 0;
 }
 
+/*
+ * vrpmb_update_mac_in_frame:
+ *
+ * From the spec:
+ *   The MAC is calculated using HMAC SHA-256. It takes
+ *   as input a key and a message. The key used for the MAC calculation
+ *   is always the 256-bit RPMB authentication key. The message used as
+ *   input to the MAC calculation is the concatenation of the fields in
+ *   the RPMB frames excluding stuff bytes and the MAC itself.
+ *
+ * The code to do this has been lifted from the optee supplicant code
+ * which itself uses a 3 clause BSD chunk of code.
+ */
+
+static void vrpmb_update_mac_in_frame(VuRpmb *r, struct virtio_rpmb_frame *frm)
+{
+    hmac_sha256_ctx ctx;
+    static const int dlen = (sizeof(struct virtio_rpmb_frame) -
+                             offsetof(struct virtio_rpmb_frame, data));
+
+    hmac_sha256_init(&ctx, r->key, RPMB_KEY_MAC_SIZE);
+    hmac_sha256_update(&ctx, frm->data, dlen);
+    hmac_sha256_final(&ctx, &frm->key_mac[0], 32);
+}
+
+/*
+ * Handlers for individual control messages
+ */
+
+/*
+ * vrpmb_handle_program_key:
+ *
+ * Program the device with our key. The spec is a little hazzy on if
+ * we respond straight away or we wait for the user to send a
+ * VIRTIO_RPMB_REQ_RESULT_READ request.
+ */
+static void vrpmb_handle_program_key(VuDev *dev, struct virtio_rpmb_frame *frame)
+{
+    VuRpmb *r = container_of(dev, VuRpmb, dev.parent);
+
+    /*
+     * Run the checks from:
+     * 5.12.6.1.1 Device Requirements: Device Operation: Program Key
+     */
+    r->last_reqresp = VIRTIO_RPMB_RESP_PROGRAM_KEY;
+
+    /* Fail if already programmed */
+    if (r->key) {
+        g_debug("key already programmed");
+        r->last_result = VIRTIO_RPMB_RES_WRITE_FAILURE;
+    } else if (be16toh(frame->block_count) != 1) {
+        g_debug("weird block counts (%d)", frame->block_count);
+        r->last_result = VIRTIO_RPMB_RES_GENERAL_FAILURE;
+    } else {
+        r->key = g_memdup(&frame->key_mac[0], RPMB_KEY_MAC_SIZE);
+        r->last_result = VIRTIO_RPMB_RES_OK;
+    }
+
+    g_info("%s: req_resp = %x, result = %x", __func__,
+           r->last_reqresp, r->last_result);
+    return;
+}
+
+/*
+ * Return the result of the last message. This is only valid if the
+ * previous message was VIRTIO_RPMB_REQ_PROGRAM_KEY or
+ * VIRTIO_RPMB_REQ_DATA_WRITE.
+ *
+ * The frame should be freed once sent.
+ */
+static struct virtio_rpmb_frame * vrpmb_handle_result_read(VuDev *dev)
+{
+    VuRpmb *r = container_of(dev, VuRpmb, dev.parent);
+    struct virtio_rpmb_frame *resp = g_new0(struct virtio_rpmb_frame, 1);
+
+    if (r->last_reqresp == VIRTIO_RPMB_RESP_PROGRAM_KEY ||
+        r->last_reqresp == VIRTIO_RPMB_REQ_DATA_WRITE) {
+        resp->result = htobe16(r->last_result);
+        resp->req_resp = htobe16(r->last_reqresp);
+    } else {
+        resp->result = htobe16(VIRTIO_RPMB_RES_GENERAL_FAILURE);
+    }
+
+    /* calculate HMAC */
+    if (!r->key) {
+        resp->result = htobe16(VIRTIO_RPMB_RES_GENERAL_FAILURE);
+    } else {
+        vrpmb_update_mac_in_frame(r, resp);
+    }
+
+    g_info("%s: result = %x req_resp = %x", __func__,
+           be16toh(resp->result),
+           be16toh(resp->req_resp));
+    return resp;
+}
+
+static void fmt_bytes(GString *s, uint8_t *bytes, int len)
+{
+    int i;
+    for (i = 0; i < len; i++) {
+        if (i % 16 == 0) {
+            g_string_append_c(s, '\n');
+        }
+        g_string_append_printf(s, "%x ", bytes[i]);
+    }
+}
+
+static void vrpmb_dump_frame(struct virtio_rpmb_frame *frame)
+{
+    g_autoptr(GString) s = g_string_new("frame: ");
+
+    g_string_append_printf(s, " %p\n", frame);
+    g_string_append_printf(s, "key_mac:");
+    fmt_bytes(s, (uint8_t *) &frame->key_mac[0], 32);
+    g_string_append_printf(s, "\ndata:");
+    fmt_bytes(s, (uint8_t *) &frame->data, 256);
+    g_string_append_printf(s, "\nnonce:");
+    fmt_bytes(s, (uint8_t *) &frame->nonce, 16);
+    g_string_append_printf(s, "\nwrite_counter: %d\n",
+                           be32toh(frame->write_counter));
+    g_string_append_printf(s, "address: %#04x\n", be16toh(frame->address));
+    g_string_append_printf(s, "block_count: %d\n", be16toh(frame->block_count));
+    g_string_append_printf(s, "result: %d\n", be16toh(frame->result));
+    g_string_append_printf(s, "req_resp: %d\n", be16toh(frame->req_resp));
+
+    g_debug("%s: %s\n", __func__, s->str);
+}
+
 static void
 vrpmb_handle_ctrl(VuDev *dev, int qidx)
 {
     VuVirtq *vq = vu_get_queue(dev, qidx);
-    struct virtio_rpmb_ctrl_command *cmd = NULL;
+    struct virtio_rpmb_frame *frames = NULL;
 
     for (;;) {
-        cmd = vu_queue_pop(dev, vq, sizeof(struct virtio_rpmb_ctrl_command));
-        if (!cmd) {
+        VuVirtqElement *elem;
+        size_t len, frame_sz = sizeof(struct virtio_rpmb_frame);
+        int n;
+
+        elem = vu_queue_pop(dev, vq, sizeof(VuVirtqElement));
+        if (!elem) {
             break;
         }
+        g_debug("%s: got queue (in %d, out %d)", __func__,
+                elem->in_num, elem->out_num);
 
-        g_debug("un-handled cmd: %p", cmd);
+        len = vrpmb_iov_size(elem->out_sg, elem->out_num);
+        frames = g_realloc(frames, len);
+        vrpmb_iov_to_buf(elem->out_sg, elem->out_num, 0, frames, len);
+
+        if (len % frame_sz != 0) {
+            g_warning("%s: incomplete frames %zu/%zu != 0\n",
+                      __func__, len, frame_sz);
+        }
+
+        for (n = 0; n < len / frame_sz; n++) {
+            struct virtio_rpmb_frame *f = &frames[n];
+            struct virtio_rpmb_frame *resp = NULL;
+            uint16_t req_resp = be16toh(f->req_resp);
+            bool responded = false;
+
+            if (debug) {
+                g_info("req_resp=%x", req_resp);
+                vrpmb_dump_frame(f);
+            }
+
+            switch (req_resp) {
+            case VIRTIO_RPMB_REQ_PROGRAM_KEY:
+                vrpmb_handle_program_key(dev, f);
+                break;
+            case VIRTIO_RPMB_REQ_RESULT_READ:
+                if (!responded) {
+                    resp = vrpmb_handle_result_read(dev);
+                } else {
+                    g_warning("%s: already sent a response in this set of frames",
+                              __func__);
+                }
+                break;
+            default:
+                g_debug("un-handled request: %x", f->req_resp);
+                break;
+            }
+
+            /*
+             * Do we have a frame to send back?
+             */
+            if (resp) {
+                g_debug("sending response frame: %p", resp);
+                if (debug) {
+                    vrpmb_dump_frame(resp);
+                }
+                len = vrpmb_iov_from_buf(elem->in_sg,
+                                         elem->in_num, 0, resp, sizeof(*resp));
+                if (len != sizeof(*resp)) {
+                    g_critical("%s: response size incorrect %zu vs %zu",
+                               __func__, len, sizeof(*resp));
+                } else {
+                    vu_queue_push(dev, vq, elem, len);
+                    vu_queue_notify(dev, vq);
+                    responded = true;
+                }
+
+                g_free(resp);
+            }
+        }
     }
 }
 
-- 
2.20.1

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

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

* [RFC PATCH 14/19] tools/vhost-user-rpmb: implement VIRTIO_RPMB_REQ_GET_WRITE_COUNTER
  2020-09-25 12:51 ` Alex Bennée
@ 2020-09-25 12:51   ` Alex Bennée
  -1 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2020-09-25 12:51 UTC (permalink / raw)
  To: qemu-devel, maxim.uvarov, joakim.bech, ilias.apalodimas,
	tomas.winkler, yang.huang, bing.zhu, Matti.Moell, hmo
  Cc: jean-philippe, takahiro.akashi, virtualization, Alex Bennée,
	arnd, stratos-dev

This is the first function with an implied response that doesn't need
a VIRTIO_RPMB_REQ_RESULT_READ.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 tools/vhost-user-rpmb/main.c | 44 ++++++++++++++++++++++++++++++++++++
 1 file changed, 44 insertions(+)

diff --git a/tools/vhost-user-rpmb/main.c b/tools/vhost-user-rpmb/main.c
index 9c98f6916f6f..88747c50fa44 100644
--- a/tools/vhost-user-rpmb/main.c
+++ b/tools/vhost-user-rpmb/main.c
@@ -121,8 +121,10 @@ typedef struct VuRpmb {
     int flash_fd;
     void *flash_map;
     uint8_t *key;
+    uint8_t  last_nonce[16];
     uint16_t last_result;
     uint16_t last_reqresp;
+    uint32_t write_count;
 } VuRpmb;
 
 /* refer to util/iov.c */
@@ -286,6 +288,42 @@ static void vrpmb_handle_program_key(VuDev *dev, struct virtio_rpmb_frame *frame
     return;
 }
 
+/*
+ * vrpmb_handle_get_write_counter:
+ *
+ * We respond straight away with re-using the frame as sent.
+ */
+static struct virtio_rpmb_frame *
+vrpmb_handle_get_write_counter(VuDev *dev, struct virtio_rpmb_frame *frame)
+{
+    VuRpmb *r = container_of(dev, VuRpmb, dev.parent);
+    struct virtio_rpmb_frame *resp = g_new0(struct virtio_rpmb_frame, 1);
+
+    /*
+     * Run the checks from:
+     * 5.12.6.1.2 Device Requirements: Device Operation: Get Write Counter
+     */
+
+    resp->req_resp = htobe16(VIRTIO_RPMB_RESP_GET_COUNTER);
+    if (!r->key) {
+        g_debug("no key programmed");
+        resp->result = htobe16(VIRTIO_RPMB_RES_NO_AUTH_KEY);
+        return resp;
+    } else if (be16toh(frame->block_count) > 1) { /* allow 0 (NONCONF) */
+        g_debug("invalid block count (%d)", be16toh(frame->block_count));
+        resp->result = htobe16(VIRTIO_RPMB_RES_GENERAL_FAILURE);
+    } else {
+        resp->write_counter = htobe32(r->write_count);
+    }
+    /* copy nonce */
+    memcpy(&resp->nonce, &frame->nonce, sizeof(frame->nonce));
+
+    /* calculate MAC */
+    vrpmb_update_mac_in_frame(r, resp);
+
+    return resp;
+}
+
 /*
  * Return the result of the last message. This is only valid if the
  * previous message was VIRTIO_RPMB_REQ_PROGRAM_KEY or
@@ -298,6 +336,9 @@ static struct virtio_rpmb_frame * vrpmb_handle_result_read(VuDev *dev)
     VuRpmb *r = container_of(dev, VuRpmb, dev.parent);
     struct virtio_rpmb_frame *resp = g_new0(struct virtio_rpmb_frame, 1);
 
+    g_info("%s: for request:%x result:%x", __func__,
+           r->last_reqresp, r->last_result);
+
     if (r->last_reqresp == VIRTIO_RPMB_RESP_PROGRAM_KEY ||
         r->last_reqresp == VIRTIO_RPMB_REQ_DATA_WRITE) {
         resp->result = htobe16(r->last_result);
@@ -393,6 +434,9 @@ vrpmb_handle_ctrl(VuDev *dev, int qidx)
             case VIRTIO_RPMB_REQ_PROGRAM_KEY:
                 vrpmb_handle_program_key(dev, f);
                 break;
+            case VIRTIO_RPMB_REQ_GET_WRITE_COUNTER:
+                resp = vrpmb_handle_get_write_counter(dev, f);
+                break;
             case VIRTIO_RPMB_REQ_RESULT_READ:
                 if (!responded) {
                     resp = vrpmb_handle_result_read(dev);
-- 
2.20.1



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

* [RFC PATCH 14/19] tools/vhost-user-rpmb: implement VIRTIO_RPMB_REQ_GET_WRITE_COUNTER
@ 2020-09-25 12:51   ` Alex Bennée
  0 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2020-09-25 12:51 UTC (permalink / raw)
  To: qemu-devel, maxim.uvarov, joakim.bech, ilias.apalodimas,
	tomas.winkler, yang.huang, bing.zhu, Matti.Moell, hmo
  Cc: jean-philippe, takahiro.akashi, virtualization, arnd, stratos-dev

This is the first function with an implied response that doesn't need
a VIRTIO_RPMB_REQ_RESULT_READ.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 tools/vhost-user-rpmb/main.c | 44 ++++++++++++++++++++++++++++++++++++
 1 file changed, 44 insertions(+)

diff --git a/tools/vhost-user-rpmb/main.c b/tools/vhost-user-rpmb/main.c
index 9c98f6916f6f..88747c50fa44 100644
--- a/tools/vhost-user-rpmb/main.c
+++ b/tools/vhost-user-rpmb/main.c
@@ -121,8 +121,10 @@ typedef struct VuRpmb {
     int flash_fd;
     void *flash_map;
     uint8_t *key;
+    uint8_t  last_nonce[16];
     uint16_t last_result;
     uint16_t last_reqresp;
+    uint32_t write_count;
 } VuRpmb;
 
 /* refer to util/iov.c */
@@ -286,6 +288,42 @@ static void vrpmb_handle_program_key(VuDev *dev, struct virtio_rpmb_frame *frame
     return;
 }
 
+/*
+ * vrpmb_handle_get_write_counter:
+ *
+ * We respond straight away with re-using the frame as sent.
+ */
+static struct virtio_rpmb_frame *
+vrpmb_handle_get_write_counter(VuDev *dev, struct virtio_rpmb_frame *frame)
+{
+    VuRpmb *r = container_of(dev, VuRpmb, dev.parent);
+    struct virtio_rpmb_frame *resp = g_new0(struct virtio_rpmb_frame, 1);
+
+    /*
+     * Run the checks from:
+     * 5.12.6.1.2 Device Requirements: Device Operation: Get Write Counter
+     */
+
+    resp->req_resp = htobe16(VIRTIO_RPMB_RESP_GET_COUNTER);
+    if (!r->key) {
+        g_debug("no key programmed");
+        resp->result = htobe16(VIRTIO_RPMB_RES_NO_AUTH_KEY);
+        return resp;
+    } else if (be16toh(frame->block_count) > 1) { /* allow 0 (NONCONF) */
+        g_debug("invalid block count (%d)", be16toh(frame->block_count));
+        resp->result = htobe16(VIRTIO_RPMB_RES_GENERAL_FAILURE);
+    } else {
+        resp->write_counter = htobe32(r->write_count);
+    }
+    /* copy nonce */
+    memcpy(&resp->nonce, &frame->nonce, sizeof(frame->nonce));
+
+    /* calculate MAC */
+    vrpmb_update_mac_in_frame(r, resp);
+
+    return resp;
+}
+
 /*
  * Return the result of the last message. This is only valid if the
  * previous message was VIRTIO_RPMB_REQ_PROGRAM_KEY or
@@ -298,6 +336,9 @@ static struct virtio_rpmb_frame * vrpmb_handle_result_read(VuDev *dev)
     VuRpmb *r = container_of(dev, VuRpmb, dev.parent);
     struct virtio_rpmb_frame *resp = g_new0(struct virtio_rpmb_frame, 1);
 
+    g_info("%s: for request:%x result:%x", __func__,
+           r->last_reqresp, r->last_result);
+
     if (r->last_reqresp == VIRTIO_RPMB_RESP_PROGRAM_KEY ||
         r->last_reqresp == VIRTIO_RPMB_REQ_DATA_WRITE) {
         resp->result = htobe16(r->last_result);
@@ -393,6 +434,9 @@ vrpmb_handle_ctrl(VuDev *dev, int qidx)
             case VIRTIO_RPMB_REQ_PROGRAM_KEY:
                 vrpmb_handle_program_key(dev, f);
                 break;
+            case VIRTIO_RPMB_REQ_GET_WRITE_COUNTER:
+                resp = vrpmb_handle_get_write_counter(dev, f);
+                break;
             case VIRTIO_RPMB_REQ_RESULT_READ:
                 if (!responded) {
                     resp = vrpmb_handle_result_read(dev);
-- 
2.20.1

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

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

* [RFC PATCH 15/19] tools/vhost-user-rpmb: implement VIRTIO_RPMB_REQ_DATA_WRITE
  2020-09-25 12:51 ` Alex Bennée
@ 2020-09-25 12:51   ` Alex Bennée
  -1 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2020-09-25 12:51 UTC (permalink / raw)
  To: qemu-devel, maxim.uvarov, joakim.bech, ilias.apalodimas,
	tomas.winkler, yang.huang, bing.zhu, Matti.Moell, hmo
  Cc: jean-philippe, takahiro.akashi, virtualization, Alex Bennée,
	arnd, stratos-dev

With this command we are finally updating data to the backing store
and cycling the write_count and each successful write. We also include
the write count in all response frames as the spec is a little unclear
but the example test code expected it.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 tools/vhost-user-rpmb/main.c | 111 +++++++++++++++++++++++++++++++++--
 1 file changed, 105 insertions(+), 6 deletions(-)

diff --git a/tools/vhost-user-rpmb/main.c b/tools/vhost-user-rpmb/main.c
index 88747c50fa44..a17c3b4bcc4e 100644
--- a/tools/vhost-user-rpmb/main.c
+++ b/tools/vhost-user-rpmb/main.c
@@ -62,6 +62,7 @@ enum {
 #define KiB     (1UL << 10)
 #define MAX_RPMB_SIZE (KiB * 128 * 256)
 #define RPMB_KEY_MAC_SIZE 32
+#define RPMB_BLOCK_SIZE 256
 
 /* RPMB Request Types */
 #define VIRTIO_RPMB_REQ_PROGRAM_KEY        0x0001
@@ -100,7 +101,7 @@ struct virtio_rpmb_config {
 struct virtio_rpmb_frame {
     uint8_t stuff[196];
     uint8_t key_mac[RPMB_KEY_MAC_SIZE];
-    uint8_t data[256];
+    uint8_t data[RPMB_BLOCK_SIZE];
     uint8_t nonce[16];
     /* remaining fields are big-endian */
     uint32_t write_counter;
@@ -124,6 +125,7 @@ typedef struct VuRpmb {
     uint8_t  last_nonce[16];
     uint16_t last_result;
     uint16_t last_reqresp;
+    uint16_t last_address;
     uint32_t write_count;
 } VuRpmb;
 
@@ -239,17 +241,30 @@ vrpmb_set_config(VuDev *dev, const uint8_t *data,
  * which itself uses a 3 clause BSD chunk of code.
  */
 
+static const int rpmb_frame_dlen = (sizeof(struct virtio_rpmb_frame) -
+                                    offsetof(struct virtio_rpmb_frame, data));
+
 static void vrpmb_update_mac_in_frame(VuRpmb *r, struct virtio_rpmb_frame *frm)
 {
     hmac_sha256_ctx ctx;
-    static const int dlen = (sizeof(struct virtio_rpmb_frame) -
-                             offsetof(struct virtio_rpmb_frame, data));
 
     hmac_sha256_init(&ctx, r->key, RPMB_KEY_MAC_SIZE);
-    hmac_sha256_update(&ctx, frm->data, dlen);
+    hmac_sha256_update(&ctx, frm->data, rpmb_frame_dlen);
     hmac_sha256_final(&ctx, &frm->key_mac[0], 32);
 }
 
+static bool vrpmb_verify_mac_in_frame(VuRpmb *r, struct virtio_rpmb_frame *frm)
+{
+    hmac_sha256_ctx ctx;
+    uint8_t calculated_mac[RPMB_KEY_MAC_SIZE];
+
+    hmac_sha256_init(&ctx, r->key, RPMB_KEY_MAC_SIZE);
+    hmac_sha256_update(&ctx, frm->data, rpmb_frame_dlen);
+    hmac_sha256_final(&ctx, calculated_mac, RPMB_KEY_MAC_SIZE);
+
+    return memcmp(calculated_mac, frm->key_mac, RPMB_KEY_MAC_SIZE) == 0;
+}
+
 /*
  * Handlers for individual control messages
  */
@@ -324,6 +339,82 @@ vrpmb_handle_get_write_counter(VuDev *dev, struct virtio_rpmb_frame *frame)
     return resp;
 }
 
+/*
+ * vrpmb_handle_write:
+ *
+ * We will report the success/fail on receipt of
+ * VIRTIO_RPMB_REQ_RESULT_READ. Returns the number of extra frames
+ * processed in the request.
+ */
+static int vrpmb_handle_write(VuDev *dev, struct virtio_rpmb_frame *frame)
+{
+    VuRpmb *r = container_of(dev, VuRpmb, dev.parent);
+    int extra_frames = 0;
+    uint16_t block_count = be16toh(frame->block_count);
+    uint32_t write_counter = be32toh(frame->write_counter);
+    size_t offset;
+
+    r->last_reqresp = VIRTIO_RPMB_RESP_DATA_WRITE;
+    r->last_address = be16toh(frame->address);
+    offset =  r->last_address * RPMB_BLOCK_SIZE;
+
+    /*
+     * Run the checks from:
+     * 5.12.6.1.3 Device Requirements: Device Operation: Data Write
+     */
+    if (!r->key) {
+        g_warning("no key programmed");
+        r->last_result = VIRTIO_RPMB_RES_NO_AUTH_KEY;
+    } else if (block_count == 0 ||
+               block_count > r->virtio_config.max_wr_cnt) {
+        r->last_result = VIRTIO_RPMB_RES_GENERAL_FAILURE;
+    } else if (false /* what does an expired write counter mean? */) {
+        r->last_result = VIRTIO_RPMB_RES_WRITE_COUNTER_EXPIRED;
+    } else if (offset > (r->virtio_config.capacity * (128 * KiB))) {
+        r->last_result = VIRTIO_RPMB_RES_ADDR_FAILURE;
+    } else if (!vrpmb_verify_mac_in_frame(r, frame)) {
+        r->last_result = VIRTIO_RPMB_RES_AUTH_FAILURE;
+    } else if (write_counter != r->write_count) {
+        r->last_result = VIRTIO_RPMB_RES_COUNT_FAILURE;
+    } else {
+        int i;
+        /* At this point we have a valid authenticated write request
+         * so the counter can incremented and we can attempt to
+         * update the backing device.
+         */
+        r->write_count++;
+        for (i = 0; i < block_count; i++) {
+            void *blk = r->flash_map + offset;
+            g_debug("%s: writing block %d", __func__, i);
+            if (mprotect(blk, RPMB_BLOCK_SIZE, PROT_WRITE) != 0) {
+                r->last_result =  VIRTIO_RPMB_RES_WRITE_FAILURE;
+                break;
+            }
+            memcpy(blk, frame[i].data, RPMB_BLOCK_SIZE);
+            if (msync(blk, RPMB_BLOCK_SIZE, MS_SYNC) != 0) {
+                g_warning("%s: failed to sync update", __func__);
+                r->last_result = VIRTIO_RPMB_RES_WRITE_FAILURE;
+                break;
+            }
+            if (mprotect(blk, RPMB_BLOCK_SIZE, PROT_READ) != 0) {
+                g_warning("%s: failed to re-apply read protection", __func__);
+                r->last_result = VIRTIO_RPMB_RES_GENERAL_FAILURE;
+                break;
+            }
+            offset += RPMB_BLOCK_SIZE;
+        }
+        r->last_result = VIRTIO_RPMB_RES_OK;
+        extra_frames = i - 1;
+    }
+
+    g_info("%s: %s (%x, %d extra frames processed), write_count=%d", __func__,
+           r->last_result == VIRTIO_RPMB_RES_OK ? "successful":"failed",
+           r->last_result, extra_frames, r->write_count);
+
+    return extra_frames;
+}
+
+
 /*
  * Return the result of the last message. This is only valid if the
  * previous message was VIRTIO_RPMB_REQ_PROGRAM_KEY or
@@ -339,10 +430,14 @@ static struct virtio_rpmb_frame * vrpmb_handle_result_read(VuDev *dev)
     g_info("%s: for request:%x result:%x", __func__,
            r->last_reqresp, r->last_result);
 
-    if (r->last_reqresp == VIRTIO_RPMB_RESP_PROGRAM_KEY ||
-        r->last_reqresp == VIRTIO_RPMB_REQ_DATA_WRITE) {
+    if (r->last_reqresp == VIRTIO_RPMB_RESP_PROGRAM_KEY) {
         resp->result = htobe16(r->last_result);
         resp->req_resp = htobe16(r->last_reqresp);
+    } else if (r->last_reqresp == VIRTIO_RPMB_RESP_DATA_WRITE) {
+        resp->result = htobe16(r->last_result);
+        resp->req_resp = htobe16(r->last_reqresp);
+        resp->write_counter = htobe32(r->write_count);
+        resp->address = htobe16(r->last_address);
     } else {
         resp->result = htobe16(VIRTIO_RPMB_RES_GENERAL_FAILURE);
     }
@@ -445,6 +540,10 @@ vrpmb_handle_ctrl(VuDev *dev, int qidx)
                               __func__);
                 }
                 break;
+            case VIRTIO_RPMB_REQ_DATA_WRITE:
+                /* we can have multiple blocks handled */
+                n += vrpmb_handle_write(dev, f);
+                break;
             default:
                 g_debug("un-handled request: %x", f->req_resp);
                 break;
-- 
2.20.1



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

* [RFC PATCH 15/19] tools/vhost-user-rpmb: implement VIRTIO_RPMB_REQ_DATA_WRITE
@ 2020-09-25 12:51   ` Alex Bennée
  0 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2020-09-25 12:51 UTC (permalink / raw)
  To: qemu-devel, maxim.uvarov, joakim.bech, ilias.apalodimas,
	tomas.winkler, yang.huang, bing.zhu, Matti.Moell, hmo
  Cc: jean-philippe, takahiro.akashi, virtualization, arnd, stratos-dev

With this command we are finally updating data to the backing store
and cycling the write_count and each successful write. We also include
the write count in all response frames as the spec is a little unclear
but the example test code expected it.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 tools/vhost-user-rpmb/main.c | 111 +++++++++++++++++++++++++++++++++--
 1 file changed, 105 insertions(+), 6 deletions(-)

diff --git a/tools/vhost-user-rpmb/main.c b/tools/vhost-user-rpmb/main.c
index 88747c50fa44..a17c3b4bcc4e 100644
--- a/tools/vhost-user-rpmb/main.c
+++ b/tools/vhost-user-rpmb/main.c
@@ -62,6 +62,7 @@ enum {
 #define KiB     (1UL << 10)
 #define MAX_RPMB_SIZE (KiB * 128 * 256)
 #define RPMB_KEY_MAC_SIZE 32
+#define RPMB_BLOCK_SIZE 256
 
 /* RPMB Request Types */
 #define VIRTIO_RPMB_REQ_PROGRAM_KEY        0x0001
@@ -100,7 +101,7 @@ struct virtio_rpmb_config {
 struct virtio_rpmb_frame {
     uint8_t stuff[196];
     uint8_t key_mac[RPMB_KEY_MAC_SIZE];
-    uint8_t data[256];
+    uint8_t data[RPMB_BLOCK_SIZE];
     uint8_t nonce[16];
     /* remaining fields are big-endian */
     uint32_t write_counter;
@@ -124,6 +125,7 @@ typedef struct VuRpmb {
     uint8_t  last_nonce[16];
     uint16_t last_result;
     uint16_t last_reqresp;
+    uint16_t last_address;
     uint32_t write_count;
 } VuRpmb;
 
@@ -239,17 +241,30 @@ vrpmb_set_config(VuDev *dev, const uint8_t *data,
  * which itself uses a 3 clause BSD chunk of code.
  */
 
+static const int rpmb_frame_dlen = (sizeof(struct virtio_rpmb_frame) -
+                                    offsetof(struct virtio_rpmb_frame, data));
+
 static void vrpmb_update_mac_in_frame(VuRpmb *r, struct virtio_rpmb_frame *frm)
 {
     hmac_sha256_ctx ctx;
-    static const int dlen = (sizeof(struct virtio_rpmb_frame) -
-                             offsetof(struct virtio_rpmb_frame, data));
 
     hmac_sha256_init(&ctx, r->key, RPMB_KEY_MAC_SIZE);
-    hmac_sha256_update(&ctx, frm->data, dlen);
+    hmac_sha256_update(&ctx, frm->data, rpmb_frame_dlen);
     hmac_sha256_final(&ctx, &frm->key_mac[0], 32);
 }
 
+static bool vrpmb_verify_mac_in_frame(VuRpmb *r, struct virtio_rpmb_frame *frm)
+{
+    hmac_sha256_ctx ctx;
+    uint8_t calculated_mac[RPMB_KEY_MAC_SIZE];
+
+    hmac_sha256_init(&ctx, r->key, RPMB_KEY_MAC_SIZE);
+    hmac_sha256_update(&ctx, frm->data, rpmb_frame_dlen);
+    hmac_sha256_final(&ctx, calculated_mac, RPMB_KEY_MAC_SIZE);
+
+    return memcmp(calculated_mac, frm->key_mac, RPMB_KEY_MAC_SIZE) == 0;
+}
+
 /*
  * Handlers for individual control messages
  */
@@ -324,6 +339,82 @@ vrpmb_handle_get_write_counter(VuDev *dev, struct virtio_rpmb_frame *frame)
     return resp;
 }
 
+/*
+ * vrpmb_handle_write:
+ *
+ * We will report the success/fail on receipt of
+ * VIRTIO_RPMB_REQ_RESULT_READ. Returns the number of extra frames
+ * processed in the request.
+ */
+static int vrpmb_handle_write(VuDev *dev, struct virtio_rpmb_frame *frame)
+{
+    VuRpmb *r = container_of(dev, VuRpmb, dev.parent);
+    int extra_frames = 0;
+    uint16_t block_count = be16toh(frame->block_count);
+    uint32_t write_counter = be32toh(frame->write_counter);
+    size_t offset;
+
+    r->last_reqresp = VIRTIO_RPMB_RESP_DATA_WRITE;
+    r->last_address = be16toh(frame->address);
+    offset =  r->last_address * RPMB_BLOCK_SIZE;
+
+    /*
+     * Run the checks from:
+     * 5.12.6.1.3 Device Requirements: Device Operation: Data Write
+     */
+    if (!r->key) {
+        g_warning("no key programmed");
+        r->last_result = VIRTIO_RPMB_RES_NO_AUTH_KEY;
+    } else if (block_count == 0 ||
+               block_count > r->virtio_config.max_wr_cnt) {
+        r->last_result = VIRTIO_RPMB_RES_GENERAL_FAILURE;
+    } else if (false /* what does an expired write counter mean? */) {
+        r->last_result = VIRTIO_RPMB_RES_WRITE_COUNTER_EXPIRED;
+    } else if (offset > (r->virtio_config.capacity * (128 * KiB))) {
+        r->last_result = VIRTIO_RPMB_RES_ADDR_FAILURE;
+    } else if (!vrpmb_verify_mac_in_frame(r, frame)) {
+        r->last_result = VIRTIO_RPMB_RES_AUTH_FAILURE;
+    } else if (write_counter != r->write_count) {
+        r->last_result = VIRTIO_RPMB_RES_COUNT_FAILURE;
+    } else {
+        int i;
+        /* At this point we have a valid authenticated write request
+         * so the counter can incremented and we can attempt to
+         * update the backing device.
+         */
+        r->write_count++;
+        for (i = 0; i < block_count; i++) {
+            void *blk = r->flash_map + offset;
+            g_debug("%s: writing block %d", __func__, i);
+            if (mprotect(blk, RPMB_BLOCK_SIZE, PROT_WRITE) != 0) {
+                r->last_result =  VIRTIO_RPMB_RES_WRITE_FAILURE;
+                break;
+            }
+            memcpy(blk, frame[i].data, RPMB_BLOCK_SIZE);
+            if (msync(blk, RPMB_BLOCK_SIZE, MS_SYNC) != 0) {
+                g_warning("%s: failed to sync update", __func__);
+                r->last_result = VIRTIO_RPMB_RES_WRITE_FAILURE;
+                break;
+            }
+            if (mprotect(blk, RPMB_BLOCK_SIZE, PROT_READ) != 0) {
+                g_warning("%s: failed to re-apply read protection", __func__);
+                r->last_result = VIRTIO_RPMB_RES_GENERAL_FAILURE;
+                break;
+            }
+            offset += RPMB_BLOCK_SIZE;
+        }
+        r->last_result = VIRTIO_RPMB_RES_OK;
+        extra_frames = i - 1;
+    }
+
+    g_info("%s: %s (%x, %d extra frames processed), write_count=%d", __func__,
+           r->last_result == VIRTIO_RPMB_RES_OK ? "successful":"failed",
+           r->last_result, extra_frames, r->write_count);
+
+    return extra_frames;
+}
+
+
 /*
  * Return the result of the last message. This is only valid if the
  * previous message was VIRTIO_RPMB_REQ_PROGRAM_KEY or
@@ -339,10 +430,14 @@ static struct virtio_rpmb_frame * vrpmb_handle_result_read(VuDev *dev)
     g_info("%s: for request:%x result:%x", __func__,
            r->last_reqresp, r->last_result);
 
-    if (r->last_reqresp == VIRTIO_RPMB_RESP_PROGRAM_KEY ||
-        r->last_reqresp == VIRTIO_RPMB_REQ_DATA_WRITE) {
+    if (r->last_reqresp == VIRTIO_RPMB_RESP_PROGRAM_KEY) {
         resp->result = htobe16(r->last_result);
         resp->req_resp = htobe16(r->last_reqresp);
+    } else if (r->last_reqresp == VIRTIO_RPMB_RESP_DATA_WRITE) {
+        resp->result = htobe16(r->last_result);
+        resp->req_resp = htobe16(r->last_reqresp);
+        resp->write_counter = htobe32(r->write_count);
+        resp->address = htobe16(r->last_address);
     } else {
         resp->result = htobe16(VIRTIO_RPMB_RES_GENERAL_FAILURE);
     }
@@ -445,6 +540,10 @@ vrpmb_handle_ctrl(VuDev *dev, int qidx)
                               __func__);
                 }
                 break;
+            case VIRTIO_RPMB_REQ_DATA_WRITE:
+                /* we can have multiple blocks handled */
+                n += vrpmb_handle_write(dev, f);
+                break;
             default:
                 g_debug("un-handled request: %x", f->req_resp);
                 break;
-- 
2.20.1

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

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

* [RFC PATCH 16/19] tools/vhost-user-rpmb: implement VIRTIO_RPMB_REQ_DATA_READ
  2020-09-25 12:51 ` Alex Bennée
@ 2020-09-25 12:51   ` Alex Bennée
  -1 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2020-09-25 12:51 UTC (permalink / raw)
  To: qemu-devel, maxim.uvarov, joakim.bech, ilias.apalodimas,
	tomas.winkler, yang.huang, bing.zhu, Matti.Moell, hmo
  Cc: jean-philippe, takahiro.akashi, virtualization, Alex Bennée,
	arnd, stratos-dev

The read command is a lot simpler to implement. However the spec does
specify you can only read a single block at a time so we limit it to
that.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 tools/vhost-user-rpmb/main.c | 52 ++++++++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)

diff --git a/tools/vhost-user-rpmb/main.c b/tools/vhost-user-rpmb/main.c
index a17c3b4bcc4e..49d4e00b24a9 100644
--- a/tools/vhost-user-rpmb/main.c
+++ b/tools/vhost-user-rpmb/main.c
@@ -414,6 +414,55 @@ static int vrpmb_handle_write(VuDev *dev, struct virtio_rpmb_frame *frame)
     return extra_frames;
 }
 
+/*
+ * vrpmb_handle_read:
+ *
+ * Unlike the write operation we return a frame with the result of the
+ * read here. While the config specifies a maximum read count the spec
+ * is limited to a single read at a time.
+ */
+static struct virtio_rpmb_frame *
+vrpmb_handle_read(VuDev *dev, struct virtio_rpmb_frame *frame)
+{
+    VuRpmb *r = container_of(dev, VuRpmb, dev.parent);
+    size_t offset = be16toh(frame->address) * RPMB_BLOCK_SIZE;
+    uint16_t block_count = be16toh(frame->block_count);
+    struct virtio_rpmb_frame *resp = g_new0(struct virtio_rpmb_frame, 1);
+
+    resp->req_resp = htobe16(VIRTIO_RPMB_RESP_DATA_READ);
+    resp->address = frame->address;
+    resp->block_count = htobe16(1);
+
+    /*
+     * Run the checks from:
+     * 5.12.6.1.4 Device Requirements: Device Operation: Data Read
+     */
+    if (!r->key) {
+        g_warning("no key programmed");
+        resp->result = htobe16(VIRTIO_RPMB_RES_NO_AUTH_KEY);
+    } else if (block_count != 1) {
+        /*
+         * Despite the config the spec only allows for reading one
+         * block at a time: "If block count has not been set to 1 then
+         * VIRTIO_RPMB_RES_GENERAL_FAILURE SHOULD be responded as
+         * result."
+         */
+        resp->result = htobe16(VIRTIO_RPMB_RES_GENERAL_FAILURE);
+    } else if (offset > (r->virtio_config.capacity * (128 * KiB))) {
+        resp->result = htobe16(VIRTIO_RPMB_RES_ADDR_FAILURE);
+    } else {
+        void *blk = r->flash_map + offset;
+        g_debug("%s: reading block from %p (%zu)", __func__, blk, offset);
+        memcpy(resp->data, blk, RPMB_BLOCK_SIZE);
+        resp->result = htobe16(VIRTIO_RPMB_RES_OK);
+    }
+
+    /* Final housekeeping, copy nonce and calculate MAC */
+    memcpy(&resp->nonce, &frame->nonce, sizeof(frame->nonce));
+    vrpmb_update_mac_in_frame(r, resp);
+
+    return resp;
+}
 
 /*
  * Return the result of the last message. This is only valid if the
@@ -544,6 +593,9 @@ vrpmb_handle_ctrl(VuDev *dev, int qidx)
                 /* we can have multiple blocks handled */
                 n += vrpmb_handle_write(dev, f);
                 break;
+            case VIRTIO_RPMB_REQ_DATA_READ:
+                resp = vrpmb_handle_read(dev, f);
+                break;
             default:
                 g_debug("un-handled request: %x", f->req_resp);
                 break;
-- 
2.20.1



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

* [RFC PATCH 16/19] tools/vhost-user-rpmb: implement VIRTIO_RPMB_REQ_DATA_READ
@ 2020-09-25 12:51   ` Alex Bennée
  0 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2020-09-25 12:51 UTC (permalink / raw)
  To: qemu-devel, maxim.uvarov, joakim.bech, ilias.apalodimas,
	tomas.winkler, yang.huang, bing.zhu, Matti.Moell, hmo
  Cc: jean-philippe, takahiro.akashi, virtualization, arnd, stratos-dev

The read command is a lot simpler to implement. However the spec does
specify you can only read a single block at a time so we limit it to
that.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 tools/vhost-user-rpmb/main.c | 52 ++++++++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)

diff --git a/tools/vhost-user-rpmb/main.c b/tools/vhost-user-rpmb/main.c
index a17c3b4bcc4e..49d4e00b24a9 100644
--- a/tools/vhost-user-rpmb/main.c
+++ b/tools/vhost-user-rpmb/main.c
@@ -414,6 +414,55 @@ static int vrpmb_handle_write(VuDev *dev, struct virtio_rpmb_frame *frame)
     return extra_frames;
 }
 
+/*
+ * vrpmb_handle_read:
+ *
+ * Unlike the write operation we return a frame with the result of the
+ * read here. While the config specifies a maximum read count the spec
+ * is limited to a single read at a time.
+ */
+static struct virtio_rpmb_frame *
+vrpmb_handle_read(VuDev *dev, struct virtio_rpmb_frame *frame)
+{
+    VuRpmb *r = container_of(dev, VuRpmb, dev.parent);
+    size_t offset = be16toh(frame->address) * RPMB_BLOCK_SIZE;
+    uint16_t block_count = be16toh(frame->block_count);
+    struct virtio_rpmb_frame *resp = g_new0(struct virtio_rpmb_frame, 1);
+
+    resp->req_resp = htobe16(VIRTIO_RPMB_RESP_DATA_READ);
+    resp->address = frame->address;
+    resp->block_count = htobe16(1);
+
+    /*
+     * Run the checks from:
+     * 5.12.6.1.4 Device Requirements: Device Operation: Data Read
+     */
+    if (!r->key) {
+        g_warning("no key programmed");
+        resp->result = htobe16(VIRTIO_RPMB_RES_NO_AUTH_KEY);
+    } else if (block_count != 1) {
+        /*
+         * Despite the config the spec only allows for reading one
+         * block at a time: "If block count has not been set to 1 then
+         * VIRTIO_RPMB_RES_GENERAL_FAILURE SHOULD be responded as
+         * result."
+         */
+        resp->result = htobe16(VIRTIO_RPMB_RES_GENERAL_FAILURE);
+    } else if (offset > (r->virtio_config.capacity * (128 * KiB))) {
+        resp->result = htobe16(VIRTIO_RPMB_RES_ADDR_FAILURE);
+    } else {
+        void *blk = r->flash_map + offset;
+        g_debug("%s: reading block from %p (%zu)", __func__, blk, offset);
+        memcpy(resp->data, blk, RPMB_BLOCK_SIZE);
+        resp->result = htobe16(VIRTIO_RPMB_RES_OK);
+    }
+
+    /* Final housekeeping, copy nonce and calculate MAC */
+    memcpy(&resp->nonce, &frame->nonce, sizeof(frame->nonce));
+    vrpmb_update_mac_in_frame(r, resp);
+
+    return resp;
+}
 
 /*
  * Return the result of the last message. This is only valid if the
@@ -544,6 +593,9 @@ vrpmb_handle_ctrl(VuDev *dev, int qidx)
                 /* we can have multiple blocks handled */
                 n += vrpmb_handle_write(dev, f);
                 break;
+            case VIRTIO_RPMB_REQ_DATA_READ:
+                resp = vrpmb_handle_read(dev, f);
+                break;
             default:
                 g_debug("un-handled request: %x", f->req_resp);
                 break;
-- 
2.20.1

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

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

* [RFC PATCH  17/19] tools/vhost-user-rpmb: add key persistence
  2020-09-25 12:51 ` Alex Bennée
@ 2020-09-25 12:51   ` Alex Bennée
  -1 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2020-09-25 12:51 UTC (permalink / raw)
  To: qemu-devel, maxim.uvarov, joakim.bech, ilias.apalodimas,
	tomas.winkler, yang.huang, bing.zhu, Matti.Moell, hmo
  Cc: jean-philippe, takahiro.akashi, virtualization, Alex Bennée,
	arnd, stratos-dev

Add support for persisting the key in --key-path. By default it will
accept the program-key command and store the key in the key file. If
you pass --key-set then the key is deemed to be programmed and can't
be re-programmed. Obviously you will need some other mechanism to let
the guest know what the key is so it can do other operations.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 tools/vhost-user-rpmb/main.c | 37 ++++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)

diff --git a/tools/vhost-user-rpmb/main.c b/tools/vhost-user-rpmb/main.c
index 49d4e00b24a9..34607ad19429 100644
--- a/tools/vhost-user-rpmb/main.c
+++ b/tools/vhost-user-rpmb/main.c
@@ -38,15 +38,19 @@
 
 static gchar *socket_path;
 static char *flash_path;
+static char *key_path;
 static gint socket_fd = -1;
 static gboolean print_cap;
 static gboolean verbose;
 static gboolean debug;
+static gboolean key_set;
 
 static GOptionEntry options[] =
 {
     { "socket-path", 0, 0, G_OPTION_ARG_FILENAME, &socket_path, "Location of vhost-user Unix domain socket, incompatible with --fd", "PATH" },
     { "flash-path", 0, 0, G_OPTION_ARG_FILENAME, &flash_path, "Location of raw flash image file", "PATH" },
+    { "key-path", 0, 0, G_OPTION_ARG_FILENAME, &key_path, "Location of persistent keyfile", "KEY"},
+    { "key-set", 0, 0, G_OPTION_ARG_NONE, &key_set, "Is the key already programmed", NULL},
     { "fd", 0, 0, G_OPTION_ARG_INT, &socket_fd, "Specify the file-descriptor of the backend, incompatible with --socket-path", "FD" },
     { "print-capabilities", 0, 0, G_OPTION_ARG_NONE, &print_cap, "Output to stdout the backend capabilities in JSON format and exit", NULL},
     { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Be more verbose in output", NULL},
@@ -296,8 +300,18 @@ static void vrpmb_handle_program_key(VuDev *dev, struct virtio_rpmb_frame *frame
     } else {
         r->key = g_memdup(&frame->key_mac[0], RPMB_KEY_MAC_SIZE);
         r->last_result = VIRTIO_RPMB_RES_OK;
+        if (key_path) {
+            GError *err = NULL;
+            if (!g_file_set_contents(key_path, (char *) r->key,
+                                     RPMB_KEY_MAC_SIZE, &err)) {
+                g_warning("%s: unable to persist key data to %s: %s",
+                          __func__, key_path, err->message);
+                g_error_free(err);
+            }
+        }
     }
 
+
     g_info("%s: req_resp = %x, result = %x", __func__,
            r->last_reqresp, r->last_result);
     return;
@@ -709,6 +723,25 @@ static bool vrpmb_load_flash_image(VuRpmb *r, char *img_path)
     return true;
 }
 
+static void vrpmb_set_key(VuRpmb *r, char *key_path)
+{
+    GError *err = NULL;
+    gsize length;
+
+    if (!g_file_get_contents(key_path, (char **) &r->key, &length, &err)) {
+        g_print("Unable to read %s: %s", key_path, err->message);
+        exit(1);
+    }
+    if (length < RPMB_KEY_MAC_SIZE) {
+        g_print("key file to small %ld < %d", length, RPMB_KEY_MAC_SIZE);
+        exit(1);
+    } else if (length > RPMB_KEY_MAC_SIZE) {
+        /* being too big isn't fatal, we just ignore the excess */
+        g_warning("%ld bytes of %s ignore (file too big)",
+                  length - RPMB_KEY_MAC_SIZE, key_path);
+    }
+}
+
 static void vrpmb_destroy(VuRpmb *r)
 {
     vug_deinit(&r->dev);
@@ -760,6 +793,10 @@ int main(int argc, char *argv[])
         vrpmb_load_flash_image(&rpmb, flash_path);
     }
 
+    if (key_path && key_set) {
+        vrpmb_set_key(&rpmb, key_path);
+    }
+
     if (!socket_path && socket_fd < 0) {
         g_printerr("Please specify either --fd or --socket-path\n");
         exit(EXIT_FAILURE);
-- 
2.20.1



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

* [RFC PATCH  17/19] tools/vhost-user-rpmb: add key persistence
@ 2020-09-25 12:51   ` Alex Bennée
  0 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2020-09-25 12:51 UTC (permalink / raw)
  To: qemu-devel, maxim.uvarov, joakim.bech, ilias.apalodimas,
	tomas.winkler, yang.huang, bing.zhu, Matti.Moell, hmo
  Cc: jean-philippe, takahiro.akashi, virtualization, arnd, stratos-dev

Add support for persisting the key in --key-path. By default it will
accept the program-key command and store the key in the key file. If
you pass --key-set then the key is deemed to be programmed and can't
be re-programmed. Obviously you will need some other mechanism to let
the guest know what the key is so it can do other operations.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 tools/vhost-user-rpmb/main.c | 37 ++++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)

diff --git a/tools/vhost-user-rpmb/main.c b/tools/vhost-user-rpmb/main.c
index 49d4e00b24a9..34607ad19429 100644
--- a/tools/vhost-user-rpmb/main.c
+++ b/tools/vhost-user-rpmb/main.c
@@ -38,15 +38,19 @@
 
 static gchar *socket_path;
 static char *flash_path;
+static char *key_path;
 static gint socket_fd = -1;
 static gboolean print_cap;
 static gboolean verbose;
 static gboolean debug;
+static gboolean key_set;
 
 static GOptionEntry options[] =
 {
     { "socket-path", 0, 0, G_OPTION_ARG_FILENAME, &socket_path, "Location of vhost-user Unix domain socket, incompatible with --fd", "PATH" },
     { "flash-path", 0, 0, G_OPTION_ARG_FILENAME, &flash_path, "Location of raw flash image file", "PATH" },
+    { "key-path", 0, 0, G_OPTION_ARG_FILENAME, &key_path, "Location of persistent keyfile", "KEY"},
+    { "key-set", 0, 0, G_OPTION_ARG_NONE, &key_set, "Is the key already programmed", NULL},
     { "fd", 0, 0, G_OPTION_ARG_INT, &socket_fd, "Specify the file-descriptor of the backend, incompatible with --socket-path", "FD" },
     { "print-capabilities", 0, 0, G_OPTION_ARG_NONE, &print_cap, "Output to stdout the backend capabilities in JSON format and exit", NULL},
     { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Be more verbose in output", NULL},
@@ -296,8 +300,18 @@ static void vrpmb_handle_program_key(VuDev *dev, struct virtio_rpmb_frame *frame
     } else {
         r->key = g_memdup(&frame->key_mac[0], RPMB_KEY_MAC_SIZE);
         r->last_result = VIRTIO_RPMB_RES_OK;
+        if (key_path) {
+            GError *err = NULL;
+            if (!g_file_set_contents(key_path, (char *) r->key,
+                                     RPMB_KEY_MAC_SIZE, &err)) {
+                g_warning("%s: unable to persist key data to %s: %s",
+                          __func__, key_path, err->message);
+                g_error_free(err);
+            }
+        }
     }
 
+
     g_info("%s: req_resp = %x, result = %x", __func__,
            r->last_reqresp, r->last_result);
     return;
@@ -709,6 +723,25 @@ static bool vrpmb_load_flash_image(VuRpmb *r, char *img_path)
     return true;
 }
 
+static void vrpmb_set_key(VuRpmb *r, char *key_path)
+{
+    GError *err = NULL;
+    gsize length;
+
+    if (!g_file_get_contents(key_path, (char **) &r->key, &length, &err)) {
+        g_print("Unable to read %s: %s", key_path, err->message);
+        exit(1);
+    }
+    if (length < RPMB_KEY_MAC_SIZE) {
+        g_print("key file to small %ld < %d", length, RPMB_KEY_MAC_SIZE);
+        exit(1);
+    } else if (length > RPMB_KEY_MAC_SIZE) {
+        /* being too big isn't fatal, we just ignore the excess */
+        g_warning("%ld bytes of %s ignore (file too big)",
+                  length - RPMB_KEY_MAC_SIZE, key_path);
+    }
+}
+
 static void vrpmb_destroy(VuRpmb *r)
 {
     vug_deinit(&r->dev);
@@ -760,6 +793,10 @@ int main(int argc, char *argv[])
         vrpmb_load_flash_image(&rpmb, flash_path);
     }
 
+    if (key_path && key_set) {
+        vrpmb_set_key(&rpmb, key_path);
+    }
+
     if (!socket_path && socket_fd < 0) {
         g_printerr("Please specify either --fd or --socket-path\n");
         exit(EXIT_FAILURE);
-- 
2.20.1

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

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

* [RFC PATCH 18/19] tools/vhost-user-rpmb: allow setting of the write_count
  2020-09-25 12:51 ` Alex Bennée
@ 2020-09-25 12:51   ` Alex Bennée
  -1 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2020-09-25 12:51 UTC (permalink / raw)
  To: qemu-devel, maxim.uvarov, joakim.bech, ilias.apalodimas,
	tomas.winkler, yang.huang, bing.zhu, Matti.Moell, hmo
  Cc: jean-philippe, takahiro.akashi, virtualization, Alex Bennée,
	arnd, stratos-dev

This is mostly useful for testing. Practically all guest operations
will probe the write count before any write transaction.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 tools/vhost-user-rpmb/main.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/tools/vhost-user-rpmb/main.c b/tools/vhost-user-rpmb/main.c
index 34607ad19429..c798a6f66cd2 100644
--- a/tools/vhost-user-rpmb/main.c
+++ b/tools/vhost-user-rpmb/main.c
@@ -39,6 +39,7 @@
 static gchar *socket_path;
 static char *flash_path;
 static char *key_path;
+static gint initial_counter;
 static gint socket_fd = -1;
 static gboolean print_cap;
 static gboolean verbose;
@@ -49,6 +50,7 @@ static GOptionEntry options[] =
 {
     { "socket-path", 0, 0, G_OPTION_ARG_FILENAME, &socket_path, "Location of vhost-user Unix domain socket, incompatible with --fd", "PATH" },
     { "flash-path", 0, 0, G_OPTION_ARG_FILENAME, &flash_path, "Location of raw flash image file", "PATH" },
+    { "initial-counter", 0, 0, G_OPTION_ARG_INT, &initial_counter, "Set initial value of write counter", NULL},
     { "key-path", 0, 0, G_OPTION_ARG_FILENAME, &key_path, "Location of persistent keyfile", "KEY"},
     { "key-set", 0, 0, G_OPTION_ARG_NONE, &key_set, "Is the key already programmed", NULL},
     { "fd", 0, 0, G_OPTION_ARG_INT, &socket_fd, "Specify the file-descriptor of the backend, incompatible with --socket-path", "FD" },
@@ -797,6 +799,10 @@ int main(int argc, char *argv[])
         vrpmb_set_key(&rpmb, key_path);
     }
 
+    if (initial_counter) {
+        rpmb.write_count = initial_counter;
+    }
+
     if (!socket_path && socket_fd < 0) {
         g_printerr("Please specify either --fd or --socket-path\n");
         exit(EXIT_FAILURE);
-- 
2.20.1



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

* [RFC PATCH 18/19] tools/vhost-user-rpmb: allow setting of the write_count
@ 2020-09-25 12:51   ` Alex Bennée
  0 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2020-09-25 12:51 UTC (permalink / raw)
  To: qemu-devel, maxim.uvarov, joakim.bech, ilias.apalodimas,
	tomas.winkler, yang.huang, bing.zhu, Matti.Moell, hmo
  Cc: jean-philippe, takahiro.akashi, virtualization, arnd, stratos-dev

This is mostly useful for testing. Practically all guest operations
will probe the write count before any write transaction.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 tools/vhost-user-rpmb/main.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/tools/vhost-user-rpmb/main.c b/tools/vhost-user-rpmb/main.c
index 34607ad19429..c798a6f66cd2 100644
--- a/tools/vhost-user-rpmb/main.c
+++ b/tools/vhost-user-rpmb/main.c
@@ -39,6 +39,7 @@
 static gchar *socket_path;
 static char *flash_path;
 static char *key_path;
+static gint initial_counter;
 static gint socket_fd = -1;
 static gboolean print_cap;
 static gboolean verbose;
@@ -49,6 +50,7 @@ static GOptionEntry options[] =
 {
     { "socket-path", 0, 0, G_OPTION_ARG_FILENAME, &socket_path, "Location of vhost-user Unix domain socket, incompatible with --fd", "PATH" },
     { "flash-path", 0, 0, G_OPTION_ARG_FILENAME, &flash_path, "Location of raw flash image file", "PATH" },
+    { "initial-counter", 0, 0, G_OPTION_ARG_INT, &initial_counter, "Set initial value of write counter", NULL},
     { "key-path", 0, 0, G_OPTION_ARG_FILENAME, &key_path, "Location of persistent keyfile", "KEY"},
     { "key-set", 0, 0, G_OPTION_ARG_NONE, &key_set, "Is the key already programmed", NULL},
     { "fd", 0, 0, G_OPTION_ARG_INT, &socket_fd, "Specify the file-descriptor of the backend, incompatible with --socket-path", "FD" },
@@ -797,6 +799,10 @@ int main(int argc, char *argv[])
         vrpmb_set_key(&rpmb, key_path);
     }
 
+    if (initial_counter) {
+        rpmb.write_count = initial_counter;
+    }
+
     if (!socket_path && socket_fd < 0) {
         g_printerr("Please specify either --fd or --socket-path\n");
         exit(EXIT_FAILURE);
-- 
2.20.1

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

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

* [RFC PATCH  19/19] docs: add a man page for vhost-user-rpmb
  2020-09-25 12:51 ` Alex Bennée
@ 2020-09-25 12:51   ` Alex Bennée
  -1 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2020-09-25 12:51 UTC (permalink / raw)
  To: qemu-devel, maxim.uvarov, joakim.bech, ilias.apalodimas,
	tomas.winkler, yang.huang, bing.zhu, Matti.Moell, hmo
  Cc: jean-philippe, takahiro.akashi, virtualization, Alex Bennée,
	arnd, stratos-dev

Basic usage and example invocation.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 docs/tools/index.rst           |   1 +
 docs/tools/vhost-user-rpmb.rst | 102 +++++++++++++++++++++++++++++++++
 2 files changed, 103 insertions(+)
 create mode 100644 docs/tools/vhost-user-rpmb.rst

diff --git a/docs/tools/index.rst b/docs/tools/index.rst
index 232ce9f3e463..488784b3bf1f 100644
--- a/docs/tools/index.rst
+++ b/docs/tools/index.rst
@@ -15,3 +15,4 @@ Contents:
    qemu-trace-stap
    virtfs-proxy-helper
    virtiofsd
+   vhost-user-rpmb
diff --git a/docs/tools/vhost-user-rpmb.rst b/docs/tools/vhost-user-rpmb.rst
new file mode 100644
index 000000000000..40d5d3bceb7c
--- /dev/null
+++ b/docs/tools/vhost-user-rpmb.rst
@@ -0,0 +1,102 @@
+QEMU vhost-user-rpmb - rpmb emulation backend
+=============================================
+
+Synopsis
+--------
+
+**vhost-user-rpmb** [*OPTIONS*]
+
+Description
+-----------
+
+This program is a vhost-user backed that emulates a VirtIO Replay
+Protected Memory Block device. These are usually special partitions
+that are part of a flash device that offer protection against reply
+attacks. They are used to store secure information in a way that is
+hard to tamper with.
+
+This program is designed to work with QEMU's ``--device
+vhost-user-rpmb-pci`` but should work with any virtual machine
+monitor (VMM) that supports vhost-user. See the Examples section
+below.
+
+This program requires a backing store to persist any data programmed
+into the device. The spec supports devices up 32Mb in size. For the
+daemon this is simply a raw file of the appropriate size. To program
+the device it needs to have a key. This can either be programmed by
+the guest at the start or come from a key file supplied to the daemon.
+
+Options
+-------
+
+.. program:: vhost-user-rpmb
+
+.. option:: -h, --help
+
+  Print help.
+
+.. option:: -V, --version
+
+  Print version.
+
+.. option:: -v, --verbose
+
+   Increase verbosity of output
+            
+.. option:: --debug
+
+  Enable debug output.
+
+.. option:: --socket-path=PATH
+
+  Listen on vhost-user UNIX domain socket at PATH. Incompatible with --fd.
+
+.. option:: --fd=FDNUM
+
+  Accept connections from vhost-user UNIX domain socket file descriptor FDNUM.
+  The file descriptor must already be listening for connections.
+  Incompatible with --socket-path.
+
+.. option:: --flash-path=PATH
+
+  Path to the backing store for the flash image, can be up to 32Mb in size.
+
+.. option:: --key-path=PATH
+
+  Path to the backing store for the key of 32 bytes.
+            
+.. option:: --key-set
+
+  Treat the value of key-path as set meaning the key cannot be
+  reprogrammed by the guest.
+
+.. option:: --initial-counter=N
+
+  Set the initial value of the devices write count. It is
+  incremented by each write operation. 
+
+Examples
+--------
+
+The daemon should be started first:
+
+::
+
+  host# vhost-user-rpmb --socket-path=vrpmb.sock \
+   --flash-path=flash.img \
+   --key-path=key --key-set \
+   --initial-counter=1234
+
+The QEMU invocation needs to create a chardev socket the device can
+use to communicate as well as share the guests memory over a memfd.
+
+::
+
+  host# qemu-system \
+      -chardev socket,path=vrpmb.sock,id=vrpmb \
+      -device vhost-user-rpmb-pci,chardev=vrpmb,id=rpmb \
+      -m 4096 \
+      -object memory-backend-file,id=mem,size=4G,mem-path=/dev/shm,share=on \
+      -numa node,memdev=mem \
+      ...
+
-- 
2.20.1



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

* [RFC PATCH  19/19] docs: add a man page for vhost-user-rpmb
@ 2020-09-25 12:51   ` Alex Bennée
  0 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2020-09-25 12:51 UTC (permalink / raw)
  To: qemu-devel, maxim.uvarov, joakim.bech, ilias.apalodimas,
	tomas.winkler, yang.huang, bing.zhu, Matti.Moell, hmo
  Cc: jean-philippe, takahiro.akashi, virtualization, arnd, stratos-dev

Basic usage and example invocation.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 docs/tools/index.rst           |   1 +
 docs/tools/vhost-user-rpmb.rst | 102 +++++++++++++++++++++++++++++++++
 2 files changed, 103 insertions(+)
 create mode 100644 docs/tools/vhost-user-rpmb.rst

diff --git a/docs/tools/index.rst b/docs/tools/index.rst
index 232ce9f3e463..488784b3bf1f 100644
--- a/docs/tools/index.rst
+++ b/docs/tools/index.rst
@@ -15,3 +15,4 @@ Contents:
    qemu-trace-stap
    virtfs-proxy-helper
    virtiofsd
+   vhost-user-rpmb
diff --git a/docs/tools/vhost-user-rpmb.rst b/docs/tools/vhost-user-rpmb.rst
new file mode 100644
index 000000000000..40d5d3bceb7c
--- /dev/null
+++ b/docs/tools/vhost-user-rpmb.rst
@@ -0,0 +1,102 @@
+QEMU vhost-user-rpmb - rpmb emulation backend
+=============================================
+
+Synopsis
+--------
+
+**vhost-user-rpmb** [*OPTIONS*]
+
+Description
+-----------
+
+This program is a vhost-user backed that emulates a VirtIO Replay
+Protected Memory Block device. These are usually special partitions
+that are part of a flash device that offer protection against reply
+attacks. They are used to store secure information in a way that is
+hard to tamper with.
+
+This program is designed to work with QEMU's ``--device
+vhost-user-rpmb-pci`` but should work with any virtual machine
+monitor (VMM) that supports vhost-user. See the Examples section
+below.
+
+This program requires a backing store to persist any data programmed
+into the device. The spec supports devices up 32Mb in size. For the
+daemon this is simply a raw file of the appropriate size. To program
+the device it needs to have a key. This can either be programmed by
+the guest at the start or come from a key file supplied to the daemon.
+
+Options
+-------
+
+.. program:: vhost-user-rpmb
+
+.. option:: -h, --help
+
+  Print help.
+
+.. option:: -V, --version
+
+  Print version.
+
+.. option:: -v, --verbose
+
+   Increase verbosity of output
+            
+.. option:: --debug
+
+  Enable debug output.
+
+.. option:: --socket-path=PATH
+
+  Listen on vhost-user UNIX domain socket at PATH. Incompatible with --fd.
+
+.. option:: --fd=FDNUM
+
+  Accept connections from vhost-user UNIX domain socket file descriptor FDNUM.
+  The file descriptor must already be listening for connections.
+  Incompatible with --socket-path.
+
+.. option:: --flash-path=PATH
+
+  Path to the backing store for the flash image, can be up to 32Mb in size.
+
+.. option:: --key-path=PATH
+
+  Path to the backing store for the key of 32 bytes.
+            
+.. option:: --key-set
+
+  Treat the value of key-path as set meaning the key cannot be
+  reprogrammed by the guest.
+
+.. option:: --initial-counter=N
+
+  Set the initial value of the devices write count. It is
+  incremented by each write operation. 
+
+Examples
+--------
+
+The daemon should be started first:
+
+::
+
+  host# vhost-user-rpmb --socket-path=vrpmb.sock \
+   --flash-path=flash.img \
+   --key-path=key --key-set \
+   --initial-counter=1234
+
+The QEMU invocation needs to create a chardev socket the device can
+use to communicate as well as share the guests memory over a memfd.
+
+::
+
+  host# qemu-system \
+      -chardev socket,path=vrpmb.sock,id=vrpmb \
+      -device vhost-user-rpmb-pci,chardev=vrpmb,id=rpmb \
+      -m 4096 \
+      -object memory-backend-file,id=mem,size=4G,mem-path=/dev/shm,share=on \
+      -numa node,memdev=mem \
+      ...
+
-- 
2.20.1

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

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

* Re: [RFC PATCH 05/19] virtio-pci: add notification trace points
  2020-09-25 12:51   ` Alex Bennée
  (?)
@ 2020-09-25 13:06   ` Philippe Mathieu-Daudé
  -1 siblings, 0 replies; 48+ messages in thread
From: Philippe Mathieu-Daudé @ 2020-09-25 13:06 UTC (permalink / raw)
  To: Alex Bennée, qemu-devel, maxim.uvarov, joakim.bech,
	ilias.apalodimas, tomas.winkler, yang.huang, bing.zhu,
	Matti.Moell, hmo
  Cc: jean-philippe, Michael S. Tsirkin, takahiro.akashi,
	virtualization, arnd, stratos-dev

On 9/25/20 2:51 PM, Alex Bennée wrote:
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> ---
>  hw/virtio/virtio-pci.c | 3 +++
>  hw/virtio/trace-events | 7 ++++++-
>  2 files changed, 9 insertions(+), 1 deletion(-)
> 
> diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
> index 507cb57c410f..33a40e31d955 100644
> --- a/hw/virtio/virtio-pci.c
> +++ b/hw/virtio/virtio-pci.c
> @@ -36,6 +36,7 @@
>  #include "qemu/range.h"
>  #include "hw/virtio/virtio-bus.h"
>  #include "qapi/visitor.h"
> +#include "trace.h"
>  
>  #define VIRTIO_PCI_REGION_SIZE(dev)     VIRTIO_PCI_CONFIG_OFF(msix_present(dev))
>  
> @@ -1340,6 +1341,7 @@ static void virtio_pci_notify_write(void *opaque, hwaddr addr,
>      unsigned queue = addr / virtio_pci_queue_mem_mult(proxy);
>  
>      if (vdev != NULL && queue < VIRTIO_QUEUE_MAX) {
> +        trace_virtio_pci_notify_write(addr, val, size);
>          virtio_queue_notify(vdev, queue);
>      }
>  }
> @@ -1353,6 +1355,7 @@ static void virtio_pci_notify_write_pio(void *opaque, hwaddr addr,
>      unsigned queue = val;
>  
>      if (vdev != NULL && queue < VIRTIO_QUEUE_MAX) {
> +        trace_virtio_pci_notify_write_pio(addr, val, size);
>          virtio_queue_notify(vdev, queue);
>      }
>  }
> diff --git a/hw/virtio/trace-events b/hw/virtio/trace-events
> index 845200bf109d..189972b9213a 100644
> --- a/hw/virtio/trace-events
> +++ b/hw/virtio/trace-events
> @@ -55,7 +55,12 @@ virtio_mmio_guest_page(uint64_t size, int shift) "guest page size 0x%" PRIx64 "
>  virtio_mmio_queue_write(uint64_t value, int max_size) "mmio_queue write 0x%" PRIx64 " max %d"
>  virtio_mmio_setting_irq(int level) "virtio_mmio setting IRQ %d"
>  
> -# virtio-iommu.c
> +# virtio-pci.c
> +virtio_pci_notify(uint16_t vector) "virtio_pci_notify vec 0x%x"

Not used.

> +virtio_pci_notify_write(uint64_t addr, uint64_t val, unsigned int size) "0x%" PRIx64" = 0x%" PRIx64 " (%d)"
> +virtio_pci_notify_write_pio(uint64_t addr, uint64_t val, unsigned int size) "0x%" PRIx64" = 0x%" PRIx64 " (%d)"
> +
> +# hw/virtio/virtio-iommu.c

Probably left-over from automatic rename from patch #3
"move virtio-pci.h into shared include space", but please
keep the local name 'virtio-iommu.c'.

Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>

>  virtio_iommu_device_reset(void) "reset!"
>  virtio_iommu_get_features(uint64_t features) "device supports features=0x%"PRIx64
>  virtio_iommu_device_status(uint8_t status) "driver status = %d"
> 



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

* Re: [RFC PATCH 00/19] vhost-user-rpmb (Replay Protected Memory Block)
  2020-09-25 12:51 ` Alex Bennée
                   ` (19 preceding siblings ...)
  (?)
@ 2020-09-25 14:07 ` no-reply
  -1 siblings, 0 replies; 48+ messages in thread
From: no-reply @ 2020-09-25 14:07 UTC (permalink / raw)
  To: alex.bennee
  Cc: jean-philippe, maxim.uvarov, bing.zhu, Matti.Moell, stratos-dev,
	ilias.apalodimas, qemu-devel, arnd, hmo, takahiro.akashi,
	joakim.bech, virtualization, alex.bennee, tomas.winkler,
	yang.huang

Patchew URL: https://patchew.org/QEMU/20200925125147.26943-1-alex.bennee@linaro.org/



Hi,

This series seems to have some coding style problems. See output below for
more information:

Type: series
Message-id: 20200925125147.26943-1-alex.bennee@linaro.org
Subject: [RFC PATCH  00/19] vhost-user-rpmb (Replay Protected Memory Block)

=== TEST SCRIPT BEGIN ===
#!/bin/bash
git rev-parse base > /dev/null || exit 0
git config --local diff.renamelimit 0
git config --local diff.renames True
git config --local diff.algorithm histogram
./scripts/checkpatch.pl --mailback base..
=== TEST SCRIPT END ===

Switched to a new branch 'test'
de93431 docs: add a man page for vhost-user-rpmb
2bc1b7e tools/vhost-user-rpmb: allow setting of the write_count
50f0f27 tools/vhost-user-rpmb: add key persistence
dd8233f tools/vhost-user-rpmb: implement VIRTIO_RPMB_REQ_DATA_READ
88283cc tools/vhost-user-rpmb: implement VIRTIO_RPMB_REQ_DATA_WRITE
aa2e735 tools/vhost-user-rpmb: implement VIRTIO_RPMB_REQ_GET_WRITE_COUNTER
24de191 tools/vhost-user-rpmb: implement the PROGRAM_KEY handshake
cf0cc66 tools/vhost-user-rpmb: import hmac_sha256 functions
f98813c tools/vhost-user-rpmb: add --flash-path for backing store
8db0f08 tools/vhost-user-rpmb: handle shutdown and SIGINT/SIGHUP cleanly
f7534d4 tools/vhost-user-rpmb: add a --verbose/debug flags for logging
4c44c17 tools/vhost-user-rpmb: connect to fd and instantiate basic run loop
061c2c0 tools/vhost-user-rpmb: implement --print-capabilities
d873168 tools/vhost-user-rpmb: add boilerplate and initial main
397a631 virtio-pci: add notification trace points
d947373 hw/block: add vhost-user-rpmb-pci boilerplate
5966eb3 hw/virtio: move virtio-pci.h into shared include space
48c264c hw/block: add boilerplate for vhost-user-rpmb device
220284c tools/virtiofsd: add support for --socket-group

=== OUTPUT BEGIN ===
1/19 Checking commit 220284c70dd3 (tools/virtiofsd: add support for --socket-group)
WARNING: line over 80 characters
#92: FILE: tools/virtiofsd/fuse_virtio.c:934:
+        old_umask = umask(S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH);

total: 0 errors, 1 warnings, 74 lines checked

Patch 1/19 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
2/19 Checking commit 48c264cdfcd0 (hw/block: add boilerplate for vhost-user-rpmb device)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#42: 
new file mode 100644

total: 0 errors, 1 warnings, 395 lines checked

Patch 2/19 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
3/19 Checking commit 5966eb3db703 (hw/virtio: move virtio-pci.h into shared include space)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#250: 
rename from hw/virtio/virtio-pci.h

total: 0 errors, 1 warnings, 144 lines checked

Patch 3/19 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
4/19 Checking commit d94737395f8f (hw/block: add vhost-user-rpmb-pci boilerplate)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#28: 
new file mode 100644

total: 0 errors, 1 warnings, 89 lines checked

Patch 4/19 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
5/19 Checking commit 397a63150433 (virtio-pci: add notification trace points)
6/19 Checking commit d8731682a51c (tools/vhost-user-rpmb: add boilerplate and initial main)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#53: 
new file mode 100644

ERROR: that open brace { should be on the previous line
#84: FILE: tools/vhost-user-rpmb/main.c:16:
+static GOptionEntry options[] =
+{

ERROR: line over 90 characters
#85: FILE: tools/vhost-user-rpmb/main.c:17:
+    { "socket-path", 0, 0, G_OPTION_ARG_FILENAME, &socket_path, "Location of vhost-user Unix domain socket, incompatible with --fd", "PATH" },

ERROR: line over 90 characters
#86: FILE: tools/vhost-user-rpmb/main.c:18:
+    { "fd", 0, 0, G_OPTION_ARG_INT, &socket_fd, "Specify the file-descriptor of the backend, incompatible with --socket-path", "FD" },

ERROR: line over 90 characters
#87: FILE: tools/vhost-user-rpmb/main.c:19:
+    { "print-capabilities", 0, 0, G_OPTION_ARG_NONE, &print_cap, "Output to stdout the backend capabilities in JSON format and exit", NULL},

ERROR: space prohibited between function name and open parenthesis '('
#91: FILE: tools/vhost-user-rpmb/main.c:23:
+int main (int argc, char *argv[])

ERROR: line over 90 characters
#96: FILE: tools/vhost-user-rpmb/main.c:28:
+    context = g_option_context_new ("vhost-user-rpmb - vhost-user emulation of RPBM device");

ERROR: space prohibited between function name and open parenthesis '('
#96: FILE: tools/vhost-user-rpmb/main.c:28:
+    context = g_option_context_new ("vhost-user-rpmb - vhost-user emulation of RPBM device");

ERROR: space prohibited between function name and open parenthesis '('
#97: FILE: tools/vhost-user-rpmb/main.c:29:
+    g_option_context_add_main_entries (context, options, "vhost-user-rpmb");

ERROR: that open brace { should be on the previous line
#98: FILE: tools/vhost-user-rpmb/main.c:30:
+    if (!g_option_context_parse (context, &argc, &argv, &error))
+    {

ERROR: space prohibited between function name and open parenthesis '('
#98: FILE: tools/vhost-user-rpmb/main.c:30:
+    if (!g_option_context_parse (context, &argc, &argv, &error))

ERROR: space prohibited between function name and open parenthesis '('
#101: FILE: tools/vhost-user-rpmb/main.c:33:
+        exit (1);

total: 11 errors, 1 warnings, 75 lines checked

Patch 6/19 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

7/19 Checking commit 061c2c0a97eb (tools/vhost-user-rpmb: implement --print-capabilities)
8/19 Checking commit 4c44c17852d6 (tools/vhost-user-rpmb: connect to fd and instantiate basic run loop)
ERROR: spaces required around that '*' (ctx:WxV)
#32: FILE: tools/vhost-user-rpmb/main.c:21:
+        const typeof(((type *) 0)->member) *__mptr = (ptr);     \
                                            ^

ERROR: space required after that ';' (ctx:VxV)
#33: FILE: tools/vhost-user-rpmb/main.c:22:
+        (type *) ((char *) __mptr - offsetof(type, member));})
                                                            ^

ERROR: space prohibited between function name and open parenthesis '('
#199: FILE: tools/vhost-user-rpmb/main.c:194:
+    context = g_option_context_new ("vhost-user emulation of RPBM device");

ERROR: line over 90 characters
#219: FILE: tools/vhost-user-rpmb/main.c:219:
+        g_autoptr(GSocket) bind_socket = g_socket_new(G_SOCKET_FAMILY_UNIX, G_SOCKET_TYPE_STREAM,

WARNING: line over 80 characters
#220: FILE: tools/vhost-user-rpmb/main.c:220:
+                                                      G_SOCKET_PROTOCOL_DEFAULT, &error);

WARNING: line over 80 characters
#246: FILE: tools/vhost-user-rpmb/main.c:246:
+    if (!vug_init(&rpmb.dev, VHOST_USER_RPMB_MAX_QUEUES, g_socket_get_fd(socket),

total: 4 errors, 2 warnings, 244 lines checked

Patch 8/19 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

9/19 Checking commit f7534d48c985 (tools/vhost-user-rpmb: add a --verbose/debug flags for logging)
WARNING: line over 80 characters
#39: FILE: tools/vhost-user-rpmb/main.c:39:
+    { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Be more verbose in output", NULL},

WARNING: line over 80 characters
#63: FILE: tools/vhost-user-rpmb/main.c:227:
+                          G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_ERROR,

total: 0 errors, 2 warnings, 49 lines checked

Patch 9/19 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.
10/19 Checking commit 8db0f083eb3e (tools/vhost-user-rpmb: handle shutdown and SIGINT/SIGHUP cleanly)
11/19 Checking commit f98813cc37dd (tools/vhost-user-rpmb: add --flash-path for backing store)
ERROR: line over 90 characters
#45: FILE: tools/vhost-user-rpmb/main.c:45:
+    { "flash-path", 0, 0, G_OPTION_ARG_FILENAME, &flash_path, "Location of raw flash image file", "PATH" },

ERROR: spaces required around that '*' (ctx:WxV)
#102: FILE: tools/vhost-user-rpmb/main.c:231:
+    r->virtio_config.capacity = map_size / (128 *KiB);
                                                 ^

total: 2 errors, 0 warnings, 115 lines checked

Patch 11/19 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

12/19 Checking commit cf0cc660d83d (tools/vhost-user-rpmb: import hmac_sha256 functions)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#15: 
new file mode 100644

ERROR: space prohibited before that close parenthesis ')'
#75: FILE: tools/vhost-user-rpmb/hmac_sha256.c:56:
+    *((str) + 3) = (uint8) ((x)      );       \

ERROR: spaces required around that '*' (ctx:WxV)
#83: FILE: tools/vhost-user-rpmb/hmac_sha256.c:64:
+    *(x) =   ((uint32) *((str) + 3)      )    \
                        ^

ERROR: space prohibited before that close parenthesis ')'
#83: FILE: tools/vhost-user-rpmb/hmac_sha256.c:64:
+    *(x) =   ((uint32) *((str) + 3)      )    \

ERROR: spaces required around that '*' (ctx:WxV)
#84: FILE: tools/vhost-user-rpmb/hmac_sha256.c:65:
+           | ((uint32) *((str) + 2) <<  8)    \
                        ^

ERROR: spaces required around that '*' (ctx:WxV)
#85: FILE: tools/vhost-user-rpmb/hmac_sha256.c:66:
+           | ((uint32) *((str) + 1) << 16)    \
                        ^

ERROR: spaces required around that '*' (ctx:WxV)
#86: FILE: tools/vhost-user-rpmb/hmac_sha256.c:67:
+           | ((uint32) *((str) + 0) << 24);   \
                        ^

ERROR: space prohibited before that close parenthesis ')'
#91: FILE: tools/vhost-user-rpmb/hmac_sha256.c:72:
+    *((str) + 7) = (uint8) ((x)      );       \

ERROR: spaces required around that '*' (ctx:WxV)
#103: FILE: tools/vhost-user-rpmb/hmac_sha256.c:84:
+    *(x) =   ((uint64) *((str) + 7)      )    \
                        ^

ERROR: space prohibited before that close parenthesis ')'
#103: FILE: tools/vhost-user-rpmb/hmac_sha256.c:84:
+    *(x) =   ((uint64) *((str) + 7)      )    \

ERROR: spaces required around that '*' (ctx:WxV)
#104: FILE: tools/vhost-user-rpmb/hmac_sha256.c:85:
+           | ((uint64) *((str) + 6) <<  8)    \
                        ^

ERROR: spaces required around that '*' (ctx:WxV)
#105: FILE: tools/vhost-user-rpmb/hmac_sha256.c:86:
+           | ((uint64) *((str) + 5) << 16)    \
                        ^

ERROR: spaces required around that '*' (ctx:WxV)
#106: FILE: tools/vhost-user-rpmb/hmac_sha256.c:87:
+           | ((uint64) *((str) + 4) << 24)    \
                        ^

ERROR: spaces required around that '*' (ctx:WxV)
#107: FILE: tools/vhost-user-rpmb/hmac_sha256.c:88:
+           | ((uint64) *((str) + 3) << 32)    \
                        ^

ERROR: spaces required around that '*' (ctx:WxV)
#108: FILE: tools/vhost-user-rpmb/hmac_sha256.c:89:
+           | ((uint64) *((str) + 2) << 40)    \
                        ^

ERROR: spaces required around that '*' (ctx:WxV)
#109: FILE: tools/vhost-user-rpmb/hmac_sha256.c:90:
+           | ((uint64) *((str) + 1) << 48)    \
                        ^

ERROR: spaces required around that '*' (ctx:WxV)
#110: FILE: tools/vhost-user-rpmb/hmac_sha256.c:91:
+           | ((uint64) *((str) + 0) << 56);   \
                        ^

ERROR: that open brace { should be on the previous line
#120: FILE: tools/vhost-user-rpmb/hmac_sha256.c:101:
+uint32 sha256_h0[8] =
+            {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,

ERROR: that open brace { should be on the previous line
#124: FILE: tools/vhost-user-rpmb/hmac_sha256.c:105:
+uint32 sha256_k[64] =
+            {0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,

WARNING: line over 80 characters
#188: FILE: tools/vhost-user-rpmb/hmac_sha256.c:169:
+void sha256(const unsigned char *message, unsigned int len, unsigned char *digest)

ERROR: space required before the open brace '{'
#282: FILE: tools/vhost-user-rpmb/hmac_sha256.c:263:
+        if (key_size > SHA256_BLOCK_SIZE){

ERROR: space prohibited after that open parenthesis '('
#396: FILE: tools/vhost-user-rpmb/hmac_sha256.h:40:
+#define SHA256_DIGEST_SIZE ( 256 / 8)

ERROR: space prohibited after that open parenthesis '('
#397: FILE: tools/vhost-user-rpmb/hmac_sha256.h:41:
+#define SHA256_BLOCK_SIZE  ( 512 / 8)

ERROR: "foo * bar" should be "foo *bar"
#413: FILE: tools/vhost-user-rpmb/hmac_sha256.h:57:
+void sha256_init(sha256_ctx * ctx);

total: 22 errors, 2 warnings, 425 lines checked

Patch 12/19 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

13/19 Checking commit 24de191d1408 (tools/vhost-user-rpmb: implement the PROGRAM_KEY handshake)
WARNING: line over 80 characters
#125: FILE: tools/vhost-user-rpmb/main.c:143:
+static size_t vrpmb_iov_to_buf(const struct iovec *iov, const unsigned int iov_cnt,

WARNING: line over 80 characters
#205: FILE: tools/vhost-user-rpmb/main.c:262:
+static void vrpmb_handle_program_key(VuDev *dev, struct virtio_rpmb_frame *frame)

ERROR: "foo * bar" should be "foo *bar"
#239: FILE: tools/vhost-user-rpmb/main.c:296:
+static struct virtio_rpmb_frame * vrpmb_handle_result_read(VuDev *dev)

WARNING: line over 80 characters
#347: FILE: tools/vhost-user-rpmb/main.c:400:
+                    g_warning("%s: already sent a response in this set of frames",

total: 1 errors, 3 warnings, 352 lines checked

Patch 13/19 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

14/19 Checking commit aa2e735c5fbb (tools/vhost-user-rpmb: implement VIRTIO_RPMB_REQ_GET_WRITE_COUNTER)
15/19 Checking commit 88283ccf688e (tools/vhost-user-rpmb: implement VIRTIO_RPMB_REQ_DATA_WRITE)
WARNING: Block comments use a leading /* on a separate line
#110: FILE: tools/vhost-user-rpmb/main.c:371:
+    } else if (false /* what does an expired write counter mean? */) {

WARNING: Block comments use a leading /* on a separate line
#120: FILE: tools/vhost-user-rpmb/main.c:381:
+        /* At this point we have a valid authenticated write request

ERROR: spaces required around that ':' (ctx:VxV)
#150: FILE: tools/vhost-user-rpmb/main.c:411:
+           r->last_result == VIRTIO_RPMB_RES_OK ? "successful":"failed",
                                                               ^

total: 1 errors, 2 warnings, 163 lines checked

Patch 15/19 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

16/19 Checking commit dd8233f9d9d3 (tools/vhost-user-rpmb: implement VIRTIO_RPMB_REQ_DATA_READ)
17/19 Checking commit 50f0f2719ffb (tools/vhost-user-rpmb: add key persistence)
ERROR: line over 90 characters
#35: FILE: tools/vhost-user-rpmb/main.c:52:
+    { "key-path", 0, 0, G_OPTION_ARG_FILENAME, &key_path, "Location of persistent keyfile", "KEY"},

ERROR: line over 90 characters
#36: FILE: tools/vhost-user-rpmb/main.c:53:
+    { "key-set", 0, 0, G_OPTION_ARG_NONE, &key_set, "Is the key already programmed", NULL},

total: 2 errors, 0 warnings, 72 lines checked

Patch 17/19 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

18/19 Checking commit 2bc1b7e86343 (tools/vhost-user-rpmb: allow setting of the write_count)
ERROR: line over 90 characters
#29: FILE: tools/vhost-user-rpmb/main.c:53:
+    { "initial-counter", 0, 0, G_OPTION_ARG_INT, &initial_counter, "Set initial value of write counter", NULL},

total: 1 errors, 0 warnings, 24 lines checked

Patch 18/19 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

19/19 Checking commit de934315542c (docs: add a man page for vhost-user-rpmb)
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#22: 
new file mode 100644

ERROR: trailing whitespace
#71: FILE: docs/tools/vhost-user-rpmb.rst:45:
+            $

ERROR: trailing whitespace
#93: FILE: docs/tools/vhost-user-rpmb.rst:67:
+            $

ERROR: trailing whitespace
#102: FILE: docs/tools/vhost-user-rpmb.rst:76:
+  incremented by each write operation. $

total: 3 errors, 1 warnings, 106 lines checked

Patch 19/19 has style problems, please review.  If any of these errors
are false positives report them to the maintainer, see
CHECKPATCH in MAINTAINERS.

=== OUTPUT END ===

Test command exited with code: 1


The full log is available at
http://patchew.org/logs/20200925125147.26943-1-alex.bennee@linaro.org/testing.checkpatch/?type=message.
---
Email generated automatically by Patchew [https://patchew.org/].
Please send your feedback to patchew-devel@redhat.com

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

* Re: [RFC PATCH  15/19] tools/vhost-user-rpmb: implement VIRTIO_RPMB_REQ_DATA_WRITE
  2020-09-25 12:51   ` Alex Bennée
  (?)
@ 2020-09-28 13:52   ` Joakim Bech
  2020-09-28 14:56       ` Alex Bennée
  -1 siblings, 1 reply; 48+ messages in thread
From: Joakim Bech @ 2020-09-28 13:52 UTC (permalink / raw)
  To: Alex Bennée
  Cc: jean-philippe, maxim.uvarov, bing.zhu, Matti.Moell,
	virtualization, ilias.apalodimas, qemu-devel, arnd,
	takahiro.akashi, tomas.winkler, stratos-dev, hmo, yang.huang

On Fri, Sep 25, 2020 at 01:51:43PM +0100, Alex Bennée wrote:
> With this command we are finally updating data to the backing store
> and cycling the write_count and each successful write. We also include
> the write count in all response frames as the spec is a little unclear
> but the example test code expected it.
> 
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> ---
>  tools/vhost-user-rpmb/main.c | 111 +++++++++++++++++++++++++++++++++--
>  1 file changed, 105 insertions(+), 6 deletions(-)
> 
> diff --git a/tools/vhost-user-rpmb/main.c b/tools/vhost-user-rpmb/main.c
> index 88747c50fa44..a17c3b4bcc4e 100644
> --- a/tools/vhost-user-rpmb/main.c
> +++ b/tools/vhost-user-rpmb/main.c
> @@ -62,6 +62,7 @@ enum {
>  #define KiB     (1UL << 10)
>  #define MAX_RPMB_SIZE (KiB * 128 * 256)
>  #define RPMB_KEY_MAC_SIZE 32
> +#define RPMB_BLOCK_SIZE 256
>  
>  /* RPMB Request Types */
>  #define VIRTIO_RPMB_REQ_PROGRAM_KEY        0x0001
> @@ -100,7 +101,7 @@ struct virtio_rpmb_config {
>  struct virtio_rpmb_frame {
>      uint8_t stuff[196];
>      uint8_t key_mac[RPMB_KEY_MAC_SIZE];
> -    uint8_t data[256];
> +    uint8_t data[RPMB_BLOCK_SIZE];
>      uint8_t nonce[16];
>      /* remaining fields are big-endian */
>      uint32_t write_counter;
> @@ -124,6 +125,7 @@ typedef struct VuRpmb {
>      uint8_t  last_nonce[16];
>      uint16_t last_result;
>      uint16_t last_reqresp;
> +    uint16_t last_address;
>      uint32_t write_count;
>  } VuRpmb;
>  
> @@ -239,17 +241,30 @@ vrpmb_set_config(VuDev *dev, const uint8_t *data,
>   * which itself uses a 3 clause BSD chunk of code.
>   */
>  
> +static const int rpmb_frame_dlen = (sizeof(struct virtio_rpmb_frame) -
> +                                    offsetof(struct virtio_rpmb_frame, data));
> +
>  static void vrpmb_update_mac_in_frame(VuRpmb *r, struct virtio_rpmb_frame *frm)
>  {
>      hmac_sha256_ctx ctx;
> -    static const int dlen = (sizeof(struct virtio_rpmb_frame) -
> -                             offsetof(struct virtio_rpmb_frame, data));
>  
>      hmac_sha256_init(&ctx, r->key, RPMB_KEY_MAC_SIZE);
> -    hmac_sha256_update(&ctx, frm->data, dlen);
> +    hmac_sha256_update(&ctx, frm->data, rpmb_frame_dlen);
>      hmac_sha256_final(&ctx, &frm->key_mac[0], 32);
>  }
>  
> +static bool vrpmb_verify_mac_in_frame(VuRpmb *r, struct virtio_rpmb_frame *frm)
> +{
> +    hmac_sha256_ctx ctx;
> +    uint8_t calculated_mac[RPMB_KEY_MAC_SIZE];
> +
> +    hmac_sha256_init(&ctx, r->key, RPMB_KEY_MAC_SIZE);
> +    hmac_sha256_update(&ctx, frm->data, rpmb_frame_dlen);
> +    hmac_sha256_final(&ctx, calculated_mac, RPMB_KEY_MAC_SIZE);
> +
> +    return memcmp(calculated_mac, frm->key_mac, RPMB_KEY_MAC_SIZE) == 0;
>
I'd prefer using a constant time comparison function for this one
instead of memcmp (regardless if it's used for simulation or not) to
prevent eventual timing attacks.

> +}
> +
>  /*
>   * Handlers for individual control messages
>   */
> @@ -324,6 +339,82 @@ vrpmb_handle_get_write_counter(VuDev *dev, struct virtio_rpmb_frame *frame)
>      return resp;
>  }
>  
> +/*
> + * vrpmb_handle_write:
> + *
> + * We will report the success/fail on receipt of
> + * VIRTIO_RPMB_REQ_RESULT_READ. Returns the number of extra frames
> + * processed in the request.
> + */
> +static int vrpmb_handle_write(VuDev *dev, struct virtio_rpmb_frame *frame)
> +{
> +    VuRpmb *r = container_of(dev, VuRpmb, dev.parent);
> +    int extra_frames = 0;
> +    uint16_t block_count = be16toh(frame->block_count);
> +    uint32_t write_counter = be32toh(frame->write_counter);
> +    size_t offset;
> +
> +    r->last_reqresp = VIRTIO_RPMB_RESP_DATA_WRITE;
> +    r->last_address = be16toh(frame->address);
> +    offset =  r->last_address * RPMB_BLOCK_SIZE;
> +
> +    /*
> +     * Run the checks from:
> +     * 5.12.6.1.3 Device Requirements: Device Operation: Data Write
> +     */
> +    if (!r->key) {
> +        g_warning("no key programmed");
> +        r->last_result = VIRTIO_RPMB_RES_NO_AUTH_KEY;
> +    } else if (block_count == 0 ||
> +               block_count > r->virtio_config.max_wr_cnt) {
> +        r->last_result = VIRTIO_RPMB_RES_GENERAL_FAILURE;
> +    } else if (false /* what does an expired write counter mean? */) {
>
IIRC, the counter has room for a 32-bit value and the counter will never
wrap around. So once the counter have reached max for uint32_t, then
there is an additional bit set (permanently) in the operation result.
I.e., writes are no longer possible once that has happened. That is
probably what you're referring to here I suppose.

> +        r->last_result = VIRTIO_RPMB_RES_WRITE_COUNTER_EXPIRED;
> +    } else if (offset > (r->virtio_config.capacity * (128 * KiB))) {
> +        r->last_result = VIRTIO_RPMB_RES_ADDR_FAILURE;
> +    } else if (!vrpmb_verify_mac_in_frame(r, frame)) {
> +        r->last_result = VIRTIO_RPMB_RES_AUTH_FAILURE;
> +    } else if (write_counter != r->write_count) {
> +        r->last_result = VIRTIO_RPMB_RES_COUNT_FAILURE;
> +    } else {
> +        int i;
> +        /* At this point we have a valid authenticated write request
> +         * so the counter can incremented and we can attempt to
> +         * update the backing device.
> +         */
> +        r->write_count++;
> +        for (i = 0; i < block_count; i++) {
> +            void *blk = r->flash_map + offset;
> +            g_debug("%s: writing block %d", __func__, i);
> +            if (mprotect(blk, RPMB_BLOCK_SIZE, PROT_WRITE) != 0) {
> +                r->last_result =  VIRTIO_RPMB_RES_WRITE_FAILURE;
> +                break;
> +            }
> +            memcpy(blk, frame[i].data, RPMB_BLOCK_SIZE);
> +            if (msync(blk, RPMB_BLOCK_SIZE, MS_SYNC) != 0) {
> +                g_warning("%s: failed to sync update", __func__);
> +                r->last_result = VIRTIO_RPMB_RES_WRITE_FAILURE;
> +                break;
> +            }
> +            if (mprotect(blk, RPMB_BLOCK_SIZE, PROT_READ) != 0) {
> +                g_warning("%s: failed to re-apply read protection", __func__);
> +                r->last_result = VIRTIO_RPMB_RES_GENERAL_FAILURE;
> +                break;
> +            }
> +            offset += RPMB_BLOCK_SIZE;
> +        }
> +        r->last_result = VIRTIO_RPMB_RES_OK;
> +        extra_frames = i - 1;
> +    }
> +
> +    g_info("%s: %s (%x, %d extra frames processed), write_count=%d", __func__,
> +           r->last_result == VIRTIO_RPMB_RES_OK ? "successful":"failed",
> +           r->last_result, extra_frames, r->write_count);
> +
> +    return extra_frames;
> +}
> +
> +
>  /*
>   * Return the result of the last message. This is only valid if the
>   * previous message was VIRTIO_RPMB_REQ_PROGRAM_KEY or
> @@ -339,10 +430,14 @@ static struct virtio_rpmb_frame * vrpmb_handle_result_read(VuDev *dev)
>      g_info("%s: for request:%x result:%x", __func__,
>             r->last_reqresp, r->last_result);
>  
> -    if (r->last_reqresp == VIRTIO_RPMB_RESP_PROGRAM_KEY ||
> -        r->last_reqresp == VIRTIO_RPMB_REQ_DATA_WRITE) {
> +    if (r->last_reqresp == VIRTIO_RPMB_RESP_PROGRAM_KEY) {
>          resp->result = htobe16(r->last_result);
>          resp->req_resp = htobe16(r->last_reqresp);
> +    } else if (r->last_reqresp == VIRTIO_RPMB_RESP_DATA_WRITE) {
> +        resp->result = htobe16(r->last_result);
> +        resp->req_resp = htobe16(r->last_reqresp);
> +        resp->write_counter = htobe32(r->write_count);
> +        resp->address = htobe16(r->last_address);
>      } else {
>          resp->result = htobe16(VIRTIO_RPMB_RES_GENERAL_FAILURE);
>      }
> @@ -445,6 +540,10 @@ vrpmb_handle_ctrl(VuDev *dev, int qidx)
>                                __func__);
>                  }
>                  break;
> +            case VIRTIO_RPMB_REQ_DATA_WRITE:
> +                /* we can have multiple blocks handled */
> +                n += vrpmb_handle_write(dev, f);
> +                break;
>              default:
>                  g_debug("un-handled request: %x", f->req_resp);
>                  break;
> -- 
> 2.20.1
> 

-- 
Regards,
Joakim


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

* Re: [RFC PATCH  15/19] tools/vhost-user-rpmb: implement VIRTIO_RPMB_REQ_DATA_WRITE
  2020-09-28 13:52   ` Joakim Bech
@ 2020-09-28 14:56       ` Alex Bennée
  0 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2020-09-28 14:56 UTC (permalink / raw)
  To: Joakim Bech
  Cc: jean-philippe, maxim.uvarov, bing.zhu, Matti.Moell,
	virtualization, ilias.apalodimas, qemu-devel, arnd,
	takahiro.akashi, tomas.winkler, stratos-dev, hmo, yang.huang


Joakim Bech <joakim.bech@linaro.org> writes:

> On Fri, Sep 25, 2020 at 01:51:43PM +0100, Alex Bennée wrote:
>> With this command we are finally updating data to the backing store
>> and cycling the write_count and each successful write. We also include
>> the write count in all response frames as the spec is a little unclear
>> but the example test code expected it.
>> 
>> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
>> ---
>>  tools/vhost-user-rpmb/main.c | 111 +++++++++++++++++++++++++++++++++--
>>  1 file changed, 105 insertions(+), 6 deletions(-)
>> 
>> diff --git a/tools/vhost-user-rpmb/main.c b/tools/vhost-user-rpmb/main.c
>> index 88747c50fa44..a17c3b4bcc4e 100644
>> --- a/tools/vhost-user-rpmb/main.c
>> +++ b/tools/vhost-user-rpmb/main.c
>> @@ -62,6 +62,7 @@ enum {
>>  #define KiB     (1UL << 10)
>>  #define MAX_RPMB_SIZE (KiB * 128 * 256)
>>  #define RPMB_KEY_MAC_SIZE 32
>> +#define RPMB_BLOCK_SIZE 256
>>  
>>  /* RPMB Request Types */
>>  #define VIRTIO_RPMB_REQ_PROGRAM_KEY        0x0001
>> @@ -100,7 +101,7 @@ struct virtio_rpmb_config {
>>  struct virtio_rpmb_frame {
>>      uint8_t stuff[196];
>>      uint8_t key_mac[RPMB_KEY_MAC_SIZE];
>> -    uint8_t data[256];
>> +    uint8_t data[RPMB_BLOCK_SIZE];
>>      uint8_t nonce[16];
>>      /* remaining fields are big-endian */
>>      uint32_t write_counter;
>> @@ -124,6 +125,7 @@ typedef struct VuRpmb {
>>      uint8_t  last_nonce[16];
>>      uint16_t last_result;
>>      uint16_t last_reqresp;
>> +    uint16_t last_address;
>>      uint32_t write_count;
>>  } VuRpmb;
>>  
>> @@ -239,17 +241,30 @@ vrpmb_set_config(VuDev *dev, const uint8_t *data,
>>   * which itself uses a 3 clause BSD chunk of code.
>>   */
>>  
>> +static const int rpmb_frame_dlen = (sizeof(struct virtio_rpmb_frame) -
>> +                                    offsetof(struct virtio_rpmb_frame, data));
>> +
>>  static void vrpmb_update_mac_in_frame(VuRpmb *r, struct virtio_rpmb_frame *frm)
>>  {
>>      hmac_sha256_ctx ctx;
>> -    static const int dlen = (sizeof(struct virtio_rpmb_frame) -
>> -                             offsetof(struct virtio_rpmb_frame, data));
>>  
>>      hmac_sha256_init(&ctx, r->key, RPMB_KEY_MAC_SIZE);
>> -    hmac_sha256_update(&ctx, frm->data, dlen);
>> +    hmac_sha256_update(&ctx, frm->data, rpmb_frame_dlen);
>>      hmac_sha256_final(&ctx, &frm->key_mac[0], 32);
>>  }
>>  
>> +static bool vrpmb_verify_mac_in_frame(VuRpmb *r, struct virtio_rpmb_frame *frm)
>> +{
>> +    hmac_sha256_ctx ctx;
>> +    uint8_t calculated_mac[RPMB_KEY_MAC_SIZE];
>> +
>> +    hmac_sha256_init(&ctx, r->key, RPMB_KEY_MAC_SIZE);
>> +    hmac_sha256_update(&ctx, frm->data, rpmb_frame_dlen);
>> +    hmac_sha256_final(&ctx, calculated_mac, RPMB_KEY_MAC_SIZE);
>> +
>> +    return memcmp(calculated_mac, frm->key_mac, RPMB_KEY_MAC_SIZE) == 0;
>>
> I'd prefer using a constant time comparison function for this one
> instead of memcmp (regardless if it's used for simulation or not) to
> prevent eventual timing attacks.

Could you recommend such a function for this?

>
>> +}
>> +
>>  /*
>>   * Handlers for individual control messages
>>   */
>> @@ -324,6 +339,82 @@ vrpmb_handle_get_write_counter(VuDev *dev, struct virtio_rpmb_frame *frame)
>>      return resp;
>>  }
>>  
>> +/*
>> + * vrpmb_handle_write:
>> + *
>> + * We will report the success/fail on receipt of
>> + * VIRTIO_RPMB_REQ_RESULT_READ. Returns the number of extra frames
>> + * processed in the request.
>> + */
>> +static int vrpmb_handle_write(VuDev *dev, struct virtio_rpmb_frame *frame)
>> +{
>> +    VuRpmb *r = container_of(dev, VuRpmb, dev.parent);
>> +    int extra_frames = 0;
>> +    uint16_t block_count = be16toh(frame->block_count);
>> +    uint32_t write_counter = be32toh(frame->write_counter);
>> +    size_t offset;
>> +
>> +    r->last_reqresp = VIRTIO_RPMB_RESP_DATA_WRITE;
>> +    r->last_address = be16toh(frame->address);
>> +    offset =  r->last_address * RPMB_BLOCK_SIZE;
>> +
>> +    /*
>> +     * Run the checks from:
>> +     * 5.12.6.1.3 Device Requirements: Device Operation: Data Write
>> +     */
>> +    if (!r->key) {
>> +        g_warning("no key programmed");
>> +        r->last_result = VIRTIO_RPMB_RES_NO_AUTH_KEY;
>> +    } else if (block_count == 0 ||
>> +               block_count > r->virtio_config.max_wr_cnt) {
>> +        r->last_result = VIRTIO_RPMB_RES_GENERAL_FAILURE;
>> +    } else if (false /* what does an expired write counter mean? */) {
>>
> IIRC, the counter has room for a 32-bit value and the counter will never
> wrap around. So once the counter have reached max for uint32_t, then
> there is an additional bit set (permanently) in the operation result.
> I.e., writes are no longer possible once that has happened. That is
> probably what you're referring to here I suppose.

That would make sense. I'll see if I can make the spec language a bit
clearer as well.

>
>> +        r->last_result = VIRTIO_RPMB_RES_WRITE_COUNTER_EXPIRED;
>> +    } else if (offset > (r->virtio_config.capacity * (128 * KiB))) {
>> +        r->last_result = VIRTIO_RPMB_RES_ADDR_FAILURE;
>> +    } else if (!vrpmb_verify_mac_in_frame(r, frame)) {
>> +        r->last_result = VIRTIO_RPMB_RES_AUTH_FAILURE;
>> +    } else if (write_counter != r->write_count) {
>> +        r->last_result = VIRTIO_RPMB_RES_COUNT_FAILURE;
>> +    } else {
>> +        int i;
>> +        /* At this point we have a valid authenticated write request
>> +         * so the counter can incremented and we can attempt to
>> +         * update the backing device.
>> +         */
>> +        r->write_count++;
>> +        for (i = 0; i < block_count; i++) {
>> +            void *blk = r->flash_map + offset;
>> +            g_debug("%s: writing block %d", __func__, i);
>> +            if (mprotect(blk, RPMB_BLOCK_SIZE, PROT_WRITE) != 0) {
>> +                r->last_result =  VIRTIO_RPMB_RES_WRITE_FAILURE;
>> +                break;
>> +            }
>> +            memcpy(blk, frame[i].data, RPMB_BLOCK_SIZE);
>> +            if (msync(blk, RPMB_BLOCK_SIZE, MS_SYNC) != 0) {
>> +                g_warning("%s: failed to sync update", __func__);
>> +                r->last_result = VIRTIO_RPMB_RES_WRITE_FAILURE;
>> +                break;
>> +            }
>> +            if (mprotect(blk, RPMB_BLOCK_SIZE, PROT_READ) != 0) {
>> +                g_warning("%s: failed to re-apply read protection", __func__);
>> +                r->last_result = VIRTIO_RPMB_RES_GENERAL_FAILURE;
>> +                break;
>> +            }
>> +            offset += RPMB_BLOCK_SIZE;
>> +        }
>> +        r->last_result = VIRTIO_RPMB_RES_OK;
>> +        extra_frames = i - 1;
>> +    }
>> +
>> +    g_info("%s: %s (%x, %d extra frames processed), write_count=%d", __func__,
>> +           r->last_result == VIRTIO_RPMB_RES_OK ? "successful":"failed",
>> +           r->last_result, extra_frames, r->write_count);
>> +
>> +    return extra_frames;
>> +}
>> +
>> +
>>  /*
>>   * Return the result of the last message. This is only valid if the
>>   * previous message was VIRTIO_RPMB_REQ_PROGRAM_KEY or
>> @@ -339,10 +430,14 @@ static struct virtio_rpmb_frame * vrpmb_handle_result_read(VuDev *dev)
>>      g_info("%s: for request:%x result:%x", __func__,
>>             r->last_reqresp, r->last_result);
>>  
>> -    if (r->last_reqresp == VIRTIO_RPMB_RESP_PROGRAM_KEY ||
>> -        r->last_reqresp == VIRTIO_RPMB_REQ_DATA_WRITE) {
>> +    if (r->last_reqresp == VIRTIO_RPMB_RESP_PROGRAM_KEY) {
>>          resp->result = htobe16(r->last_result);
>>          resp->req_resp = htobe16(r->last_reqresp);
>> +    } else if (r->last_reqresp == VIRTIO_RPMB_RESP_DATA_WRITE) {
>> +        resp->result = htobe16(r->last_result);
>> +        resp->req_resp = htobe16(r->last_reqresp);
>> +        resp->write_counter = htobe32(r->write_count);
>> +        resp->address = htobe16(r->last_address);
>>      } else {
>>          resp->result = htobe16(VIRTIO_RPMB_RES_GENERAL_FAILURE);
>>      }
>> @@ -445,6 +540,10 @@ vrpmb_handle_ctrl(VuDev *dev, int qidx)
>>                                __func__);
>>                  }
>>                  break;
>> +            case VIRTIO_RPMB_REQ_DATA_WRITE:
>> +                /* we can have multiple blocks handled */
>> +                n += vrpmb_handle_write(dev, f);
>> +                break;
>>              default:
>>                  g_debug("un-handled request: %x", f->req_resp);
>>                  break;
>> -- 
>> 2.20.1
>> 

Thanks!

-- 
Alex Bennée


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

* Re: [RFC PATCH  15/19] tools/vhost-user-rpmb: implement VIRTIO_RPMB_REQ_DATA_WRITE
@ 2020-09-28 14:56       ` Alex Bennée
  0 siblings, 0 replies; 48+ messages in thread
From: Alex Bennée @ 2020-09-28 14:56 UTC (permalink / raw)
  To: Joakim Bech
  Cc: jean-philippe, maxim.uvarov, bing.zhu, Matti.Moell,
	virtualization, ilias.apalodimas, qemu-devel, arnd,
	takahiro.akashi, tomas.winkler, stratos-dev, hmo, yang.huang


Joakim Bech <joakim.bech@linaro.org> writes:

> On Fri, Sep 25, 2020 at 01:51:43PM +0100, Alex Bennée wrote:
>> With this command we are finally updating data to the backing store
>> and cycling the write_count and each successful write. We also include
>> the write count in all response frames as the spec is a little unclear
>> but the example test code expected it.
>> 
>> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
>> ---
>>  tools/vhost-user-rpmb/main.c | 111 +++++++++++++++++++++++++++++++++--
>>  1 file changed, 105 insertions(+), 6 deletions(-)
>> 
>> diff --git a/tools/vhost-user-rpmb/main.c b/tools/vhost-user-rpmb/main.c
>> index 88747c50fa44..a17c3b4bcc4e 100644
>> --- a/tools/vhost-user-rpmb/main.c
>> +++ b/tools/vhost-user-rpmb/main.c
>> @@ -62,6 +62,7 @@ enum {
>>  #define KiB     (1UL << 10)
>>  #define MAX_RPMB_SIZE (KiB * 128 * 256)
>>  #define RPMB_KEY_MAC_SIZE 32
>> +#define RPMB_BLOCK_SIZE 256
>>  
>>  /* RPMB Request Types */
>>  #define VIRTIO_RPMB_REQ_PROGRAM_KEY        0x0001
>> @@ -100,7 +101,7 @@ struct virtio_rpmb_config {
>>  struct virtio_rpmb_frame {
>>      uint8_t stuff[196];
>>      uint8_t key_mac[RPMB_KEY_MAC_SIZE];
>> -    uint8_t data[256];
>> +    uint8_t data[RPMB_BLOCK_SIZE];
>>      uint8_t nonce[16];
>>      /* remaining fields are big-endian */
>>      uint32_t write_counter;
>> @@ -124,6 +125,7 @@ typedef struct VuRpmb {
>>      uint8_t  last_nonce[16];
>>      uint16_t last_result;
>>      uint16_t last_reqresp;
>> +    uint16_t last_address;
>>      uint32_t write_count;
>>  } VuRpmb;
>>  
>> @@ -239,17 +241,30 @@ vrpmb_set_config(VuDev *dev, const uint8_t *data,
>>   * which itself uses a 3 clause BSD chunk of code.
>>   */
>>  
>> +static const int rpmb_frame_dlen = (sizeof(struct virtio_rpmb_frame) -
>> +                                    offsetof(struct virtio_rpmb_frame, data));
>> +
>>  static void vrpmb_update_mac_in_frame(VuRpmb *r, struct virtio_rpmb_frame *frm)
>>  {
>>      hmac_sha256_ctx ctx;
>> -    static const int dlen = (sizeof(struct virtio_rpmb_frame) -
>> -                             offsetof(struct virtio_rpmb_frame, data));
>>  
>>      hmac_sha256_init(&ctx, r->key, RPMB_KEY_MAC_SIZE);
>> -    hmac_sha256_update(&ctx, frm->data, dlen);
>> +    hmac_sha256_update(&ctx, frm->data, rpmb_frame_dlen);
>>      hmac_sha256_final(&ctx, &frm->key_mac[0], 32);
>>  }
>>  
>> +static bool vrpmb_verify_mac_in_frame(VuRpmb *r, struct virtio_rpmb_frame *frm)
>> +{
>> +    hmac_sha256_ctx ctx;
>> +    uint8_t calculated_mac[RPMB_KEY_MAC_SIZE];
>> +
>> +    hmac_sha256_init(&ctx, r->key, RPMB_KEY_MAC_SIZE);
>> +    hmac_sha256_update(&ctx, frm->data, rpmb_frame_dlen);
>> +    hmac_sha256_final(&ctx, calculated_mac, RPMB_KEY_MAC_SIZE);
>> +
>> +    return memcmp(calculated_mac, frm->key_mac, RPMB_KEY_MAC_SIZE) == 0;
>>
> I'd prefer using a constant time comparison function for this one
> instead of memcmp (regardless if it's used for simulation or not) to
> prevent eventual timing attacks.

Could you recommend such a function for this?

>
>> +}
>> +
>>  /*
>>   * Handlers for individual control messages
>>   */
>> @@ -324,6 +339,82 @@ vrpmb_handle_get_write_counter(VuDev *dev, struct virtio_rpmb_frame *frame)
>>      return resp;
>>  }
>>  
>> +/*
>> + * vrpmb_handle_write:
>> + *
>> + * We will report the success/fail on receipt of
>> + * VIRTIO_RPMB_REQ_RESULT_READ. Returns the number of extra frames
>> + * processed in the request.
>> + */
>> +static int vrpmb_handle_write(VuDev *dev, struct virtio_rpmb_frame *frame)
>> +{
>> +    VuRpmb *r = container_of(dev, VuRpmb, dev.parent);
>> +    int extra_frames = 0;
>> +    uint16_t block_count = be16toh(frame->block_count);
>> +    uint32_t write_counter = be32toh(frame->write_counter);
>> +    size_t offset;
>> +
>> +    r->last_reqresp = VIRTIO_RPMB_RESP_DATA_WRITE;
>> +    r->last_address = be16toh(frame->address);
>> +    offset =  r->last_address * RPMB_BLOCK_SIZE;
>> +
>> +    /*
>> +     * Run the checks from:
>> +     * 5.12.6.1.3 Device Requirements: Device Operation: Data Write
>> +     */
>> +    if (!r->key) {
>> +        g_warning("no key programmed");
>> +        r->last_result = VIRTIO_RPMB_RES_NO_AUTH_KEY;
>> +    } else if (block_count == 0 ||
>> +               block_count > r->virtio_config.max_wr_cnt) {
>> +        r->last_result = VIRTIO_RPMB_RES_GENERAL_FAILURE;
>> +    } else if (false /* what does an expired write counter mean? */) {
>>
> IIRC, the counter has room for a 32-bit value and the counter will never
> wrap around. So once the counter have reached max for uint32_t, then
> there is an additional bit set (permanently) in the operation result.
> I.e., writes are no longer possible once that has happened. That is
> probably what you're referring to here I suppose.

That would make sense. I'll see if I can make the spec language a bit
clearer as well.

>
>> +        r->last_result = VIRTIO_RPMB_RES_WRITE_COUNTER_EXPIRED;
>> +    } else if (offset > (r->virtio_config.capacity * (128 * KiB))) {
>> +        r->last_result = VIRTIO_RPMB_RES_ADDR_FAILURE;
>> +    } else if (!vrpmb_verify_mac_in_frame(r, frame)) {
>> +        r->last_result = VIRTIO_RPMB_RES_AUTH_FAILURE;
>> +    } else if (write_counter != r->write_count) {
>> +        r->last_result = VIRTIO_RPMB_RES_COUNT_FAILURE;
>> +    } else {
>> +        int i;
>> +        /* At this point we have a valid authenticated write request
>> +         * so the counter can incremented and we can attempt to
>> +         * update the backing device.
>> +         */
>> +        r->write_count++;
>> +        for (i = 0; i < block_count; i++) {
>> +            void *blk = r->flash_map + offset;
>> +            g_debug("%s: writing block %d", __func__, i);
>> +            if (mprotect(blk, RPMB_BLOCK_SIZE, PROT_WRITE) != 0) {
>> +                r->last_result =  VIRTIO_RPMB_RES_WRITE_FAILURE;
>> +                break;
>> +            }
>> +            memcpy(blk, frame[i].data, RPMB_BLOCK_SIZE);
>> +            if (msync(blk, RPMB_BLOCK_SIZE, MS_SYNC) != 0) {
>> +                g_warning("%s: failed to sync update", __func__);
>> +                r->last_result = VIRTIO_RPMB_RES_WRITE_FAILURE;
>> +                break;
>> +            }
>> +            if (mprotect(blk, RPMB_BLOCK_SIZE, PROT_READ) != 0) {
>> +                g_warning("%s: failed to re-apply read protection", __func__);
>> +                r->last_result = VIRTIO_RPMB_RES_GENERAL_FAILURE;
>> +                break;
>> +            }
>> +            offset += RPMB_BLOCK_SIZE;
>> +        }
>> +        r->last_result = VIRTIO_RPMB_RES_OK;
>> +        extra_frames = i - 1;
>> +    }
>> +
>> +    g_info("%s: %s (%x, %d extra frames processed), write_count=%d", __func__,
>> +           r->last_result == VIRTIO_RPMB_RES_OK ? "successful":"failed",
>> +           r->last_result, extra_frames, r->write_count);
>> +
>> +    return extra_frames;
>> +}
>> +
>> +
>>  /*
>>   * Return the result of the last message. This is only valid if the
>>   * previous message was VIRTIO_RPMB_REQ_PROGRAM_KEY or
>> @@ -339,10 +430,14 @@ static struct virtio_rpmb_frame * vrpmb_handle_result_read(VuDev *dev)
>>      g_info("%s: for request:%x result:%x", __func__,
>>             r->last_reqresp, r->last_result);
>>  
>> -    if (r->last_reqresp == VIRTIO_RPMB_RESP_PROGRAM_KEY ||
>> -        r->last_reqresp == VIRTIO_RPMB_REQ_DATA_WRITE) {
>> +    if (r->last_reqresp == VIRTIO_RPMB_RESP_PROGRAM_KEY) {
>>          resp->result = htobe16(r->last_result);
>>          resp->req_resp = htobe16(r->last_reqresp);
>> +    } else if (r->last_reqresp == VIRTIO_RPMB_RESP_DATA_WRITE) {
>> +        resp->result = htobe16(r->last_result);
>> +        resp->req_resp = htobe16(r->last_reqresp);
>> +        resp->write_counter = htobe32(r->write_count);
>> +        resp->address = htobe16(r->last_address);
>>      } else {
>>          resp->result = htobe16(VIRTIO_RPMB_RES_GENERAL_FAILURE);
>>      }
>> @@ -445,6 +540,10 @@ vrpmb_handle_ctrl(VuDev *dev, int qidx)
>>                                __func__);
>>                  }
>>                  break;
>> +            case VIRTIO_RPMB_REQ_DATA_WRITE:
>> +                /* we can have multiple blocks handled */
>> +                n += vrpmb_handle_write(dev, f);
>> +                break;
>>              default:
>>                  g_debug("un-handled request: %x", f->req_resp);
>>                  break;
>> -- 
>> 2.20.1
>> 

Thanks!

-- 
Alex Bennée
_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

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

* Re: [RFC PATCH  15/19] tools/vhost-user-rpmb: implement VIRTIO_RPMB_REQ_DATA_WRITE
  2020-09-28 14:56       ` Alex Bennée
  (?)
@ 2020-09-28 15:18       ` Joakim Bech
  -1 siblings, 0 replies; 48+ messages in thread
From: Joakim Bech @ 2020-09-28 15:18 UTC (permalink / raw)
  To: Alex Bennée
  Cc: jean-philippe, maxim.uvarov, bing.zhu, Matti.Moell,
	virtualization, ilias.apalodimas, qemu-devel, arnd,
	takahiro.akashi, tomas.winkler, stratos-dev, hmo, yang.huang

On Mon, Sep 28, 2020 at 03:56:19PM +0100, Alex Bennée wrote:
> 
> Joakim Bech <joakim.bech@linaro.org> writes:
> 
> > On Fri, Sep 25, 2020 at 01:51:43PM +0100, Alex Bennée wrote:
> >> With this command we are finally updating data to the backing store
> >> and cycling the write_count and each successful write. We also include
> >> the write count in all response frames as the spec is a little unclear
> >> but the example test code expected it.
> >> 
> >> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> >> ---
> >>  tools/vhost-user-rpmb/main.c | 111 +++++++++++++++++++++++++++++++++--
> >>  1 file changed, 105 insertions(+), 6 deletions(-)
> >> 
> >> diff --git a/tools/vhost-user-rpmb/main.c b/tools/vhost-user-rpmb/main.c
> >> index 88747c50fa44..a17c3b4bcc4e 100644
> >> --- a/tools/vhost-user-rpmb/main.c
> >> +++ b/tools/vhost-user-rpmb/main.c
> >> @@ -62,6 +62,7 @@ enum {
> >>  #define KiB     (1UL << 10)
> >>  #define MAX_RPMB_SIZE (KiB * 128 * 256)
> >>  #define RPMB_KEY_MAC_SIZE 32
> >> +#define RPMB_BLOCK_SIZE 256
> >>  
> >>  /* RPMB Request Types */
> >>  #define VIRTIO_RPMB_REQ_PROGRAM_KEY        0x0001
> >> @@ -100,7 +101,7 @@ struct virtio_rpmb_config {
> >>  struct virtio_rpmb_frame {
> >>      uint8_t stuff[196];
> >>      uint8_t key_mac[RPMB_KEY_MAC_SIZE];
> >> -    uint8_t data[256];
> >> +    uint8_t data[RPMB_BLOCK_SIZE];
> >>      uint8_t nonce[16];
> >>      /* remaining fields are big-endian */
> >>      uint32_t write_counter;
> >> @@ -124,6 +125,7 @@ typedef struct VuRpmb {
> >>      uint8_t  last_nonce[16];
> >>      uint16_t last_result;
> >>      uint16_t last_reqresp;
> >> +    uint16_t last_address;
> >>      uint32_t write_count;
> >>  } VuRpmb;
> >>  
> >> @@ -239,17 +241,30 @@ vrpmb_set_config(VuDev *dev, const uint8_t *data,
> >>   * which itself uses a 3 clause BSD chunk of code.
> >>   */
> >>  
> >> +static const int rpmb_frame_dlen = (sizeof(struct virtio_rpmb_frame) -
> >> +                                    offsetof(struct virtio_rpmb_frame, data));
> >> +
> >>  static void vrpmb_update_mac_in_frame(VuRpmb *r, struct virtio_rpmb_frame *frm)
> >>  {
> >>      hmac_sha256_ctx ctx;
> >> -    static const int dlen = (sizeof(struct virtio_rpmb_frame) -
> >> -                             offsetof(struct virtio_rpmb_frame, data));
> >>  
> >>      hmac_sha256_init(&ctx, r->key, RPMB_KEY_MAC_SIZE);
> >> -    hmac_sha256_update(&ctx, frm->data, dlen);
> >> +    hmac_sha256_update(&ctx, frm->data, rpmb_frame_dlen);
> >>      hmac_sha256_final(&ctx, &frm->key_mac[0], 32);
> >>  }
> >>  
> >> +static bool vrpmb_verify_mac_in_frame(VuRpmb *r, struct virtio_rpmb_frame *frm)
> >> +{
> >> +    hmac_sha256_ctx ctx;
> >> +    uint8_t calculated_mac[RPMB_KEY_MAC_SIZE];
> >> +
> >> +    hmac_sha256_init(&ctx, r->key, RPMB_KEY_MAC_SIZE);
> >> +    hmac_sha256_update(&ctx, frm->data, rpmb_frame_dlen);
> >> +    hmac_sha256_final(&ctx, calculated_mac, RPMB_KEY_MAC_SIZE);
> >> +
> >> +    return memcmp(calculated_mac, frm->key_mac, RPMB_KEY_MAC_SIZE) == 0;
> >>
> > I'd prefer using a constant time comparison function for this one
> > instead of memcmp (regardless if it's used for simulation or not) to
> > prevent eventual timing attacks.
> 
> Could you recommend such a function for this?
> 
Here is such an implementation:
https://github.com/OP-TEE/optee_os/blob/master/lib/libutils/ext/consttime_memcmp.c

However, cross check the license so it's OK to use. If not there are
similar implementations out there under other licenses.

> >
> >> +}
> >> +
> >>  /*
> >>   * Handlers for individual control messages
> >>   */
> >> @@ -324,6 +339,82 @@ vrpmb_handle_get_write_counter(VuDev *dev, struct virtio_rpmb_frame *frame)
> >>      return resp;
> >>  }
> >>  
> >> +/*
> >> + * vrpmb_handle_write:
> >> + *
> >> + * We will report the success/fail on receipt of
> >> + * VIRTIO_RPMB_REQ_RESULT_READ. Returns the number of extra frames
> >> + * processed in the request.
> >> + */
> >> +static int vrpmb_handle_write(VuDev *dev, struct virtio_rpmb_frame *frame)
> >> +{
> >> +    VuRpmb *r = container_of(dev, VuRpmb, dev.parent);
> >> +    int extra_frames = 0;
> >> +    uint16_t block_count = be16toh(frame->block_count);
> >> +    uint32_t write_counter = be32toh(frame->write_counter);
> >> +    size_t offset;
> >> +
> >> +    r->last_reqresp = VIRTIO_RPMB_RESP_DATA_WRITE;
> >> +    r->last_address = be16toh(frame->address);
> >> +    offset =  r->last_address * RPMB_BLOCK_SIZE;
> >> +
> >> +    /*
> >> +     * Run the checks from:
> >> +     * 5.12.6.1.3 Device Requirements: Device Operation: Data Write
> >> +     */
> >> +    if (!r->key) {
> >> +        g_warning("no key programmed");
> >> +        r->last_result = VIRTIO_RPMB_RES_NO_AUTH_KEY;
> >> +    } else if (block_count == 0 ||
> >> +               block_count > r->virtio_config.max_wr_cnt) {
> >> +        r->last_result = VIRTIO_RPMB_RES_GENERAL_FAILURE;
> >> +    } else if (false /* what does an expired write counter mean? */) {
> >>
> > IIRC, the counter has room for a 32-bit value and the counter will never
> > wrap around. So once the counter have reached max for uint32_t, then
> > there is an additional bit set (permanently) in the operation result.
> > I.e., writes are no longer possible once that has happened. That is
> > probably what you're referring to here I suppose.
> 
> That would make sense. I'll see if I can make the spec language a bit
> clearer as well.
> 
> >
> >> +        r->last_result = VIRTIO_RPMB_RES_WRITE_COUNTER_EXPIRED;
> >> +    } else if (offset > (r->virtio_config.capacity * (128 * KiB))) {
> >> +        r->last_result = VIRTIO_RPMB_RES_ADDR_FAILURE;
> >> +    } else if (!vrpmb_verify_mac_in_frame(r, frame)) {
> >> +        r->last_result = VIRTIO_RPMB_RES_AUTH_FAILURE;
> >> +    } else if (write_counter != r->write_count) {
> >> +        r->last_result = VIRTIO_RPMB_RES_COUNT_FAILURE;
> >> +    } else {
> >> +        int i;
> >> +        /* At this point we have a valid authenticated write request
> >> +         * so the counter can incremented and we can attempt to
> >> +         * update the backing device.
> >> +         */
> >> +        r->write_count++;
> >> +        for (i = 0; i < block_count; i++) {
> >> +            void *blk = r->flash_map + offset;
> >> +            g_debug("%s: writing block %d", __func__, i);
> >> +            if (mprotect(blk, RPMB_BLOCK_SIZE, PROT_WRITE) != 0) {
> >> +                r->last_result =  VIRTIO_RPMB_RES_WRITE_FAILURE;
> >> +                break;
> >> +            }
> >> +            memcpy(blk, frame[i].data, RPMB_BLOCK_SIZE);
> >> +            if (msync(blk, RPMB_BLOCK_SIZE, MS_SYNC) != 0) {
> >> +                g_warning("%s: failed to sync update", __func__);
> >> +                r->last_result = VIRTIO_RPMB_RES_WRITE_FAILURE;
> >> +                break;
> >> +            }
> >> +            if (mprotect(blk, RPMB_BLOCK_SIZE, PROT_READ) != 0) {
> >> +                g_warning("%s: failed to re-apply read protection", __func__);
> >> +                r->last_result = VIRTIO_RPMB_RES_GENERAL_FAILURE;
> >> +                break;
> >> +            }
> >> +            offset += RPMB_BLOCK_SIZE;
> >> +        }
> >> +        r->last_result = VIRTIO_RPMB_RES_OK;
> >> +        extra_frames = i - 1;
> >> +    }
> >> +
> >> +    g_info("%s: %s (%x, %d extra frames processed), write_count=%d", __func__,
> >> +           r->last_result == VIRTIO_RPMB_RES_OK ? "successful":"failed",
> >> +           r->last_result, extra_frames, r->write_count);
> >> +
> >> +    return extra_frames;
> >> +}
> >> +
> >> +
> >>  /*
> >>   * Return the result of the last message. This is only valid if the
> >>   * previous message was VIRTIO_RPMB_REQ_PROGRAM_KEY or
> >> @@ -339,10 +430,14 @@ static struct virtio_rpmb_frame * vrpmb_handle_result_read(VuDev *dev)
> >>      g_info("%s: for request:%x result:%x", __func__,
> >>             r->last_reqresp, r->last_result);
> >>  
> >> -    if (r->last_reqresp == VIRTIO_RPMB_RESP_PROGRAM_KEY ||
> >> -        r->last_reqresp == VIRTIO_RPMB_REQ_DATA_WRITE) {
> >> +    if (r->last_reqresp == VIRTIO_RPMB_RESP_PROGRAM_KEY) {
> >>          resp->result = htobe16(r->last_result);
> >>          resp->req_resp = htobe16(r->last_reqresp);
> >> +    } else if (r->last_reqresp == VIRTIO_RPMB_RESP_DATA_WRITE) {
> >> +        resp->result = htobe16(r->last_result);
> >> +        resp->req_resp = htobe16(r->last_reqresp);
> >> +        resp->write_counter = htobe32(r->write_count);
> >> +        resp->address = htobe16(r->last_address);
> >>      } else {
> >>          resp->result = htobe16(VIRTIO_RPMB_RES_GENERAL_FAILURE);
> >>      }
> >> @@ -445,6 +540,10 @@ vrpmb_handle_ctrl(VuDev *dev, int qidx)
> >>                                __func__);
> >>                  }
> >>                  break;
> >> +            case VIRTIO_RPMB_REQ_DATA_WRITE:
> >> +                /* we can have multiple blocks handled */
> >> +                n += vrpmb_handle_write(dev, f);
> >> +                break;
> >>              default:
> >>                  g_debug("un-handled request: %x", f->req_resp);
> >>                  break;
> >> -- 
> >> 2.20.1
> >> 
> 
> Thanks!
> 
> -- 
> Alex Bennée

-- 
Regards,
Joakim


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

* Re: [RFC PATCH  01/19] tools/virtiofsd: add support for --socket-group
  2020-09-25 12:51   ` Alex Bennée
@ 2020-10-07 10:48     ` Dr. David Alan Gilbert
  -1 siblings, 0 replies; 48+ messages in thread
From: Dr. David Alan Gilbert @ 2020-10-07 10:48 UTC (permalink / raw)
  To: Alex Bennée
  Cc: jean-philippe, maxim.uvarov, bing.zhu, Matti.Moell,
	virtualization, ilias.apalodimas, qemu-devel, arnd, hmo,
	takahiro.akashi, Stefan Hajnoczi, joakim.bech, stratos-dev,
	tomas.winkler, yang.huang

* Alex Bennée (alex.bennee@linaro.org) wrote:
> If you like running QEMU as a normal user (very common for TCG runs)
> but you have to run virtiofsd as a root user you run into connection
> problems. Adding support for an optional --socket-group allows the
> users to keep using the command line.
> 
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>

Queued

> ---
> v1
>   - tweak documentation and commentary
> ---
>  docs/tools/virtiofsd.rst        |  4 ++++
>  tools/virtiofsd/fuse_i.h        |  1 +
>  tools/virtiofsd/fuse_lowlevel.c |  6 ++++++
>  tools/virtiofsd/fuse_virtio.c   | 20 ++++++++++++++++++--
>  4 files changed, 29 insertions(+), 2 deletions(-)
> 
> diff --git a/docs/tools/virtiofsd.rst b/docs/tools/virtiofsd.rst
> index e33c81ed41f1..085f9b12a6a3 100644
> --- a/docs/tools/virtiofsd.rst
> +++ b/docs/tools/virtiofsd.rst
> @@ -87,6 +87,10 @@ Options
>  
>    Listen on vhost-user UNIX domain socket at PATH.
>  
> +.. option:: --socket-group=GROUP
> +
> +  Set the vhost-user UNIX domain socket gid to GROUP.
> +
>  .. option:: --fd=FDNUM
>  
>    Accept connections from vhost-user UNIX domain socket file descriptor FDNUM.
> diff --git a/tools/virtiofsd/fuse_i.h b/tools/virtiofsd/fuse_i.h
> index 1240828208ab..492e002181e2 100644
> --- a/tools/virtiofsd/fuse_i.h
> +++ b/tools/virtiofsd/fuse_i.h
> @@ -68,6 +68,7 @@ struct fuse_session {
>      size_t bufsize;
>      int error;
>      char *vu_socket_path;
> +    char *vu_socket_group;
>      int   vu_listen_fd;
>      int   vu_socketfd;
>      struct fv_VuDev *virtio_dev;
> diff --git a/tools/virtiofsd/fuse_lowlevel.c b/tools/virtiofsd/fuse_lowlevel.c
> index 2dd36ec03b6e..4d1ba2925d1b 100644
> --- a/tools/virtiofsd/fuse_lowlevel.c
> +++ b/tools/virtiofsd/fuse_lowlevel.c
> @@ -2523,6 +2523,7 @@ static const struct fuse_opt fuse_ll_opts[] = {
>      LL_OPTION("--debug", debug, 1),
>      LL_OPTION("allow_root", deny_others, 1),
>      LL_OPTION("--socket-path=%s", vu_socket_path, 0),
> +    LL_OPTION("--socket-group=%s", vu_socket_group, 0),
>      LL_OPTION("--fd=%d", vu_listen_fd, 0),
>      LL_OPTION("--thread-pool-size=%d", thread_pool_size, 0),
>      FUSE_OPT_END
> @@ -2630,6 +2631,11 @@ struct fuse_session *fuse_session_new(struct fuse_args *args,
>                   "fuse: --socket-path and --fd cannot be given together\n");
>          goto out4;
>      }
> +    if (se->vu_socket_group && !se->vu_socket_path) {
> +        fuse_log(FUSE_LOG_ERR,
> +                 "fuse: --socket-group can only be used with --socket-path\n");
> +        goto out4;
> +    }
>  
>      se->bufsize = FUSE_MAX_MAX_PAGES * getpagesize() + FUSE_BUFFER_HEADER_SIZE;
>  
> diff --git a/tools/virtiofsd/fuse_virtio.c b/tools/virtiofsd/fuse_virtio.c
> index 9e5537506c16..7942d3d11a87 100644
> --- a/tools/virtiofsd/fuse_virtio.c
> +++ b/tools/virtiofsd/fuse_virtio.c
> @@ -31,6 +31,8 @@
>  #include <sys/socket.h>
>  #include <sys/types.h>
>  #include <sys/un.h>
> +#include <sys/types.h>
> +#include <grp.h>
>  #include <unistd.h>
>  
>  #include "contrib/libvhost-user/libvhost-user.h"
> @@ -924,15 +926,29 @@ static int fv_create_listen_socket(struct fuse_session *se)
>  
>      /*
>       * Unfortunately bind doesn't let you set the mask on the socket,
> -     * so set umask to 077 and restore it later.
> +     * so set umask appropriately and restore it later.
>       */
> -    old_umask = umask(0077);
> +    if (se->vu_socket_group) {
> +        old_umask = umask(S_IROTH | S_IWOTH | S_IXOTH);
> +    } else {
> +        old_umask = umask(S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH);
> +    }
>      if (bind(listen_sock, (struct sockaddr *)&un, addr_len) == -1) {
>          fuse_log(FUSE_LOG_ERR, "vhost socket bind: %m\n");
>          close(listen_sock);
>          umask(old_umask);
>          return -1;
>      }
> +    if (se->vu_socket_group) {
> +        struct group *g = getgrnam(se->vu_socket_group);
> +        if (g) {
> +            if (!chown(se->vu_socket_path, -1, g->gr_gid)) {
> +                fuse_log(FUSE_LOG_WARNING,
> +                         "vhost socket failed to set group to %s (%d)\n",
> +                         se->vu_socket_group, g->gr_gid);
> +            }
> +        }
> +    }
>      umask(old_umask);
>  
>      if (listen(listen_sock, 1) == -1) {
> -- 
> 2.20.1
> 
-- 
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK



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

* Re: [RFC PATCH  01/19] tools/virtiofsd: add support for --socket-group
@ 2020-10-07 10:48     ` Dr. David Alan Gilbert
  0 siblings, 0 replies; 48+ messages in thread
From: Dr. David Alan Gilbert @ 2020-10-07 10:48 UTC (permalink / raw)
  To: Alex Bennée
  Cc: jean-philippe, maxim.uvarov, bing.zhu, Matti.Moell,
	virtualization, ilias.apalodimas, qemu-devel, arnd, hmo,
	takahiro.akashi, Stefan Hajnoczi, joakim.bech, stratos-dev,
	tomas.winkler, yang.huang

* Alex Bennée (alex.bennee@linaro.org) wrote:
> If you like running QEMU as a normal user (very common for TCG runs)
> but you have to run virtiofsd as a root user you run into connection
> problems. Adding support for an optional --socket-group allows the
> users to keep using the command line.
> 
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>

Queued

> ---
> v1
>   - tweak documentation and commentary
> ---
>  docs/tools/virtiofsd.rst        |  4 ++++
>  tools/virtiofsd/fuse_i.h        |  1 +
>  tools/virtiofsd/fuse_lowlevel.c |  6 ++++++
>  tools/virtiofsd/fuse_virtio.c   | 20 ++++++++++++++++++--
>  4 files changed, 29 insertions(+), 2 deletions(-)
> 
> diff --git a/docs/tools/virtiofsd.rst b/docs/tools/virtiofsd.rst
> index e33c81ed41f1..085f9b12a6a3 100644
> --- a/docs/tools/virtiofsd.rst
> +++ b/docs/tools/virtiofsd.rst
> @@ -87,6 +87,10 @@ Options
>  
>    Listen on vhost-user UNIX domain socket at PATH.
>  
> +.. option:: --socket-group=GROUP
> +
> +  Set the vhost-user UNIX domain socket gid to GROUP.
> +
>  .. option:: --fd=FDNUM
>  
>    Accept connections from vhost-user UNIX domain socket file descriptor FDNUM.
> diff --git a/tools/virtiofsd/fuse_i.h b/tools/virtiofsd/fuse_i.h
> index 1240828208ab..492e002181e2 100644
> --- a/tools/virtiofsd/fuse_i.h
> +++ b/tools/virtiofsd/fuse_i.h
> @@ -68,6 +68,7 @@ struct fuse_session {
>      size_t bufsize;
>      int error;
>      char *vu_socket_path;
> +    char *vu_socket_group;
>      int   vu_listen_fd;
>      int   vu_socketfd;
>      struct fv_VuDev *virtio_dev;
> diff --git a/tools/virtiofsd/fuse_lowlevel.c b/tools/virtiofsd/fuse_lowlevel.c
> index 2dd36ec03b6e..4d1ba2925d1b 100644
> --- a/tools/virtiofsd/fuse_lowlevel.c
> +++ b/tools/virtiofsd/fuse_lowlevel.c
> @@ -2523,6 +2523,7 @@ static const struct fuse_opt fuse_ll_opts[] = {
>      LL_OPTION("--debug", debug, 1),
>      LL_OPTION("allow_root", deny_others, 1),
>      LL_OPTION("--socket-path=%s", vu_socket_path, 0),
> +    LL_OPTION("--socket-group=%s", vu_socket_group, 0),
>      LL_OPTION("--fd=%d", vu_listen_fd, 0),
>      LL_OPTION("--thread-pool-size=%d", thread_pool_size, 0),
>      FUSE_OPT_END
> @@ -2630,6 +2631,11 @@ struct fuse_session *fuse_session_new(struct fuse_args *args,
>                   "fuse: --socket-path and --fd cannot be given together\n");
>          goto out4;
>      }
> +    if (se->vu_socket_group && !se->vu_socket_path) {
> +        fuse_log(FUSE_LOG_ERR,
> +                 "fuse: --socket-group can only be used with --socket-path\n");
> +        goto out4;
> +    }
>  
>      se->bufsize = FUSE_MAX_MAX_PAGES * getpagesize() + FUSE_BUFFER_HEADER_SIZE;
>  
> diff --git a/tools/virtiofsd/fuse_virtio.c b/tools/virtiofsd/fuse_virtio.c
> index 9e5537506c16..7942d3d11a87 100644
> --- a/tools/virtiofsd/fuse_virtio.c
> +++ b/tools/virtiofsd/fuse_virtio.c
> @@ -31,6 +31,8 @@
>  #include <sys/socket.h>
>  #include <sys/types.h>
>  #include <sys/un.h>
> +#include <sys/types.h>
> +#include <grp.h>
>  #include <unistd.h>
>  
>  #include "contrib/libvhost-user/libvhost-user.h"
> @@ -924,15 +926,29 @@ static int fv_create_listen_socket(struct fuse_session *se)
>  
>      /*
>       * Unfortunately bind doesn't let you set the mask on the socket,
> -     * so set umask to 077 and restore it later.
> +     * so set umask appropriately and restore it later.
>       */
> -    old_umask = umask(0077);
> +    if (se->vu_socket_group) {
> +        old_umask = umask(S_IROTH | S_IWOTH | S_IXOTH);
> +    } else {
> +        old_umask = umask(S_IRGRP | S_IWGRP | S_IXGRP | S_IROTH | S_IWOTH | S_IXOTH);
> +    }
>      if (bind(listen_sock, (struct sockaddr *)&un, addr_len) == -1) {
>          fuse_log(FUSE_LOG_ERR, "vhost socket bind: %m\n");
>          close(listen_sock);
>          umask(old_umask);
>          return -1;
>      }
> +    if (se->vu_socket_group) {
> +        struct group *g = getgrnam(se->vu_socket_group);
> +        if (g) {
> +            if (!chown(se->vu_socket_path, -1, g->gr_gid)) {
> +                fuse_log(FUSE_LOG_WARNING,
> +                         "vhost socket failed to set group to %s (%d)\n",
> +                         se->vu_socket_group, g->gr_gid);
> +            }
> +        }
> +    }
>      umask(old_umask);
>  
>      if (listen(listen_sock, 1) == -1) {
> -- 
> 2.20.1
> 
-- 
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK

_______________________________________________
Virtualization mailing list
Virtualization@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/virtualization

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

end of thread, other threads:[~2020-10-07 10:49 UTC | newest]

Thread overview: 48+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-09-25 12:51 [RFC PATCH 00/19] vhost-user-rpmb (Replay Protected Memory Block) Alex Bennée
2020-09-25 12:51 ` Alex Bennée
2020-09-25 12:51 ` [RFC PATCH 01/19] tools/virtiofsd: add support for --socket-group Alex Bennée
2020-09-25 12:51   ` Alex Bennée
2020-10-07 10:48   ` Dr. David Alan Gilbert
2020-10-07 10:48     ` Dr. David Alan Gilbert
2020-09-25 12:51 ` [RFC PATCH 02/19] hw/block: add boilerplate for vhost-user-rpmb device Alex Bennée
2020-09-25 12:51   ` Alex Bennée
2020-09-25 12:51 ` [RFC PATCH 03/19] hw/virtio: move virtio-pci.h into shared include space Alex Bennée
2020-09-25 12:51   ` Alex Bennée
2020-09-25 12:51 ` [RFC PATCH 04/19] hw/block: add vhost-user-rpmb-pci boilerplate Alex Bennée
2020-09-25 12:51   ` Alex Bennée
2020-09-25 12:51 ` [RFC PATCH 05/19] virtio-pci: add notification trace points Alex Bennée
2020-09-25 12:51   ` Alex Bennée
2020-09-25 13:06   ` Philippe Mathieu-Daudé
2020-09-25 12:51 ` [RFC PATCH 06/19] tools/vhost-user-rpmb: add boilerplate and initial main Alex Bennée
2020-09-25 12:51   ` Alex Bennée
2020-09-25 12:51 ` [RFC PATCH 07/19] tools/vhost-user-rpmb: implement --print-capabilities Alex Bennée
2020-09-25 12:51   ` Alex Bennée
2020-09-25 12:51 ` [RFC PATCH 08/19] tools/vhost-user-rpmb: connect to fd and instantiate basic run loop Alex Bennée
2020-09-25 12:51   ` Alex Bennée
2020-09-25 12:51 ` [RFC PATCH 09/19] tools/vhost-user-rpmb: add a --verbose/debug flags for logging Alex Bennée
2020-09-25 12:51   ` Alex Bennée
2020-09-25 12:51 ` [RFC PATCH 10/19] tools/vhost-user-rpmb: handle shutdown and SIGINT/SIGHUP cleanly Alex Bennée
2020-09-25 12:51   ` Alex Bennée
2020-09-25 12:51 ` [RFC PATCH 11/19] tools/vhost-user-rpmb: add --flash-path for backing store Alex Bennée
2020-09-25 12:51   ` Alex Bennée
2020-09-25 12:51 ` [RFC PATCH 12/19] tools/vhost-user-rpmb: import hmac_sha256 functions Alex Bennée
2020-09-25 12:51   ` Alex Bennée
2020-09-25 12:51 ` [RFC PATCH 13/19] tools/vhost-user-rpmb: implement the PROGRAM_KEY handshake Alex Bennée
2020-09-25 12:51   ` Alex Bennée
2020-09-25 12:51 ` [RFC PATCH 14/19] tools/vhost-user-rpmb: implement VIRTIO_RPMB_REQ_GET_WRITE_COUNTER Alex Bennée
2020-09-25 12:51   ` Alex Bennée
2020-09-25 12:51 ` [RFC PATCH 15/19] tools/vhost-user-rpmb: implement VIRTIO_RPMB_REQ_DATA_WRITE Alex Bennée
2020-09-25 12:51   ` Alex Bennée
2020-09-28 13:52   ` Joakim Bech
2020-09-28 14:56     ` Alex Bennée
2020-09-28 14:56       ` Alex Bennée
2020-09-28 15:18       ` Joakim Bech
2020-09-25 12:51 ` [RFC PATCH 16/19] tools/vhost-user-rpmb: implement VIRTIO_RPMB_REQ_DATA_READ Alex Bennée
2020-09-25 12:51   ` Alex Bennée
2020-09-25 12:51 ` [RFC PATCH 17/19] tools/vhost-user-rpmb: add key persistence Alex Bennée
2020-09-25 12:51   ` Alex Bennée
2020-09-25 12:51 ` [RFC PATCH 18/19] tools/vhost-user-rpmb: allow setting of the write_count Alex Bennée
2020-09-25 12:51   ` Alex Bennée
2020-09-25 12:51 ` [RFC PATCH 19/19] docs: add a man page for vhost-user-rpmb Alex Bennée
2020-09-25 12:51   ` Alex Bennée
2020-09-25 14:07 ` [RFC PATCH 00/19] vhost-user-rpmb (Replay Protected Memory Block) no-reply

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.