Skip to content

Commit

Permalink
Sanitize EPUB paths and skip invalid ones
Browse files Browse the repository at this point in the history
Paths specified in href attributes inside an EPUB could potentially
point outside the EPUB container (e.g. href="../../../../outside").
Make sure this does not happen: abort parsing if the rootfile points
outside the EPUB container and skip parsing files with invalid paths,
printing a warning.
  • Loading branch information
mebeim committed Jul 1, 2022
1 parent 54b41e8 commit f2e35e6
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 4 deletions.
33 changes: 30 additions & 3 deletions src/epub2txt.c
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,7 @@ void epub2txt_do_file (const char *file, const Epub2TxtOptions *options,
run_command((const char *[]){"chmod", "-R", "744", tempdir, NULL}, FALSE);
log_debug ("Permissions fixed");

char *opf;
char *opf, *tmp;
asprintf (&opf, "%s/META-INF/container.xml", tempdir);
log_debug ("OPF path is: %s", opf);
String *rootfile = epub2txt_get_root_file (opf, error);
Expand All @@ -458,7 +458,20 @@ void epub2txt_do_file (const char *file, const Epub2TxtOptions *options,
log_debug ("OPF rootfile is: %s", string_cstr(rootfile));

free (opf);
asprintf (&opf, "%s/%s", tempdir, string_cstr (rootfile));
asprintf (&tmp, "%s/%s", tempdir, string_cstr (rootfile));
opf = canonicalize_file_name (tmp);
free (tmp);

if (opf == NULL || !is_subpath (tempdir, opf))
{
if (opf == NULL)
asprintf (error, "Bad OPF rootfile path: %s", strerror (errno));
else
asprintf (error, "Bad OPF rootfile path \"%s\": outside EPUB "
"container", opf);
free (tempdir);
return;
}

char *content_dir = strdup (opf);
char *p = strrchr (content_dir, '/');
Expand Down Expand Up @@ -489,7 +502,21 @@ void epub2txt_do_file (const char *file, const Epub2TxtOptions *options,
{
const char *item = (const char *)list_get (list, i);
free (opf);
asprintf (&opf, "%s/%s", content_dir, item);
asprintf (&tmp, "%s/%s", content_dir, item);
opf = canonicalize_file_name (tmp);
free (tmp);

if (opf == NULL || !is_subpath (content_dir, opf))
{
if (opf == NULL)
log_warning ("Skipping EPUB file \"%s\": invalid path (%s)",
item, strerror (errno));
else
log_warning ("Skipping EPUB file \"%s\": outside EPUB content "
"directory", item);
continue;
}

xhtml_file_to_stdout (opf, options, error);
}
list_destroy (list);
Expand Down
16 changes: 15 additions & 1 deletion src/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,4 +80,18 @@ char *decode_url (const char *url)
return ret;
}


/*==========================================================================
is_subpath
Determine whether path is a subpath of root; or in other words, whether path
points to a file/directory inside root. Both root and path are assumed to be
in canonical form, therefore the caller should make sure of this using e.g.
canonicalize_file_name().
(Marco Bonelli)
*==========================================================================*/
BOOL is_subpath (const char *root, const char *path)
{
size_t root_len = strlen (root);
size_t path_len = strlen (path);
return path_len > root_len && !strncmp (root, path, root_len)
&& path[root_len] == '/';
}
4 changes: 4 additions & 0 deletions src/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,7 @@ int run_command (const char *const argv[], BOOL abort_on_error);
/** Decode %xx in URL-type strings. The caller must free the resulting
string, which will be no longer than the input. */
char *decode_url (const char *url);

/** Determine whether path is a subpath of root, assuming both paths are in
canonical form. */
BOOL is_subpath (const char *root, const char *path);

0 comments on commit f2e35e6

Please sign in to comment.