This commit is contained in:
lw-everestlinux committed 2026-10-05 14:47:58 -04:00
1 parent c432274936
commit ee4bcc3b77
27 files changed
+2719 -589

No files matched your search

+65 -1
View File
@@ -20,6 +20,64 @@ typedef struct
}
dir_t;
/*
* On-disk layout. Each scope keeps everything it ever creates, renames
* or locks under ONE base directory it owns:
*
* /glacier/usr/<uid>/{index,store,links,stage,old,lock} owned by uid, 0700
* /glacier/sys/{index,store,links,stage,old,lock} root
*
* /glacier/usr itself is root-owned and not group/world-writable, so a
* user can never create (or squat) another uid's base; root creates
* each one (gl_init_user, via `gstore -n` directly or through doas).
* Every transaction step — stage, old/, lock, the commit renames — then
* happens inside a directory the acting user owns, which is what lets
* an unprivileged user run their own transactions at all.
*/
#define GL_USR_ROOT "/glacier/usr"
#define GL_SYS_ROOT "/glacier/sys"
static inline void
gl_usr_base(uid_t uid, char *out, size_t outsz)
{
snprintf(out, outsz, GL_USR_ROOT "/%u", (unsigned)uid);
}
typedef enum {
GL_USR_BASE_OK = 0,
GL_USR_BASE_MISSING, /* no /glacier/usr/<uid> yet: run gstore -n */
GL_USR_BASE_UNSAFE_ROOT, /* /glacier/usr not root-owned, or group/world-writable */
GL_USR_BASE_UNSAFE /* not a real dir, not owned by uid, or not 0700-ish */
} gl_usr_base_status_t;
/* Refuse to operate on a user base we didn't hand out. lstat(), never
* stat(): a symlink in place of /glacier/usr/<uid> is exactly what a
* squatter would plant. Backstop for the layout invariant above, so a
* hand-loosened /glacier/usr can't silently turn into one user writing
* another's store. */
static inline gl_usr_base_status_t
gl_usr_base_check(uid_t uid)
{
struct stat st;
if (lstat(GL_USR_ROOT, &st) != 0) { return GL_USR_BASE_MISSING; }
if (!S_ISDIR(st.st_mode) || st.st_uid != 0 ||
(st.st_mode & (S_IWGRP | S_IWOTH)) != 0) {
return GL_USR_BASE_UNSAFE_ROOT;
}
char base[PATH_MAX];
gl_usr_base(uid, base, sizeof(base));
if (lstat(base, &st) != 0) { return GL_USR_BASE_MISSING; }
if (!S_ISDIR(st.st_mode) || st.st_uid != uid ||
(st.st_mode & (S_IRWXG | S_IRWXO)) != 0) {
return GL_USR_BASE_UNSAFE;
}
return GL_USR_BASE_OK;
}
static inline int
gl_mkdirp(const char *path, mode_t mode)
{
@@ -52,7 +110,13 @@ gl_rmdir_recursive(const char *path)
struct dirent *ent;
while ((ent = readdir(dir))) {
if (ent->d_name[0] == '.') { continue; }
/* Only . and .. — skipping every dotfile left any directory
* containing one (a package's own dotfiles, the store's
* .displaced tree) impossible to rmdir, so the old/ and stage
* wipes silently failed and the next commit hit ENOTEMPTY. */
if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) {
continue;
}
char full[PATH_MAX];
snprintf(full, sizeof(full), "%s/%s", path, ent->d_name);