[PATCH] sparc/prom: size path-component buffers to fit node names

Pengpeng Hou posted 1 patch 2 months, 1 week ago
arch/sparc/kernel/prom_32.c |  84 +++++++++---------
arch/sparc/kernel/prom_64.c | 172 +++++++++++++++++-------------------
2 files changed, 122 insertions(+), 134 deletions(-)
[PATCH] sparc/prom: size path-component buffers to fit node names
Posted by Pengpeng Hou 2 months, 1 week ago
build_path_component() in both sparc PROM variants formats fully-named
path components in a fixed 64-byte local buffer and feeds raw firmware
node names
into a chain of sprintf() helpers.

That leaves two problems in the current tree: malformed or unterminated
name properties are treated as C strings, and long node names can
overflow the fixed local scratch buffer before the formatted path
component is copied into early memory.

Read the node name with of_property_read_string(), size the destination
buffer from the validated name length plus the maximum address suffix, and
use bounded formatting in the helper chain.

Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
---
 arch/sparc/kernel/prom_32.c |  84 +++++++++---------
 arch/sparc/kernel/prom_64.c | 172 +++++++++++++++++-------------------
 2 files changed, 122 insertions(+), 134 deletions(-)

diff --git a/arch/sparc/kernel/prom_32.c b/arch/sparc/kernel/prom_32.c
index cd94f1e8d644..b2a717a44105 100644
--- a/arch/sparc/kernel/prom_32.c
+++ b/arch/sparc/kernel/prom_32.c
@@ -16,6 +16,7 @@
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/memblock.h>
+#include <linux/of.h>
 
 #include <asm/prom.h>
 #include <asm/oplib.h>
@@ -24,6 +25,8 @@
 
 #include "prom.h"
 
