Skip to content

Commit

Permalink
cramfs: basic symlink support
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
tylerwhall authored and trini committed Apr 18, 2017
1 parent a6ea791 commit d39a0d2
Showing 1 changed file with 50 additions and 12 deletions.
62 changes: 50 additions & 12 deletions fs/cramfs/cramfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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");

Expand Down

0 comments on commit d39a0d2

Please sign in to comment.