diff --git a/nbdkit.fc b/nbdkit.fc
new file mode 100644
index 0000000..4877736
--- /dev/null
+++ b/nbdkit.fc
@@ -0,0 +1,3 @@
+/usr/sbin/nbdkit -- gen_context(system_u:object_r:nbdkit_exec_t,s0)
+
+/usr/lib/systemd/system/nbdkit.* gen_context(system_u:object_r:nbdkit_unit_file_t,s0)
diff --git a/nbdkit.if b/nbdkit.if
new file mode 100644
index 0000000..315fead
--- /dev/null
+++ b/nbdkit.if
@@ -0,0 +1,207 @@
+## policy for nbdkit
+
+########################################
+##
+## Execute nbdkit_exec_t in the nbdkit domain.
+##
+##
+##
+## Domain allowed to transition.
+##
+##
+#
+interface(`nbdkit_domtrans',`
+ gen_require(`
+ type nbdkit_t, nbdkit_exec_t;
+ ')
+
+ corecmd_search_bin($1)
+ domtrans_pattern($1, nbdkit_exec_t, nbdkit_t)
+')
+
+######################################
+##
+## Execute nbdkit in the caller domain.
+##
+##
+##
+## Domain allowed access.
+##
+##
+#
+interface(`nbdkit_exec',`
+ gen_require(`
+ type nbdkit_exec_t;
+ ')
+
+ corecmd_search_bin($1)
+ can_exec($1, nbdkit_exec_t)
+')
+
+########################################
+##
+## Execute nbdkit in the nbdkit domain, and
+## allow the specified role the nbdkit domain.
+##
+##
+##
+## Domain allowed to transition
+##
+##
+##
+##
+## The role to be allowed the nbdkit domain.
+##
+##
+#
+interface(`nbdkit_run',`
+ gen_require(`
+ type nbdkit_t;
+ attribute_role nbdkit_roles;
+ ')
+
+ nbdkit_domtrans($1)
+ roleattribute $2 nbdkit_roles;
+')
+
+########################################
+##
+## Role access for nbdkit
+##
+##
+##
+## Role allowed access
+##
+##
+##
+##
+## User domain for the role
+##
+##
+#
+interface(`nbdkit_role',`
+ gen_require(`
+ type nbdkit_t;
+ attribute_role nbdkit_roles;
+ ')
+
+ roleattribute $1 nbdkit_roles;
+
+ nbdkit_domtrans($2)
+
+ ps_process_pattern($2, nbdkit_t)
+ allow $2 nbdkit_t:process { signull signal sigkill };
+')
+
+########################################
+##
+## Allow attempts to connect to nbdkit
+## with a unix stream socket.
+##
+##
+##
+## Domain to not audit.
+##
+##
+#
+interface(`nbdkit_stream_connect',`
+ gen_require(`
+ type nbdkit_t;
+ ')
+
+ allow $1 nbdkit_t:unix_stream_socket connectto;
+')
+
+########################################
+##
+## Allow nbdkit_exec_t to be an entrypoint
+## of the specified domain
+##
+##
+##
+## Domain allowed access.
+##
+##
+##
+#
+interface(`nbdkit_entrypoint',`
+ gen_require(`
+ type nbdkit_exec_t;
+ ')
+ allow $1 nbdkit_exec_t:file entrypoint;
+')
+
+# ----------------------------------------------------------------------
+# RWMJ: See:
+# https://issues.redhat.com/browse/RHEL-5174?focusedId=23387259&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#comment-23387259
+# Remove this when virt.if gets updated.
+
+########################################
+#
+# Interface compatibility blocks
+#
+# The following definitions ensure compatibility with distribution policy
+# versions that do not contain given interfaces (epel, or older Fedora
+# releases).
+# Each block tests for existence of given interface and defines it if needed.
+#
+
+########################################
+##
+## Read and write to svirt_image dirs.
+##
+##
+##
+## Domain allowed access.
+##
+##
+#
+ifndef(`virt_rw_svirt_image_dirs',`
+ interface(`virt_rw_svirt_image_dirs',`
+ gen_require(`
+ type svirt_image_t;
+ ')
+
+ allow $1 svirt_image_t:dir rw_dir_perms;
+ ')
+')
+
+########################################
+##
+## Create svirt_image sock_files.
+##
+##
+##
+## Domain allowed access.
+##
+##
+#
+ifndef(`virt_create_svirt_image_sock_files',`
+ interface(`virt_create_svirt_image_sock_files',`
+ gen_require(`
+ type svirt_image_t;
+ ')
+
+ allow $1 svirt_image_t:sock_file create_sock_file_perms;
+ ')
+')
+
+########################################
+##
+## Read and write virtlogd pipes.
+##
+##
+##
+## Domain allowed access.
+##
+##
+#
+ifndef(`virtlogd_rw_pipes',`
+ interface(`virtlogd_rw_pipes',`
+ gen_require(`
+ type virtlogd_t;
+ ')
+
+ allow $1 virtlogd_t:fifo_file rw_fifo_file_perms;
+ ')
+')
diff --git a/nbdkit.spec b/nbdkit.spec
index 1d74532..2b6e004 100644
--- a/nbdkit.spec
+++ b/nbdkit.spec
@@ -25,6 +25,11 @@
# but somehow "fixed itself", keep an eye on it.
%global have_blkio 1
+# Enable nbdkit-selinux package.
+%global with_selinux 1
+%global modulename nbdkit
+%global selinuxtype targeted
+
# Architectures where we run the complete test suite including
# the libguestfs tests.
#
@@ -56,7 +61,7 @@ ExclusiveArch: x86_64
Name: nbdkit
Version: 1.37.1
-Release: 1%{?dist}
+Release: 2%{?dist}
Summary: NBD server
License: BSD-3-Clause
@@ -82,6 +87,11 @@ Source3: copy-patches.sh
Source4: nbdkit.attr
Source5: nbdkit-find-provides
+# For nbdkit-selinux package:
+Source6: %{modulename}.te
+Source7: %{modulename}.if
+Source8: %{modulename}.fc
+
BuildRequires: make
%if 0%{patches_touch_autotools}
BuildRequires: autoconf, automake, libtool
@@ -168,6 +178,13 @@ Requires: nbdkit-server%{?_isa} = %{version}-%{release}
Requires: nbdkit-basic-plugins%{?_isa} = %{version}-%{release}
Requires: nbdkit-basic-filters%{?_isa} = %{version}-%{release}
+%if 0%{?with_selinux}
+# This ensures that the nbdkit-selinux package and all its
+# dependencies are not pulled into containers and other systems that
+# do not use SELinux.
+Requires: (%{name}-selinux if selinux-policy-%{selinuxtype})
+%endif
+
%description
NBD is a protocol for accessing block devices (hard disks and
@@ -660,6 +677,20 @@ Install this package if you want intelligent bash tab-completion
for %{name}.
+%if 0%{?with_selinux}
+%package selinux
+Summary: %{name} SELinux policy
+BuildArch: noarch
+Requires: selinux-policy-%{selinuxtype}
+Requires(post):selinux-policy-%{selinuxtype}
+BuildRequires: selinux-policy-devel
+%{?selinux_requires}
+
+%description selinux
+%{nbdkit} SELinux policy module.
+%endif
+
+
%prep
%if 0%{verify_tarball_signature}
%{gpgverify} --keyring='%{SOURCE2}' --signature='%{SOURCE1}' --data='%{SOURCE0}'
@@ -750,6 +781,18 @@ grep '^PYTHON_VERSION = 3' Makefile
%make_build
+%if 0%{?with_selinux}
+# SELinux policy (originally from selinux-policy-contrib)
+# this policy module will override the production module
+mkdir selinux
+cp -p %{SOURCE6} selinux/
+cp -p %{SOURCE7} selinux/
+cp -p %{SOURCE8} selinux/
+
+make -f %{_datadir}/selinux/devel/Makefile %{modulename}.pp
+bzip2 -9 %{modulename}.pp
+%endif
+
%install
%make_install
@@ -778,6 +821,11 @@ mkdir -p $RPM_BUILD_ROOT%{_rpmconfigdir}/fileattrs/
install -m 0644 %{SOURCE4} $RPM_BUILD_ROOT%{_rpmconfigdir}/fileattrs/
install -m 0755 %{SOURCE5} $RPM_BUILD_ROOT%{_rpmconfigdir}/
+%if 0%{?with_selinux}
+install -D -m 0644 %{modulename}.pp.bz2 $RPM_BUILD_ROOT%{_datadir}/selinux/packages/%{selinuxtype}/%{modulename}.pp.bz2
+install -D -p -m 0644 selinux/%{modulename}.if $RPM_BUILD_ROOT%{_datadir}/selinux/devel/include/distributed/%{modulename}.if
+%endif
+
%check
%ifnarch %{broken_test_arches}
@@ -833,6 +881,26 @@ export LIBGUESTFS_TRACE=1
%endif
+%if 0%{?with_selinux}
+# SELinux contexts are saved so that only affected files can be
+# relabeled after the policy module installation
+%pre selinux
+%selinux_relabel_pre -s %{selinuxtype}
+
+%post selinux
+%selinux_modules_install -s %{selinuxtype} %{_datadir}/selinux/packages/%{selinuxtype}/%{modulename}.pp.bz2
+
+%postun selinux
+if [ $1 -eq 0 ]; then
+ %selinux_modules_uninstall -s %{selinuxtype} %{modulename}
+fi
+
+%posttrans selinux
+%selinux_relabel_post -s %{selinuxtype}
+# if with_selinux
+%endif
+
+
%files
# metapackage so empty
@@ -1245,7 +1313,18 @@ export LIBGUESTFS_TRACE=1
%{_datadir}/bash-completion/completions/nbdkit
+%if 0%{?with_selinux}
+%files selinux
+%{_datadir}/selinux/packages/%{selinuxtype}/%{modulename}.pp.*
+%{_datadir}/selinux/devel/include/distributed/%{modulename}.if
+%ghost %verify(not md5 size mode mtime) %{_sharedstatedir}/selinux/%{selinuxtype}/active/modules/200/%{modulename}
+%endif
+
+
%changelog
+* Wed Nov 01 2023 Richard W.M. Jones - 1.37.1-2
+- Add experimental SELinux support (RHEL-5174)
+
* Mon Oct 23 2023 Richard W.M. Jones - 1.37.1-1
- New upstream development version 1.37.1
diff --git a/nbdkit.te b/nbdkit.te
new file mode 100644
index 0000000..dbc518e
--- /dev/null
+++ b/nbdkit.te
@@ -0,0 +1,100 @@
+policy_module(nbdkit, 1.0.0)
+
+########################################
+#
+# Declarations
+#
+
+gen_require(`
+ type unconfined_t;
+')
+
+type nbdkit_t;
+type nbdkit_exec_t;
+application_domain(nbdkit_t, nbdkit_exec_t)
+mcs_constrained(nbdkit_t)
+role system_r types nbdkit_t;
+
+type nbdkit_home_t;
+userdom_user_home_content(nbdkit_home_t)
+
+type nbdkit_tmp_t;
+files_tmp_file(nbdkit_tmp_t)
+
+type nbdkit_unit_file_t;
+systemd_unit_file(nbdkit_unit_file_t)
+
+permissive nbdkit_t;
+
+########################################
+#
+# nbdkit local policy
+#
+allow nbdkit_t self:capability { setgid setuid };
+allow nbdkit_t self:fifo_file rw_fifo_file_perms;
+allow nbdkit_t self:netlink_route_socket rw_netlink_socket_perms;
+allow nbdkit_t self:process { fork setsockcreate signal_perms };
+allow nbdkit_t self:tcp_socket create_stream_socket_perms;
+allow nbdkit_t self:udp_socket create_socket_perms;
+
+manage_dirs_pattern(nbdkit_t, nbdkit_tmp_t, nbdkit_tmp_t)
+manage_files_pattern(nbdkit_t, nbdkit_tmp_t, nbdkit_tmp_t)
+userdom_user_tmp_filetrans(nbdkit_t, nbdkit_tmp_t, { dir file })
+
+manage_dirs_pattern(nbdkit_t, nbdkit_home_t, nbdkit_home_t)
+manage_files_pattern(nbdkit_t, nbdkit_home_t, nbdkit_home_t)
+userdom_user_home_dir_filetrans(nbdkit_t, nbdkit_home_t, { dir file })
+
+corenet_tcp_connect_http_port(nbdkit_t)
+corenet_tcp_connect_ssh_port(nbdkit_t)
+corenet_tcp_connect_tftp_port(nbdkit_t)
+corenet_tcp_bind_generic_port(nbdkit_t)
+corenet_tcp_bind_generic_node(nbdkit_t)
+
+domain_use_interactive_fds(nbdkit_t)
+
+files_read_etc_files(nbdkit_t)
+
+init_abstract_socket_activation(nbdkit_t)
+init_ioctl_stream_sockets(nbdkit_t)
+init_rw_stream_sockets(nbdkit_t)
+
+optional_policy(`
+ auth_use_nsswitch(nbdkit_t)
+')
+
+optional_policy(`
+ logging_send_syslog_msg(nbdkit_t)
+')
+
+optional_policy(`
+ miscfiles_read_localization(nbdkit_t)
+ miscfiles_read_generic_certs(nbdkit_t)
+')
+
+optional_policy(`
+ sysnet_dns_name_resolve(nbdkit_t)
+ sysnet_read_config(nbdkit_t)
+')
+
+optional_policy(`
+ userdom_read_user_home_content_files(nbdkit_t)
+ userdom_use_inherited_user_ptys(nbdkit_t)
+')
+
+optional_policy(`
+ virt_create_svirt_image_sock_files(nbdkit_t)
+ virt_read_qemu_pid_files(nbdkit_t)
+ virtlogd_rw_pipes(nbdkit_t)
+ virt_rw_svirt_image(nbdkit_t)
+ virt_rw_svirt_image_dirs(nbdkit_t)
+ virt_search_lib(nbdkit_t)
+ virt_stream_connect_svirt(nbdkit_t)
+')
+
+
+# FIXME: It would be nice to allow libvirt to transition nbdkit_exec_t to
+# nbdkit_t when libvirtd was started manually from the commandline (i.e. in
+# unconfined_t), but we don't want this transition to happen automatically
+# when starting directly from the shell. I'm not sure how to achieve this...
+#nbdkit_domtrans(unconfined_t, nbdkit_exec_t, nbdkit_t)