+#define SPARC_PATH_COMPONENT_EXTRA 32
+
 void * __init prom_early_alloc(unsigned long size)
 {
 	void *ret;
@@ -52,9 +55,10 @@ void * __init prom_early_alloc(unsigned long size)
  * we walk up the tree until we discover a "device_type" property
  * we recognize and we go from there.
  */
-static void __init sparc32_path_component(struct device_node *dp, char *tmp_buf)
+static void __init sparc32_path_component(const char *name,
+					  struct device_node *dp,
+					  char *tmp_buf, size_t len)
 {
-	const char *name = of_get_property(dp, "name", NULL);
 	struct linux_prom_registers *regs;
 	struct property *rprop;
 
@@ -63,15 +67,14 @@ static void __init sparc32_path_component(struct device_node *dp, char *tmp_buf)
 		return;
 
 	regs = rprop->value;
-	sprintf(tmp_buf, "%s@%x,%x",
-		name,
-		regs->which_io, regs->phys_addr);
+	scnprintf(tmp_buf, len, "%s@%x,%x",
+		  name, regs->which_io, regs->phys_addr);
 }
 
 /* "name@slot,offset"  */
-static void __init sbus_path_component(struct device_node *dp, char *tmp_buf)
+static void __init sbus_path_component(const char *name, struct device_node *dp,
+				       char *tmp_buf, size_t len)
 {
-	const char *name = of_get_property(dp, "name", NULL);
 	struct linux_prom_registers *regs;
 	struct property *prop;
 
@@ -80,16 +83,14 @@ static void __init sbus_path_component(struct device_node *dp, char *tmp_buf)
 		return;
 
 	regs = prop->value;
-	sprintf(tmp_buf, "%s@%x,%x",
-		name,
-		regs->which_io,
-		regs->phys_addr);
+	scnprintf(tmp_buf, len, "%s@%x,%x",
+		  name, regs->which_io, regs->phys_addr);
 }
 
 /* "name@devnum[,func]" */
-static void __init pci_path_component(struct device_node *dp, char *tmp_buf)
+static void __init pci_path_component(const char *name, struct device_node *dp,
+				      char *tmp_buf, size_t len)
 {
-	const char *name = of_get_property(dp, "name", NULL);
 	struct linux_prom_pci_registers *regs;
 	struct property *prop;
 	unsigned int devfn;
@@ -101,21 +102,17 @@ static void __init pci_path_component(struct device_node *dp, char *tmp_buf)
 	regs = prop->value;
 	devfn = (regs->phys_hi >> 8) & 0xff;
 	if (devfn & 0x07) {
-		sprintf(tmp_buf, "%s@%x,%x",
-			name,
-			devfn >> 3,
-			devfn & 0x07);
+		scnprintf(tmp_buf, len, "%s@%x,%x",
+			  name, devfn >> 3, devfn & 0x07);
 	} else {
-		sprintf(tmp_buf, "%s@%x",
-			name,
-			devfn >> 3);
+		scnprintf(tmp_buf, len, "%s@%x", name, devfn >> 3);
 	}
 }
 
 /* "name@addrhi,addrlo" */
-static void __init ebus_path_component(struct device_node *dp, char *tmp_buf)
+static void __init ebus_path_component(const char *name, struct device_node *dp,
+				       char *tmp_buf, size_t len)
 {
-	const char *name = of_get_property(dp, "name", NULL);
 	struct linux_prom_registers *regs;
 	struct property *prop;
 
@@ -125,15 +122,15 @@ static void __init ebus_path_component(struct device_node *dp, char *tmp_buf)
 
 	regs = prop->value;
 
-	sprintf(tmp_buf, "%s@%x,%x",
-		name,
-		regs->which_io, regs->phys_addr);
+	scnprintf(tmp_buf, len, "%s@%x,%x",
+		  name, regs->which_io, regs->phys_addr);
 }
 
 /* "name@irq,addrlo" */
-static void __init ambapp_path_component(struct device_node *dp, char *tmp_buf)
+static void __init ambapp_path_component(const char *name,
+					 struct device_node *dp,
+					 char *tmp_buf, size_t len)
 {
-	const char *name = of_get_property(dp, "name", NULL);
 	struct amba_prom_registers *regs;
 	unsigned int *intr;
 	unsigned int reg0;
@@ -158,45 +155,46 @@ static void __init ambapp_path_component(struct device_node *dp, char *tmp_buf)
 	else
 		intr = prop->value;
 
-	sprintf(tmp_buf, "%s@%x,%x", name, *intr, reg0);
+	scnprintf(tmp_buf, len, "%s@%x,%x", name, *intr, reg0);
 }
 
-static void __init __build_path_component(struct device_node *dp, char *tmp_buf)
+static void __init __build_path_component(const char *name,
+					  struct device_node *dp,
+					  char *tmp_buf, size_t len)
 {
 	struct device_node *parent = dp->parent;
 
 	if (parent != NULL) {
 		if (of_node_is_type(parent, "pci") ||
 		    of_node_is_type(parent, "pciex"))
-			return pci_path_component(dp, tmp_buf);
+			return pci_path_component(name, dp, tmp_buf, len);
 		if (of_node_is_type(parent, "sbus"))
-			return sbus_path_component(dp, tmp_buf);
+			return sbus_path_component(name, dp, tmp_buf, len);
 		if (of_node_is_type(parent, "ebus"))
-			return ebus_path_component(dp, tmp_buf);
+			return ebus_path_component(name, dp, tmp_buf, len);
 		if (of_node_is_type(parent, "ambapp"))
-			return ambapp_path_component(dp, tmp_buf);
+			return ambapp_path_component(name, dp, tmp_buf, len);
 
 		/* "isa" is handled with platform naming */
 	}
 
 	/* Use platform naming convention.  */
-	return sparc32_path_component(dp, tmp_buf);
+	return sparc32_path_component(name, dp, tmp_buf, len);
 }
 
 char * __init build_path_component(struct device_node *dp)
 {
-	const char *name = of_get_property(dp, "name", NULL);
-	char tmp_buf[64], *n;
+	const char *name = "";
+	char *n;
 	size_t n_sz;
 
-	tmp_buf[0] = '\0';
-	__build_path_component(dp, tmp_buf);
-	if (tmp_buf[0] == '\0')
-		strscpy(tmp_buf, name);
-
-	n_sz = strlen(tmp_buf) + 1;
+	of_property_read_string(dp, "name", &name);
+	n_sz = strlen(name) + SPARC_PATH_COMPONENT_EXTRA;
 	n = prom_early_alloc(n_sz);
-	strscpy(n, tmp_buf, n_sz);
+	n[0] = '\0';
+	__build_path_component(name, dp, n, n_sz);
+	if (n[0] == '\0')
+		strscpy(n, name, n_sz);
 
 	return n;
 }
diff --git a/arch/sparc/kernel/prom_64.c b/arch/sparc/kernel/prom_64.c
index aa4799cbb9c1..e8053cf545ea 100644
--- a/arch/sparc/kernel/prom_64.c
+++ b/arch/sparc/kernel/prom_64.c
@@ -28,6 +28,8 @@
 
 #include "prom.h"
 
+#define SPARC_PATH_COMPONENT_EXTRA 32
+
 void * __init prom_early_alloc(unsigned long size)
 {
 	void *ret = memblock_alloc(size, SMP_CACHE_BYTES);
@@ -63,9 +65,10 @@ void * __init prom_early_alloc(unsigned long size)
  *
  *	/pci@1e,600000/ide@d/disk@0,0:c
  */
-static void __init sun4v_path_component(struct device_node *dp, char *tmp_buf)
+static void __init sun4v_path_component(const char *name,
+					struct device_node *dp,
+					char *tmp_buf, size_t len)
 {
-	const char *name = of_get_property(dp, "name", NULL);
 	struct linux_prom64_registers *regs;
 	struct property *rprop;
 	u32 high_bits, low_bits, type;
@@ -76,10 +79,10 @@ static void __init sun4v_path_component(struct device_node *dp, char *tmp_buf)
 
 	regs = rprop->value;
 	if (!of_node_is_root(dp->parent)) {
-		sprintf(tmp_buf, "%s@%x,%x",
-			name,
-			(unsigned int) (regs->phys_addr >> 32UL),
-			(unsigned int) (regs->phys_addr & 0xffffffffUL));
+		scnprintf(tmp_buf, len, "%s@%x,%x",
+			  name,
+			  (unsigned int)(regs->phys_addr >> 32UL),
+			  (unsigned int)(regs->phys_addr & 0xffffffffUL));
 		return;
 	}
 
@@ -91,23 +94,20 @@ static void __init sun4v_path_component(struct device_node *dp, char *tmp_buf)
 		const char *prefix = (type == 0) ? "m" : "i";
 
 		if (low_bits)
-			sprintf(tmp_buf, "%s@%s%x,%x",
-				name, prefix,
-				high_bits, low_bits);
+			scnprintf(tmp_buf, len, "%s@%s%x,%x",
+				  name, prefix, high_bits, low_bits);
 		else
-			sprintf(tmp_buf, "%s@%s%x",
-				name,
-				prefix,
-				high_bits);
+			scnprintf(tmp_buf, len, "%s@%s%x",
+				  name, prefix, high_bits);
 	} else if (type == 12) {
-		sprintf(tmp_buf, "%s@%x",
-			name, high_bits);
+		scnprintf(tmp_buf, len, "%s@%x", name, high_bits);
 	}
 }
 
-static void __init sun4u_path_component(struct device_node *dp, char *tmp_buf)
+static void __init sun4u_path_component(const char *name,
+					struct device_node *dp,
+					char *tmp_buf, size_t len)
 {
-	const char *name = of_get_property(dp, "name", NULL);
 	struct linux_prom64_registers *regs;
 	struct property *prop;
 
@@ -117,10 +117,10 @@ static void __init sun4u_path_component(struct device_node *dp, char *tmp_buf)
 
 	regs = prop->value;
 	if (!of_node_is_root(dp->parent)) {
-		sprintf(tmp_buf, "%s@%x,%x",
-			name,
-			(unsigned int) (regs->phys_addr >> 32UL),
-			(unsigned int) (regs->phys_addr & 0xffffffffUL));
+		scnprintf(tmp_buf, len, "%s@%x,%x",
+			  name,
+			  (unsigned int)(regs->phys_addr >> 32UL),
+			  (unsigned int)(regs->phys_addr & 0xffffffffUL));
 		return;
 	}
 
@@ -133,17 +133,16 @@ static void __init sun4u_path_component(struct device_node *dp, char *tmp_buf)
 		if (tlb_type >= cheetah)
 			mask = 0x7fffff;
 
-		sprintf(tmp_buf, "%s@%x,%x",
-			name,
-			*(u32 *)prop->value,
-			(unsigned int) (regs->phys_addr & mask));
+		scnprintf(tmp_buf, len, "%s@%x,%x",
+			  name, *(u32 *)prop->value,
+			  (unsigned int)(regs->phys_addr & mask));
 	}
 }
 
 /* "name@slot,offset"  */
