Skip to contentSkip to conversation

KVM: arm64: vgic-its: Remove VLA usage

PATCH In review Kees Cook 4 participants 6 messages Jun 29, 2018 – Jul 9, 2018 KVM arm64

lore
Share & tools
lore

Kees Cook

author
#0 lore raw

PATCH 1/1 KVM: arm64: vgic-its: Remove VLA usage

In the quest to remove all stack VLA usage from the kernel[1], this switches to using a maximum size and adds sanity checks. Additionally cleans up some of the int-vs-u32 usage and adds additional bounds checking. As it currently stands, this will always be 8 bytes until the ABI changes.

[1] https://lkml.kernel.org/r/CA+55aFzCG-zNmZwX4A2FQpadafLfEzK6CC=qPXydAacU1RqZWA@mail.gmail.com

Cc Christoffer Dall <[email protected]>
Cc Marc Zyngier <[email protected]>
Cc Eric Auger <[email protected]>
Cc Andre Przywara <[email protected]>
---
 virt/kvm/arm/vgic/vgic-its.c | 19 +++++++++++++++----
 1 file changed, 15 insertions(+), 4 deletions(-)
virt/kvm/arm/vgic/vgic-its.c +15 -4
index 4ed79c939fb4..3143fc047fcf 100644
@@ -168,8 +168,14 @@ struct vgic_its_abi {
 	int (*commit)(struct vgic_its *its);
 };
 
