[PATCH] sparc/prom: size path-component buffers to fit node names
From: Pengpeng Hou
Date: Sat Apr 04 2026 - 09:55:09 EST
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@xxxxxxxxxxx>
---
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)