-static void __init sbus_path_component(struct device_node *dp, char *tmp_buf)
+static void __init sbus_path_component(const char *name, struct device_node *dp,
+				       char *tmp_buf, size_t len)
 {
-	const char *name = of_get_property(dp, "name", NULL);
 	struct linux_prom_registers *regs;
 	struct property *prop;
 
@@ -152,16 +151,14 @@ static void __init sbus_path_component(struct device_node *dp, char *tmp_buf)
 		return;
 
 	regs = prop->value;
-	sprintf(tmp_buf, "%s@%x,%x",
-		name,
-		regs->which_io,
-		regs->phys_addr);
+	scnprintf(tmp_buf, len, "%s@%x,%x",
+		  name, regs->which_io, regs->phys_addr);
 }
 
 /* "name@devnum[,func]" */
-static void __init pci_path_component(struct device_node *dp, char *tmp_buf)
+static void __init pci_path_component(const char *name, struct device_node *dp,
+				      char *tmp_buf, size_t len)
 {
-	const char *name = of_get_property(dp, "name", NULL);
 	struct linux_prom_pci_registers *regs;
 	struct property *prop;
 	unsigned int devfn;
@@ -173,21 +170,17 @@ static void __init pci_path_component(struct device_node *dp, char *tmp_buf)
 	regs = prop->value;
 	devfn = (regs->phys_hi >> 8) & 0xff;
 	if (devfn & 0x07) {
-		sprintf(tmp_buf, "%s@%x,%x",
-			name,
-			devfn >> 3,
-			devfn & 0x07);
+		scnprintf(tmp_buf, len, "%s@%x,%x",
+			  name, devfn >> 3, devfn & 0x07);
 	} else {
-		sprintf(tmp_buf, "%s@%x",
-			name,
-			devfn >> 3);
+		scnprintf(tmp_buf, len, "%s@%x", name, devfn >> 3);
 	}
 }
 
 /* "name@UPA_PORTID,offset" */
-static void __init upa_path_component(struct device_node *dp, char *tmp_buf)
+static void __init upa_path_component(const char *name, struct device_node *dp,
+				      char *tmp_buf, size_t len)
 {
-	const char *name = of_get_property(dp, "name", NULL);
 	struct linux_prom64_registers *regs;
 	struct property *prop;
 
@@ -201,16 +194,15 @@ static void __init upa_path_component(struct device_node *dp, char *tmp_buf)
 	if (!prop)
 		return;
 
-	sprintf(tmp_buf, "%s@%x,%x",
-		name,
-		*(u32 *) prop->value,
-		(unsigned int) (regs->phys_addr & 0xffffffffUL));
+	scnprintf(tmp_buf, len, "%s@%x,%x",
+		  name, *(u32 *)prop->value,
+		  (unsigned int)(regs->phys_addr & 0xffffffffUL));
 }
 
 /* "name@reg" */
-static void __init vdev_path_component(struct device_node *dp, char *tmp_buf)
+static void __init vdev_path_component(const char *name, struct device_node *dp,
+				       char *tmp_buf, size_t len)
 {
-	const char *name = of_get_property(dp, "name", NULL);
 	struct property *prop;
 	u32 *regs;
 
@@ -220,13 +212,13 @@ static void __init vdev_path_component(struct device_node *dp, char *tmp_buf)
 
 	regs = prop->value;
 
-	sprintf(tmp_buf, "%s@%x", name, *regs);
+	scnprintf(tmp_buf, len, "%s@%x", name, *regs);
 }
 
 /* "name@addrhi,addrlo" */
