powerpc/prom_init: don't use string functions from lib/
authorChristophe Leroy <christophe.leroy@c-s.fr>
Fri, 26 Apr 2019 16:23:28 +0000 (16:23 +0000)
committerMichael Ellerman <mpe@ellerman.id.au>
Thu, 2 May 2019 15:20:25 +0000 (01:20 +1000)
When KASAN is active, the string functions in lib/ are doing the
KASAN checks. This is too early for prom_init.

This patch implements dedicated string functions for prom_init,
which will be compiled in with KASAN disabled.

Size of prom_init before the patch:
   text    data     bss     dec     hex filename
  12060     488    6960   19508    4c34 arch/powerpc/kernel/prom_init.o

Size of prom_init after the patch:
   text    data     bss     dec     hex filename
  12460     488    6960   19908    4dc4 arch/powerpc/kernel/prom_init.o

This increases the size of prom_init a bit, but as prom_init is
in __init section, it is freed after boot anyway.

Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
arch/powerpc/kernel/prom_init.c
arch/powerpc/kernel/prom_init_check.sh

index ecf083c46bdb0b28819234b9fe2a65e76d105dff..7017156168e8a5025cee60b760599fc56ed3c20b 100644 (file)
@@ -224,6 +224,135 @@ static bool  __prombss rtas_has_query_cpu_stopped;
 #define PHANDLE_VALID(p)       ((p) != 0 && (p) != PROM_ERROR)
 #define IHANDLE_VALID(i)       ((i) != 0 && (i) != PROM_ERROR)
 
+/* Copied from lib/string.c and lib/kstrtox.c */
+
+static int __init prom_strcmp(const char *cs, const char *ct)
+{
+       unsigned char c1, c2;
+
+       while (1) {
+               c1 = *cs++;
+               c2 = *ct++;
+               if (c1 != c2)
+                       return c1 < c2 ? -1 : 1;
+               if (!c1)
+                       break;
+       }
+       return 0;
+}
+
+static char __init *prom_strcpy(char *dest, const char *src)
+{
+       char *tmp = dest;
+
+       while ((*dest++ = *src++) != '\0')
+               /* nothing */;
+       return tmp;
+}
+
+static int __init prom_strncmp(const char *cs, const char *ct, size_t count)
+{
+       unsigned char c1, c2;
+
+       while (count) {
+               c1 = *cs++;
+               c2 = *ct++;
+               if (c1 != c2)
+                       return c1 < c2 ? -1 : 1;
+               if (!c1)
+                       break;
+               count--;
+       }
+       return 0;
+}
+
+static size_t __init prom_strlen(const char *s)
+{
+       const char *sc;
+
+       for (sc = s; *sc != '\0'; ++sc)
+               /* nothing */;
+       return sc - s;
+}
+
+static int __init prom_memcmp(const void *cs, const void *ct, size_t count)
+{
+       const unsigned char *su1, *su2;
+       int res = 0;
+
+       for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
+               if ((res = *su1 - *su2) != 0)
+                       break;
+       return res;
+}
+
+static char __init *prom_strstr(const char *s1, const char *s2)
+{
+       size_t l1, l2;
+
+       l2 = prom_strlen(s2);
+       if (!l2)
+               return (char *)s1;
+       l1 = prom_strlen(s1);
+       while (l1 >= l2) {
+               l1--;
+               if (!prom_memcmp(s1, s2, l2))
+                       return (char *)s1;
+               s1++;
+       }
+       return NULL;
+}
+
+static size_t __init prom_strlcpy(char *dest, const char *src, size_t size)
+{
+       size_t ret = prom_strlen(src);
+
+       if (size) {
+               size_t len = (ret >= size) ? size - 1 : ret;
+               memcpy(dest, src, len);
+               dest[len] = '\0';
+       }
+       return ret;
+}
+
+#ifdef CONFIG_PPC_PSERIES
+static int __init prom_strtobool(const char *s, bool *res)
+{
+       if (!s)
+               return -EINVAL;
+
+       switch (s[0]) {
+       case 'y':
+       case 'Y':
+       case '1':
+               *res = true;
+               return 0;
+       case 'n':
+       case 'N':
+       case '0':
+               *res = false;
+               return 0;
+       case 'o':
+       case 'O':
+               switch (s[1]) {
+               case 'n':
+               case 'N':
+                       *res = true;
+                       return 0;
+               case 'f':
+               case 'F':
+                       *res = false;
+                       return 0;
+               default:
+                       break;
+               }
+       default:
+               break;
+       }
+
+       return -EINVAL;
+}
+#endif
 
 /* This is the one and *ONLY* place where we actually call open
  * firmware.
@@ -555,7 +684,7 @@ static int __init prom_setprop(phandle node, const char *nodename,
        add_string(&p, tohex((u32)(unsigned long) value));
        add_string(&p, tohex(valuelen));
        add_string(&p, tohex(ADDR(pname)));
-       add_string(&p, tohex(strlen(pname)));
+       add_string(&p, tohex(prom_strlen(pname)));
        add_string(&p, "property");
        *p = 0;
        return call_prom("interpret", 1, 1, (u32)(unsigned long) cmd);
@@ -638,23 +767,23 @@ static void __init early_cmdline_parse(void)
        if ((long)prom.chosen > 0)
                l = prom_getprop(prom.chosen, "bootargs", p, COMMAND_LINE_SIZE-1);
        if (IS_ENABLED(CONFIG_CMDLINE_BOOL) && (l <= 0 || p[0] == '\0')) /* dbl check */
