Skip to content

Commit

Permalink
scsi: build qemu-pr-helper
Browse files Browse the repository at this point in the history
Introduce a privileged helper to run persistent reservation commands.
This lets virtual machines send persistent reservations without using
CAP_SYS_RAWIO or out-of-tree patches.  The helper uses Unix permissions
and SCM_RIGHTS to restrict access to processes that can access its socket
and prove that they have an open file descriptor for a raw SCSI device.

The next patch will also correct the usage of persistent reservations
with multipath devices.

It would also be possible to support for Linux's IOC_PR_* ioctls in
the future, to support NVMe devices.  For now, however, only SCSI is
supported.

Signed-off-by: Paolo Bonzini <[email protected]>
  • Loading branch information
bonzini committed Sep 22, 2017
1 parent 7c9e527 commit b855f8d
Show file tree
Hide file tree
Showing 6 changed files with 905 additions and 5 deletions.
4 changes: 3 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,8 @@ qemu-bridge-helper$(EXESUF): qemu-bridge-helper.o $(COMMON_LDADDS)
fsdev/virtfs-proxy-helper$(EXESUF): fsdev/virtfs-proxy-helper.o fsdev/9p-marshal.o fsdev/9p-iov-marshal.o $(COMMON_LDADDS)
fsdev/virtfs-proxy-helper$(EXESUF): LIBS += -lcap

scsi/qemu-pr-helper$(EXESUF): scsi/qemu-pr-helper.o scsi/utils.o $(crypto-obj-y) $(io-obj-y) $(qom-obj-y) $(COMMON_LDADDS)

qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx $(SRC_PATH)/scripts/hxtool
$(call quiet-command,sh $(SRC_PATH)/scripts/hxtool -h < $< > $@,"GEN","$@")

Expand Down Expand Up @@ -488,7 +490,7 @@ clean:
rm -f *.msi
find . \( -name '*.so' -o -name '*.dll' -o -name '*.mo' -o -name '*.[oda]' \) -type f -exec rm {} +
rm -f $(filter-out %.tlb,$(TOOLS)) $(HELPERS-y) qemu-ga TAGS cscope.* *.pod *~ */*~
rm -f fsdev/*.pod
rm -f fsdev/*.pod scsi/*.pod
rm -f qemu-img-cmds.h
rm -f ui/shader/*-vert.h ui/shader/*-frag.h
@# May not be present in GENERATED_FILES
Expand Down
14 changes: 10 additions & 4 deletions configure
Original file line number Diff line number Diff line change
Expand Up @@ -5034,16 +5034,22 @@ if test "$want_tools" = "yes" ; then
fi
fi
if test "$softmmu" = yes ; then
if test "$virtfs" != no ; then
if test "$cap" = yes && test "$linux" = yes && test "$attr" = yes ; then
if test "$linux" = yes; then
if test "$virtfs" != no && test "$cap" = yes && test "$attr" = yes ; then
virtfs=yes
tools="$tools fsdev/virtfs-proxy-helper\$(EXESUF)"
else
if test "$virtfs" = yes; then
error_exit "VirtFS is supported only on Linux and requires libcap devel and libattr devel"
error_exit "VirtFS requires libcap devel and libattr devel"
fi
virtfs=no
fi
tools="$tools scsi/qemu-pr-helper\$(EXESUF)"
else
if test "$virtfs" = yes; then
error_exit "VirtFS is supported only on Linux"
fi
virtfs=no
fi
fi

Expand Down Expand Up @@ -6506,7 +6512,7 @@ fi

# build tree in object directory in case the source is not in the current directory
DIRS="tests tests/tcg tests/tcg/cris tests/tcg/lm32 tests/libqos tests/qapi-schema tests/tcg/xtensa tests/qemu-iotests"
DIRS="$DIRS docs docs/interop fsdev"
DIRS="$DIRS docs docs/interop fsdev scsi"
DIRS="$DIRS pc-bios/optionrom pc-bios/spapr-rtas pc-bios/s390-ccw"
DIRS="$DIRS roms/seabios roms/vgabios"
DIRS="$DIRS qapi-generated"
Expand Down
83 changes: 83 additions & 0 deletions docs/interop/pr-helper.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
..
======================================
Persistent reservation helper protocol
======================================

QEMU's SCSI passthrough devices, ``scsi-block`` and ``scsi-generic``,
can delegate implementation of persistent reservations to an external
(and typically privileged) program. Persistent Reservations allow
restricting access to block devices to specific initiators in a shared
storage setup.

For a more detailed reference please refer the the SCSI Primary
Commands standard, specifically the section on Reservations and the
"PERSISTENT RESERVE IN" and "PERSISTENT RESERVE OUT" commands.

This document describes the socket protocol used between QEMU's
``pr-manager-helper`` object and the external program.

.. contents::

Connection and initialization
-----------------------------

All data transmitted on the socket is big-endian.

After connecting to the helper program's socket, the helper starts a simple
feature negotiation process by writing four bytes corresponding to
the features it exposes (``supported_features``). QEMU reads it,
then writes four bytes corresponding to the desired features of the
helper program (``requested_features``).

If a bit is 1 in ``requested_features`` and 0 in ``supported_features``,
the corresponding feature is not supported by the helper and the connection
is closed. On the other hand, it is acceptable for a bit to be 0 in
``requested_features`` and 1 in ``supported_features``; in this case,
the helper will not enable the feature.

Right now no feature is defined, so the two parties always write four
zero bytes.

Command format
--------------

It is invalid to send multiple commands concurrently on the same
socket. It is however possible to connect multiple sockets to the
helper and send multiple commands to the helper for one or more
file descriptors.

A command consists of a request and a response. A request consists
of a 16-byte SCSI CDB. A file descriptor must be passed to the helper
together with the SCSI CDB using ancillary data.

The CDB has the following limitations:

- the command (stored in the first byte) must be one of 0x5E
(PERSISTENT RESERVE IN) or 0x5F (PERSISTENT RESERVE OUT).

- the allocation length (stored in bytes 7-8 of the CDB for PERSISTENT
RESERVE IN) or parameter list length (stored in bytes 5-8 of the CDB
for PERSISTENT RESERVE OUT) is limited to 8 KiB.

For PERSISTENT RESERVE OUT, the parameter list is sent right after the
CDB. The length of the parameter list is taken from the CDB itself.

The helper's reply has the following structure:

- 4 bytes for the SCSI status

- 4 bytes for the payload size (nonzero only for PERSISTENT RESERVE IN
and only if the SCSI status is 0x00, i.e. GOOD)

- 96 bytes for the SCSI sense data

- if the size is nonzero, the payload follows

The sense data is always sent to keep the protocol simple, even though
it is only valid if the SCSI status is CHECK CONDITION (0x02).

The payload size is always less than or equal to the allocation length
specified in the CDB for the PERSISTENT RESERVE IN command.

If the protocol is violated, the helper closes the socket.
33 changes: 33 additions & 0 deletions docs/pr-manager.rst
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,36 @@ Alternatively, using ``-blockdev``::
-object pr-manager-helper,id=helper0,path=/var/run/qemu-pr-helper.sock
-blockdev node-name=hd,driver=raw,file.driver=host_device,file.filename=/dev/sdb,file.pr-manager=helper0
-device scsi-block,drive=hd

----------------------------------
Invoking :program:`qemu-pr-helper`
----------------------------------

QEMU provides an implementation of the persistent reservation helper,
called :program:`qemu-pr-helper`. The helper should be started as a
system service and supports the following option:

-d, --daemon run in the background
-q, --quiet decrease verbosity
-f, --pidfile=path PID file when running as a daemon
-k, --socket=path path to the socket
-T, --trace=trace-opts tracing options

By default, the socket and PID file are placed in the runtime state
directory, for example :file:`/var/run/qemu-pr-helper.sock` and
:file:`/var/run/qemu-pr-helper.pid`. The PID file is not created
unless :option:`-d` is passed too.

:program:`qemu-pr-helper` can also use the systemd socket activation
protocol. In this case, the systemd socket unit should specify a
Unix stream socket, like this::

[Socket]
ListenStream=/var/run/qemu-pr-helper.sock

After connecting to the socket, :program:`qemu-pr-helper`` can optionally drop
root privileges, except for those capabilities that are needed for
its operation. To do this, add the following options:

-u, --user=user user to drop privileges to
-g, --group=group group to drop privileges to
41 changes: 41 additions & 0 deletions scsi/pr-helper.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/* Definitions for QEMU's persistent reservation helper daemon
*
* Copyright (C) 2017 Red Hat, Inc.
*
* Author:
* Paolo Bonzini <[email protected]>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef QEMU_PR_HELPER_H
#define QEMU_PR_HELPER_H 1

#include <stdint.h>

#define PR_HELPER_CDB_SIZE 16
#define PR_HELPER_SENSE_SIZE 96
#define PR_HELPER_DATA_SIZE 8192

typedef struct PRHelperResponse {
int32_t result;
int32_t sz;
uint8_t sense[PR_HELPER_SENSE_SIZE];
} PRHelperResponse;

#endif
Loading

0 comments on commit b855f8d

Please sign in to comment.