Commit a0124352 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull xen fixes from Juergen Gross:
 "Restrict the xen privcmd driver in unprivileged domU to only allow
  hypercalls to target domain when using secure boot"

* tag 'xsa482-7.0-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip:
  xen/privcmd: add boot control for restricted usage in domU
  xen/privcmd: restrict usage in unprivileged domU
parents c3692998 1613462b
Loading
Loading
Loading
Loading
+70 −3
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@
#include <linux/eventfd.h>
#include <linux/file.h>
#include <linux/kernel.h>
#include <linux/kstrtox.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/poll.h>
@@ -30,7 +31,10 @@
#include <linux/seq_file.h>
#include <linux/miscdevice.h>
#include <linux/moduleparam.h>
#include <linux/notifier.h>
#include <linux/security.h>
#include <linux/virtio_mmio.h>
#include <linux/wait.h>

#include <asm/xen/hypervisor.h>
#include <asm/xen/hypercall.h>
@@ -46,6 +50,7 @@
#include <xen/page.h>
#include <xen/xen-ops.h>
#include <xen/balloon.h>
#include <xen/xenbus.h>
#ifdef CONFIG_XEN_ACPI
#include <xen/acpi.h>
#endif
@@ -68,10 +73,20 @@ module_param_named(dm_op_buf_max_size, privcmd_dm_op_buf_max_size, uint,
MODULE_PARM_DESC(dm_op_buf_max_size,
		 "Maximum size of a dm_op hypercall buffer");

static bool unrestricted;
module_param(unrestricted, bool, 0);
MODULE_PARM_DESC(unrestricted,
	"Don't restrict hypercalls to target domain if running in a domU");

struct privcmd_data {
	domid_t domid;
};

/* DOMID_INVALID implies no restriction */
static domid_t target_domain = DOMID_INVALID;
static bool restrict_wait;
static DECLARE_WAIT_QUEUE_HEAD(restrict_wait_wq);

static int privcmd_vma_range_is_mapped(
               struct vm_area_struct *vma,
               unsigned long addr,
@@ -1563,13 +1578,16 @@ static long privcmd_ioctl(struct file *file,

static int privcmd_open(struct inode *ino, struct file *file)
{
	struct privcmd_data *data = kzalloc_obj(*data);
	struct privcmd_data *data;

	if (wait_event_interruptible(restrict_wait_wq, !restrict_wait) < 0)
		return -EINTR;

	data = kzalloc_obj(*data);
	if (!data)
		return -ENOMEM;

	/* DOMID_INVALID implies no restriction */
	data->domid = DOMID_INVALID;
	data->domid = target_domain;

	file->private_data = data;
	return 0;
@@ -1662,6 +1680,52 @@ static struct miscdevice privcmd_dev = {
	.fops = &xen_privcmd_fops,
};

static int init_restrict(struct notifier_block *notifier,
			 unsigned long event,
			 void *data)
{
	char *target;
	unsigned int domid;

	/* Default to an guaranteed unused domain-id. */
	target_domain = DOMID_IDLE;

	target = xenbus_read(XBT_NIL, "target", "", NULL);
	if (IS_ERR(target) || kstrtouint(target, 10, &domid)) {
		pr_err("No target domain found, blocking all hypercalls\n");
		goto out;
	}

	target_domain = domid;

 out:
	if (!IS_ERR(target))
		kfree(target);

	restrict_wait = false;
	wake_up_all(&restrict_wait_wq);

	return NOTIFY_DONE;
}

static struct notifier_block xenstore_notifier = {
	.notifier_call = init_restrict,
};

static void __init restrict_driver(void)
{
	if (unrestricted) {
		if (security_locked_down(LOCKDOWN_XEN_USER_ACTIONS))
			pr_warn("Kernel is locked down, parameter \"unrestricted\" ignored\n");
		else
			return;
	}

	restrict_wait = true;

	register_xenstore_notifier(&xenstore_notifier);
}

static int __init privcmd_init(void)
{
	int err;
@@ -1669,6 +1733,9 @@ static int __init privcmd_init(void)
	if (!xen_domain())
		return -ENODEV;

	if (!xen_initial_domain())
		restrict_driver();

	err = misc_register(&privcmd_dev);
	if (err != 0) {
		pr_err("Could not register Xen privcmd device\n");
+1 −0
Original line number Diff line number Diff line
@@ -145,6 +145,7 @@ enum lockdown_reason {
	LOCKDOWN_BPF_WRITE_USER,
	LOCKDOWN_DBG_WRITE_KERNEL,
	LOCKDOWN_RTAS_ERROR_INJECTION,
	LOCKDOWN_XEN_USER_ACTIONS,
	LOCKDOWN_INTEGRITY_MAX,
	LOCKDOWN_KCORE,
	LOCKDOWN_KPROBES,
+1 −0
Original line number Diff line number Diff line
@@ -61,6 +61,7 @@ const char *const lockdown_reasons[LOCKDOWN_CONFIDENTIALITY_MAX + 1] = {
	[LOCKDOWN_BPF_WRITE_USER] = "use of bpf to write user RAM",
	[LOCKDOWN_DBG_WRITE_KERNEL] = "use of kgdb/kdb to write kernel RAM",
	[LOCKDOWN_RTAS_ERROR_INJECTION] = "RTAS error injection",
	[LOCKDOWN_XEN_USER_ACTIONS] = "Xen guest user action",
	[LOCKDOWN_INTEGRITY_MAX] = "integrity",
	[LOCKDOWN_KCORE] = "/proc/kcore access",
	[LOCKDOWN_KPROBES] = "use of kprobes",