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 v4] environment: support reading and writing of efivar
Date: Thu, 24 Apr 2025 14:59:58 +0200	[thread overview]
Message-ID: <20250424130000.13763-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 with fstatfs if the file
descriptor is pointing to an efi vars.
If this is the case 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.
We only do the fstatfs in scripts/bareboxenv as it is not needed in
__BAREBOX__

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 | 58 ++++++++++++++++++++++++++++++++++++++------
 scripts/bareboxenv.c | 26 ++++++++++++--------
 2 files changed, 67 insertions(+), 17 deletions(-)

diff --git a/common/environment.c b/common/environment.c
index 37adb5d678..e7a77807f9 100644
--- a/common/environment.c
+++ b/common/environment.c
@@ -34,6 +34,8 @@
 #define EXPORT_SYMBOL(x)
 #endif
 
+#define EFIVAR_ATTR_SIZE 4
+
 struct envfs_entry {
 	char *name;
 	void *buf;
@@ -147,6 +149,11 @@ static int do_compare_file(const char *filename, const char *base)
 	return ret;
 }
 
+static bool is_efivarsfs_fd(int fd)
+{
+	return false;
+}
+
 #else
 #define ERASE_SIZE_ALL 0
 static inline int protect(int fd, size_t count, unsigned long offset, int prot)
@@ -290,6 +297,25 @@ 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) {
+	int ret;
+
+	*wbuf = buf_with_efi + EFIVAR_ATTR_SIZE;
+	if (!is_efivarsfs_fd(fd))
+		return 0;
+
+	pr_info("Assuming EFI variable. Keeping attributes\n");
+	ret = read(fd, buf_with_efi, EFIVAR_ATTR_SIZE);
+	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 +331,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 +368,8 @@ 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 +397,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 +412,11 @@ 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 +427,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 +449,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 +480,7 @@ int envfs_load(const char *filename, const char *dir, unsigned flags)
 	int envfd;
 	int ret = 0;
 	size_t size, rsize;
+	uint32_t efi_attributes;
 
 	if (!filename)
 		filename = default_environment_path_get();
@@ -466,6 +498,18 @@ int envfs_load(const char *filename, const char *dir, unsigned flags)
 		return -1;
 	}
 
+	/* check if we reading efi vars */
+	if (is_efivarsfs_fd(envfd)) {
+		pr_info("Assuming EFI variable. Skip attributes\n");
+		ret = read(envfd, &efi_attributes,
+			   EFIVAR_ATTR_SIZE);
+		if (ret < EFIVAR_ATTR_SIZE) {
+			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/bareboxenv.c b/scripts/bareboxenv.c
index e954447015..b0da965eba 100644
--- a/scripts/bareboxenv.c
+++ b/scripts/bareboxenv.c
@@ -6,6 +6,9 @@
 #include <stdio.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/statfs.h>
+#include <linux/magic.h>
+#include <stdbool.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <stdint.h>
@@ -83,6 +86,18 @@ static char *concat_subpath_file(const char *path, const char *f)
 	return concat_path_file(path, f);
 }
 
+static bool is_efivarsfs_fd(int fd)
+{
+	struct statfs env_statfs;
+	int ret;
+
+	ret = fstatfs(fd, &env_statfs);
+	if (ret)
+		return false;
+
+	return env_statfs.f_type == EFIVARFS_MAGIC;
+}
+
 #include <linux/list.h>
 #include <linux/list_sort.h>
 #include "../lib/list_sort.c"
@@ -117,7 +132,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 +171,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.49.0




      parent reply	other threads:[~2025-04-24 13:50 UTC|newest]

Thread overview: 7+ 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 ` [PATCH v2] " Jonas Licht
2025-03-20  9:22 ` [PATCH v3] " Jonas Licht
2025-04-04 14:51   ` Ahmad Fatoum
2025-04-24 13:04     ` Jonas Licht
2025-04-24 12:59 ` 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=20250424130000.13763-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