qemu: add SELinux hook for loading virtual hard disk
Subsystems (2)
RFC PATCH 1/1 qemu: add SELinux hook for loading virtual hard disk
Add infrastructure to qemu to make it an SELinux object manager. Currently, the AVC is not being used, since only one permission is currently being checked.
kvm-userspace/qemu/vl.c +14 -0
@@ -92,6 +92,8 @@#include "qemu-kvm.h" #endif +#include "selinux.h" +#define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup"#ifdef __sun__#define SMBD_COMMAND "/usr/sfw/sbin/smbd"
@@ -7522,6 +7524,14 @@ int main(int argc, char **argv) }#endif +#ifdef CONFIG_VM_SECURITY +/* Initialize SELinux */ +if (selinux_init ()) { +fprintf (stderr,"Could not initialize SELinux\n" ); +exit (1 ); + } +#endif +/* we always create the cdrom drive, even if no disk is there */ bdrv_init ();if (cdrom_index >=0 ) {
@@ -7537,6 +7547,14 @@ int main(int argc, char **argv)snprintf (buf,sizeof (buf),"hd%c" , i +'a' ); bs_table[i] =bdrv_new (buf); } + +#ifdef CONFIG_VM_SECURITY +if (selinux_vm_use_block_device (hd_filename[i])) { + fprintf(stderr, "qemu: SELinux denied access to hard disk
image '%s'\n", hd_filename[i]);
+ exit(1);
+ }
+#endif
+
if (bdrv_open(bs_table[i], hd_filename[i], snapshot ?BDRV_O_SNAPSHOT : 0) < 0) {
fprintf(stderr, "qemu: could not open hard disk image
'%s'\n",
hd_filename[i]);
kvm-userspace/qemu/configure +10 -1
@@ -90,6 +90,7 @@ bsd="no" linux="no" kqemu="no" kvm="no" +vm_security="no" profiler="no" kernel_path="" cocoa="no"
@@ -238,6 +239,8 @@ for opt do ;; --enable-kvm) kvm="yes" ;; + --enable-vm-security) vm_security="yes" + ;; --enable-profiler) profiler="yes" ;; --kernel-path=*) kernel_path="$optarg"
@@ -287,6 +290,7 @@ echo "kqemu kernel acceleration support: echo " --disable-kqemu disable kqemu support" echo " --kernel-path=PATH set the kernel path (configure probes it)" echo " --enable-kvm enable kernel virtual machine support" +echo " --enable-vm-security enable SELinux enforcement hooks" echo "" echo "Advanced options (experts only):" echo " --source-path=PATH path of source code [$source_path]"
@@ -868,13 +872,18 @@ bflt="no" interp_prefix1=`echo "$interp_prefix" | sed "s/%M/$target_cpu/g"` echo "#define CONFIG_QEMU_PREFIX \"$interp_prefix1\"" >> $config_h +if test $vm_security = "yes" ; then + echo "#define CONFIG_VM_SECURITY 1" >> $config_h + echo "CONFIG_VM_SECURITY=yes" >> $config_mak +fi + configure_kvm() { if test $kvm = "yes" -a "$target_softmmu" = "yes" -a \ \( "$cpu" = "i386" -o "$cpu" = "x86_64" \); then echo "#define USE_KVM 1" >> $config_h echo "CONFIG_KVM_KERNEL_INC=$kernel_path/include" >> $config_mak fi -} + } if test "$target_cpu" = "i386" ; then echo "TARGET_ARCH=i386" >> $config_mak
kvm-userspace/configure +1 -0
@@ -5,6 +5,7 @@ kerneldir=/lib/modules/$(uname -r)/build want_module=1 qemu_cc=$(ls /usr/bin/gcc3* /usr/bin/gcc-3* 2>/dev/null | tail -n1) disable_gcc_check= +enable_vm_security= usage() { cat <<-EOF
@@ -18,6 +19,7 @@ usage() { --qemu-cc="$qemu_cc" compiler for qemu (needs gcc3.x)
($qemu_cc)
--disable-gcc-check don't insist on gcc-3.x
- this will break running without kvm
+ --enable-vm-security enable SELinux security enforcement
EOF
exit 1
}
@@ -53,6 +55,9 @@ while [[ "$1" = -* ]]; do
--disable-gcc-check)
disable_gcc_check=1
;;
+ --enable-vm-security)
+ enable_vm_security=1
+ ;;
--help)
usage
;;
@@ -87,6 +92,7 @@ target_cpu() {
--enable-kvm --kernel-path="$libkvm_kerneldir" \
--enable-alsa \
${disable_gcc_check:+"--disable-gcc-check"} \
+ ${enable_vm_security:+"--enable-vm-security"}\
--prefix="$prefix")
kvm-userspace/qemu/Makefile.target +0 -0
@@ -232,7 +232,7 @@ OBJS+= libqemu.a # cpu emulator library LIBOBJS=exec.o kqemu.o qemu-kvm.o translate-op.o translate-all.o
cpu-exec.o\
- translate.o op.o
+ translate.o op.o selinux.o
ifdef CONFIG_SOFTFLOAT
LIBOBJS+=fpu/softfloat.o
else
@@ -364,6 +364,9 @@ CFLAGS += -I $(CONFIG_KVM_KERNEL_INC)
LIBS += -lkvm
DEPLIBS += ../user/libkvm.a
endif
+ifdef CONFIG_VM_SECURITY
+LIBS += -lselinux
+endif
# SCSI layer
VL_OBJS+= scsi-disk.o cdrom.o lsi53c895a.o
kvm-userspace/qemu/selinux.h new file +18 -0
@@ -0,0 +1,24 @@ +#ifndef _QEMU_SELINUX_H_ +#define _QEMU_SELINUX_H_ + +/* +* Initialize qemu's SELinux subsystem. +* +* Returns 0 on success, non-zero on error. +* This function will only return non-zero when SELinux is +* enabled in the running kernel and is in enforcing mode. +*/ +int selinux_init (void ); + +/* +* Check the SELinux policy as to whether the current process is allowed +* to load a virtual disk into a virtual machine. +* This function should only be called after calling selinux_init. +* +* Returns 0 if the operation is allowed, non-zero if the operation is
denied.
+ * This function will only return non-zero if SELinux is enabled
+ * in the running kernel and is in enforcing mode.
+ */
+int selinux_vm_use_block_device(const char *hd_filename); +
+#endif
kvm-userspace/qemu/selinux.c new file +39 -0
@@ -0,0 +1,114 @@ +#include <stdlib.h> +#include <stdio.h> +#include <selinux/flask.h> +#include <selinux/av_permissions.h> +#include <selinux/selinux.h> + +#include "selinux.h" + +static int qemu_selinux_enabled =0 ; + +/* +* Initialize qemu's SELinux subsystem. +* +* Returns 0 on success, non-zero on error. +* This function will return non-zero only when SELinux is +* enabled in the running kernel and is in enforcing mode. +*/ +int selinux_init (void ) +{ +int retval =-1 ; +struct security_class_mapping map[] = { + {"vm" , + {"entrypoint" ,NULL }}, + {NULL } + }; + +if (qemu_selinux_enabled) { + retval =0 ; + goto out; + } + + retval =is_selinux_enabled (); +if (!retval) + goto out; + +/* Create userspace object class and permission mappings */ + retval =selinux_set_mapping (map); +if (retval <0 ) { + printf("SELinux: failed to set up security class
mapping\n");
+ goto out;
+ }
+
+ qemu_selinux_enabled = 1;
+out:
+ if (retval != 0 && !security_getenforce())
+ retval = 0;
+ return retval;
+}
+
+/*
+ * Check the SELinux policy as to whether the current process is
+ * allowed to load a virtual disk into a virtual machine.
+ * This function should only be called after calling selinux_init.
+ *
+ * Returns 0 if the operation is allowed, non-zero if the operation is denied.
+ * This function will only return non-zero if SELinux is enabled
+ * in the running kernel and is in enforcing mode.
+ */
+int selinux_vm_use_block_device(const char *hd_filename)
+{
+ security_context_t scon; + security_context_t tcon; + security_class_t vm_class; + access_vector_t vm_perms; + struct av_decision avd; + int retval = -1;
+
+ retval = is_selinux_enabled();
+ if (!retval) {
+ retval = 0;
+ goto out;
+ }
+
+ vm_class = string_to_security_class("vm");
+ if (!vm_class) {
+ retval = -1;
+ goto out;
+ }
+
+ vm_perms = string_to_av_perm(vm_class, "entrypoint");
+ if (!vm_perms) {
+ retval = -1;
+ goto out;
+ }
+
+ /* The context of the VM is the context of the current process */
+ retval = getcon(&scon);
+ if (retval)
+ goto out;
+
+ /* Get the context of the virtual disk */
+ retval = getfilecon(hd_filename, &tcon);
+ if (retval < 0) {+ freecon(scon);
+ goto out;
+ }
+
+ retval = security_compute_av(scon, tcon, vm_class,
+ vm_perms, &avd);
+ freecon(scon);
+ freecon(tcon);
+ if (!retval && ((vm_perms & avd.allowed) == vm_perms)) {
+ goto out;
+ } else {
+ /* Access is denied */
+ retval = 1;
+ goto out;+ }
+
+out:
+ if (retval != 0 && !security_getenforce())
+ retval = 0;
+ return retval;
+}
-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
RFC PATCH 1/1 qemu: add SELinux hook for loading virtual hard disk
Add infrastructure to qemu to make it an SELinux object manager. Currently, the AVC is not being used, since only one permission is currently being checked.
kvm-userspace/qemu/vl.c +14 -0
@@ -92,6 +92,8 @@#include "qemu-kvm.h" #endif +#include "selinux.h" +#define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup"#ifdef __sun__#define SMBD_COMMAND "/usr/sfw/sbin/smbd"
@@ -7522,6 +7524,14 @@ int main(int argc, char **argv) }#endif +#ifdef CONFIG_VM_SECURITY +/* Initialize SELinux */ +if (selinux_init ()) { +fprintf (stderr,"Could not initialize SELinux\n" ); +exit (1 ); + } +#endif +/* we always create the cdrom drive, even if no disk is there */ bdrv_init ();if (cdrom_index >=0 ) {
@@ -7537,6 +7547,14 @@ int main(int argc, char **argv)snprintf (buf,sizeof (buf),"hd%c" , i +'a' ); bs_table[i] =bdrv_new (buf); } + +#ifdef CONFIG_VM_SECURITY +if (selinux_vm_use_block_device (hd_filename[i])) { + fprintf(stderr, "qemu: SELinux denied access to hard disk
image '%s'\n", hd_filename[i]);
+ exit(1);
+ }
+#endif
+
if (bdrv_open(bs_table[i], hd_filename[i], snapshot ?BDRV_O_SNAPSHOT : 0) < 0) {
fprintf(stderr, "qemu: could not open hard disk image
'%s'\n",
hd_filename[i]);
kvm-userspace/qemu/configure +10 -1
@@ -90,6 +90,7 @@ bsd="no" linux="no" kqemu="no" kvm="no" +vm_security="no" profiler="no" kernel_path="" cocoa="no"
@@ -238,6 +239,8 @@ for opt do ;; --enable-kvm) kvm="yes" ;; + --enable-vm-security) vm_security="yes" + ;; --enable-profiler) profiler="yes" ;; --kernel-path=*) kernel_path="$optarg"
@@ -287,6 +290,7 @@ echo "kqemu kernel acceleration support: echo " --disable-kqemu disable kqemu support" echo " --kernel-path=PATH set the kernel path (configure probes it)" echo " --enable-kvm enable kernel virtual machine support" +echo " --enable-vm-security enable SELinux enforcement hooks" echo "" echo "Advanced options (experts only):" echo " --source-path=PATH path of source code [$source_path]"
@@ -868,13 +872,18 @@ bflt="no" interp_prefix1=`echo "$interp_prefix" | sed "s/%M/$target_cpu/g"` echo "#define CONFIG_QEMU_PREFIX \"$interp_prefix1\"" >> $config_h +if test $vm_security = "yes" ; then + echo "#define CONFIG_VM_SECURITY 1" >> $config_h + echo "CONFIG_VM_SECURITY=yes" >> $config_mak +fi + configure_kvm() { if test $kvm = "yes" -a "$target_softmmu" = "yes" -a \ \( "$cpu" = "i386" -o "$cpu" = "x86_64" \); then echo "#define USE_KVM 1" >> $config_h echo "CONFIG_KVM_KERNEL_INC=$kernel_path/include" >> $config_mak fi -} + } if test "$target_cpu" = "i386" ; then echo "TARGET_ARCH=i386" >> $config_mak
kvm-userspace/configure +1 -0
@@ -5,6 +5,7 @@ kerneldir=/lib/modules/$(uname -r)/build want_module=1 qemu_cc=$(ls /usr/bin/gcc3* /usr/bin/gcc-3* 2>/dev/null | tail -n1) disable_gcc_check= +enable_vm_security= usage() { cat <<-EOF
@@ -18,6 +19,7 @@ usage() { --qemu-cc="$qemu_cc" compiler for qemu (needs gcc3.x)
($qemu_cc)
--disable-gcc-check don't insist on gcc-3.x
- this will break running without kvm
+ --enable-vm-security enable SELinux security enforcement
EOF
exit 1
}
@@ -53,6 +55,9 @@ while [[ "$1" = -* ]]; do
--disable-gcc-check)
disable_gcc_check=1
;;
+ --enable-vm-security)
+ enable_vm_security=1
+ ;;
--help)
usage
;;
@@ -87,6 +92,7 @@ target_cpu() {
--enable-kvm --kernel-path="$libkvm_kerneldir" \
--enable-alsa \
${disable_gcc_check:+"--disable-gcc-check"} \
+ ${enable_vm_security:+"--enable-vm-security"}\
--prefix="$prefix")
kvm-userspace/qemu/Makefile.target +0 -0
@@ -232,7 +232,7 @@ OBJS+= libqemu.a # cpu emulator library LIBOBJS=exec.o kqemu.o qemu-kvm.o translate-op.o translate-all.o
cpu-exec.o\
- translate.o op.o
+ translate.o op.o selinux.o
ifdef CONFIG_SOFTFLOAT
LIBOBJS+=fpu/softfloat.o
else
@@ -364,6 +364,9 @@ CFLAGS += -I $(CONFIG_KVM_KERNEL_INC)
LIBS += -lkvm
DEPLIBS += ../user/libkvm.a
endif
+ifdef CONFIG_VM_SECURITY
+LIBS += -lselinux
+endif
# SCSI layer
VL_OBJS+= scsi-disk.o cdrom.o lsi53c895a.o
kvm-userspace/qemu/selinux.h new file +18 -0
@@ -0,0 +1,24 @@ +#ifndef _QEMU_SELINUX_H_ +#define _QEMU_SELINUX_H_ + +/* +* Initialize qemu's SELinux subsystem. +* +* Returns 0 on success, non-zero on error. +* This function will only return non-zero when SELinux is +* enabled in the running kernel and is in enforcing mode. +*/ +int selinux_init (void ); + +/* +* Check the SELinux policy as to whether the current process is allowed +* to load a virtual disk into a virtual machine. +* This function should only be called after calling selinux_init. +* +* Returns 0 if the operation is allowed, non-zero if the operation is
denied.
+ * This function will only return non-zero if SELinux is enabled
+ * in the running kernel and is in enforcing mode.
+ */
+int selinux_vm_use_block_device(const char *hd_filename); +
+#endif
kvm-userspace/qemu/selinux.c new file +39 -0
@@ -0,0 +1,114 @@ +#include <stdlib.h> +#include <stdio.h> +#include <selinux/flask.h> +#include <selinux/av_permissions.h> +#include <selinux/selinux.h> + +#include "selinux.h" + +static int qemu_selinux_enabled =0 ; + +/* +* Initialize qemu's SELinux subsystem. +* +* Returns 0 on success, non-zero on error. +* This function will return non-zero only when SELinux is +* enabled in the running kernel and is in enforcing mode. +*/ +int selinux_init (void ) +{ +int retval =-1 ; +struct security_class_mapping map[] = { + {"vm" , + {"entrypoint" ,NULL }}, + {NULL } + }; + +if (qemu_selinux_enabled) { + retval =0 ; + goto out; + } + + retval =is_selinux_enabled (); +if (!retval) + goto out; + +/* Create userspace object class and permission mappings */ + retval =selinux_set_mapping (map); +if (retval <0 ) { + printf("SELinux: failed to set up security class
mapping\n");
+ goto out;
+ }
+
+ qemu_selinux_enabled = 1;
+out:
+ if (retval != 0 && !security_getenforce())
+ retval = 0;
+ return retval;
+}
+
+/*
+ * Check the SELinux policy as to whether the current process is
+ * allowed to load a virtual disk into a virtual machine.
+ * This function should only be called after calling selinux_init.
+ *
+ * Returns 0 if the operation is allowed, non-zero if the operation is denied.
+ * This function will only return non-zero if SELinux is enabled
+ * in the running kernel and is in enforcing mode.
+ */
+int selinux_vm_use_block_device(const char *hd_filename)
+{
+ security_context_t scon; + security_context_t tcon; + security_class_t vm_class; + access_vector_t vm_perms; + struct av_decision avd; + int retval = -1;
+
+ retval = is_selinux_enabled();
+ if (!retval) {
+ retval = 0;
+ goto out;
+ }
+
+ vm_class = string_to_security_class("vm");
+ if (!vm_class) {
+ retval = -1;
+ goto out;
+ }
+
+ vm_perms = string_to_av_perm(vm_class, "entrypoint");
+ if (!vm_perms) {
+ retval = -1;
+ goto out;
+ }
+
+ /* The context of the VM is the context of the current process */
+ retval = getcon(&scon);
+ if (retval)
+ goto out;
+
+ /* Get the context of the virtual disk */
+ retval = getfilecon(hd_filename, &tcon);
+ if (retval < 0) {+ freecon(scon);
+ goto out;
+ }
+
+ retval = security_compute_av(scon, tcon, vm_class,
+ vm_perms, &avd);
+ freecon(scon);
+ freecon(tcon);
+ if (!retval && ((vm_perms & avd.allowed) == vm_perms)) {
+ goto out;
+ } else {
+ /* Access is denied */
+ retval = 1;
+ goto out;+ }
+
+out:
+ if (retval != 0 && !security_getenforce())
+ retval = 0;
+ return retval;
+}