mail archive of the barebox mailing list
 help / color / mirror / Atom feed
From: Jonas Licht <jonas.licht@gmail.com>
To: barebox@lists.infradead.org
Cc: Jonas Licht <jonas.licht@gmail.com>
Subject: [PATCH v2] environment: support reading and writing of efivar
Date: Tue, 18 Mar 2025 17:32:51 +0100	[thread overview]
Message-ID: <20250318163251.352-1-jonas.licht@gmail.com> (raw)
In-Reply-To: <20250311141713.30947-1-jonas.licht@gmail.com>

scripts/bareboxenv: skip file creation to allow reading the destination
file, when existing.

In envfs_load before reading the superblock, we check if our superblock
magic exists after an EFIVAR_ATTR_SIZE offset. This is necessary because
linux kernel adds four byte variable attributes in front of each efi
variable in sysfs. When the magic is found after EFIVAR_ATTR_SIZE, we
skip reading the four bytes variable attributes.
For envfs_save detection of an efi var is done the same way. But we need
to keep the attributes, as they are required for writing as well.

In order to write to efivars, you still need to remove immutable flag
from the file with 'chattr -i' .

Signed-off-by: Jonas Licht <jonas.licht@gmail.com>
Fixes: #29
Link: https://github.com/barebox/barebox/issues/29
---
 common/environment.c | 80 ++++++++++++++++++++++++++++++++++++++++----
 scripts/Makefile     |  2 ++
 scripts/bareboxenv.c | 11 +-----
 3 files changed, 76 insertions(+), 17 deletions(-)

diff --git a/common/environment.c b/common/environment.c
index 37adb5d678..b91c3e0afa 100644
--- a/common/environment.c
+++ b/common/environment.c
@@ -32,8 +32,11 @@
 #include <magicvar.h>
 #else
 #define EXPORT_SYMBOL(x)
+#include <autoconf.h>
 #endif
 
