From: Tyler H. <ty...@ca...> - 2017-11-29 17:07:06
|
This patch fixes a bug that caused symlinks created by unsquashfs to use the current time for atime and mtime rather than the times present in the squashfs archive. The timestamps are set using utimensat(2) which does not dereference the symlink when the AT_SYMLINK_NOFOLLOW flag is used. The utimensat(2) system call supports nanosecond precision but that's not needed by squashfs so timespec.tv_nsec is unconditionally set to 0. Signed-off-by: Tyler Hicks <ty...@ca...> --- squashfs-tools/unsquashfs.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/squashfs-tools/unsquashfs.c b/squashfs-tools/unsquashfs.c index c5e0876..5141c27 100644 --- a/squashfs-tools/unsquashfs.c +++ b/squashfs-tools/unsquashfs.c @@ -1089,7 +1089,12 @@ int create_inode(char *pathname, struct inode *i) file_count ++; break; case SQUASHFS_SYMLINK_TYPE: - case SQUASHFS_LSYMLINK_TYPE: + case SQUASHFS_LSYMLINK_TYPE: { + struct timespec times[2] = { + { i->time, 0 }, + { i->time, 0 } + }; + TRACE("create_inode: symlink, symlink_size %lld\n", i->data); @@ -1103,6 +1108,13 @@ int create_inode(char *pathname, struct inode *i) break; } + if (utimensat(AT_FDCWD, pathname, times, + AT_SYMLINK_NOFOLLOW) == -1) { + ERROR("create_inode: failed to set time on " + "%s, because %s\n", pathname, + strerror(errno)); + } + write_xattr(pathname, i->xattr); if(root_process) { @@ -1115,6 +1127,7 @@ int create_inode(char *pathname, struct inode *i) sym_count ++; break; + } case SQUASHFS_BLKDEV_TYPE: case SQUASHFS_CHRDEV_TYPE: case SQUASHFS_LBLKDEV_TYPE: -- 2.7.4 |
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 |