[U-Boot] [PATCH v2 0/3] cramfs fixes and symlink support

This adds initial support for symlinks in cramfs and fixes cramfs so that it can be tested in the sandbox. "cramfs: block pointers are 32 bits" fixes a crash on 64-bit which I have experienced on ARMv8 as well as the sandbox.
Changes in v2: * Add missing include and pointer cast needed on some architectures
https://travis-ci.org/tylerwhall/u-boot/builds/221383040
Tyler Hall (3): cmd: cramfs: use map_sysmem for sandbox support cramfs: block pointers are 32 bits cramfs: basic symlink support
cmd/cramfs.c | 14 +++++++++--- fs/cramfs/cramfs.c | 64 +++++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 62 insertions(+), 16 deletions(-)

As with most other commands, this needs to factor in the sysmem offset in the sandbox or it will try to dereference the simulated physical address directly.
Signed-off-by: Tyler Hall tylerwhall@gmail.com --- cmd/cramfs.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/cmd/cramfs.c b/cmd/cramfs.c index 965ca4e60d..4e75de8f29 100644 --- a/cmd/cramfs.c +++ b/cmd/cramfs.c @@ -13,11 +13,13 @@ #include <common.h> #include <command.h> #include <malloc.h> +#include <mapmem.h> #include <linux/list.h> #include <linux/ctype.h> #include <jffs2/jffs2.h> #include <jffs2/load_kernel.h> #include <cramfs/cramfs_fs.h> +#include <asm/io.h>
/* enable/disable debugging messages */ #define DEBUG_CRAMFS @@ -95,6 +97,7 @@ int do_cramfs_load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) char *filename; int size; ulong offset = load_addr; + char *offset_virt;
struct part_info part; struct mtd_device dev; @@ -111,7 +114,7 @@ int do_cramfs_load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) dev.id = &id; part.dev = &dev; /* fake the address offset */ - part.offset = addr - OFFSET_ADJUSTMENT; + part.offset = (u64)(uintptr_t) map_sysmem(addr - OFFSET_ADJUSTMENT, 0);
/* pre-set Boot file name */ if ((filename = getenv("bootfile")) == NULL) { @@ -127,9 +130,10 @@ int do_cramfs_load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) filename = argv[2]; }
+ offset_virt = map_sysmem(offset, 0); size = 0; if (cramfs_check(&part)) - size = cramfs_load ((char *) offset, &part, filename); + size = cramfs_load (offset_virt, &part, filename);
if (size > 0) { printf("### CRAMFS load complete: %d bytes loaded to 0x%lx\n", @@ -139,6 +143,9 @@ int do_cramfs_load(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) printf("### CRAMFS LOAD ERROR<%x> for %s!\n", size, filename); }
+ unmap_sysmem(offset_virt); + unmap_sysmem((void *)(uintptr_t)part.offset); + return !(size > 0); }
@@ -172,7 +179,7 @@ int do_cramfs_ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) dev.id = &id; part.dev = &dev; /* fake the address offset */ - part.offset = addr - OFFSET_ADJUSTMENT; + part.offset = (u64)(uintptr_t) map_sysmem(addr - OFFSET_ADJUSTMENT, 0);
if (argc == 2) filename = argv[1]; @@ -180,6 +187,7 @@ int do_cramfs_ls(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) ret = 0; if (cramfs_check(&part)) ret = cramfs_ls (&part, filename); + unmap_sysmem((void *)(uintptr_t)part.offset);
return ret ? 0 : 1; }

On Wed, Apr 12, 2017 at 04:29:15PM -0400, Tyler Hall wrote:
As with most other commands, this needs to factor in the sysmem offset in the sandbox or it will try to dereference the simulated physical address directly.
Signed-off-by: Tyler Hall tylerwhall@gmail.com
Applied to u-boot/master, thanks!