-               strlcpy(prom_cmd_line, CONFIG_CMDLINE, sizeof(prom_cmd_line));
+               prom_strlcpy(prom_cmd_line, CONFIG_CMDLINE, sizeof(prom_cmd_line));
        prom_printf("command line: %s\n", prom_cmd_line);
 
 #ifdef CONFIG_PPC64
-       opt = strstr(prom_cmd_line, "iommu=");
+       opt = prom_strstr(prom_cmd_line, "iommu=");
        if (opt) {
                prom_printf("iommu opt is: %s\n", opt);
                opt += 6;
                while (*opt && *opt == ' ')
                        opt++;
-               if (!strncmp(opt, "off", 3))
+               if (!prom_strncmp(opt, "off", 3))
                        prom_iommu_off = 1;
-               else if (!strncmp(opt, "force", 5))
+               else if (!prom_strncmp(opt, "force", 5))
                        prom_iommu_force_on = 1;
        }
 #endif
-       opt = strstr(prom_cmd_line, "mem=");
+       opt = prom_strstr(prom_cmd_line, "mem=");
        if (opt) {
                opt += 4;
                prom_memory_limit = prom_memparse(opt, (const char **)&opt);
@@ -666,13 +795,13 @@ static void __init early_cmdline_parse(void)
 
 #ifdef CONFIG_PPC_PSERIES
        prom_radix_disable = !IS_ENABLED(CONFIG_PPC_RADIX_MMU_DEFAULT);
-       opt = strstr(prom_cmd_line, "disable_radix");
+       opt = prom_strstr(prom_cmd_line, "disable_radix");
        if (opt) {
                opt += 13;
                if (*opt && *opt == '=') {
                        bool val;
 
-                       if (kstrtobool(++opt, &val))
+                       if (prom_strtobool(++opt, &val))
                                prom_radix_disable = false;
                        else
                                prom_radix_disable = val;
@@ -1025,7 +1154,7 @@ static int __init prom_count_smt_threads(void)
                type[0] = 0;
                prom_getprop(node, "device_type", type, sizeof(type));
 
-               if (strcmp(type, "cpu"))
+               if (prom_strcmp(type, "cpu"))
                        continue;
                /*
                 * There is an entry for each smt thread, each entry being
@@ -1472,7 +1601,7 @@ static void __init prom_init_mem(void)
                         */
                        prom_getprop(node, "name", type, sizeof(type));
                }
-               if (strcmp(type, "memory"))
+               if (prom_strcmp(type, "memory"))
                        continue;
 
                plen = prom_getprop(node, "reg", regbuf, sizeof(regbuf));
@@ -1753,19 +1882,19 @@ static void __init prom_initialize_tce_table(void)
                prom_getprop(node, "device_type", type, sizeof(type));
                prom_getprop(node, "model", model, sizeof(model));
 
-               if ((type[0] == 0) || (strstr(type, "pci") == NULL))
+               if ((type[0] == 0) || (prom_strstr(type, "pci") == NULL))
                        continue;
 
                /* Keep the old logic intact to avoid regression. */
                if (compatible[0] != 0) {
-                       if ((strstr(compatible, "python") == NULL) &&
-                           (strstr(compatible, "Speedwagon") == NULL) &&
-                           (strstr(compatible, "Winnipeg") == NULL))
+                       if ((prom_strstr(compatible, "python") == NULL) &&
+                           (prom_strstr(compatible, "Speedwagon") == NULL) &&
+                           (prom_strstr(compatible, "Winnipeg") == NULL))
                                continue;
                } else if (model[0] != 0) {
-                       if ((strstr(model, "ython") == NULL) &&
-                           (strstr(model, "peedwagon") == NULL) &&
-                           (strstr(model, "innipeg") == NULL))
+                       if ((prom_strstr(model, "ython") == NULL) &&
+                           (prom_strstr(model, "peedwagon") == NULL) &&
+                           (prom_strstr(model, "innipeg") == NULL))
                                continue;
                }
 
@@ -1914,12 +2043,12 @@ static void __init prom_hold_cpus(void)
 
                type[0] = 0;
                prom_getprop(node, "device_type", type, sizeof(type));
-               if (strcmp(type, "cpu") != 0)
+               if (prom_strcmp(type, "cpu") != 0)
                        continue;
 
                /* Skip non-configured cpus. */
                if (prom_getprop(node, "status", type, sizeof(type)) > 0)
-                       if (strcmp(type, "okay") != 0)
+                       if (prom_strcmp(type, "okay") != 0)
                                continue;
 
                reg = cpu_to_be32(-1); /* make sparse happy */
@@ -1995,9 +2124,9 @@ static void __init prom_find_mmu(void)
                return;
        version[sizeof(version) - 1] = 0;
        /* XXX might need to add other versions here */
-       if (strcmp(version, "Open Firmware, 1.0.5") == 0)
+       if (prom_strcmp(version, "Open Firmware, 1.0.5") == 0)
                of_workarounds = OF_WA_CLAIM;
-       else if (strncmp(version, "FirmWorks,3.", 12) == 0) {
+       else if (prom_strncmp(version, "FirmWorks,3.", 12) == 0) {
                of_workarounds = OF_WA_CLAIM | OF_WA_LONGTRAIL;
                call_prom("interpret", 1, 1, "dev /memory 0 to allow-reclaim");
        } else
@@ -2030,7 +2159,7 @@ static void __init prom_init_stdout(void)
        call_prom("instance-to-path", 3, 1, prom.stdout, path, 255);
        prom_printf("OF stdout device is: %s\n", of_stdout_device);
        prom_setprop(prom.chosen, "/chosen", "linux,stdout-path",
-                    path, strlen(path) + 1);
+                    path, prom_strlen(path) + 1);
 
        /* instance-to-package fails on PA-Semi */
        stdout_node = call_prom("instance-to-package", 1, 1, prom.stdout);
@@ -2040,7 +2169,7 @@ static void __init prom_init_stdout(void)
                /* If it's a display, note it */
                memset(type, 0, sizeof(type));
                prom_getprop(stdout_node, "device_type", type, sizeof(type));
-               if (strcmp(type, "display") == 0)
+               if (prom_strcmp(type, "display") == 0)
                        prom_setprop(stdout_node, path, "linux,boot-display", NULL, 0);
        }
 }