+#define EFIVAR_ATTR_SIZE 4
+
 struct envfs_entry {
 	char *name;
 	void *buf;
@@ -290,6 +293,41 @@ static int file_remove_action(const char *filename, struct stat *statbuf,
 }
 #endif
 
+static int detect_efi_vars(int fd, void* buf_with_efi, void** wbuf, int *size) {
+	uint32_t magic;
+	int ret;
+
+	*wbuf = buf_with_efi + EFIVAR_ATTR_SIZE;
+#ifndef CONFIG_EFI
+		return 0;
+#endif
+
+	ret = pread(fd, &magic, sizeof(uint32_t),
+		EFIVAR_ATTR_SIZE);
+	if (ret == -1 && errno == ENOENT) {
+		perror("pread");
+		// skip as file don't exist
+		return 0;
+	}
+	if (ret < sizeof(u_int32_t)) {
+		perror("pread");
+		return 0;
+	}
+
+	if (ENVFS_32(magic) == ENVFS_MAGIC) {
+		pr_info("Assuming EFI variable. Keeping attributes\n");
+		ret = pread(fd, buf_with_efi, EFIVAR_ATTR_SIZE, 0);
+		if (ret < EFIVAR_ATTR_SIZE) {
+			ret = -errno;
+			perror("read of efi attributes failed");
+			return ret;
+		}
+		*size += EFIVAR_ATTR_SIZE;
+		*wbuf = buf_with_efi;
+	}
+	return 0;
+}
+
 /**
  * Make the current environment persistent
  * @param[in] filename where to store
@@ -305,7 +343,7 @@ int envfs_save(const char *filename, const char *dirname, unsigned flags)
 	struct envfs_super *super;
 	int envfd, size, ret;
 	struct action_data data = {};
-	void *buf = NULL, *wbuf;
+	void *buf = NULL, *wbuf = NULL, *buf_with_efi;
 	struct envfs_entry *env;
 	const char *defenv_path = default_environment_path_get();
 
@@ -342,7 +380,9 @@ int envfs_save(const char *filename, const char *dirname, unsigned flags)
 		}
 	}
 
-	buf = xzalloc(size + sizeof(struct envfs_super));
+	buf_with_efi = xzalloc(size + sizeof(struct envfs_super) +
+	EFIVAR_ATTR_SIZE);
+	buf = buf_with_efi + EFIVAR_ATTR_SIZE;
 	data.writep = buf + sizeof(struct envfs_super);
 
 	super = buf;
@@ -370,7 +410,7 @@ int envfs_save(const char *filename, const char *dirname, unsigned flags)
 	super->crc = ENVFS_32(crc32(0, buf + sizeof(struct envfs_super), size));
 	super->sb_crc = ENVFS_32(crc32(0, buf, sizeof(struct envfs_super) - 4));
 
-	envfd = open(filename, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
+	envfd = open(filename, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
 	if (envfd < 0) {
 		printf("could not open %s: %m\n", filename);
 		ret = -errno;
@@ -385,6 +425,12 @@ int envfs_save(const char *filename, const char *dirname, unsigned flags)
 		goto out;
 	}
 
+	/* check if we writing efi vars */
+	ret = detect_efi_vars(envfd, buf_with_efi, &wbuf, &size);
+	if (ret != 0) {
+		goto out;
+	}
+
 	ret = erase(envfd, ERASE_SIZE_ALL, 0, ERASE_TO_WRITE);
 
 	/* ENOSYS and EOPNOTSUPP aren't errors here, many devices don't need it */
@@ -395,12 +441,11 @@ int envfs_save(const char *filename, const char *dirname, unsigned flags)
 
 	size += sizeof(struct envfs_super);
 
-	wbuf = buf;
-
 	while (size) {
 		ssize_t now = write(envfd, wbuf, size);
 		if (now < 0) {
 			ret = -errno;
+			perror("write");
 			goto out;
 		}
 
@@ -418,14 +463,14 @@ int envfs_save(const char *filename, const char *dirname, unsigned flags)
 
 	ret = 0;
 
-#ifdef CONFIG_NVVAR
+#if defined CONFIG_NVVAR && defined __BAREBOX__
 	if (defenv_path && !strcmp(filename, defenv_path))
 	    nv_var_set_clean();
 #endif
 out:
 	close(envfd);
 out1:
-	free(buf);
+	free(buf_with_efi);
 #ifdef __BAREBOX__
 	unlink_recursive(TMPDIR, NULL);
 #endif
@@ -449,6 +494,7 @@ int envfs_load(const char *filename, const char *dir, unsigned flags)
 	int envfd;
 	int ret = 0;
 	size_t size, rsize;
+	uint32_t magic;
 
 	if (!filename)
 		filename = default_environment_path_get();
@@ -466,6 +512,26 @@ int envfs_load(const char *filename, const char *dir, unsigned flags)
 		return -1;
 	}
 
+	/* check if we reading efi vars */
+	ret = pread(envfd, &magic, sizeof(uint32_t),
+		    EFIVAR_ATTR_SIZE);
+	if (ret < sizeof(u_int32_t)) {
+		perror("read");
+		ret = -errno;
+		goto out;
+	}
+
+	if (ENVFS_32(magic) == ENVFS_MAGIC) {
+		pr_info("Assuming EFI variable. Skip attributes\n");
+		ret = read(envfd, &magic,
+			   sizeof(uint32_t)); // simply reuse the memory
+		if (ret < sizeof(uint32_t)) {
+			perror("read");
+			ret = -errno;
+			goto out;
+		}
+	}
+
 	/* read superblock */
 	ret = read(envfd, &super, sizeof(struct envfs_super));
 	if ( ret < sizeof(struct envfs_super)) {
diff --git a/scripts/Makefile b/scripts/Makefile
index 6d89af7d4f..57d8ddb54d 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -30,6 +30,7 @@ hostprogs-always-$(CONFIG_RK_IMAGE)			+= rkimage
 HOSTCFLAGS_rkimage.o = `$(PKG_CONFIG) --cflags openssl`
 HOSTLDLIBS_rkimage = `$(PKG_CONFIG) --libs openssl`
 KBUILD_HOSTCFLAGS += -I$(srctree)/scripts/include/
+KBUILD_HOSTCFLAGS += -I$(objtree)/include/generated/
 HOSTCFLAGS_mxsimage.o = `$(PKG_CONFIG) --cflags openssl`
 HOSTLDLIBS_mxsimage  = `$(PKG_CONFIG) --libs openssl`
 HOSTCFLAGS_omap3-usb-loader.o = `$(PKG_CONFIG) --cflags libusb-1.0`
@@ -57,6 +58,7 @@ omap4_usbboot-target-userccflags += `$(CROSS_PKG_CONFIG) --cflags libusb-1.0`
 omap4_usbboot-target-userldlibs += -lpthread `$(CROSS_PKG_CONFIG) --libs libusb-1.0`
 rk-usb-loader-target-userccflags += `$(CROSS_PKG_CONFIG) --cflags libusb-1.0`
 rk-usb-loader-target-userldlibs += `$(CROSS_PKG_CONFIG) --libs libusb-1.0`
+bareboxenv-target-userccflags += -I$(objtree)/include/generated/
 
 userccflags += -I $(srctree)/$(src)/include -isystem $(srctree)/scripts/include
 
diff --git a/scripts/bareboxenv.c b/scripts/bareboxenv.c
index e954447015..6b9b8d90c4 100644
--- a/scripts/bareboxenv.c
+++ b/scripts/bareboxenv.c
@@ -117,7 +117,7 @@ static void usage(char *prgname)
 int main(int argc, char *argv[])
 {
 	int opt;
-	int save = 0, load = 0, pad = 0, err = 0, fd;
+	int save = 0, load = 0, pad = 0, err = 0;
 	char *filename = NULL, *dirname = NULL;
 	unsigned envfs_flags = 0;
 	int verbose = 0;
@@ -156,15 +156,6 @@ int main(int argc, char *argv[])
 		exit(1);
 	}
 
-	if (save) {
-		fd = open(filename, O_CREAT | O_TRUNC | O_WRONLY, 0644);
-		if (fd < 0) {
-			perror("open");
-			exit(1);
-		}
-		close(fd);
-	}
-
 	if (save && pad) {
 		if (truncate(filename, pad)) {
 			perror("truncate");
-- 
2.45.3




      parent reply	other threads:[~2025-03-18 16:47 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-03-11 14:17 [PATCH] " Jonas Licht
2025-03-17 10:42 ` Ahmad Fatoum
2025-03-18 16:32 ` Jonas Licht [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250318163251.352-1-jonas.licht@gmail.com \
    --to=jonas.licht@gmail.com \
    --cc=barebox@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox