diff options
| author | Leah Rowe <leah@libreboot.org> | 2026-03-22 16:43:28 +0000 |
|---|---|---|
| committer | Leah Rowe <leah@libreboot.org> | 2026-03-22 16:50:01 +0000 |
| commit | c766c819b320c0b08cc0cb8e7b98b300a72e5806 (patch) | |
| tree | 1567bad888fd2359a5658dadbf6af286e442591b /util | |
| parent | 7694b307b82d58bd6b08876c432e196baea5d0dc (diff) | |
WIP: fs_resolve_at
yes. mkhtemp is ccoming along nicely
Signed-off-by: Leah Rowe <leah@libreboot.org>
Diffstat (limited to 'util')
| -rw-r--r-- | util/nvmutil/include/common.h | 2 | ||||
| -rw-r--r-- | util/nvmutil/lib/file.c | 153 |
2 files changed, 155 insertions, 0 deletions
diff --git a/util/nvmutil/include/common.h b/util/nvmutil/include/common.h index 48de3b97..5803fa90 100644 --- a/util/nvmutil/include/common.h +++ b/util/nvmutil/include/common.h @@ -491,6 +491,8 @@ int close_on_eintr(int fd); int fsync_on_eintr(int fd); int fs_resolve(const char *path, int flags); int fs_root_fd(void); +int fs_mkdir_p_at(int dirfd, const char *path, mode_t mode); +int fs_resolve_at(int dirfd, const char *path, int flags); int fs_next_component(const char **p, char *name, size_t namesz); int fs_open_component(int dirfd, const char *name, diff --git a/util/nvmutil/lib/file.c b/util/nvmutil/lib/file.c index fd93bd6b..875f08a8 100644 --- a/util/nvmutil/lib/file.c +++ b/util/nvmutil/lib/file.c @@ -1932,6 +1932,159 @@ fs_root_fd(void) return open("/", O_RDONLY | O_DIRECTORY | O_CLOEXEC); } +/* implementation of: mkdir -p + */ +int +fs_mkdir_p_at(int dirfd, const char *path, mode_t mode) +{ + const char *p; + char name[256]; + int nextfd = -1; + int saved_errno = errno; + int close_errno; + int r; + int is_last; + + if (dirfd < 0 || path == NULL || *path == '\0') { + errno = EINVAL; + return -1; + } + + p = path; + + for (;;) { + + r = fs_next_component(&p, name, sizeof(name)); + if (r < 0) + goto err; + if (r == 0) + break; + + is_last = (*p == '\0'); + + /* TODO: consider more flags + * or make configurable + */ + nextfd = openat(dirfd, name, + O_RDONLY | O_DIRECTORY | O_CLOEXEC); + + if (nextfd < 0) { + + if (errno != ENOENT) + goto err; + + if (mkdirat(dirfd, name, mode) < 0) + goto err; + + /* TODO: consider more flags + * or make configurable? + */ + nextfd = openat(dirfd, name, + O_RDONLY | O_DIRECTORY | O_CLOEXEC); + if (nextfd < 0) + goto err; + } + + close_errno = errno; + (void) close_on_eintr(dirfd); + errno = close_errno; + + dirfd = nextfd; + nextfd = -1; + } + + errno = saved_errno; + return 0; + +err: + saved_errno = errno; + + if (dirfd >= 0) + (void) close_on_eintr(dirfd); + if (nextfd >= 0) + (void) close_on_eintr(nextfd); + + errno = saved_errno; + return -1; +} + +/* use in conjunction with fs_resolve. example: + * int rootfd = fs_resolve("/safe/root", O_RDONLY | O_DIRECTORY); + * now, you can resolve everything relatively, for instance: + * fd = fs_resolve_at(rootfd, "file.txt", O_RDONLY); + * if a user then tries e.g. ../etc/password ?????? + * BLOCKED + * basically userspace sandboxing, similar to e.g. + * openbsd unveil + * freebsd capsicum + * openat2 RESOLVE_BENEATH + * ...but in ****userspace**** + * no need for chroot (you should still use one in critical code) + * cannot escape the relative root that you set. + * no dependence on CWD + * probably safe in multi-threaded code (with some care) + * + * ps: you should still use unveil. unveil is awesome. + */ +int +fs_resolve_at(int dirfd, const char *path, int flags) +{ + int nextfd = -1; + const char *p; + char name[256]; /* TODO: make configurable */ + int saved_errno = errno; + int saved_close_errno; + int r; + int is_last; + + if (dirfd < 0 || + path == NULL || + *path == '\0') { + + errno = EINVAL; + return -1; + } + + p = path; + + for (;;) { + + r = fs_next_component(&p, name, sizeof(name)); + if (r < 0) + goto err; + if (r == 0) + break; + + is_last = (*p == '\0'); + + nextfd = fs_open_component(dirfd, + name, flags, is_last); + if (nextfd < 0) + goto err; + + saved_close_errno = errno; + (void) close_on_eintr(dirfd); + errno = saved_close_errno; + + dirfd = nextfd; + nextfd = -1; + } + + errno = saved_errno; + return dirfd; + +err: + saved_errno = errno; + + if (dirfd >= 0) + close(dirfd); + if (nextfd >= 0) + close(nextfd); + + errno = saved_errno; + return -1; +} + int fs_next_component(const char **p, char *name, size_t namesz) |