@@ -2061,19 +2190,19 @@ static int __init prom_find_machine_type(void)
                compat[len] = 0;
                while (i < len) {
                        char *p = &compat[i];
-                       int sl = strlen(p);
+                       int sl = prom_strlen(p);
                        if (sl == 0)
                                break;
-                       if (strstr(p, "Power Macintosh") ||
-                           strstr(p, "MacRISC"))
+                       if (prom_strstr(p, "Power Macintosh") ||
+                           prom_strstr(p, "MacRISC"))
                                return PLATFORM_POWERMAC;
 #ifdef CONFIG_PPC64
                        /* We must make sure we don't detect the IBM Cell
                         * blades as pSeries due to some firmware issues,
                         * so we do it here.
                         */
-                       if (strstr(p, "IBM,CBEA") ||
-                           strstr(p, "IBM,CPBW-1.0"))
+                       if (prom_strstr(p, "IBM,CBEA") ||
+                           prom_strstr(p, "IBM,CPBW-1.0"))
                                return PLATFORM_GENERIC;
 #endif /* CONFIG_PPC64 */
                        i += sl + 1;
@@ -2090,7 +2219,7 @@ static int __init prom_find_machine_type(void)
                           compat, sizeof(compat)-1);
        if (len <= 0)
                return PLATFORM_GENERIC;
-       if (strcmp(compat, "chrp"))
+       if (prom_strcmp(compat, "chrp"))
                return PLATFORM_GENERIC;
 
        /* Default to pSeries. We need to know if we are running LPAR */
