meson.build | 10 +++- qemu-nbd.c | 46 +++++++++++++++++++ meson_options.txt | 3 ++ scripts/meson-buildoptions.sh | 3 ++ tests/docker/dockerfiles/centos8.docker | 1 + .../dockerfiles/fedora-i386-cross.docker | 1 + tests/docker/dockerfiles/fedora.docker | 1 + tests/docker/dockerfiles/opensuse-leap.docker | 1 + tests/docker/dockerfiles/ubuntu1804.docker | 1 + tests/docker/dockerfiles/ubuntu2004.docker | 1 + 10 files changed, 67 insertions(+), 1 deletion(-)
From: "Richard W.M. Jones" <rjones@redhat.com>
Under SELinux, Unix domain sockets have two labels. One is on the
disk and can be set with commands such as chcon(1). There is a
different label stored in memory (called the process label). This can
only be set by the process creating the socket. When using SELinux +
SVirt and wanting qemu to be able to connect to a qemu-nbd instance,
you must set both labels correctly first.
For qemu-nbd the options to set the second label are awkward. You can
create the socket in a wrapper program and then exec into qemu-nbd.
Or you could try something with LD_PRELOAD.
This commit adds the ability to set the label straightforwardly on the
command line, via the new --selinux-label flag. (The name of the flag
is the same as the equivalent nbdkit option.)
A worked example showing how to use the new option can be found in
this bug: https://bugzilla.redhat.com/show_bug.cgi?id=1984938
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1984938
Signed-off-by: Richard W.M. Jones <rjones@redhat.com>
Reviewed-by: Daniel P. Berrangé <berrange@redhat.com>
Message-Id: <20210930084701.3899578-1-rjones@redhat.com>
[eblake: rebase to configure changes, reject --selinux-label if it is
not compiled in or not used on a Unix socket]
Signed-off-by: Eric Blake <eblake@redhat.com>
---
v3 was here:
https://lists.gnu.org/archive/html/qemu-devel/2021-09/msg07677.html
since then: another rework of the configure logic (now that
meson-buildoptions.sh exists), and a rework of the error reporting
(for now, loudly complain on all unsupported attempts at labeling. We
may later allow things that currently fail)
Candidate for 6.2 in spite of soft freeze because of earlier attempted
pull request here:
https://lists.gnu.org/archive/html/qemu-devel/2021-09/msg07081.html
and my apologies for letting this slip a month without action.
meson.build | 10 +++-
qemu-nbd.c | 46 +++++++++++++++++++
meson_options.txt | 3 ++
scripts/meson-buildoptions.sh | 3 ++
tests/docker/dockerfiles/centos8.docker | 1 +
.../dockerfiles/fedora-i386-cross.docker | 1 +
tests/docker/dockerfiles/fedora.docker | 1 +
tests/docker/dockerfiles/opensuse-leap.docker | 1 +
tests/docker/dockerfiles/ubuntu1804.docker | 1 +
tests/docker/dockerfiles/ubuntu2004.docker | 1 +
10 files changed, 67 insertions(+), 1 deletion(-)
diff --git a/meson.build b/meson.build
index 2ece4fe0889a..73b7deaa0ef3 100644
--- a/meson.build
+++ b/meson.build
@@ -1201,6 +1201,11 @@ keyutils = dependency('libkeyutils', required: false,
has_gettid = cc.has_function('gettid')
+# libselinux
+selinux = dependency('libselinux',
+ required: get_option('selinux'),
+ method: 'pkg-config', kwargs: static_kwargs)
+
# Malloc tests
malloc = []
@@ -1479,6 +1484,7 @@ config_host_data.set('CONFIG_SPICE_PROTOCOL', spice_protocol.found())
config_host_data.set('CONFIG_SPICE', spice.found())
config_host_data.set('CONFIG_X11', x11.found())
config_host_data.set('CONFIG_CFI', get_option('cfi'))
+config_host_data.set('CONFIG_SELINUX', selinux.found())
config_host_data.set('QEMU_VERSION', '"@0@"'.format(meson.project_version()))
config_host_data.set('QEMU_VERSION_MAJOR', meson.project_version().split('.')[0])
config_host_data.set('QEMU_VERSION_MINOR', meson.project_version().split('.')[1])
@@ -3054,7 +3060,8 @@ if have_tools
qemu_io = executable('qemu-io', files('qemu-io.c'),
dependencies: [block, qemuutil], install: true)
qemu_nbd = executable('qemu-nbd', files('qemu-nbd.c'),
- dependencies: [blockdev, qemuutil, gnutls], install: true)
+ dependencies: [blockdev, qemuutil, gnutls, selinux],
+ install: true)
subdir('storage-daemon')
subdir('contrib/rdmacm-mux')
@@ -3430,6 +3437,7 @@ summary_info += {'libdaxctl support': libdaxctl}
summary_info += {'libudev': libudev}
# Dummy dependency, keep .found()
summary_info += {'FUSE lseek': fuse_lseek.found()}
+summary_info += {'selinux': selinux.found()}
summary(summary_info, bool_yn: true, section: 'Dependencies')
if not supported_cpus.contains(cpu)
diff --git a/qemu-nbd.c b/qemu-nbd.c
index 9d895ba24b1e..c6c20df68a4d 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -47,6 +47,10 @@
#include "trace/control.h"
#include "qemu-version.h"
+#ifdef CONFIG_SELINUX
+#include <selinux/selinux.h>
+#endif
+
#ifdef __linux__
#define HAVE_NBD_DEVICE 1
#else
@@ -64,6 +68,7 @@
#define QEMU_NBD_OPT_FORK 263
#define QEMU_NBD_OPT_TLSAUTHZ 264
#define QEMU_NBD_OPT_PID_FILE 265
+#define QEMU_NBD_OPT_SELINUX_LABEL 266
#define MBR_SIZE 512
@@ -116,6 +121,9 @@ static void usage(const char *name)
" --fork fork off the server process and exit the parent\n"
" once the server is running\n"
" --pid-file=PATH store the server's process ID in the given file\n"
+#ifdef CONFIG_SELINUX
+" --selinux-label=LABEL set SELinux process label on listening socket\n"
+#endif
#if HAVE_NBD_DEVICE
"\n"
"Kernel NBD client support:\n"
@@ -454,6 +462,7 @@ static const char *socket_activation_validate_opts(const char *device,
const char *sockpath,
const char *address,
const char *port,
+ const char *selinux,
bool list)
{
if (device != NULL) {
@@ -472,6 +481,10 @@ static const char *socket_activation_validate_opts(const char *device,
return "TCP port number can't be set when using socket activation";
}
+ if (selinux != NULL) {
+ return "SELinux label can't be set when using socket activation";
+ }
+
if (list) {
return "List mode is incompatible with socket activation";
}
@@ -534,6 +547,8 @@ int main(int argc, char **argv)
{ "trace", required_argument, NULL, 'T' },
{ "fork", no_argument, NULL, QEMU_NBD_OPT_FORK },
{ "pid-file", required_argument, NULL, QEMU_NBD_OPT_PID_FILE },
+ { "selinux-label", required_argument, NULL,
+ QEMU_NBD_OPT_SELINUX_LABEL },
{ NULL, 0, NULL, 0 }
};
int ch;
@@ -560,6 +575,7 @@ int main(int argc, char **argv)
int old_stderr = -1;
unsigned socket_activation;
const char *pid_file_name = NULL;
+ const char *selinux_label = NULL;
BlockExportOptions *export_opts;
#ifdef CONFIG_POSIX
@@ -749,6 +765,9 @@ int main(int argc, char **argv)
case QEMU_NBD_OPT_PID_FILE:
pid_file_name = optarg;
break;
+ case QEMU_NBD_OPT_SELINUX_LABEL:
+ selinux_label = optarg;
+ break;
}
}
@@ -788,6 +807,7 @@ int main(int argc, char **argv)
/* Using socket activation - check user didn't use -p etc. */
const char *err_msg = socket_activation_validate_opts(device, sockpath,
bindto, port,
+ selinux_label,
list);
if (err_msg != NULL) {
error_report("%s", err_msg);
@@ -827,6 +847,18 @@ int main(int argc, char **argv)
}
}
+ if (selinux_label) {
+#ifdef CONFIG_SELINUX
+ if (sockpath == NULL && device == NULL) {
+ error_report("--selinux-label is not permitted without --socket");
+ exit(EXIT_FAILURE);
+ }
+#else
+ error_report("SELinux support not enabled in this binary");
+ exit(EXIT_FAILURE);
+#endif
+ }
+
if (list) {
saddr = nbd_build_socket_address(sockpath, bindto, port);
return qemu_nbd_client_list(saddr, tlscreds, bindto);
@@ -940,6 +972,13 @@ int main(int argc, char **argv)
} else {
backlog = MIN(shared, SOMAXCONN);
}
+#ifdef CONFIG_SELINUX
+ if (selinux_label && setsockcreatecon_raw(selinux_label) == -1) {
+ error_report("Cannot set SELinux socket create context to %s: %s",
+ selinux_label, strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+#endif
saddr = nbd_build_socket_address(sockpath, bindto, port);
if (qio_net_listener_open_sync(server, saddr, backlog,
&local_err) < 0) {
@@ -947,6 +986,13 @@ int main(int argc, char **argv)
error_report_err(local_err);
exit(EXIT_FAILURE);
}
+#ifdef CONFIG_SELINUX
+ if (selinux_label && setsockcreatecon_raw(NULL) == -1) {
+ error_report("Cannot clear SELinux socket create context: %s",
+ strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+#endif
} else {
size_t i;
/* See comment in check_socket_activation above. */
diff --git a/meson_options.txt b/meson_options.txt
index 411952bc91af..e3923237322a 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -201,3 +201,6 @@ option('slirp', type: 'combo', value: 'auto',
option('fdt', type: 'combo', value: 'auto',
choices: ['disabled', 'enabled', 'auto', 'system', 'internal'],
description: 'Whether and how to find the libfdt library')
+
+option('selinux', type: 'feature', value: 'auto',
+ description: 'SELinux support in qemu-nbd')
diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh
index 45e1f2e20daa..7a17ff42182f 100644
--- a/scripts/meson-buildoptions.sh
+++ b/scripts/meson-buildoptions.sh
@@ -72,6 +72,7 @@ meson_options_help() {
printf "%s\n" ' sdl SDL user interface'
printf "%s\n" ' sdl-image SDL Image support for icons'
printf "%s\n" ' seccomp seccomp support'
+ printf "%s\n" ' selinux SELinux support in qemu-nbd'
printf "%s\n" ' smartcard CA smartcard emulation support'
printf "%s\n" ' snappy snappy compression support'
printf "%s\n" ' sparse sparse checker'
@@ -215,6 +216,8 @@ _meson_option_parse() {
--disable-sdl-image) printf "%s" -Dsdl_image=disabled ;;
--enable-seccomp) printf "%s" -Dseccomp=enabled ;;
--disable-seccomp) printf "%s" -Dseccomp=disabled ;;
+ --enable-selinux) printf "%s" -Dselinux=enabled ;;
+ --disable-selinux) printf "%s" -Dselinux=disabled ;;
--enable-slirp) printf "%s" -Dslirp=enabled ;;
--disable-slirp) printf "%s" -Dslirp=disabled ;;
--enable-slirp=*) quote_sh "-Dslirp=$2" ;;
diff --git a/tests/docker/dockerfiles/centos8.docker b/tests/docker/dockerfiles/centos8.docker
index 46398c61eea9..7f135f8e8c00 100644
--- a/tests/docker/dockerfiles/centos8.docker
+++ b/tests/docker/dockerfiles/centos8.docker
@@ -51,6 +51,7 @@ ENV PACKAGES \
libpng-devel \
librbd-devel \
libseccomp-devel \
+ libselinux-devel \
libslirp-devel \
libssh-devel \
libtasn1-devel \
diff --git a/tests/docker/dockerfiles/fedora-i386-cross.docker b/tests/docker/dockerfiles/fedora-i386-cross.docker
index f62a71ce2296..13328e6081f9 100644
--- a/tests/docker/dockerfiles/fedora-i386-cross.docker
+++ b/tests/docker/dockerfiles/fedora-i386-cross.docker
@@ -8,6 +8,7 @@ ENV PACKAGES \
gcc \
git \
libffi-devel.i686 \
+ libselinux-devel.i686 \
libtasn1-devel.i686 \
libzstd-devel.i686 \
make \
diff --git a/tests/docker/dockerfiles/fedora.docker b/tests/docker/dockerfiles/fedora.docker
index eec1add7f620..c6fd7e1113d4 100644
--- a/tests/docker/dockerfiles/fedora.docker
+++ b/tests/docker/dockerfiles/fedora.docker
@@ -53,6 +53,7 @@ ENV PACKAGES \
libpng-devel \
librbd-devel \
libseccomp-devel \
+ libselinux-devel \
libslirp-devel \
libssh-devel \
libtasn1-devel \
diff --git a/tests/docker/dockerfiles/opensuse-leap.docker b/tests/docker/dockerfiles/opensuse-leap.docker
index 5a8bee028951..3bbdb67f4fad 100644
--- a/tests/docker/dockerfiles/opensuse-leap.docker
+++ b/tests/docker/dockerfiles/opensuse-leap.docker
@@ -55,6 +55,7 @@ ENV PACKAGES \
libpulse-devel \
librbd-devel \
libseccomp-devel \
+ libselinux-devel \
libspice-server-devel \
libssh-devel \
libtasn1-devel \
diff --git a/tests/docker/dockerfiles/ubuntu1804.docker b/tests/docker/dockerfiles/ubuntu1804.docker
index 0880bf3e2928..450fd06d0d57 100644
--- a/tests/docker/dockerfiles/ubuntu1804.docker
+++ b/tests/docker/dockerfiles/ubuntu1804.docker
@@ -60,6 +60,7 @@ ENV PACKAGES \
libsdl2-dev \
libsdl2-image-dev \
libseccomp-dev \
+ libselinux-dev \
libsnappy-dev \
libspice-protocol-dev \
libspice-server-dev \
diff --git a/tests/docker/dockerfiles/ubuntu2004.docker b/tests/docker/dockerfiles/ubuntu2004.docker
index 39de63d0129f..15a026be0913 100644
--- a/tests/docker/dockerfiles/ubuntu2004.docker
+++ b/tests/docker/dockerfiles/ubuntu2004.docker
@@ -60,6 +60,7 @@ ENV PACKAGES \
libsdl2-dev \
libsdl2-image-dev \
libseccomp-dev \
+ libselinux-dev \
libslirp-dev \
libsnappy-dev \
libspice-protocol-dev \
--
2.33.1
On 15/11/2021 21.29, Eric Blake wrote: > From: "Richard W.M. Jones" <rjones@redhat.com> > > Under SELinux, Unix domain sockets have two labels. One is on the > disk and can be set with commands such as chcon(1). There is a > different label stored in memory (called the process label). This can > only be set by the process creating the socket. When using SELinux + > SVirt and wanting qemu to be able to connect to a qemu-nbd instance, > you must set both labels correctly first. > > For qemu-nbd the options to set the second label are awkward. You can > create the socket in a wrapper program and then exec into qemu-nbd. > Or you could try something with LD_PRELOAD. > > This commit adds the ability to set the label straightforwardly on the > command line, via the new --selinux-label flag. (The name of the flag > is the same as the equivalent nbdkit option.) ... > @@ -3430,6 +3437,7 @@ summary_info += {'libdaxctl support': libdaxctl} > summary_info += {'libudev': libudev} > # Dummy dependency, keep .found() > summary_info += {'FUSE lseek': fuse_lseek.found()} > +summary_info += {'selinux': selinux.found()} It's nicer if you do it like this (i.e. without the .found()): summary_info += {'selinux': selinux} ... then meson prints out the version of the library, too. Apart from that, patch looks fine to me: Reviewed-by: Thomas Huth <thuth@redhat.com>
On Tue, Nov 16, 2021 at 08:06:03AM +0100, Thomas Huth wrote: > On 15/11/2021 21.29, Eric Blake wrote: > > From: "Richard W.M. Jones" <rjones@redhat.com> > > > > Under SELinux, Unix domain sockets have two labels. One is on the > > disk and can be set with commands such as chcon(1). There is a > > different label stored in memory (called the process label). This can > > only be set by the process creating the socket. When using SELinux + > > SVirt and wanting qemu to be able to connect to a qemu-nbd instance, > > you must set both labels correctly first. > > > > For qemu-nbd the options to set the second label are awkward. You can > > create the socket in a wrapper program and then exec into qemu-nbd. > > Or you could try something with LD_PRELOAD. > > > > This commit adds the ability to set the label straightforwardly on the > > command line, via the new --selinux-label flag. (The name of the flag > > is the same as the equivalent nbdkit option.) > ... > > @@ -3430,6 +3437,7 @@ summary_info += {'libdaxctl support': libdaxctl} > > summary_info += {'libudev': libudev} > > # Dummy dependency, keep .found() > > summary_info += {'FUSE lseek': fuse_lseek.found()} > > +summary_info += {'selinux': selinux.found()} > > It's nicer if you do it like this (i.e. without the .found()): > > summary_info += {'selinux': selinux} > > ... then meson prints out the version of the library, too. Will tweak on the pull request. > > Apart from that, patch looks fine to me: > > Reviewed-by: Thomas Huth <thuth@redhat.com> > Thanks. I'll send a pull request through my NBD tree soon. -- Eric Blake, Principal Software Engineer Red Hat, Inc. +1-919-301-3266 Virtualization: qemu.org | libvirt.org
© 2016 - 2024 Red Hat, Inc.