-static void __init ebus_path_component(struct device_node *dp, char *tmp_buf)
+static void __init ebus_path_component(const char *name, struct device_node *dp,
+				       char *tmp_buf, size_t len)
 {
-	const char *name = of_get_property(dp, "name", NULL);
 	struct linux_prom64_registers *regs;
 	struct property *prop;
 
@@ -236,16 +228,16 @@ static void __init ebus_path_component(struct device_node *dp, char *tmp_buf)
 
 	regs = prop->value;
 
-	sprintf(tmp_buf, "%s@%x,%x",
-		name,
-		(unsigned int) (regs->phys_addr >> 32UL),
-		(unsigned int) (regs->phys_addr & 0xffffffffUL));
+	scnprintf(tmp_buf, len, "%s@%x,%x",
+		  name,
+		  (unsigned int)(regs->phys_addr >> 32UL),
+		  (unsigned int)(regs->phys_addr & 0xffffffffUL));
 }
 
 /* "name@bus,addr" */
-static void __init i2c_path_component(struct device_node *dp, char *tmp_buf)
+static void __init i2c_path_component(const char *name, struct device_node *dp,
+				      char *tmp_buf, size_t len)
 {
-	const char *name = of_get_property(dp, "name", NULL);
 	struct property *prop;
 	u32 *regs;
 
@@ -258,14 +250,13 @@ static void __init i2c_path_component(struct device_node *dp, char *tmp_buf)
 	/* This actually isn't right... should look at the #address-cells
 	 * property of the i2c bus node etc. etc.
 	 */
-	sprintf(tmp_buf, "%s@%x,%x",
-		name, regs[0], regs[1]);
+	scnprintf(tmp_buf, len, "%s@%x,%x", name, regs[0], regs[1]);
 }
 
 /* "name@reg0[,reg1]" */
-static void __init usb_path_component(struct device_node *dp, char *tmp_buf)
+static void __init usb_path_component(const char *name, struct device_node *dp,
+				      char *tmp_buf, size_t len)
 {
-	const char *name = of_get_property(dp, "name", NULL);
 	struct property *prop;
 	u32 *regs;
 
@@ -276,18 +267,17 @@ static void __init usb_path_component(struct device_node *dp, char *tmp_buf)
 	regs = prop->value;
 
 	if (prop->length == sizeof(u32) || regs[1] == 1) {
-		sprintf(tmp_buf, "%s@%x",
-			name, regs[0]);
+		scnprintf(tmp_buf, len, "%s@%x", name, regs[0]);
 	} else {
-		sprintf(tmp_buf, "%s@%x,%x",
-			name, regs[0], regs[1]);
+		scnprintf(tmp_buf, len, "%s@%x,%x", name, regs[0], regs[1]);
 	}
 }
 
 /* "name@reg0reg1[,reg2reg3]" */
