Refuse base-repo installs under GL_SCOPE_USR at the library level

gl_install_pkg now returns GL_INSTALL_ERR_SCOPE for
scope == GL_SCOPE_USR && repo == "base", checked immediately after
manifest parse and before any store path construction or filesystem
mutation. Per SECURITY_DESIGN.txt section 8: enforced in the library
rather than a CLI, since the split-.so architecture lets third-party
tools call gl_install_pkg directly.

Also drops src/istoreutils.c.rej, .c.back, .h.back — stale leftovers
from the uid -> gl_context_t migration patch; that migration is fully
present in the current tree, so these were dead weight.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
lw-everestlinuxandClaude Sonnet 5 committed 2026-09-18 11:20:59 -04:00
1 parent 7b22e3746a
commit c432274936
5 files changed
+22 -1768

No files matched your search

+21
View File
@@ -1189,6 +1189,27 @@ gl_install_pkg(gl_context_t *ctx, const char *gpkg_path)
return GL_INSTALL_ERR_MANIFEST; return GL_INSTALL_ERR_MANIFEST;
} }
/*
* Base-repo packages can NEVER be installed under per-user scope.
* Enforced here, at the library level, rather than in any CLI: the
* split-.so architecture means a third-party tool can call
* gl_install_pkg directly without going through gpkg/syspkg, and a
* rule only one CLI respects is not a real guarantee. See
* SECURITY_DESIGN.txt section 8.
*
* This is the earliest possible point — pkg.pkg_repo only exists
* once the manifest is parsed — and deliberately sits before any
* store path construction or filesystem mutation below.
*/
if (ctx->scope == GL_SCOPE_USR &&
strcmp(pkg.pkg_repo, GL_BASE_REPO) == 0) {
lg_printf(2,
"Refusing to install base-repo package '%s' under user scope.",
pkg.pkg_name);
gl_free_pkg(&pkg);
return GL_INSTALL_ERR_SCOPE;
}
char pkg_store_base[PATH_MAX]; char pkg_store_base[PATH_MAX];
char pkg_store_final[PATH_MAX]; char pkg_store_final[PATH_MAX];
File diff suppressed because it is too large. Load diff
-302
View File
@@ -1,302 +0,0 @@
--- istoreutils.c.orig 2026-06-01 19:43:00.493773073 +0000
+++ istoreutils.c.new 2026-06-01 19:43:00.573469330 +0000
@@ -21,6 +21,7 @@
#include "istoreutils.h"
#include "log.h"
#include "pkg.h"
+#include "transaction.h"
static const dir_t usr_index = { "/glacier/usr/index", 0700 };
static const dir_t sys_index = { "/glacier/sys/index", 0700 };
@@ -29,6 +30,7 @@
static const dir_t sys_store = { "/glacier/sys/store", 0700 };
static const dir_t usr_links = { "/glacier/usr/links", 0700 };
+static const dir_t sys_links = { "/glacier/sys/links", 0700 };
bool
gl_usr_istore_exists(index_store_t index_or_store, int uid)
@@ -253,6 +255,46 @@
return 0;
}
+int
+gl_init_sys(bool isVerbose)
+{
+ const char *paths[] = {
+ sys_index.path,
+ sys_store.path,
+ sys_links.path,
+ };
+ mode_t modes[] = {
+ sys_index.mode,
+ sys_store.mode,
+ sys_links.mode,
+ };
+
+ for (int i = 0; i < 3; i++) {
+ if (isVerbose) { lg_printf(0, "Creating %s", paths[i]); }
+
+ if (mkdir(paths[i], modes[i]) == -1) {
+ switch (errno) {
+ case EEXIST:
+ break;
+ case EACCES:
+ lg_printf(2, "Cannot create %s: permission denied", paths[i]);
+ return 1;
+ case ENOSPC:
+ lg_printf(2, "Cannot create %s: no space left on device", paths[i]);
+ return 1;
+ case EROFS:
+ lg_printf(2, "Cannot create %s: read-only filesystem", paths[i]);
+ return 1;
+ default:
+ lg_printf(2, "Cannot create %s: mkdir failed", paths[i]);
+ return -1;
+ }
+ }
+ }
+
+ return 0;
+}
+
static void
trim(char *s)
{
@@ -409,12 +451,11 @@
*/
int
-gl_rebuild_index(uid_t uid, const char *out_dir)
+gl_rebuild_index(gl_context_t *ctx)
{
- char store_path[PATH_MAX];
- snprintf(store_path, sizeof(store_path), "%s/%d", usr_store.path, uid);
+ if (!ctx) { return -1; }
- DIR *store_dir = opendir(store_path);
+ DIR *store_dir = opendir(ctx->store_path);
if (!store_dir) return -1;
/* Write to a new timestamped index file */
@@ -422,7 +463,8 @@
make_index_name(fname, sizeof(fname));
char new_index_path[PATH_MAX];
- snprintf(new_index_path, sizeof(new_index_path), "%s/%s", out_dir, fname);
+ snprintf(new_index_path, sizeof(new_index_path), "%s/%s",
+ ctx->index_path, fname);
FILE *out = fopen(new_index_path, "w");
if (!out) {
@@ -438,7 +480,7 @@
char repo_path[PATH_MAX];
snprintf(repo_path, sizeof(repo_path), "%s/%s",
- store_path, repo_ent->d_name);
+ ctx->store_path, repo_ent->d_name);
struct stat rst;
if (stat(repo_path, &rst) != 0 || !S_ISDIR(rst.st_mode)) {
@@ -476,14 +518,15 @@
if (!tmp_in) return -1;
char tmp_path[PATH_MAX];
- snprintf(tmp_path, sizeof(tmp_path), "%s/.index_tmp_XXXXXX", out_dir);
+ snprintf(tmp_path, sizeof(tmp_path), "%s/.index_tmp_XXXXXX",
+ ctx->index_path);
int tmp_fd = mkstemp(tmp_path);
if (tmp_fd < 0) { fclose(tmp_in); return -1; }
FILE *tmp_out = fdopen(tmp_fd, "w");
if (!tmp_out) { close(tmp_fd); fclose(tmp_in); return -1; }
- fprintf(tmp_out, "uid = %d\n", uid);
+ fprintf(tmp_out, "uid = %d\n", ctx->uid);
fprintf(tmp_out, "listed = %zu\n\n", listed);
char line[512];
@@ -494,15 +537,15 @@
fclose(tmp_out);
rename(tmp_path, new_index_path);
- chown(new_index_path, uid, (gid_t)-1);
+ chown(new_index_path, ctx->uid, (gid_t)-1);
/* Update the "current" symlink to point at the new index */
char link_path[PATH_MAX];
- snprintf(link_path, sizeof(link_path), "%s/current", out_dir);
+ snprintf(link_path, sizeof(link_path), "%s/current", ctx->index_path);
unlink(link_path);
if (symlink(fname, link_path) != 0) { return -1; }
- lchown(link_path, uid, (gid_t)-1);
+ lchown(link_path, ctx->uid, (gid_t)-1);
return 0;
}
@@ -672,10 +715,10 @@
}
static int
-gl_unlink_pkg(const char *pkg_store_final, uid_t uid)
+gl_unlink_pkg(gl_context_t *ctx, const char *pkg_store_final)
{
char links_base[PATH_MAX];
- snprintf(links_base, sizeof(links_base), "%s/%d", usr_links.path, uid);
+ strncpy(links_base, ctx->links_path, PATH_MAX - 1);
size_t strip_len = strlen(pkg_store_final);
@@ -729,12 +772,14 @@
}
gl_remove_status_t
-gl_remove_pkg(const char *pkg_name, const char *pkg_repo, uid_t uid)
+gl_remove_pkg(gl_context_t *ctx, const char *pkg_name, const char *pkg_repo)
{
+ if (!ctx) { return GL_REMOVE_ERR_NOT_FOUND; }
+
/* find the package base directory in the store */
char pkg_store_base[PATH_MAX];
snprintf(pkg_store_base, sizeof(pkg_store_base),
- "%s/%d/%s/%s", usr_store.path, uid, pkg_repo, pkg_name);
+ "%s/%s/%s", ctx->store_path, pkg_repo, pkg_name);
struct stat st;
if (stat(pkg_store_base, &st) != 0 || !S_ISDIR(st.st_mode)) {
@@ -760,7 +805,7 @@
}
/* remove symlinks from links tree */
- if (gl_unlink_pkg(pkg_store_final, uid) != 0) {
+ if (gl_unlink_pkg(ctx, pkg_store_final) != 0) {
return GL_REMOVE_ERR_UNLINK;
}
@@ -770,10 +815,7 @@
}
/* rebuild index */
- char index_dir[PATH_MAX];
- snprintf(index_dir, sizeof(index_dir), "%s/%d", usr_index.path, uid);
-
- if (gl_rebuild_index(uid, index_dir) != 0) {
+ if (gl_rebuild_index(ctx) != 0) {
return GL_REMOVE_ERR_INDEX;
}
@@ -781,10 +823,10 @@
}
static int
-gl_link_pkg(const char *pkg_store_final, uid_t uid)
+gl_link_pkg(gl_context_t *ctx, const char *pkg_store_final)
{
char links_base[PATH_MAX];
- snprintf(links_base, sizeof(links_base), "%s/%d", usr_links.path, uid);
+ strncpy(links_base, ctx->links_path, PATH_MAX - 1);
size_t strip_len = strlen(pkg_store_final);
@@ -854,7 +896,7 @@
return -1;
}
- lchown(link_path, uid, (gid_t)-1);
+ lchown(link_path, ctx->uid, (gid_t)-1);
}
}
@@ -898,11 +940,10 @@
}
char
-*gl_find_pkg_repo(const char *pkg_name, uid_t uid)
+*gl_find_pkg_repo(gl_context_t *ctx, const char *pkg_name)
{
char store_path[PATH_MAX];
- snprintf(store_path, sizeof(store_path),
-"/glacier/usr/store/%u", uid);
+ strncpy(store_path, ctx->store_path, PATH_MAX - 1);
DIR *uid_dir = opendir(store_path);
if (!uid_dir) { return NULL; }
@@ -927,13 +968,12 @@
}
gl_repo_list_t
-gl_find_pkg_repos(const char *pkg_name, uid_t uid)
+gl_find_pkg_repos(gl_context_t *ctx, const char *pkg_name)
{
gl_repo_list_t result = { NULL, 0 };
char store_path[PATH_MAX];
- snprintf(store_path, sizeof(store_path),
- "/glacier/usr/store/%u", uid);
+ strncpy(store_path, ctx->store_path, PATH_MAX - 1);
DIR *uid_dir = opendir(store_path);
if (!uid_dir) { return result; }
@@ -1033,8 +1073,9 @@
}
gl_install_status_t
-gl_install_pkg(const char *gpkg_path, uid_t uid)
+gl_install_pkg(gl_context_t *ctx, const char *gpkg_path)
{
+ if (!ctx) { return GL_INSTALL_ERR_OPEN; }
char original_cwd[PATH_MAX];
if (getcwd(original_cwd, sizeof(original_cwd)) == NULL) {
return GL_INSTALL_ERR_OPEN;
@@ -1108,7 +1149,7 @@
/* construct the directory for the package in the store */
snprintf(pkg_store_base, sizeof(pkg_store_base),
- "%s/%d/%s/%s", usr_store.path, uid, pkg.pkg_repo, pkg.pkg_name);
+ "%s/%s/%s", ctx->store_path, pkg.pkg_repo, pkg.pkg_name);
snprintf(pkg_store_final, sizeof(pkg_store_final),
"%s/%s-%d.%d.%d", pkg_store_base, pkg.pkg_name,
@@ -1208,15 +1249,9 @@
archive_read_free(a2);
/* now the index will be updated */
-
- /* now the index will be updated */
- char index_dir[PATH_MAX];
- snprintf(index_dir, sizeof(index_dir),
- "%s/%d", usr_index.path, uid);
-
/* Resolve "current" symlink to find the actual index file to append to */
char current_link[PATH_MAX];
- snprintf(current_link, sizeof(current_link), "%s/current", index_dir);
+ snprintf(current_link, sizeof(current_link), "%s/current", ctx->index_path);
char current_target[PATH_MAX];
ssize_t len = readlink(current_link, current_target, sizeof(current_target) - 1);
@@ -1227,7 +1262,8 @@
current_target[len] = '\0';
char index_path[PATH_MAX];
- snprintf(index_path, sizeof(index_path), "%s/%s", index_dir, current_target);
+ snprintf(index_path, sizeof(index_path), "%s/%s",
+ ctx->index_path, current_target);
FILE *idx = fopen(index_path, "a");
if (!idx) {
@@ -1238,12 +1274,12 @@
fprintf(idx, "%s::%s\n", pkg.pkg_repo, pkg.pkg_name);
fclose(idx);
- if (gl_rebuild_index(uid, index_dir) != 0) {
+ if (gl_rebuild_index(ctx) != 0) {
gl_free_pkg(&pkg);
return GL_INSTALL_ERR_INDEX;
}
- if (gl_link_pkg(pkg_store_final, uid) != 0) {
+ if (gl_link_pkg(ctx, pkg_store_final) != 0) {
gl_free_pkg(&pkg);
return GL_INSTALL_ERR_EXTRACT;
}
+1
View File
@@ -47,6 +47,7 @@ typedef enum {
GL_INSTALL_ERR_INDEX = 4, GL_INSTALL_ERR_INDEX = 4,
GL_INSTALL_ERR_ALREADY_INSTALLED = 5, GL_INSTALL_ERR_ALREADY_INSTALLED = 5,
GL_INSTALL_SKIPPED = 6, GL_INSTALL_SKIPPED = 6,
GL_INSTALL_ERR_SCOPE = 7,
} }
gl_install_status_t; gl_install_status_t;
-101
View File
@@ -1,101 +0,0 @@
#ifndef ISTOREUTILS_H_
#define ISTOREUTILS_H_
#include <stdbool.h>
#include <stdio.h>
#include <sys/types.h>
typedef enum {
INDEX,
STORE
}
index_store_t;
typedef enum {
GL_BACKUP_OK = 0,
GL_BACKUP_ERR_ALLOC = 1,
GL_BACKUP_ERR_OPEN = 2,
GL_BACKUP_ERR_ADD_INDEX = 3,
GL_BACKUP_ERR_ADD_STORE = 4,
GL_BACKUP_ERR_ADD_LINKS = 5,
GL_BACKUP_ERR_CLOSE = 6
}
gl_backup_status_t;
typedef enum {
GL_RESTORE_OK = 0,
GL_RESTORE_ERR_OPEN = 1,
GL_RESTORE_ERR_EXTRACT = 2
} gl_restore_status_t;
/*
* GL_INSTALL_OK: installation successful
* GL_INSTALL_ERR_OPEN: unable to open .gpkg file
* GL_INSTALL_ERR_MANIFEST: manifest is missing or unparseable
* GL_INSTALL_ERR_EXTRACT: unable to extract files
* GL_INSTALL_ERR_INDEX: unable to update index
* GL_INSTALL_ERR_ALREADY_INSTALLED: package already installed
*/
typedef enum {
GL_INSTALL_OK = 0,
GL_INSTALL_ERR_OPEN = 1,
GL_INSTALL_ERR_MANIFEST = 2,
GL_INSTALL_ERR_EXTRACT = 3,
GL_INSTALL_ERR_INDEX = 4,
GL_INSTALL_ERR_ALREADY_INSTALLED = 5,
GL_INSTALL_SKIPPED = 6,
}
gl_install_status_t;
typedef enum {
GL_REMOVE_OK = 0,
GL_REMOVE_ERR_NOT_FOUND = 1,
GL_REMOVE_ERR_UNLINK = 2,
GL_REMOVE_ERR_INDEX = 3,
} gl_remove_status_t;
struct gpkg_entry {
char *repo;
char *pkg;
};
struct gindex {
int uid;
int listed;
struct gpkg_entry *entries;
size_t count;
};
bool gl_usr_istore_exists(index_store_t index_or_store, int uid);
bool gl_sys_istore_exists(index_store_t index_or_store);
int gl_init_user(uid_t uid, bool isVerbose);
int gl_delete_user(uid_t uid, bool isVerbose);
int gl_parse_index(struct gindex *idx, FILE *f);
void gl_free_index(struct gindex *idx);
int gl_rebuild_index(uid_t uid, const char *out_dir);
char *gl_find_pkg_repo(const char *pkg_name, uid_t uid);
typedef struct {
char **repos;
size_t count;
}
gl_repo_list_t;
gl_repo_list_t gl_find_pkg_repos(const char *pkg_name, uid_t uid);
void gl_free_repo_list(gl_repo_list_t *list);
gl_backup_status_t gl_backup_istore(const char *tar_path, const char *glacier_root,
const char *uid);
gl_restore_status_t gl_restore_istore(const char *tar_path, const char *glacier_root, const char *uid);
gl_install_status_t gl_install_pkg(const char *gpkg_path, uid_t uid);
gl_remove_status_t gl_remove_pkg(const char *pkg_name, const char *pkg_repo, uid_t uid);
#endif