diff mbox series

[kvmtool] Fix 9pfs open device file security flaw

Message ID tencent_3FBF289C57BD1C8C31601110D5726C3E380A@qq.com (mailing list archive)
State New, archived
Headers show
Series [kvmtool] Fix 9pfs open device file security flaw | expand

Commit Message

Mr-Mr-key Feb. 25, 2024, 4:31 p.m. UTC
---
Hi,

Our team found that a public QEMU's 9pfs security issue[1] also exists in upstream kvmtool's 9pfs device. A privileged guest user can create and access the special device file(e.g., block files) in the shared folder, allowing the malicious user to access the host device and acheive privileged escalation. And I have sent the reproduction steps to Will.
[1] https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-2861

Root cause && fix suggestions:
The virtio_p9_open function code on the 9p.c only checks file directory attributes, but does not check special files.
Special device files can be filtered on the device through the S_IFREG and S_IFDIR flag bits. A possible patch is as follows, and I have verified that it does make a difference.

 ...n-kernel-irqchip-before-creating-PIT.patch | 45 +++++++++++++++++++
 virtio/9p.c                                   | 15 ++++++-
 2 files changed, 59 insertions(+), 1 deletion(-)
 create mode 100644 0001-x86-Enable-in-kernel-irqchip-before-creating-PIT.patch

Comments

Will Deacon Feb. 27, 2024, 9:54 a.m. UTC | #1
Hi,

On Mon, Feb 26, 2024 at 12:31:55AM +0800, Mr-Mr-key wrote:
> Our team found that a public QEMU's 9pfs security issue[1] also exists in
> upstream kvmtool's 9pfs device. A privileged guest user can create and
> access the special device file(e.g., block files) in the shared folder,
> allowing the malicious user to access the host device and acheive
> privileged escalation. And I have sent the reproduction steps to Will.
> [1] https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-2861
> 
> Root cause && fix suggestions:
> The virtio_p9_open function code on the 9p.c only checks file directory attributes, but does not check special files.
> Special device files can be filtered on the device through the S_IFREG and
> S_IFDIR flag bits. A possible patch is as follows, and I have verified
> that it does make a difference.

Missing Signed-off-by line.

>  ...n-kernel-irqchip-before-creating-PIT.patch | 45 +++++++++++++++++++
>  virtio/9p.c                                   | 15 ++++++-
>  2 files changed, 59 insertions(+), 1 deletion(-)
>  create mode 100644 0001-x86-Enable-in-kernel-irqchip-before-creating-PIT.patch

(aside: I think you've accidentally included another patch here)

> diff --git a/virtio/9p.c b/virtio/9p.c
> index 2fa6f28..902da90 100644
> --- a/virtio/9p.c
> +++ b/virtio/9p.c
> @@ -221,6 +221,15 @@ static bool is_dir(struct p9_fid *fid)
>  	return S_ISDIR(st.st_mode);
>  }
>  
> +static bool is_reg(struct p9_fid *fid)
> +{
> +	struct stat st;
> +
> +	stat(fid->abs_path, &st);
> +
> +	return S_ISREG(st.st_mode);
> +}
> +
>  /* path is always absolute */
>  static bool path_is_illegal(const char *path)
>  {
> @@ -290,7 +299,11 @@ static void virtio_p9_open(struct p9_dev *p9dev,
>  		goto err_out;
>  
>  	stat2qid(&st, &qid);
> -
> +	
> +	if (!is_dir(new_fid) && !is_reg(new_fid)){
> +		goto err_out;
> +	}

We already check is_dir() immediately below, so I think you can rewrite
this as:

  if (is_dir(new_fid)) {
	...
  } else if (is_reg(new_fid)) {
	...
  } else {
	goto err_out;
  }

I was also wondering whether we care about symlinks, but I couldn't get
S_ISLNK to do anything useful in my local testing as I think stat() is
always following them. So that should mean that we're ok.

Will
diff mbox series

Patch

diff --git a/0001-x86-Enable-in-kernel-irqchip-before-creating-PIT.patch b/0001-x86-Enable-in-kernel-irqchip-before-creating-PIT.patch
new file mode 100644
index 0000000..54005b4
--- /dev/null
+++ b/0001-x86-Enable-in-kernel-irqchip-before-creating-PIT.patch
@@ -0,0 +1,45 @@ 
+From e73a6b29f1ebf30c44f59a0a228ebed70aa76586 Mon Sep 17 00:00:00 2001
+From: Tengfei Yu <moehanabichan@gmail.com>
+Date: Mon, 29 Jan 2024 20:33:10 +0800
+Subject: [PATCH] x86: Enable in-kernel irqchip before creating PIT
+
+As the kvm api(https://docs.kernel.org/virt/kvm/api.html) reads,
+KVM_CREATE_PIT2 call is only valid after enabling in-kernel irqchip
+support via KVM_CREATE_IRQCHIP.
+
+Signed-off-by: Tengfei Yu <moehanabichan@gmail.com>
+Link: https://lore.kernel.org/r/20240129123310.28118-1-moehanabichan@gmail.com
+Signed-off-by: Will Deacon <will@kernel.org>
+---
+ x86/kvm.c | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/x86/kvm.c b/x86/kvm.c
+index 328fa75..71ebb1e 100644
+--- a/x86/kvm.c
++++ b/x86/kvm.c
+@@ -150,10 +150,6 @@ void kvm__arch_init(struct kvm *kvm)
+ 	if (ret < 0)
+ 		die_perror("KVM_SET_TSS_ADDR ioctl");
+ 
+-	ret = ioctl(kvm->vm_fd, KVM_CREATE_PIT2, &pit_config);
+-	if (ret < 0)
+-		die_perror("KVM_CREATE_PIT2 ioctl");
+-
+ 	if (ram_size < KVM_32BIT_GAP_START) {
+ 		kvm->ram_size = ram_size;
+ 		kvm->ram_start = mmap_anon_or_hugetlbfs(kvm, hugetlbfs_path, ram_size);
+@@ -175,6 +171,10 @@ void kvm__arch_init(struct kvm *kvm)
+ 	ret = ioctl(kvm->vm_fd, KVM_CREATE_IRQCHIP);
+ 	if (ret < 0)
+ 		die_perror("KVM_CREATE_IRQCHIP ioctl");
++
++	ret = ioctl(kvm->vm_fd, KVM_CREATE_PIT2, &pit_config);
++	if (ret < 0)
++		die_perror("KVM_CREATE_PIT2 ioctl");
+ }
+ 
+ void kvm__arch_delete_ram(struct kvm *kvm)
+-- 
+2.25.1
+
diff --git a/virtio/9p.c b/virtio/9p.c
index 2fa6f28..902da90 100644
--- a/virtio/9p.c
+++ b/virtio/9p.c
@@ -221,6 +221,15 @@  static bool is_dir(struct p9_fid *fid)
 	return S_ISDIR(st.st_mode);
 }
 
+static bool is_reg(struct p9_fid *fid)
+{
+	struct stat st;
+
+	stat(fid->abs_path, &st);
+
+	return S_ISREG(st.st_mode);
+}
+
 /* path is always absolute */
 static bool path_is_illegal(const char *path)
 {
@@ -290,7 +299,11 @@  static void virtio_p9_open(struct p9_dev *p9dev,
 		goto err_out;
 
 	stat2qid(&st, &qid);
-
+	
+	if (!is_dir(new_fid) && !is_reg(new_fid)){
+		goto err_out;
+	}
+	
 	if (is_dir(new_fid)) {
 		new_fid->dir = opendir(new_fid->abs_path);
 		if (!new_fid->dir)