From: Luis H. C. <lhc...@go...> - 2017-12-08 01:08:24
|
Add flags that allow the user to choose uid/gid mappings before writing the inodes. This is helpful to create container images that need uids/gids to be shifted. Signed-off-by: Luis Héctor Chávez <lhc...@go...> --- squashfs-tools/mksquashfs.c | 148 ++++++++++++++++++++++++++++++++++++++++++-- squashfs-tools/mksquashfs.h | 4 +- squashfs-tools/read_fs.c | 8 +-- 3 files changed, 148 insertions(+), 12 deletions(-) diff --git a/squashfs-tools/mksquashfs.c b/squashfs-tools/mksquashfs.c index 75b3577..6bb2d26 100644 --- a/squashfs-tools/mksquashfs.c +++ b/squashfs-tools/mksquashfs.c @@ -250,6 +250,17 @@ char *destination_file = NULL; char *recovery_file = NULL; int recover = TRUE; +/* uid/gid mapping tables */ +#define UGID_ENTRIES 340 + +struct ugid_map_entry { + unsigned int child_id; + unsigned int parent_id; + unsigned int length; +}; +struct ugid_map_entry uid_mapping[UGID_ENTRIES], gid_mapping[UGID_ENTRIES]; +unsigned int uid_map_count = 0, gid_map_count = 0; + struct id *id_hash_table[ID_ENTRIES]; struct id *id_table[SQUASHFS_IDS], *sid_table[SQUASHFS_IDS]; unsigned int uid_count = 0, guid_count = 0; @@ -696,9 +707,33 @@ struct id *create_id(unsigned int id) } -unsigned int get_uid(unsigned int uid) +int resolve_child_ugid(unsigned int *ugid, + const struct ugid_map_entry *ugid_mapping, + unsigned int ugid_map_count) +{ + unsigned int i; + + for (i = 0; i < ugid_map_count; i++) { + if (ugid_mapping[i].parent_id <= *ugid && + *ugid < + ugid_mapping[i].parent_id + ugid_mapping[i].length) { + *ugid = ugid_mapping[i].child_id + *ugid - + ugid_mapping[i].parent_id; + return 1; + } + } + + return 0; +} + + +unsigned int get_uid(unsigned int uid, int resolve) { - struct id *entry = get_id(uid); + struct id *entry; + + if (resolve && !resolve_child_ugid(&uid, uid_mapping, uid_map_count)) + BAD_ERROR("uid not found in mapping: %d\n", uid); + entry = get_id(uid); if(entry == NULL) { if(id_count == SQUASHFS_IDS) @@ -715,9 +750,13 @@ unsigned int get_uid(unsigned int uid) } -unsigned int get_guid(unsigned int guid) +unsigned int get_guid(unsigned int guid, int resolve) { - struct id *entry = get_id(guid); + struct id *entry; + + if (resolve && !resolve_child_ugid(&guid, gid_mapping, gid_map_count)) + BAD_ERROR("gid not found in mapping: %d\n", guid); + entry = get_id(guid); if(entry == NULL) { if(id_count == SQUASHFS_IDS) @@ -891,10 +930,10 @@ int create_inode(squashfs_inode *i_no, struct dir_info *dir_info, base->mode = SQUASHFS_MODE(buf->st_mode); base->uid = get_uid((unsigned int) global_uid == -1 ? - buf->st_uid : global_uid); + buf->st_uid : global_uid, 1); base->inode_type = type; base->guid = get_guid((unsigned int) global_gid == -1 ? - buf->st_gid : global_gid); + buf->st_gid : global_gid, 1); base->mtime = buf->st_mtime; base->inode_number = get_inode_no(dir_ent->inode); @@ -4985,6 +5024,60 @@ int parse_num(char *arg, int *res) } +int parse_ugid_map(char *map_str, + struct ugid_map_entry ugid_mapping[UGID_ENTRIES], + unsigned int *ugid_map_count) +{ + char *line_state, *token_state; + char *line, *line_str, *token, *token_str; + long long numbers[3]; + int i; + + for (*ugid_map_count = 0, line_str = map_str;; + ++*ugid_map_count, line_str = NULL) { + line = strtok_r(line_str, "\n", &line_state); + if (line == NULL) + break; + if (*ugid_map_count >= UGID_ENTRIES) { + ERROR("Too many entries for u/gid mapping\n"); + return -1; + } + + for (i = 0, token_str = line; i < 3; i++, token_str = NULL) { + token = strtok_r(token_str, " ", &token_state); + if (token == NULL || + !parse_numberll(token, &numbers[i], 0) || + numbers[i] < 0 || numbers[i] > ULONG_MAX) { + ERROR("Malformed u/gid mapping line\n"); + return -1; + } + } + + if (numbers[0] + numbers[2] > ULONG_MAX) { + ERROR("u/gid mapping overflow\n"); + return -1; + } + if (numbers[1] + numbers[2] > ULONG_MAX) { + ERROR("u/gid mapping overflow\n"); + return -1; + } + + if (strtok_r(NULL, " ", &token_state) != NULL) { + ERROR("Malformed u/gid mapping line\n"); + return -1; + } + + ugid_mapping[*ugid_map_count].child_id = + (unsigned int)numbers[0]; + ugid_mapping[*ugid_map_count].parent_id = + (unsigned int)numbers[1]; + ugid_mapping[*ugid_map_count].length = (unsigned int)numbers[2]; + } + + return 0; +} + + int get_physical_memory() { /* @@ -5571,6 +5664,30 @@ print_compressor_options: exit(1); } root_name = argv[i]; + } else if (strcmp(argv[i], "-uid-map") == 0) { + if (++i == argc) { + ERROR("%s: -uid-map: missing mapping\n", + argv[0]); + exit(1); + } + if (parse_ugid_map(argv[i], uid_mapping, + &uid_map_count) != 0) { + ERROR("%s: -uid-map: invalid mapping\n", + argv[0]); + exit(1); + } + } else if (strcmp(argv[i], "-gid-map") == 0) { + if (++i == argc) { + ERROR("%s: -gid-map: missing mapping\n", + argv[0]); + exit(1); + } + if (parse_ugid_map(argv[i], gid_mapping, + &uid_map_count) != 0) { + ERROR("%s: -gid-map: invalid mapping\n", + argv[0]); + exit(1); + } } else if(strcmp(argv[i], "-version") == 0) { VERSION(); } else { @@ -5639,6 +5756,12 @@ printOptions: "dirs/files\n"); ERROR("-regex\t\t\tAllow POSIX regular expressions to " "be used in exclude\n\t\t\tdirs/files\n"); + ERROR("-uid-map <mapping>\tUser ID mapping.\n"); + ERROR("\t\t\tFollows the format described in " + "user_namespaces(7).\n"); + ERROR("-gid-map <mapping>\tGroup ID mapping.\n"); + ERROR("\t\t\tFollows the format described in " + "user_namespaces(7).\n"); ERROR("\nFilesystem append options:\n"); ERROR("-noappend\t\tdo not append to existing " "filesystem\n"); @@ -5695,6 +5818,19 @@ printOptions: } } + if (!uid_map_count) { + uid_mapping[0].child_id = 0; + uid_mapping[0].parent_id = 0; + uid_mapping[0].length = 4294967295u; + uid_map_count = 1; + } + if (!gid_map_count) { + gid_mapping[0].child_id = 0; + gid_mapping[0].parent_id = 0; + gid_mapping[0].length = 4294967295u; + gid_map_count = 1; + } + /* * Some compressors may need the options to be checked for validity * once all the options have been processed diff --git a/squashfs-tools/mksquashfs.h b/squashfs-tools/mksquashfs.h index 55708a3..1e4b419 100644 --- a/squashfs-tools/mksquashfs.h +++ b/squashfs-tools/mksquashfs.h @@ -147,8 +147,8 @@ extern int read_fs_bytes(int, long long, int, void *); extern void add_file(long long, long long, long long, unsigned int *, int, unsigned int, int, int); extern struct id *create_id(unsigned int); -extern unsigned int get_uid(unsigned int); -extern unsigned int get_guid(unsigned int); +extern unsigned int get_uid(unsigned int, int); +extern unsigned int get_guid(unsigned int, int); extern int read_bytes(int, void *, int); extern unsigned short get_checksum_mem(char *, int); #endif diff --git a/squashfs-tools/read_fs.c b/squashfs-tools/read_fs.c index ca84460..3ea9262 100644 --- a/squashfs-tools/read_fs.c +++ b/squashfs-tools/read_fs.c @@ -214,8 +214,8 @@ int scan_inode_table(int fd, long long start, long long end, /* bad type, corrupted filesystem */ goto corrupted; - get_uid(id_table[dir_inode->base.uid]); - get_guid(id_table[dir_inode->base.guid]); + get_uid(id_table[dir_inode->base.uid], 0); + get_guid(id_table[dir_inode->base.guid], 0); /* allocate fragment to file mapping table */ file_mapping = calloc(sBlk->fragments, sizeof(struct append_file *)); @@ -234,8 +234,8 @@ int scan_inode_table(int fd, long long start, long long end, (unsigned int) (cur_ptr - *inode_table), base.inode_type); - get_uid(id_table[base.uid]); - get_guid(id_table[base.guid]); + get_uid(id_table[base.uid], 0); + get_guid(id_table[base.guid], 0); switch(base.inode_type) { case SQUASHFS_FILE_TYPE: { -- 2.15.1.424.g9478a66081-goog |