@@ -2152,7 +2281,7 @@ static void __init prom_check_displays(void)
        for (node = 0; prom_next_node(&node); ) {
                memset(type, 0, sizeof(type));
                prom_getprop(node, "device_type", type, sizeof(type));
-               if (strcmp(type, "display") != 0)
+               if (prom_strcmp(type, "display") != 0)
                        continue;
 
                /* It seems OF doesn't null-terminate the path :-( */
@@ -2256,9 +2385,9 @@ static unsigned long __init dt_find_string(char *str)
        s = os = (char *)dt_string_start;
        s += 4;
        while (s <  (char *)dt_string_end) {
-               if (strcmp(s, str) == 0)
+               if (prom_strcmp(s, str) == 0)
                        return s - os;
-               s += strlen(s) + 1;
+               s += prom_strlen(s) + 1;
        }
        return 0;
 }
@@ -2291,7 +2420,7 @@ static void __init scan_dt_build_strings(phandle node,
                }
 
                /* skip "name" */
-               if (strcmp(namep, "name") == 0) {
+               if (prom_strcmp(namep, "name") == 0) {
                        *mem_start = (unsigned long)namep;
                        prev_name = "name";
                        continue;
@@ -2303,7 +2432,7 @@ static void __init scan_dt_build_strings(phandle node,
                        namep = sstart + soff;
                } else {
                        /* Trim off some if we can */
-                       *mem_start = (unsigned long)namep + strlen(namep) + 1;
+                       *mem_start = (unsigned long)namep + prom_strlen(namep) + 1;
                        dt_string_end = *mem_start;
                }
                prev_name = namep;
@@ -2372,7 +2501,7 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
                        break;
 
                /* skip "name" */
-               if (strcmp(pname, "name") == 0) {
+               if (prom_strcmp(pname, "name") == 0) {
                        prev_name = "name";
                        continue;
                }
@@ -2403,7 +2532,7 @@ static void __init scan_dt_build_struct(phandle node, unsigned long *mem_start,
                call_prom("getprop", 4, 1, node, pname, valp, l);
                *mem_start = _ALIGN(*mem_start, 4);
 
-               if (!strcmp(pname, "phandle"))
+               if (!prom_strcmp(pname, "phandle"))
                        has_phandle = 1;
        }
 
@@ -2473,8 +2602,8 @@ static void __init flatten_device_tree(void)
 
        /* Add "phandle" in there, we'll need it */
        namep = make_room(&mem_start, &mem_end, 16, 1);
-       strcpy(namep, "phandle");
-       mem_start = (unsigned long)namep + strlen(namep) + 1;
+       prom_strcpy(namep, "phandle");
+       mem_start = (unsigned long)namep + prom_strlen(namep) + 1;
 
        /* Build string array */
        prom_printf("Building dt strings...\n"); 
@@ -2796,7 +2925,7 @@ static void __init fixup_device_tree_efika(void)
        rv = prom_getprop(node, "model", prop, sizeof(prop));
        if (rv == PROM_ERROR)
                return;
-       if (strcmp(prop, "EFIKA5K2"))
+       if (prom_strcmp(prop, "EFIKA5K2"))
                return;
 
        prom_printf("Applying EFIKA device tree fixups\n");
@@ -2804,13 +2933,13 @@ static void __init fixup_device_tree_efika(void)
        /* Claiming to be 'chrp' is death */
        node = call_prom("finddevice", 1, 1, ADDR("/"));
        rv = prom_getprop(node, "device_type", prop, sizeof(prop));
-       if (rv != PROM_ERROR && (strcmp(prop, "chrp") == 0))
+       if (rv != PROM_ERROR && (prom_strcmp(prop, "chrp") == 0))
                prom_setprop(node, "/", "device_type", "efika", sizeof("efika"));
 
        /* CODEGEN,description is exposed in /proc/cpuinfo so
           fix that too */
        rv = prom_getprop(node, "CODEGEN,description", prop, sizeof(prop));
-       if (rv != PROM_ERROR && (strstr(prop, "CHRP")))
+       if (rv != PROM_ERROR && (prom_strstr(prop, "CHRP")))
                prom_setprop(node, "/", "CODEGEN,description",
                             "Efika 5200B PowerPC System",
                             sizeof("Efika 5200B PowerPC System"));
index 181fd10008efbf2b6ef0033f85558174689f644a..4cac45cb5de53dc8738b29241d4344972bf42881 100644 (file)
@@ -27,7 +27,7 @@ fi
 WHITELIST="add_reloc_offset __bss_start __bss_stop copy_and_flush
 _end enter_prom $MEM_FUNCS reloc_offset __secondary_hold
 __secondary_hold_acknowledge __secondary_hold_spinloop __start
-strcmp strcpy strlcpy strlen strncmp strstr kstrtobool logo_linux_clut224
+logo_linux_clut224
 reloc_got2 kernstart_addr memstart_addr linux_banner _stext
 __prom_init_toc_start __prom_init_toc_end btext_setup_display TOC."