[PATCH] sparc/prom: size path-component buffers to fit node names
Pengpeng Hou <[email protected]>
| Newsgroups | org.kernel.vger.sparclinux,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
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 <[email protected]> --- 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)