Using a variably-sized type is incorrect here since we're reading a fixed file format. Fixes cramfs on 64-bit platforms.
Signed-off-by: Tyler Hall tylerwhall@gmail.com --- fs/cramfs/cramfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/fs/cramfs/cramfs.c b/fs/cramfs/cramfs.c index 05ed27240a..ca8bc5e12b 100644 --- a/fs/cramfs/cramfs.c +++ b/fs/cramfs/cramfs.c @@ -162,7 +162,7 @@ static int cramfs_uncompress (unsigned long begin, unsigned long offset, unsigned long loadoffset) { struct cramfs_inode *inode = (struct cramfs_inode *) (begin + offset); - unsigned long *block_ptrs = (unsigned long *) + u32 *block_ptrs = (u32 *) (begin + (CRAMFS_GET_OFFSET (inode) << 2)); unsigned long curr_block = (CRAMFS_GET_OFFSET (inode) + (((CRAMFS_24 (inode->size)) +

On Wed, Apr 12, 2017 at 04:29:16PM -0400, Tyler Hall wrote:
Using a variably-sized type is incorrect here since we're reading a fixed file format. Fixes cramfs on 64-bit platforms.
Signed-off-by: Tyler Hall tylerwhall@gmail.com
Applied to u-boot/master, thanks!

Handle symlinks to files in the current directory. Other cases could be handled with additional code, but this is a start.
Add explicit errors for absolute paths and links found in the middle of a path (directories). Other cases like '..' or '.' will result with the file not being found as when those path components are explicitly provided.
Add a helper to decompress a null-terminated link name which is shared with cramfs_list_inode.
Signed-off-by: Tyler Hall tylerwhall@gmail.com --- fs/cramfs/cramfs.c | 62 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 50 insertions(+), 12 deletions(-)
diff --git a/fs/cramfs/cramfs.c b/fs/cramfs/cramfs.c index ca8bc5e12b..228f599d44 100644 --- a/fs/cramfs/cramfs.c +++ b/fs/cramfs/cramfs.c @@ -49,6 +49,9 @@ extern flash_info_t flash_info[]; #define PART_OFFSET(x) ((ulong)x->offset) #endif
+static int cramfs_uncompress (unsigned long begin, unsigned long offset, + unsigned long loadoffset); + static int cramfs_read_super (struct part_info *info) { unsigned long root_offset; @@ -94,6 +97,22 @@ static int cramfs_read_super (struct part_info *info) return 0; }
+/* Unpack to an allocated buffer, trusting in the inode's size field. */ +static char *cramfs_uncompress_link (unsigned long begin, unsigned long offset) +{ + struct cramfs_inode *inode = (struct cramfs_inode *)(begin + offset); + unsigned long size = CRAMFS_24 (inode->size); + char *link = malloc (size + 1); + + if (!link || cramfs_uncompress (begin, offset, (unsigned long)link) != size) { + free (link); + link = NULL; + } else { + link[size] = '\0'; + } + return link; +} + static unsigned long cramfs_resolve (unsigned long begin, unsigned long offset, unsigned long size, int raw, char *filename) @@ -143,6 +162,33 @@ static unsigned long cramfs_resolve (unsigned long begin, unsigned long offset, p); } else if (S_ISREG (CRAMFS_16 (inode->mode))) { return offset + inodeoffset; + } else if (S_ISLNK (CRAMFS_16 (inode->mode))) { + unsigned long ret; + char *link; + if (p && strlen(p)) { + printf ("unsupported symlink to \ + non-terminal path\n"); + return 0; + } + link = cramfs_uncompress_link (begin, + offset + inodeoffset); + if (!link) { + printf ("%*.*s: Error reading link\n", + namelen, namelen, name); + return 0; + } else if (link[0] == '/') { + printf ("unsupported symlink to \ + absolute path\n"); + free (link); + return 0; + } + ret = cramfs_resolve (begin, + offset, + size, + raw, + strtok(link, "/")); + free (link); + return ret; } else { printf ("%*.*s: unsupported file type (%x)\n", namelen, namelen, name, @@ -235,20 +281,12 @@ static int cramfs_list_inode (struct part_info *info, unsigned long offset) CRAMFS_24 (inode->size), namelen, namelen, name);
if ((CRAMFS_16 (inode->mode) & S_IFMT) == S_IFLNK) { - /* symbolic link. - * Unpack the link target, trusting in the inode's size field. - */ - unsigned long size = CRAMFS_24 (inode->size); - char *link = malloc (size); - - if (link != NULL && cramfs_uncompress (PART_OFFSET(info), offset, - (unsigned long) link) - == size) - printf (" -> %*.*s\n", (int) size, (int) size, link); + char *link = cramfs_uncompress_link (PART_OFFSET(info), offset); + if (link) + printf (" -> %s\n", link); else printf (" [Error reading link]\n"); - if (link) - free (link); + free (link); } else printf ("\n");

On Wed, Apr 12, 2017 at 04:29:17PM -0400, Tyler Hall wrote:
Handle symlinks to files in the current directory. Other cases could be handled with additional code, but this is a start.
Add explicit errors for absolute paths and links found in the middle of a path (directories). Other cases like '..' or '.' will result with the file not being found as when those path components are explicitly provided.
Add a helper to decompress a null-terminated link name which is shared with cramfs_list_inode.
Signed-off-by: Tyler Hall tylerwhall@gmail.com
Applied to u-boot/master, thanks!

On Wed, Apr 12, 2017 at 04:29:14PM -0400, Tyler Hall wrote:
This adds initial support for symlinks in cramfs and fixes cramfs so that it can be tested in the sandbox. "cramfs: block pointers are 32 bits" fixes a crash on 64-bit which I have experienced on ARMv8 as well as the sandbox.
Changes in v2:
- Add missing include and pointer cast needed on some architectures
https://travis-ci.org/tylerwhall/u-boot/builds/221383040
Tyler Hall (3): cmd: cramfs: use map_sysmem for sandbox support cramfs: block pointers are 32 bits cramfs: basic symlink support
cmd/cramfs.c | 14 +++++++++--- fs/cramfs/cramfs.c | 64 +++++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 62 insertions(+), 16 deletions(-)
Thanks for pushing this through travis-ci as well. Assuming there's no further comments I'll pick this up in a few days.
participants (2)
-
Tom Rini
-
Tyler Hall