util/nvmutil: tighter pledge and unveil

call it sooner. set new_state afterward.

i had to uncouple nv from some functions
for this, and i also added some extra
checks especially at exit, about whether
to touch nv (whether it is initialised)

Signed-off-by: Leah Rowe <leah@libreboot.org>
This commit is contained in:
Leah Rowe
2026-03-17 22:14:48 +00:00
parent 6e6b1dd366
commit 72dab46dbc
2 changed files with 73 additions and 67 deletions
+68 -66
View File
@@ -151,6 +151,10 @@ main(int argc, char *argv[])
{ {
struct commands *cmd; struct commands *cmd;
struct xfile *f; struct xfile *f;
int fd;
struct stat st;
char *tmp_path = NULL;
unsigned long *i; unsigned long *i;
@@ -161,33 +165,21 @@ main(int argc, char *argv[])
err(EINVAL, "Unsupported char size"); err(EINVAL, "Unsupported char size");
#endif #endif
nv = new_xstate();
if (nv == NULL)
err(errno, NULL);
if (nv->f.buf == NULL)
err(EINVAL, "Work buffer not initialised");
nv->argv0 = argv[0];
if (argc < 3) if (argc < 3)
usage(); usage();
f = &nv->f;
f->fname = argv[1];
#ifdef NVMUTIL_UNVEIL #ifdef NVMUTIL_UNVEIL
/* /*
* if global tmp is a different filesystem, * if global tmp is a different filesystem,
* unveil would trap on final file rename * unveil would trap on final file rename
* and we can't know the path in advance * and we can't know the path in advance
*/ */
f->tname = new_tmpfile(&f->tmp_fd, 1, NULL); tmp_path = new_tmpfile(&fd, 1, NULL);
#else #else
f->tname = new_tmpfile(&f->tmp_fd, 0, NULL); tmp_path = new_tmpfile(&fd, 0, NULL);
#endif #endif
if (f->tname == NULL) if (tmp_path == NULL)
err(errno, "Can't create tmpfile"); err(errno, "Can't create tmpfile");
#ifdef NVMUTIL_PLEDGE #ifdef NVMUTIL_PLEDGE
@@ -204,6 +196,26 @@ main(int argc, char *argv[])
#endif #endif
#endif #endif
nv = new_xstate();
if (nv == NULL)
err(errno, NULL);
if (nv->f.buf == NULL)
err(EINVAL, "Work buffer not initialised");
nv->argv0 = argv[0];
f = &nv->f;
f->fname = argv[1];
f->tname = tmp_path;
f->tmp_fd = fd;
if(fstat(fd, &st) < 0)
err(errno, "can't stat tmpfile");
f->tmp_dev = st.st_dev;
f->tmp_ino = st.st_ino;
sanitize_command_list(); sanitize_command_list();
set_cmd(argc, argv); set_cmd(argc, argv);
@@ -214,11 +226,11 @@ main(int argc, char *argv[])
#ifdef NVMUTIL_UNVEIL #ifdef NVMUTIL_UNVEIL
if (cmd->flags == O_RDONLY) { if (cmd->flags == O_RDONLY) {
if (unveil(fname, "r") == -1) if (unveil(f->fname, "r") == -1)
err(errno, "%s: unveil r", fname); err(errno, "%s: unveil r", f->fname);
} else { } else {
if (unveil(fname, "rwc") == -1) if (unveil(f->tname, "rwc") == -1)
err(errno, "%s: unveil rw", fname); err(errno, "%s: unveil rw", f->tname);
} }
if (unveil(tname, "rwc") == -1) if (unveil(tname, "rwc") == -1)
@@ -513,19 +525,18 @@ open_gbe_file(void)
err(EINVAL, "File size must be 8KB, 16KB or 128KB"); err(EINVAL, "File size must be 8KB, 16KB or 128KB");
} }
if (lock_file(f->gbe_fd) == -1) if (lock_file(f->gbe_fd, cmd->flags) == -1)
err(errno, "%s: can't lock", f->fname); err(errno, "%s: can't lock", f->fname);
} }
int int
lock_file(int fd) lock_file(int fd, int flags)
{ {
struct flock fl; struct flock fl;
struct commands *cmd = &nv->cmd[nv->i];
memset(&fl, 0, sizeof(fl)); memset(&fl, 0, sizeof(fl));
if (cmd->flags == O_RDONLY) if ((flags & O_ACCMODE) == O_RDONLY)
fl.l_type = F_RDLCK; fl.l_type = F_RDLCK;
else else
fl.l_type = F_WRLCK; fl.l_type = F_WRLCK;
@@ -2340,8 +2351,6 @@ usage(void)
void void
err(int nvm_errval, const char *msg, ...) err(int nvm_errval, const char *msg, ...)
{ {
struct xfile *f = &nv->f;
va_list args; va_list args;
if (errno == 0) if (errno == 0)
@@ -2357,12 +2366,7 @@ err(int nvm_errval, const char *msg, ...)
vfprintf(stderr, msg, args); vfprintf(stderr, msg, args);
va_end(args); va_end(args);
fprintf(stderr, ": %s", strerror(errno)); fprintf(stderr, ": %s\n", strerror(errno));
fprintf(stderr, "\n");
if (f->tname != NULL)
free(f->tname);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
@@ -2370,28 +2374,32 @@ err(int nvm_errval, const char *msg, ...)
int int
exit_cleanup(void) exit_cleanup(void)
{ {
struct xfile *f = &nv->f; struct xfile *f;
int close_err = 0; int close_err = 0;
int saved_errno = errno; int saved_errno = errno;
if (f->gbe_fd > -1) { if (nv != NULL) {
if (x_i_close(f->gbe_fd) == -1) f = &nv->f;
close_err = 1;
f->gbe_fd = -1;
}
if (f->tmp_fd > -1) { if (f->gbe_fd > -1) {
if (x_i_close(f->tmp_fd) == -1) if (x_i_close(f->gbe_fd) == -1)
close_err = 1; close_err = 1;
} f->gbe_fd = -1;
}
if (f->tname != NULL) { if (f->tmp_fd > -1) {
if (unlink(f->tname) == -1) if (x_i_close(f->tmp_fd) == -1)
close_err = 1; close_err = 1;
} }
f->tmp_fd = -1; if (f->tname != NULL) {
if (unlink(f->tname) == -1)
close_err = 1;
}
f->tmp_fd = -1;
}
if (saved_errno) if (saved_errno)
errno = saved_errno; errno = saved_errno;
@@ -2445,8 +2453,6 @@ getnvmprogname(void)
char * char *
new_tmpfile(int *fd, int local, const char *path) new_tmpfile(int *fd, int local, const char *path)
{ {
struct xfile *f = &nv->f;
unsigned long maxlen; unsigned long maxlen;
struct stat st; struct stat st;
@@ -2563,7 +2569,20 @@ new_tmpfile(int *fd, int local, const char *path)
if (x_i_fchmod(fd_tmp, 0600) == -1) if (x_i_fchmod(fd_tmp, 0600) == -1)
goto err_new_tmpfile; goto err_new_tmpfile;
if (lock_file(fd_tmp) == -1) flags = fcntl(fd_tmp, F_GETFL);
if (flags == -1)
goto err_new_tmpfile;
/*
* O_APPEND would permit offsets
* to be ignored, which breaks
* positional read/write
*/
if (flags & O_APPEND)
goto err_new_tmpfile;
if (lock_file(fd_tmp, flags) == -1)
goto err_new_tmpfile; goto err_new_tmpfile;
if (fstat(fd_tmp, &st) == -1) if (fstat(fd_tmp, &st) == -1)
@@ -2582,10 +2601,6 @@ new_tmpfile(int *fd, int local, const char *path)
if (lseek(fd_tmp, 0, SEEK_CUR) == (off_t)-1) if (lseek(fd_tmp, 0, SEEK_CUR) == (off_t)-1)
goto err_new_tmpfile; goto err_new_tmpfile;
/* inode will be checked later on write */
f->tmp_dev = st.st_dev;
f->tmp_ino = st.st_ino;
/* tmpfile has >1 hardlinks */ /* tmpfile has >1 hardlinks */
if (st.st_nlink > 1) if (st.st_nlink > 1)
goto err_new_tmpfile; goto err_new_tmpfile;
@@ -2594,19 +2609,6 @@ new_tmpfile(int *fd, int local, const char *path)
if (st.st_nlink == 0) if (st.st_nlink == 0)
goto err_new_tmpfile; goto err_new_tmpfile;
flags = fcntl(fd_tmp, F_GETFL);
if (flags == -1)
goto err_new_tmpfile;
/*
* O_APPEND would permit offsets
* to be ignored, which breaks
* positional read/write
*/
if (flags & O_APPEND)
goto err_new_tmpfile;
*fd = fd_tmp; *fd = fd_tmp;
return dest; return dest;
+5 -1
View File
@@ -66,6 +66,10 @@
#define EXIT_SUCCESS 0 #define EXIT_SUCCESS 0
#endif #endif
#ifndef O_ACCMODE
#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
#endif
#ifndef O_BINARY #ifndef O_BINARY
#define O_BINARY 0 #define O_BINARY 0
#endif #endif
@@ -311,7 +315,7 @@ int xstrxcmp(const char *a, const char *b, unsigned long maxlen);
* Prep files for reading * Prep files for reading
*/ */
void open_gbe_file(void); void open_gbe_file(void);
int lock_file(int fd); int lock_file(int fd, int flags);
void xopen(int *fd, const char *path, int flags, struct stat *st); void xopen(int *fd, const char *path, int flags, struct stat *st);
/* /*