From 4568b2d3efdf1f78efa3bcdd740babd2f337a583 Mon Sep 17 00:00:00 2001 From: Krishna Chilleri Date: Wed, 25 Sep 2024 14:00:04 -0600 Subject: [PATCH] identify, validate, and run SIF files draft [skip ci] --- bin/ch-run.c | 4 ++++ bin/ch_core.c | 30 +++++++++++++++++++++++++++--- bin/ch_core.h | 2 ++ bin/ch_fuse.c | 35 ++++++++++++++++++++++++++++++++++- bin/ch_fuse.h | 1 + 5 files changed, 68 insertions(+), 4 deletions(-) diff --git a/bin/ch-run.c b/bin/ch-run.c index bf3c41934..2096b8758 100644 --- a/bin/ch-run.c +++ b/bin/ch-run.c @@ -208,6 +208,10 @@ int main(int argc, char *argv[]) Tf (!args.c.writable || args.unsafe, "--write invalid when running by name"); break; + case IMG_SIF: + INFO("SIF file detected!"); + //args.c.newroot = realpath_(args.c.img_ref, false); + break; case IMG_SQUASH: #ifndef HAVE_LIBSQUASHFUSE FATAL(0, "this ch-run does not support internal SquashFS mounts"); diff --git a/bin/ch_core.c b/bin/ch_core.c index 60dcd1097..dca7d94d5 100644 --- a/bin/ch_core.c +++ b/bin/ch_core.c @@ -280,7 +280,7 @@ void containerize(struct container *c) // reduce the number of code paths. setup_namespaces(c, geteuid(), 0, getegid(), 0); #ifdef HAVE_LIBSQUASHFUSE - if (c->type == IMG_SQUASH) + if ((c->type == IMG_SQUASH) || (c->type == IMG_SIF)) sq_fork(c); #endif setup_namespaces(c, 0, c->container_uid, 0, c->container_gid); @@ -391,6 +391,7 @@ enum img_type image_type(const char *ref, const char *storage_dir) struct stat st; FILE *fp; char magic[4]; // four bytes, not a string + char header[42]; // thirty-two bytes for launch len and ten for magic len // If there’s a directory in storage where we would expect there to be if // ref were an image name, assume it really is an image name. @@ -409,8 +410,7 @@ enum img_type image_type(const char *ref, const char *storage_dir) fp = fopen(ref, "rb"); Tf (fp != NULL, "can't open: %s", ref); Tf (fread(magic, sizeof(char), 4, fp) == 4, "can't read: %s", ref); - Zf (fclose(fp), "can't close: %s", ref); - VERBOSE("image file magic expected: 6873 7173; actual: %x%x %x%x", + VERBOSE("squash image file magic expected: 6873 7173; actual: %x%x %x%x", magic[0], magic[1], magic[2], magic[3]); // If magic number matches, it’s a squash. Note: Magic number is 6873 7173, @@ -420,10 +420,34 @@ enum img_type image_type(const char *ref, const char *storage_dir) if (memcmp(magic, "hsqs", 4) == 0) return IMG_SQUASH; + // Check if it is a SIF file + // See: https://github.com/sylabs/sif/tree/main + // Parse header: skip launch constant and record magic value + fseek(fp, 0, SEEK_SET); // start from beginning of file + Tf (fread(header, sizeof(char), 32, fp) == 32, "can't read: %s", ref); + Tf (fread(header, 1, 10, fp) == 10, "can't read: %s", ref); + char *magic_val = to_string(header); + VERBOSE("sif file magic expected: SIF_MAGIC: actual: %s", magic_val); + if (strcmp(magic_val, "SIF_MAGIC") == 0) + return IMG_SIF; + + Zf (fclose(fp), "can't close: %s", ref); + // Well now we’re stumped. FATAL(0, "unknown image type: %s", ref); } +char *to_string(char *c) +{ + char *str = malloc(strlen(c) + 1); + if (str == NULL) { + perror("Failed to allocate memory"); + exit(EXIT_FAILURE); + } + strcpy(str, c); + return str; +} + char *img_name2path(const char *name, const char *storage_dir) { char *path; diff --git a/bin/ch_core.h b/bin/ch_core.h index f65cfc083..7a5385446 100644 --- a/bin/ch_core.h +++ b/bin/ch_core.h @@ -22,6 +22,7 @@ struct bind { enum img_type { IMG_DIRECTORY, // normal directory, perhaps an external mount of some kind + IMG_SIF, // SIF file (squash portion not yet mounted) IMG_SQUASH, // SquashFS archive file (not yet mounted) IMG_NAME, // name of image in storage IMG_NONE, // image type is not set yet @@ -53,6 +54,7 @@ void containerize(struct container *c); enum img_type image_type(const char *ref, const char *images_dir); char *img_name2path(const char *name, const char *storage_dir); void run_user_command(char *argv[], const char *initial_dir); +char *to_string(char *c); #ifdef HAVE_SECCOMP void seccomp_install(void); #endif diff --git a/bin/ch_fuse.c b/bin/ch_fuse.c index 22ac1e5ca..5f702961f 100644 --- a/bin/ch_fuse.c +++ b/bin/ch_fuse.c @@ -217,6 +217,35 @@ int sq_loop(void) return exit_code; } +/* Find the byte offset of where the squash portion begins */ +int sq_offset(const char *sif_path) +{ + FILE *fp = fopen(sif_path, "rb"); + char offset[8]; + char magic[4]; + int squash_offset = 0; + int i; + + Tf (fp != NULL, "can't open: %s", sif_path); + + // iterate through file in chunks of size eight until squash magic number appears + while (fread(offset,8,1,fp) != 0) { + for (i=0; i < 4; i++) { + magic[i] = offset[i]; + } + if (memcmp(magic, "hsqs", 4) == 0) { // 6873 7173 + // Squash byte offset is zero if IMG_SQUASH + // Squash byte offset is > zero if IMG_SIF + squash_offset = ftell(fp)-8; + VERBOSE("Squash byte offset: %d\n", squash_offset); + VERBOSE("Magic is: %x%x %x%x\n", magic[0],magic[1],magic[2],magic[3]); + break; + } + } + Zf (fclose(fp), "can't close: %s", sif_path); + return squash_offset; +} + /* Mount the SquashFS img_path at mountpt. Exit on any errors. */ void sq_mount(const char *img_path, char *mountpt) { @@ -231,7 +260,11 @@ void sq_mount(const char *img_path, char *mountpt) sq.mountpt = mountpt; T_ (sq.chan = malloc(sizeof(sqfs_ll_chan))); - sq.ll = sqfs_ll_open(img_path, 0); + int byte_offset = 0; + + byte_offset = sq_offset(img_path); + sq.ll = sqfs_ll_open(img_path, byte_offset); + Te (sq.ll != NULL, "can't open SquashFS: %s; try ch-run -vv?", img_path); // sqfs_ll_mount() is squirrely for a couple reasons: diff --git a/bin/ch_fuse.h b/bin/ch_fuse.h index 5250ed85a..d9c948c3b 100644 --- a/bin/ch_fuse.h +++ b/bin/ch_fuse.h @@ -5,3 +5,4 @@ /** Function prototypes **/ void sq_fork(struct container *c); +int sq_offset(const char *sif_path);