diff mbox series

[OpenWrt-Devel,procd] system: add "validate_firmware_image" ubus method

Message ID 20190830072834.23213-1-zajec5@gmail.com
State Accepted
Delegated to: Rafał Miłecki
Headers show
Series [OpenWrt-Devel,procd] system: add "validate_firmware_image" ubus method | expand

Commit Message

Rafał Miłecki Aug. 30, 2019, 7:28 a.m. UTC
From: Rafał Miłecki <rafal@milecki.pl>

This new method allows validating firmware image (stored on a device)
using ubus. It uses new executable helper that provides detailed info
about firmware image.

The point of this method is to allow user interfaces provide various
info before starting actual upgrade process.

Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
---
 system.c | 113 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 113 insertions(+)

Comments

Rafał Miłecki Aug. 30, 2019, 7:30 a.m. UTC | #1
On 30.08.2019 09:28, Rafał Miłecki wrote:
> This new method allows validating firmware image (stored on a device)
> using ubus. It uses new executable helper that provides detailed info
> about firmware image.
> 
> The point of this method is to allow user interfaces provide various
> info before starting actual upgrade process.

Example:

root@OpenWrt:/# ubus call system validate_firmware_image '{ "path": "/tmp/openwrt-brcm47xx-mips74k-standard-squashfs.trx" }'
{
	"tests": {
		"fwtool_signature": true,
		"fwtool_device_match": true
	},
	"valid": true,
	"forceable": true
}
diff mbox series

Patch

diff --git a/system.c b/system.c
index 738f327..35d5a23 100644
--- a/system.c
+++ b/system.c
@@ -25,6 +25,8 @@ 
 #include <unistd.h>
 #include <stdlib.h>
 
+#include <json-c/json_tokener.h>
+#include <libubox/blobmsg_json.h>
 #include <libubox/uloop.h>
 
 #include "procd.h"
@@ -376,6 +378,116 @@  static int proc_signal(struct ubus_context *ctx, struct ubus_object *obj,
 	return 0;
 }
 
+/**
+ * validate_firmware_image_call - perform validation & store result in global b
+ *
+ * @file: firmware image path
+ */
+static int validate_firmware_image_call(const char *file)
+{
+	const char *path = "/usr/libexec/validate_firmware_image";
+	json_tokener *tok;
+	json_object *jsobj;
+	char buf[64];
+	ssize_t len;
+	int fds[2];
+	int err;
+	int fd;
+
+	if (pipe(fds))
+		return -errno;
+
+	switch (fork()) {
+	case -1:
+		return -errno;
+	case 0:
+		/* Set stdin & stderr to /dev/null */
+		if (fd >= 0) {
+			dup2(fd, 0);
+			dup2(fd, 2);
+			close(fd);
+		}
+
+		/* Set stdout to the shared pipe */
+		dup2(fds[1], 1);
+		close(fds[0]);
+		close(fds[1]);
+
+		execl(path, path, file, NULL);
+		exit(errno);
+	}
+
+	/* Parent process */
+
+	tok = json_tokener_new();
+	if (!tok) {
+		close(fds[0]);
+		close(fds[1]);
+		return -ENOMEM;
+	}
+
+	blob_buf_init(&b, 0);
+	while ((len = read(fds[0], buf, sizeof(buf)))) {
+		jsobj = json_tokener_parse_ex(tok, buf, len);
+
+		if (json_tokener_get_error(tok) == json_tokener_success)
+			break;
+		else if (json_tokener_get_error(tok) == json_tokener_continue)
+			continue;
+		else
+			fprintf(stderr, "Failed to parse JSON: %d\n",
+				json_tokener_get_error(tok));
+	}
+
+	close(fds[0]);
+	close(fds[1]);
+
+	err = -ENOENT;
+	if (jsobj) {
+		if (json_object_get_type(jsobj) == json_type_object) {
+			blobmsg_add_object(&b, jsobj);
+			err = 0;
+		}
+
+		json_object_put(jsobj);
+	}
+
+	json_tokener_free(tok);
+
+	return err;
+}
+
+enum {
+	VALIDATE_FIRMWARE_IMAGE_PATH,
+	__VALIDATE_FIRMWARE_IMAGE_MAX,
+};
+
+static const struct blobmsg_policy validate_firmware_image_policy[__VALIDATE_FIRMWARE_IMAGE_MAX] = {
+	[VALIDATE_FIRMWARE_IMAGE_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING },
+};
+
+static int validate_firmware_image(struct ubus_context *ctx,
+				   struct ubus_object *obj,
+				   struct ubus_request_data *req,
+				   const char *method, struct blob_attr *msg)
+{
+	struct blob_attr *tb[__VALIDATE_FIRMWARE_IMAGE_MAX];
+
+	if (!msg)
+		return UBUS_STATUS_INVALID_ARGUMENT;
+
+	blobmsg_parse(validate_firmware_image_policy, __VALIDATE_FIRMWARE_IMAGE_MAX, tb, blob_data(msg), blob_len(msg));
+	if (!tb[VALIDATE_FIRMWARE_IMAGE_PATH])
+		return UBUS_STATUS_INVALID_ARGUMENT;
+
+	if (validate_firmware_image_call(blobmsg_get_string(tb[VALIDATE_FIRMWARE_IMAGE_PATH])))
+		return UBUS_STATUS_UNKNOWN_ERROR;
+
+	ubus_send_reply(ctx, req, b.head);
+
+	return UBUS_STATUS_OK;
+}
+
 enum {
 	SYSUPGRADE_PATH,
 	SYSUPGRADE_PREFIX,
@@ -426,6 +538,7 @@  static const struct ubus_method system_methods[] = {
 	UBUS_METHOD_NOARG("reboot", system_reboot),
 	UBUS_METHOD("watchdog", watchdog_set, watchdog_policy),
 	UBUS_METHOD("signal", proc_signal, signal_policy),
+	UBUS_METHOD("validate_firmware_image", validate_firmware_image, validate_firmware_image_policy),
 	UBUS_METHOD("sysupgrade", sysupgrade, sysupgrade_policy),
 };