-static void __init ieee1394_path_component(struct device_node *dp, char *tmp_buf)
+static void __init ieee1394_path_component(const char *name,
+					   struct device_node *dp,
+					   char *tmp_buf, size_t len)
 {
-	const char *name = of_get_property(dp, "name", NULL);
 	struct property *prop;
 	u32 *regs;
 
@@ -298,51 +288,52 @@ static void __init ieee1394_path_component(struct device_node *dp, char *tmp_buf
 	regs = prop->value;
 
 	if (regs[2] || regs[3]) {
-		sprintf(tmp_buf, "%s@%08x%08x,%04x%08x",
-			name, regs[0], regs[1], regs[2], regs[3]);
+		scnprintf(tmp_buf, len, "%s@%08x%08x,%04x%08x",
+			  name, regs[0], regs[1], regs[2], regs[3]);
 	} else {
-		sprintf(tmp_buf, "%s@%08x%08x",
-			name, regs[0], regs[1]);
+		scnprintf(tmp_buf, len, "%s@%08x%08x", name, regs[0], regs[1]);
 	}
 }
 
-static void __init __build_path_component(struct device_node *dp, char *tmp_buf)
+static void __init __build_path_component(const char *name,
+					  struct device_node *dp,
+					  char *tmp_buf, size_t len)
 {
 	struct device_node *parent = dp->parent;
 
 	if (parent != NULL) {
 		if (of_node_is_type(parent, "pci") ||
 		    of_node_is_type(parent, "pciex")) {
-			pci_path_component(dp, tmp_buf);
+			pci_path_component(name, dp, tmp_buf, len);
 			return;
 		}
 		if (of_node_is_type(parent, "sbus")) {
-			sbus_path_component(dp, tmp_buf);
+			sbus_path_component(name, dp, tmp_buf, len);
 			return;
 		}
 		if (of_node_is_type(parent, "upa")) {
-			upa_path_component(dp, tmp_buf);
+			upa_path_component(name, dp, tmp_buf, len);
 			return;
 		}
 		if (of_node_is_type(parent, "ebus")) {
-			ebus_path_component(dp, tmp_buf);
+			ebus_path_component(name, dp, tmp_buf, len);
 			return;
 		}
 		if (of_node_name_eq(parent, "usb") ||
 		    of_node_name_eq(parent, "hub")) {
-			usb_path_component(dp, tmp_buf);
+			usb_path_component(name, dp, tmp_buf, len);
 			return;
 		}
 		if (of_node_is_type(parent, "i2c")) {
-			i2c_path_component(dp, tmp_buf);
+			i2c_path_component(name, dp, tmp_buf, len);
 			return;
 		}
 		if (of_node_is_type(parent, "firewire")) {
-			ieee1394_path_component(dp, tmp_buf);
+			ieee1394_path_component(name, dp, tmp_buf, len);
 			return;
 		}
 		if (of_node_is_type(parent, "virtual-devices")) {
-			vdev_path_component(dp, tmp_buf);
+			vdev_path_component(name, dp, tmp_buf, len);
 			return;
 		}
 		/* "isa" is handled with platform naming */
@@ -350,27 +341,26 @@ static void __init __build_path_component(struct device_node *dp, char *tmp_buf)
 
 	/* Use platform naming convention.  */
 	if (tlb_type == hypervisor) {
-		sun4v_path_component(dp, tmp_buf);
+		sun4v_path_component(name, dp, tmp_buf, len);
 		return;
 	} else {
-		sun4u_path_component(dp, tmp_buf);
+		sun4u_path_component(name, dp, tmp_buf, len);
 	}
 }
 
 char * __init build_path_component(struct device_node *dp)
 {
-	const char *name = of_get_property(dp, "name", NULL);
-	char tmp_buf[64], *n;
+	const char *name = "";
+	char *n;
 	size_t n_sz;
 
-	tmp_buf[0] = '\0';
-	__build_path_component(dp, tmp_buf);
-	if (tmp_buf[0] == '\0')
-		strscpy(tmp_buf, name);
-
-	n_sz = strlen(tmp_buf) + 1;
+	of_property_read_string(dp, "name", &name);
+	n_sz = strlen(name) + SPARC_PATH_COMPONENT_EXTRA;
 	n = prom_early_alloc(n_sz);
-	strscpy(n, tmp_buf, n_sz);
+	n[0] = '\0';
+	__build_path_component(name, dp, n, n_sz);
+	if (n[0] == '\0')
+		strscpy(n, name, n_sz);
 
 	return n;
 }
-- 
2.50.1 (Apple Git-155)