Fix Ubuntu Firefox permissions and APT sources

This commit is contained in:
James Stringer committed 2026-09-13 14:33:53 -04:00
1 parent 6d2e10fd0b
commit 16f8a72cc0
5 files changed
+212 -2

No files matched your search

+52 -1
View File
@@ -30,7 +30,7 @@
#define EXT4_FIRST_INO 11u /* s_first_ino: first non-reserved */
/* Feature flags - kept very small. */
#define EXT4_FEATURE_COMPAT 0
#define EXT4_FEATURE_COMPAT 0x08u
#define EXT4_FEATURE_INCOMPAT (0x02u | 0x40u) /* FILETYPE | EXTENTS */
#define EXT4_FEATURE_RO_COMPAT (0x01u | 0x02u | 0x08u | 0x20u | 0x40u)
/* SPARSE_SUPER | LARGE_FILE | HUGE_FILE
@@ -224,6 +224,15 @@ typedef struct {
} ext4_inode_t;
/* sizeof = 0xa0 = 160. Inode-size 256 leaves 96 trailing bytes (xattrs). */
typedef struct {
uint8_t e_name_len;
uint8_t e_name_index;
uint16_t e_value_offs;
uint32_t e_value_inum;
uint32_t e_value_size;
uint32_t e_hash;
} ext4_xattr_entry_t;
typedef struct {
uint16_t eh_magic;
uint16_t eh_entries;
@@ -291,6 +300,8 @@ typedef struct {
/* For dirs only - serialized entry blob (filled at close). */
uint8_t *dir_blob;
uint32_t dir_blob_len;
void *capability;
uint32_t capability_size;
} inode_rec_t;
struct ext4_writer {
@@ -1022,6 +1033,29 @@ int ext4_writer_add_file(ext4_writer_t *w, const char *path,
return 0;
}
int ext4_writer_set_capability(ext4_writer_t *w, const char *path,
const void *data, size_t size)
{
if (!data || (size != 12 && size != 20 && size != 24)) return -1;
dir_node_t *parent;
char leaf[256];
if (split_path(w, path, &parent, leaf, sizeof(leaf)) != 0) return -1;
for (dir_entry_rec_t *e = parent->entries; e; e = e->next) {
if (strcmp(e->name, leaf) != 0) continue;
if (e->file_type != EXT4_FT_REG_FILE) return -1;
inode_rec_t *r = w->inodes[e->inode];
void *copy = malloc(size);
if (!copy) return -1;
memcpy(copy, data, size);
free(r->capability);
r->capability = copy;
r->capability_size = (uint32_t)size;
r->body.i_extra_isize = (uint16_t)(sizeof(ext4_inode_t) - 128);
return 0;
}
return -1;
}
int ext4_writer_add_symlink(ext4_writer_t *w, const char *path,
const char *target, size_t target_len,
uint32_t uid, uint32_t gid, uint32_t mtime)
@@ -1232,6 +1266,22 @@ static int write_all_inodes(ext4_writer_t *w)
memcpy(tbl + idx * INODE_SIZE,
&w->inodes[inode_num]->body,
sizeof(ext4_inode_t));
inode_rec_t *r = w->inodes[inode_num];
if (r->capability_size) {
uint8_t *inode = tbl + idx * INODE_SIZE;
uint32_t magic = 0xEA020000u;
memcpy(inode + sizeof(ext4_inode_t), &magic, sizeof(magic));
ext4_xattr_entry_t *entry = (ext4_xattr_entry_t *)(
inode + sizeof(ext4_inode_t) + sizeof(magic));
entry->e_name_len = 10;
entry->e_name_index = 6;
entry->e_value_offs = (uint16_t)(INODE_SIZE - r->capability_size -
sizeof(ext4_inode_t) - sizeof(magic));
entry->e_value_size = r->capability_size;
memcpy(entry + 1, "capability", entry->e_name_len);
memcpy(inode + INODE_SIZE - r->capability_size,
r->capability, r->capability_size);
}
any = 1;
}
if (!any) continue;
@@ -1474,6 +1524,7 @@ int ext4_writer_close(ext4_writer_t *w)
for (uint32_t i = 1; i <= w->total_inodes; i++) {
if (w->inodes[i]) {
free(w->inodes[i]->dir_blob);
free(w->inodes[i]->capability);
free(w->inodes[i]);
}
}
+2 -1
View File
@@ -3,7 +3,6 @@
* Feature subset (deliberately small):
* INCOMPAT : FILETYPE | EXTENTS
* RO_COMPAT : SPARSE_SUPER | LARGE_FILE | HUGE_FILE | DIR_NLINK | EXTRA_ISIZE
* No journal, no metadata_csum, no xattrs, no flex_bg, no 64bit, no HTREE.
*
* Layout:
* block_size = 4096
@@ -47,6 +46,8 @@ int ext4_writer_add_dir(ext4_writer_t *w, const char *path,
int ext4_writer_add_file(ext4_writer_t *w, const char *path,
uint16_t perms, uint32_t uid, uint32_t gid,
uint32_t mtime, const void *data, uint64_t size);
int ext4_writer_set_capability(ext4_writer_t *w, const char *path,
const void *data, size_t size);
int ext4_writer_add_symlink(ext4_writer_t *w, const char *path,
const char *target, size_t target_len,
uint32_t uid, uint32_t gid, uint32_t mtime);
+139
View File
@@ -453,6 +453,143 @@ int sqfs_read_metadata_block(sqfs_ctx_t *ctx, uint64_t *off,
return -1;
}
typedef struct {
uint64_t next_block;
uint64_t end;
size_t pos;
size_t len;
uint8_t data[SQFS_METADATA_SIZE];
} sqfs_xattr_cursor_t;
static int xattr_next_block(sqfs_ctx_t *ctx, sqfs_xattr_cursor_t *c)
{
uint16_t hdr;
if (c->next_block >= c->end || c->end - c->next_block < 2 ||
sqfs_read_raw(ctx, c->next_block, &hdr, sizeof(hdr)) != 0 ||
(hdr & 0x7fff) > c->end - c->next_block - 2)
return -1;
if (sqfs_read_metadata_block(ctx, &c->next_block, c->data, &c->len) != 0 ||
c->len == 0 || (c->next_block != c->end && c->len != SQFS_METADATA_SIZE))
return -1;
c->pos = 0;
return 0;
}
static int xattr_cursor_start(sqfs_ctx_t *ctx, sqfs_xattr_cursor_t *c,
uint64_t start, uint64_t end, size_t offset)
{
if (end > ctx->sb.bytes_used || start >= end || offset >= SQFS_METADATA_SIZE)
return -1;
c->next_block = start;
c->end = end;
if (xattr_next_block(ctx, c) != 0 || offset >= c->len) return -1;
c->pos = offset;
return 0;
}
static int xattr_read(sqfs_ctx_t *ctx, sqfs_xattr_cursor_t *c,
void *out, size_t size)
{
uint8_t *p = (uint8_t *)out;
while (size) {
if (c->pos == c->len && xattr_next_block(ctx, c) != 0) return -1;
size_t n = c->len - c->pos;
if (n > size) n = size;
if (p) { memcpy(p, c->data + c->pos, n); p += n; }
c->pos += n;
size -= n;
}
return 0;
}
int sqfs_read_capability(sqfs_ctx_t *ctx, const sqfs_entry_t *entry,
void **out_data, size_t *out_size)
{
*out_data = NULL;
*out_size = 0;
if (entry->type != SQFS_EREG_TYPE || entry->_xattr_idx == UINT32_MAX)
return 0;
struct {
uint64_t start;
uint32_t count;
uint32_t unused;
} table;
struct {
uint64_t ref;
uint32_t count;
uint32_t size;
} id;
uint64_t table_off = ctx->sb.xattr_id_table_start;
if (table_off > ctx->sb.bytes_used ||
sizeof(table) > ctx->sb.bytes_used - table_off ||
sqfs_read_raw(ctx, table_off, &table, sizeof(table)) != 0 ||
entry->_xattr_idx >= table.count)
return -1;
uint64_t index_bytes = (((uint64_t)table.count * sizeof(id) +
SQFS_METADATA_SIZE - 1) / SQFS_METADATA_SIZE) * 8;
table_off += sizeof(table);
if (index_bytes != ctx->sb.bytes_used - table_off) return -1;
uint64_t xattr_end, id_block;
uint64_t id_offset = (uint64_t)entry->_xattr_idx * sizeof(id);
if (sqfs_read_raw(ctx, table_off, &xattr_end, sizeof(xattr_end)) != 0 ||
sqfs_read_raw(ctx, table_off + (id_offset / SQFS_METADATA_SIZE) * 8,
&id_block, sizeof(id_block)) != 0 ||
table.start < sizeof(sqfs_superblock_t) || table.start >= xattr_end ||
xattr_end > id_block || id_block >= ctx->sb.xattr_id_table_start)
return -1;
sqfs_xattr_cursor_t c;
if (xattr_cursor_start(ctx, &c, id_block, ctx->sb.xattr_id_table_start,
(size_t)(id_offset % SQFS_METADATA_SIZE)) != 0 ||
xattr_read(ctx, &c, &id, sizeof(id)) != 0 ||
id.count == 0 ||
(id.ref >> 16) >= xattr_end - table.start ||
xattr_cursor_start(ctx, &c, table.start + (id.ref >> 16), xattr_end,
(size_t)(id.ref & 0xffff)) != 0)
return -1;
for (uint32_t i = 0; i < id.count; i++) {
uint16_t attr[2];
char name[sizeof("capability") - 1];
uint32_t value_size;
if (xattr_read(ctx, &c, attr, sizeof(attr)) != 0 ||
attr[1] == 0 || (attr[0] & ~0x1ffu) != 0)
return -1;
int match = (attr[0] & 0xff) == 2 && attr[1] == sizeof(name);
if (xattr_read(ctx, &c, match ? name : NULL, attr[1]) != 0 ||
xattr_read(ctx, &c, &value_size, sizeof(value_size)) != 0 ||
((attr[0] & 0x100) && value_size != sizeof(uint64_t)))
return -1;
if (!match || memcmp(name, "capability", sizeof(name)) != 0) {
if (xattr_read(ctx, &c, NULL, value_size) != 0) return -1;
continue;
}
if (attr[0] & 0x100) {
uint64_t ref;
if (xattr_read(ctx, &c, &ref, sizeof(ref)) != 0 ||
(ref >> 16) >= xattr_end - table.start ||
xattr_cursor_start(ctx, &c, table.start + (ref >> 16), xattr_end,
(size_t)(ref & 0xffff)) != 0 ||
xattr_read(ctx, &c, &value_size, sizeof(value_size)) != 0)
return -1;
}
if (value_size != 12 && value_size != 20 && value_size != 24) return -1;
void *value = malloc(value_size);
if (!value) return -1;
if (xattr_read(ctx, &c, value, value_size) != 0) {
free(value);
return -1;
}
*out_data = value;
*out_size = value_size;
return 0;
}
return 0;
}
/* ---- Inode + directory parsing ----
*
* All structs are stored little-endian. We use memcpy into local typed
@@ -688,6 +825,7 @@ static int walk_inode(walk_state_t *w, uint64_t inode_ref)
e.gid = id_lookup(ctx, hdr.gid_idx);
e.mtime = hdr.mtime;
e._file_inode_off = (size_t)(p - ctx->inode_stream.buf);
e._xattr_idx = UINT32_MAX;
switch (hdr.type) {
case SQFS_DIR_TYPE: {
@@ -730,6 +868,7 @@ static int walk_inode(walk_state_t *w, uint64_t inode_ref)
sqfs_ext_file_t f;
memcpy(&f, body, sizeof(f));
e.size = f.file_size;
e._xattr_idx = f.xattr_idx;
if (w->cb_rc == 0) w->cb_rc = w->cb(&e, w->user);
w->n_files++;
return w->cb_rc;
+4
View File
@@ -118,6 +118,7 @@ typedef struct {
/* For regular files, set by the walker, used by the callback to fetch
* the bytes (deferred so the callback can stream / skip as needed). */
uint64_t _file_inode_off; /* internal: offset of file's inode in table */
uint32_t _xattr_idx;
} sqfs_entry_t;
/* Callback signature. Return 0 to continue, non-zero to abort traversal. */
@@ -135,4 +136,7 @@ int sqfs_walk(sqfs_ctx_t *ctx, sqfs_walk_cb_t cb, void *user);
int sqfs_read_file(sqfs_ctx_t *ctx, const sqfs_entry_t *entry,
void **out_data, size_t *out_size);
int sqfs_read_capability(sqfs_ctx_t *ctx, const sqfs_entry_t *entry,
void **out_data, size_t *out_size);
#endif
+15
View File
@@ -544,6 +544,8 @@ typedef struct slot {
uint32_t uid, gid, mtime, rdev;
uint64_t size;
void *data;
void *capability;
size_t capability_size;
char *symlink_target;
uint32_t symlink_target_size;
uint64_t mem_bytes;
@@ -707,6 +709,14 @@ static DWORD WINAPI decompress_worker(LPVOID arg)
}
s->size = sz;
s->mem_bytes += sz;
if (sqfs_read_capability(p->sq, &e, &s->capability, &s->capability_size) != 0) {
log_err(L"sqfs_read_capability failed");
free(s->data); free(s->path); free(s);
InterlockedIncrement((volatile LONG *)&p->n_errors);
free(w);
continue;
}
s->mem_bytes += s->capability_size;
pipeline_push(p, s);
free(w);
}
@@ -783,6 +793,9 @@ static DWORD WINAPI consumer_thread(LPVOID arg)
case SQFS_REG_TYPE: case SQFS_EREG_TYPE:
rc = ext4_writer_add_file(p->ew, s->path, s->mode, s->uid, s->gid, s->mtime,
s->data, s->size);
if (rc == 0 && s->capability_size)
rc = ext4_writer_set_capability(p->ew, s->path,
s->capability, s->capability_size);
if (rc == 0) { p->n_files++; p->bytes_total += s->size; }
/* Mirror unicode.pf2 into /boot/grub/fonts/ (loadfont's default
* search path). */
@@ -832,6 +845,7 @@ static DWORD WINAPI consumer_thread(LPVOID arg)
free(s->path);
free(s->data);
free(s->capability);
free(s->symlink_target);
free(s);
}
@@ -1281,6 +1295,7 @@ static void plant_firstboot_service(ext4_writer_t *ew)
"# in one shot — saves repeated apt overhead and avoids the\n"
"# install-build-deps-after-trying-to-build ordering bug.\n"
"echo \"==== STEP 7.4: apt sources + install all build tools ====\"\n"
"rm -f /etc/apt/sources.list.d/cdrom.sources\n"
"APT_SOURCES_DIR=/etc/apt/appsandbox-sources.list.d\n"
"install -d \"$APT_SOURCES_DIR\"\n"
"if [ -d /opt/appsandbox/local-apt/dists ]; then\n"