mirror of
https://codeberg.org/libreboot/lbmk.git
synced 2026-03-25 13:29:03 +02:00
WIP: fs_resolve_at
yes. mkhtemp is ccoming along nicely Signed-off-by: Leah Rowe <leah@libreboot.org>
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user