+#define ABI_0_ESZ	8
+#define ESZ_MAX		ABI_0_ESZ
+
 static const struct vgic_its_abi its_table_abi_versions[] = {
-	[0] = {.cte_esz = 8, .dte_esz = 8, .ite_esz = 8,
+	[0] = {
+	 .cte_esz = ABI_0_ESZ,
+	 .dte_esz = ABI_0_ESZ,
+	 .ite_esz = ABI_0_ESZ,
 	 .save_tables = vgic_its_save_tables_v0,
 	 .restore_tables = vgic_its_restore_tables_v0,
 	 .commit = vgic_its_commit_v0,
@@ -180,10 +186,12 @@ static const struct vgic_its_abi its_table_abi_versions[] = {
 
 inline const struct vgic_its_abi *vgic_its_get_abi(struct vgic_its *its)
 {
+	if (WARN_ON(its->abi_rev >= NR_ITS_ABIS))
+		return NULL;
 	return &its_table_abi_versions[its->abi_rev];
 }
 
-int vgic_its_set_abi(struct vgic_its *its, int rev)
+static int vgic_its_set_abi(struct vgic_its *its, u32 rev)
 {
 	const struct vgic_its_abi *abi;
 
@@ -1881,16 +1889,19 @@ typedef int (*entry_fn_t)(struct vgic_its *its, u32 id, void *entry,
  * Return: < 0 on error, 0 if last element was identified, 1 otherwise
  * (the last element may not be found on second level tables)
  */
-static int scan_its_table(struct vgic_its *its, gpa_t base, int size, int esz,
+static int scan_its_table(struct vgic_its *its, gpa_t base, int size, u32 esz,
 			  int start_id, entry_fn_t fn, void *opaque)
 {
 	struct kvm *kvm = its->dev->kvm;
 	unsigned long len = size;
 	int id = start_id;
 	gpa_t gpa = base;
-	char entry[esz];
+	char entry[ESZ_MAX];
 	int ret;
 
+	if (WARN_ON(esz > ESZ_MAX))
+		return -EINVAL;
+
 	memset(entry, 0, esz);
 
 	while (len > 0) {
Signature · 6 lines
2.17.1


-- 
Kees Cook
Pixel Security
#1 lore raw
Quoted 7 lines · Kees Cook

In the quest to remove all stack VLA usage from the kernel[1], this switches to using a maximum size and adds sanity checks. Additionally cleans up some of the int-vs-u32 usage and adds additional bounds checking. As it currently stands, this will always be 8 bytes until the ABI changes.

[1] https://lkml.kernel.org/r/CA+55aFzCG-zNmZwX4A2FQpadafLfEzK6CC=qPXydAacU1RqZWA@mail.gmail.com

Quoted 7 lines
Cc Christoffer Dall <[email protected]>
Cc Marc Zyngier <[email protected]>
Cc Eric Auger <[email protected]>
Cc Andre Przywara <[email protected]>

Looks good to me.

Arnd

#2 lore raw
In reply to Kees Cook

Hi Kees,

Quoted 40 lines · Kees Cook

In the quest to remove all stack VLA usage from the kernel[1], this switches to using a maximum size and adds sanity checks. Additionally cleans up some of the int-vs-u32 usage and adds additional bounds checking. As it currently stands, this will always be 8 bytes until the ABI changes.

[1] https://lkml.kernel.org/r/CA+55aFzCG-zNmZwX4A2FQpadafLfEzK6CC=qPXydAacU1RqZWA@mail.gmail.com

Cc Christoffer Dall <[email protected]>
Cc Marc Zyngier <[email protected]>
Cc Eric Auger <[email protected]>
Cc Andre Przywara <[email protected]>
---
 virt/kvm/arm/vgic/vgic-its.c | 19 +++++++++++++++----
 1 file changed, 15 insertions(+), 4 deletions(-)
virt/kvm/arm/vgic/vgic-its.c +7 -1
index 4ed79c939fb4..3143fc047fcf 100644
@@ -168,8 +168,14 @@ struct vgic_its_abi {
 	int (*commit)(struct vgic_its *its);
 };
 
+#define ABI_0_ESZ	8
+#define ESZ_MAX		ABI_0_ESZ
+
 static const struct vgic_its_abi its_table_abi_versions[] = {
-	[0] = {.cte_esz = 8, .dte_esz = 8, .ite_esz = 8,
+	[0] = {
+	 .cte_esz = ABI_0_ESZ,
+	 .dte_esz = ABI_0_ESZ,
+	 .ite_esz = ABI_0_ESZ,
 	 .save_tables = vgic_its_save_tables_v0,
 	 .restore_tables = vgic_its_restore_tables_v0,
 	 .commit = vgic_its_commit_v0,
@@ -180,10 +186,12 @@ static const struct vgic_its_abi its_table_abi_versions[] = {
 

virt/kvm/arm/vgic/vgic-its.c static const struct vgic_its_abi its_table_abi_versions[] = { · line 195

Quoted 10 lines
virt/kvm/arm/vgic/vgic-its.c +3 -1
 inline const struct vgic_its_abi *vgic_its_get_abi(struct vgic_its *its)
 {
+	if (WARN_ON(its->abi_rev >= NR_ITS_ABIS))
+		return NULL;
 	return &its_table_abi_versions[its->abi_rev];
 }
 
-int vgic_its_set_abi(struct vgic_its *its, int rev)
+static int vgic_its_set_abi(struct vgic_its *its, u32 rev)
 {

if vgic_its_get_abi is likely to return NULL, don't we need to check abi != NULL in all call sites.

abi_rev is actually set by vgic_its_set_abi() which is actually called by vgic_mmio_uaccess_write_its_iidr() and vgic_its_create().

Only vgic_mmio_uaccess_write_its_iidr allows the userspace to overwrite the default abi_rev. At this point a check against NR_ITS_ABIS is already done. So to me the check is done at the source?

Thanks

Eric

Quoted 25 lines
virt/kvm/arm/vgic/vgic-its.c +5 -2
 	const struct vgic_its_abi *abi;
 
@@ -1881,16 +1889,19 @@ typedef int (*entry_fn_t)(struct vgic_its *its, u32 id, void *entry,
  * Return: < 0 on error, 0 if last element was identified, 1 otherwise
  * (the last element may not be found on second level tables)
  */
-static int scan_its_table(struct vgic_its *its, gpa_t base, int size, int esz,
+static int scan_its_table(struct vgic_its *its, gpa_t base, int size, u32 esz,
 			  int start_id, entry_fn_t fn, void *opaque)
 {
 	struct kvm *kvm = its->dev->kvm;
 	unsigned long len = size;
 	int id = start_id;
 	gpa_t gpa = base;
-	char entry[esz];
+	char entry[ESZ_MAX];
 	int ret;
 
+	if (WARN_ON(esz > ESZ_MAX))
+		return -EINVAL;
+
 	memset(entry, 0, esz);
 
 	while (len > 0) {
author
#3 lore raw
Quoted 50 lines · Auger Eric

Hi Kees,

Quoted 47 lines · Kees Cook

In the quest to remove all stack VLA usage from the kernel[1], this switches to using a maximum size and adds sanity checks. Additionally cleans up some of the int-vs-u32 usage and adds additional bounds checking. As it currently stands, this will always be 8 bytes until the ABI changes.

[1] https://lkml.kernel.org/r/CA+55aFzCG-zNmZwX4A2FQpadafLfEzK6CC=qPXydAacU1RqZWA@mail.gmail.com

Cc Christoffer Dall <[email protected]>
Cc Marc Zyngier <[email protected]>
Cc Eric Auger <[email protected]>
Cc Andre Przywara <[email protected]>
---
 virt/kvm/arm/vgic/vgic-its.c | 19 +++++++++++++++----
 1 file changed, 15 insertions(+), 4 deletions(-)
virt/kvm/arm/vgic/vgic-its.c +9 -1
index 4ed79c939fb4..3143fc047fcf 100644
@@ -168,8 +168,14 @@ struct vgic_its_abi {
      int (*commit)(struct vgic_its *its);
 };
 
+#define ABI_0_ESZ    8
+#define ESZ_MAX              ABI_0_ESZ
+
 static const struct vgic_its_abi its_table_abi_versions[] = {
-     [0] = {.cte_esz = 8, .dte_esz = 8, .ite_esz = 8,
+     [0] = {
+      .cte_esz = ABI_0_ESZ,
+      .dte_esz = ABI_0_ESZ,
+      .ite_esz = ABI_0_ESZ,
       .save_tables = vgic_its_save_tables_v0,
       .restore_tables = vgic_its_restore_tables_v0,
       .commit = vgic_its_commit_v0,
@@ -180,10 +186,12 @@ static const struct vgic_its_abi its_table_abi_versions[] = {
 
 inline const struct vgic_its_abi *vgic_its_get_abi(struct vgic_its *its)
 {
+     if (WARN_ON(its->abi_rev >= NR_ITS_ABIS))
+             return NULL;
      return &its_table_abi_versions[its->abi_rev];
 }
 
Quoted 5 lines

virt/kvm/arm/vgic/vgic-its.c static const struct vgic_its_abi its_table_abi_versions[] = { · line 195

Quoted 3 lines
virt/kvm/arm/vgic/vgic-its.c +1 -1
-int vgic_its_set_abi(struct vgic_its *its, int rev)
+static int vgic_its_set_abi(struct vgic_its *its, u32 rev)
 {

if vgic_its_get_abi is likely to return NULL, don't we need to check abi != NULL in all call sites.

My thinking was that since it should never happen, a WARN_ON would be sufficient. But I can drop all these changes if you want. I just wanted to see the VLA removed. :)

-Kees

Quoted 36 lines

abi_rev is actually set by vgic_its_set_abi() which is actually called by vgic_mmio_uaccess_write_its_iidr() and vgic_its_create().

Only vgic_mmio_uaccess_write_its_iidr allows the userspace to overwrite the default abi_rev. At this point a check against NR_ITS_ABIS is already done. So to me the check is done at the source?

Thanks

Eric

Quoted 25 lines
virt/kvm/arm/vgic/vgic-its.c +5 -2
      const struct vgic_its_abi *abi;
 
@@ -1881,16 +1889,19 @@ typedef int (*entry_fn_t)(struct vgic_its *its, u32 id, void *entry,
  * Return: < 0 on error, 0 if last element was identified, 1 otherwise
  * (the last element may not be found on second level tables)
  */
-static int scan_its_table(struct vgic_its *its, gpa_t base, int size, int esz,
+static int scan_its_table(struct vgic_its *its, gpa_t base, int size, u32 esz,
                        int start_id, entry_fn_t fn, void *opaque)
 {
      struct kvm *kvm = its->dev->kvm;
      unsigned long len = size;
      int id = start_id;
      gpa_t gpa = base;
-     char entry[esz];
+     char entry[ESZ_MAX];
      int ret;
 
+     if (WARN_ON(esz > ESZ_MAX))
+             return -EINVAL;
+
      memset(entry, 0, esz);
 
      while (len > 0) {
Signature · 2 lines
Kees Cook
Pixel Security
#4 lore raw

Hi kees,

Quoted 57 lines · Kees Cook
Quoted 50 lines · Auger Eric

Hi Kees,

Quoted 47 lines · Kees Cook

In the quest to remove all stack VLA usage from the kernel[1], this switches to using a maximum size and adds sanity checks. Additionally cleans up some of the int-vs-u32 usage and adds additional bounds checking. As it currently stands, this will always be 8 bytes until the ABI changes.

[1] https://lkml.kernel.org/r/CA+55aFzCG-zNmZwX4A2FQpadafLfEzK6CC=qPXydAacU1RqZWA@mail.gmail.com

Cc Christoffer Dall <[email protected]>
Cc Marc Zyngier <[email protected]>
Cc Eric Auger <[email protected]>
Cc Andre Przywara <[email protected]>
---
 virt/kvm/arm/vgic/vgic-its.c | 19 +++++++++++++++----
 1 file changed, 15 insertions(+), 4 deletions(-)
virt/kvm/arm/vgic/vgic-its.c +9 -1
index 4ed79c939fb4..3143fc047fcf 100644
@@ -168,8 +168,14 @@ struct vgic_its_abi {
      int (*commit)(struct vgic_its *its);
 };
 
+#define ABI_0_ESZ    8
+#define ESZ_MAX              ABI_0_ESZ
+
 static const struct vgic_its_abi its_table_abi_versions[] = {
-     [0] = {.cte_esz = 8, .dte_esz = 8, .ite_esz = 8,
+     [0] = {
+      .cte_esz = ABI_0_ESZ,
+      .dte_esz = ABI_0_ESZ,
+      .ite_esz = ABI_0_ESZ,
       .save_tables = vgic_its_save_tables_v0,
       .restore_tables = vgic_its_restore_tables_v0,
       .commit = vgic_its_commit_v0,
@@ -180,10 +186,12 @@ static const struct vgic_its_abi its_table_abi_versions[] = {
 
 inline const struct vgic_its_abi *vgic_its_get_abi(struct vgic_its *its)
 {
+     if (WARN_ON(its->abi_rev >= NR_ITS_ABIS))
+             return NULL;
      return &its_table_abi_versions[its->abi_rev];
 }
 
Quoted 5 lines

virt/kvm/arm/vgic/vgic-its.c static const struct vgic_its_abi its_table_abi_versions[] = { · line 195

Quoted 3 lines
virt/kvm/arm/vgic/vgic-its.c +1 -1
-int vgic_its_set_abi(struct vgic_its *its, int rev)
+static int vgic_its_set_abi(struct vgic_its *its, u32 rev)
 {

if vgic_its_get_abi is likely to return NULL, don't we need to check abi != NULL in all call sites.

Quoted 3 lines

My thinking was that since it should never happen, a WARN_ON would be sufficient. But I can drop all these changes if you want. I just wanted to see the VLA removed. :)

Are you going to respin this patch limiting it to just the VLA changes? I'm actively queuing stuff for the next merge window, and it'd be good to get that one in.

Alternatively, I can drop the WARN_ONs myself. Just let me know.

Thanks,

	M.
Signature · 1 line
Jazz is not dead. It just smells funny...
author
#5 lore raw
Quoted 64 lines · Marc Zyngier

Hi kees,

Quoted 57 lines · Kees Cook
Quoted 50 lines · Auger Eric

Hi Kees,

Quoted 47 lines · Kees Cook

In the quest to remove all stack VLA usage from the kernel[1], this switches to using a maximum size and adds sanity checks. Additionally cleans up some of the int-vs-u32 usage and adds additional bounds checking. As it currently stands, this will always be 8 bytes until the ABI changes.

[1] https://lkml.kernel.org/r/CA+55aFzCG-zNmZwX4A2FQpadafLfEzK6CC=qPXydAacU1RqZWA@mail.gmail.com

Cc Christoffer Dall <[email protected]>
Cc Marc Zyngier <[email protected]>
Cc Eric Auger <[email protected]>
Cc Andre Przywara <[email protected]>
---
 virt/kvm/arm/vgic/vgic-its.c | 19 +++++++++++++++----
 1 file changed, 15 insertions(+), 4 deletions(-)
virt/kvm/arm/vgic/vgic-its.c +9 -1
index 4ed79c939fb4..3143fc047fcf 100644
@@ -168,8 +168,14 @@ struct vgic_its_abi {
      int (*commit)(struct vgic_its *its);
 };
 
+#define ABI_0_ESZ    8
+#define ESZ_MAX              ABI_0_ESZ
+
 static const struct vgic_its_abi its_table_abi_versions[] = {
-     [0] = {.cte_esz = 8, .dte_esz = 8, .ite_esz = 8,
+     [0] = {
+      .cte_esz = ABI_0_ESZ,
+      .dte_esz = ABI_0_ESZ,
+      .ite_esz = ABI_0_ESZ,
       .save_tables = vgic_its_save_tables_v0,
       .restore_tables = vgic_its_restore_tables_v0,
       .commit = vgic_its_commit_v0,
@@ -180,10 +186,12 @@ static const struct vgic_its_abi its_table_abi_versions[] = {
 
 inline const struct vgic_its_abi *vgic_its_get_abi(struct vgic_its *its)
 {
+     if (WARN_ON(its->abi_rev >= NR_ITS_ABIS))
+             return NULL;
      return &its_table_abi_versions[its->abi_rev];
 }
 
Quoted 5 lines

virt/kvm/arm/vgic/vgic-its.c static const struct vgic_its_abi its_table_abi_versions[] = { · line 195

Quoted 3 lines
virt/kvm/arm/vgic/vgic-its.c +1 -1
-int vgic_its_set_abi(struct vgic_its *its, int rev)
+static int vgic_its_set_abi(struct vgic_its *its, u32 rev)
 {

if vgic_its_get_abi is likely to return NULL, don't we need to check abi != NULL in all call sites.

Quoted 3 lines

My thinking was that since it should never happen, a WARN_ON would be sufficient. But I can drop all these changes if you want. I just wanted to see the VLA removed. :)

Quoted 5 lines

Are you going to respin this patch limiting it to just the VLA changes? I'm actively queuing stuff for the next merge window, and it'd be good to get that one in.

Alternatively, I can drop the WARN_ONs myself. Just let me know.

If you can just drop them that would be best, thanks!

-Kees

Signature · 2 lines
Kees Cook
Pixel Security