diff --git a/policy/modules/contrib/nbdkit.fc b/policy/modules/contrib/nbdkit.fc
new file mode 100644
index 0000000000..4877736868
--- /dev/null
+++ b/policy/modules/contrib/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/policy/modules/contrib/nbdkit.if b/policy/modules/contrib/nbdkit.if
new file mode 100644
index 0000000000..cdfd5f006c
--- /dev/null
+++ b/policy/modules/contrib/nbdkit.if
@@ -0,0 +1,134 @@
+[root@ci-vm-10-0-136-52 policy]# cat nbdkit.if
+
+## 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;
+')
diff --git a/policy/modules/contrib/nbdkit.te b/policy/modules/contrib/nbdkit.te
new file mode 100644
index 0000000000..dbc518e1a3
--- /dev/null
+++ b/policy/modules/contrib/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)
diff --git a/policy/modules/contrib/virt.if b/policy/modules/contrib/virt.if
index f0f042845c..9bde1c6c6a 100644
--- a/policy/modules/contrib/virt.if
+++ b/policy/modules/contrib/virt.if
@@ -1740,6 +1740,42 @@ interface(`virt_rw_svirt_image',`
allow $1 svirt_image_t:file rw_file_perms;
')
+########################################
+##
+## Read and write to svirt_image dirs.
+##
+##
+##
+## Domain allowed access.
+##
+##
+#
+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.
+##
+##
+#
+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 to svirt_image devices.
@@ -2080,3 +2116,21 @@ interface(`virt_manage_qemu_pid_sock_files',`
files_search_pids($1)
manage_sock_files_pattern($1, qemu_var_run_t, qemu_var_run_t)
')
+
+########################################
+##
+## Read and write virtlogd pipes.
+##
+##
+##
+## Domain allowed access.
+##
+##
+#
+interface(`virtlogd_rw_pipes',`
+ gen_require(`
+ type virtlogd_t;
+ ')
+
+ allow $1 virtlogd_t:fifo_file rw_fifo_file_perms;
+')
diff --git a/policy/modules/contrib/virt.te b/policy/modules/contrib/virt.te
index af18689495..a6d864a3ab 100644
--- a/policy/modules/contrib/virt.te
+++ b/policy/modules/contrib/virt.te
@@ -484,6 +484,10 @@ storage_rw_inherited_fixed_disk_dev(svirt_t)
userdom_read_all_users_state(svirt_t)
+optional_policy(`
+ nbdkit_stream_connect(svirt_t)
+')
+
#######################################
#
# svirt_prot_exec local policy
@@ -504,6 +508,10 @@ ps_process_pattern(svirt_tcg_t, virtd_t)
virt_dontaudit_read_state(svirt_tcg_t)
+optional_policy(`
+ nbdkit_stream_connect(svirt_tcg_t)
+')
+
########################################
#
# virtd local policy
@@ -845,6 +853,11 @@ optional_policy(`
mount_signal(virtd_t)
')
+optional_policy(`
+ nbdkit_domtrans(virtd_t)
+ nbdkit_stream_connect(virtd_t)
+')
+
optional_policy(`
numad_domtrans(virtd_t)
numad_dbus_chat(virtd_t)
diff --git a/policy/modules/roles/unconfineduser.te b/policy/modules/roles/unconfineduser.te
index b77f83d949..05b5b7b7c2 100644
--- a/policy/modules/roles/unconfineduser.te
+++ b/policy/modules/roles/unconfineduser.te
@@ -362,6 +362,10 @@ optional_policy(`
chronyd_run_chronyc(unconfined_t, unconfined_r)
')
+optional_policy(`
+ nbdkit_entrypoint(unconfined_t)
+')
+
optional_policy(`
oddjob_run_mkhomedir(unconfined_t, unconfined_r)
oddjob_run(unconfined_t, unconfined_r)