linux_spi.c: align argument parsing with upstream and fix memory leaks

Reorder argument parsing and free() strings returned by
parse_programmer_param() to match upstream. To reduce the
complexity assiciated with freeing the device filename string,
check_fdt() and check_sysfs() now return heap allocated strings.

This commit is mostly a repeat of `ac7ed8b70847`, which was
reverted in `5556b94dedcb` because it was built on top of a commit
that needed to be reverted, but did not cause a regression itself.

An additional difference between this and the original patch
is that check_sysfs() has been changed to return a heap-allocated
string in this patch, whereas it had been deleted in the original
patch. Also, malloc/sprintf have been changed to calloc/snprintf
as suggested by quasisec@.

BUG=b:153598437
BRANCH=none
TEST=builds

Signed-off-by: Nikolai Artemiev <nartemiev@chromium.org>
Change-Id: I71f94ce0598d3b3ff24c789d6844e03d6df7ba8c
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/flashrom/+/2383220
Tested-by: Nikolai Artemiev <nartemiev@google.com>
Commit-Queue: Sam McNally <sammc@chromium.org>
Reviewed-by: Sam McNally <sammc@chromium.org>
Reviewed-by: Edward O'Callaghan <quasisec@chromium.org>
diff --git a/linux_spi.c b/linux_spi.c
index 4a0aba5..15921ed 100644
--- a/linux_spi.c
+++ b/linux_spi.c
@@ -48,6 +48,9 @@
 #define MODALIAS_FILE		"modalias"
 #define LINUX_SPI_SYSFS_ROOT	"/sys/bus/spi/devices"
 
+/* At least big enough to fit /dev/spidevX.Y */
+#define DEVFS_PATH_LEN 32
+
 static int fd = -1;
 #define BUF_SIZE_FROM_SYSFS	"/sys/module/spidev/parameters/bufsiz"
 static size_t max_kernel_buf_size;
@@ -72,11 +75,11 @@
 	.write_256	= linux_spi_write_256,
 };
 
-static char devfs_path[32]; 	/* at least big enough to fit /dev/spidevX.Y */
 static char *check_sysfs(void)
 {
 	int i;
 	const char *sysfs_path = NULL;
+	char *devfs_path = NULL;
 	char *p;
 	char *modalias[] = {
 		"spi:spidev",	/* raw access over SPI bus (newer kernels) */
@@ -100,7 +103,8 @@
 		if (sscanf(p, "spi%u.%u", &major, &minor) == 2) {
 			msg_pdbg("Found SPI device %s on spi%u.%u\n",
 				modalias[i], major, minor);
-			sprintf(devfs_path, "/dev/spidev%u.%u", major, minor);
+			devfs_path = calloc(1, DEVFS_PATH_LEN);
+			snprintf(devfs_path, DEVFS_PATH_LEN, "/dev/spidev%u.%u", major, minor);
 			free((void *)sysfs_path);
 			break;
 		}
@@ -116,10 +120,11 @@
 {
 	unsigned int bus, cs;
 
+	char *devfs_path = calloc(1, DEVFS_PATH_LEN);
 	if (fdt_find_spi_nor_flash(&bus, &cs) < 0)
 		return NULL;
 
-	sprintf(devfs_path, "/dev/spidev%u.%u", bus, cs);
+	snprintf(devfs_path, DEVFS_PATH_LEN, "/dev/spidev%u.%u", bus, cs);
 	return devfs_path;
 }
 
@@ -155,20 +160,12 @@
 	if (alias && alias->type != ALIAS_HOST)
 		return 1;
 
-	dev = extract_programmer_param("dev");
-	if (!dev)
-		dev = linux_spi_probe();
-	if (!dev || !strlen(dev)) {
-		msg_perr("No SPI device found. Use flashrom -p "
-			 "linux_spi:dev=/dev/spidevX.Y\n");
-		return 1;
-	}
-
 	p = extract_programmer_param("spispeed");
 	if (p && strlen(p)) {
 		speed_hz = (uint32_t)strtoul(p, &endp, 10) * 1000;
 		if (p == endp || speed_hz == 0) {
 			msg_perr("%s: invalid clock: %s kHz\n", __func__, p);
+			free(p);
 			return 1;
 		}
 	} else {
@@ -176,14 +173,26 @@
 			  "kHz clock. Use 'spispeed' parameter to override.\n",
 			  speed_hz / 1000);
 	}
+	free(p);
+
+	dev = extract_programmer_param("dev");
+	if (!dev)
+		dev = linux_spi_probe();
+	if (!dev || !strlen(dev)) {
+		msg_perr("No SPI device found. Use flashrom -p "
+			 "linux_spi:dev=/dev/spidevX.Y\n");
+		free(dev);
+		return 1;
+	}
 
 	msg_pdbg("Using device %s\n", dev);
 	if ((fd = open(dev, O_RDWR)) == -1) {
 		msg_perr("%s: failed to open %s: %s\n", __func__,
 			 dev, strerror(errno));
-
+		free(dev);
 		return 1;
 	}
+	free(dev);
 
 	if (register_shutdown(linux_spi_shutdown, NULL))
 		return 1;