Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions messages/internal_error/root.txt
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,7 @@ root:table {
I5048E:string{ "Unexpected partition map in a label." }
I5049E:string{ "Unexpected blocksize in a label." }
I5050E:string{ "Unexpected compression in a label." }
I5051E:string{ "Directory nesting in the index is too deep." }

// Special error codes
I9997E:string{ "Child process error (ltfsck/mkltfs): %s (%d)." }
Expand Down
1 change: 1 addition & 0 deletions messages/libltfs/root.txt
Original file line number Diff line number Diff line change
Expand Up @@ -836,6 +836,7 @@ v
17292I:string { "Current position is (%llu, %llu), Error position is (%llu, %llu)." }
17293E:string { "Position mismatch. Cached tape position = %llu. Current tape position = %llu." }
17294I:string { "Continue signal (%d) received" }
17295E:string { "XML parser: directory nesting is too deep (limit %d)." }

// For Debug 19999I:string { "%s %s %d." }

Expand Down
1 change: 1 addition & 0 deletions src/libltfs/arch/errormap.c
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@ static struct error_map fuse_error_list[] = {
{ LTFS_XML_WRONG_PART_MAP, "I5048E", EINVAL},
{ LTFS_XML_WRONG_BLOCKSIZE, "I5049E", EINVAL},
{ LTFS_XML_WRONG_COMP, "I5050E", EINVAL},
{ LTFS_XML_DEEP_NESTING, "I5051E", EINVAL},
{ EDEV_NO_SENSE, "D0000E", EIO},
{ EDEV_OVERRUN, "D0002E", EIO},
{ EDEV_UNDERRUN, "D0003E", ENODATA},
Expand Down
1 change: 1 addition & 0 deletions src/libltfs/ltfs_error.h
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,7 @@
#define LTFS_XML_WRONG_PART_MAP 5048 /* Unexpected partition map in a label */
#define LTFS_XML_WRONG_BLOCKSIZE 5049 /* Unexpected blocksize in a label */
#define LTFS_XML_WRONG_COMP 5050 /* Unexpected compression in a label */
#define LTFS_XML_DEEP_NESTING 5051 /* Directory nesting in the index is too deep */

#define LTFS_ERR_MAX 19999

Expand Down
4 changes: 3 additions & 1 deletion src/libltfs/xml_reader.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,9 @@ int xml_next_tag(xmlTextReaderPtr reader, const char *containing_name,
return ret;
*name = (const char *)xmlTextReaderConstName(reader);
*type = xmlTextReaderNodeType(reader);
} while (strcmp(*name, containing_name) && (*type) != XML_ELEMENT_NODE);
/* libxml2 returns a NULL name for some node types; keep reading
* rather than dereferencing NULL in strcmp below. */
} while (! *name || (strcmp(*name, containing_name) && (*type) != XML_ELEMENT_NODE));

return 0;
}
Expand Down
46 changes: 36 additions & 10 deletions src/libltfs/xml_reader_libltfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,10 @@ static int decode_entry_name(char **new_name, const char *name)
/* Always, length must be shorter than original but allocate null termination space */
len = strlen(name);
tmp_name = malloc((len * sizeof(UChar)) + 1);
if (! tmp_name) {
ltfsmsg(LTFS_ERR, 10001E, "decode_entry_name: tmp_name");
return -LTFS_NO_MEMORY;
}
buf_decode[2] = '\0';

while (i < len) {
Expand Down Expand Up @@ -575,8 +579,15 @@ static int _xml_parse_ip_criteria(xmlTextReaderPtr reader, struct ltfs_index *id

++num_patterns;
/* quite inefficient, but the number of patterns should be small. */
idx->original_criteria.glob_patterns = realloc(idx->original_criteria.glob_patterns,
(num_patterns + 1) * sizeof(struct ltfs_name));
{
struct ltfs_name *new_patterns = realloc(idx->original_criteria.glob_patterns,
(num_patterns + 1) * sizeof(struct ltfs_name));
if (! new_patterns) {
ltfsmsg(LTFS_ERR, 10001E, "_xml_parse_ip_criteria: glob_patterns");
return -LTFS_NO_MEMORY;
}
idx->original_criteria.glob_patterns = new_patterns;
}

if (_xml_parse_nametype(reader,
&idx->original_criteria.glob_patterns[num_patterns - 1],
Expand Down Expand Up @@ -863,10 +874,10 @@ static int _xml_parse_one_xattr(xmlTextReaderPtr reader, struct dentry *d)
if (xattr) {
TAILQ_INSERT_TAIL(&d->xattrlist, xattr, list);

if (!strcmp(xattr->key.name, "ltfs.vendor.IBM.immutable") && !strcmp(xattr->value, "1") ) {
if (xattr->value && !strcmp(xattr->key.name, "ltfs.vendor.IBM.immutable") && !strcmp(xattr->value, "1") ) {
d->is_immutable = true;
}
if (!strcmp(xattr->key.name, "ltfs.vendor.IBM.appendonly") && !strcmp(xattr->value, "1") ) {
if (xattr->value && !strcmp(xattr->key.name, "ltfs.vendor.IBM.appendonly") && !strcmp(xattr->value, "1") ) {
d->is_appendonly = true;
}
}
Expand Down Expand Up @@ -1192,11 +1203,21 @@ static int _xml_parse_file(xmlTextReaderPtr reader, struct ltfs_index *idx, stru
* Parse a dir into the given directory.
*/

/* Guard against C-stack exhaustion while parsing the directory tree:
* _xml_parse_dirtree recurses once per nesting level and XML_PARSE_HUGE
* removes libxml2's own nesting limit, so a crafted index could otherwise
* recurse until the stack overflows. This is a stack-safety bound, not an
* LTFS format limit (the format defines no maximum depth); it is set far
* above any tree that fits in a conventional PATH_MAX, so it cannot reject
* a volume produced from a real filesystem. */
#define XML_MAX_DIRTREE_DEPTH 1024

static int _xml_parse_dirtree(xmlTextReaderPtr reader, struct dentry *parent,
struct ltfs_index *idx, struct ltfs_volume *vol,
struct name_list *dirname); /* Forward reference */
struct name_list *dirname, int depth); /* Forward reference */

static int _xml_parse_dir_contents(xmlTextReaderPtr reader, struct dentry *dir, struct ltfs_index *idx)
static int _xml_parse_dir_contents(xmlTextReaderPtr reader, struct dentry *dir,
struct ltfs_index *idx, int depth)
{
struct name_list *list = NULL, *entry_name = NULL;
CHECK_ARG_NULL(dir, -LTFS_NULL_ARG);
Expand Down Expand Up @@ -1228,7 +1249,7 @@ static int _xml_parse_dir_contents(xmlTextReaderPtr reader, struct dentry *dir,
ltfsmsg(LTFS_ERR, 10001E, "_xml_parse_dir_contents: dir");
return -LTFS_NO_MEMORY;
}
ret = _xml_parse_dirtree(reader, dir, idx, dir->vol, entry_name);
ret = _xml_parse_dirtree(reader, dir, idx, dir->vol, entry_name, depth + 1);
if (ret < 0) {
free(entry_name);
return ret;
Expand Down Expand Up @@ -1285,14 +1306,19 @@ static int _xml_parse_dir_contents(xmlTextReaderPtr reader, struct dentry *dir,
*/
static int _xml_parse_dirtree(xmlTextReaderPtr reader, struct dentry *parent,
struct ltfs_index *idx, struct ltfs_volume *vol,
struct name_list *dirname)
struct name_list *dirname, int depth)
{
unsigned long long value_int;
struct dentry *dir;

declare_parser_vars("directory");
declare_tracking_arrays(9, 1);

if (depth > XML_MAX_DIRTREE_DEPTH) {
ltfsmsg(LTFS_ERR, 17295E, XML_MAX_DIRTREE_DEPTH);
return -LTFS_XML_DEEP_NESTING;
}

if (! parent && idx->root) {
dir = idx->root;
dir->vol = vol;
Expand Down Expand Up @@ -1407,7 +1433,7 @@ static int _xml_parse_dirtree(xmlTextReaderPtr reader, struct dentry *parent,
check_required_tag(6);
check_empty();
if (empty == 0) {
ret = _xml_parse_dir_contents(reader, dir, idx);
ret = _xml_parse_dir_contents(reader, dir, idx, depth);
if (ret < 0)
return ret;
}
Expand Down Expand Up @@ -1598,7 +1624,7 @@ static int _xml_parse_schema(xmlTextReaderPtr reader, struct ltfs_index *idx, st
} else if (! strcmp(name, "directory")) {
check_required_tag(6);
assert_not_empty();
ret = _xml_parse_dirtree(reader, NULL, idx, vol, NULL);
ret = _xml_parse_dirtree(reader, NULL, idx, vol, NULL, 0);
if (ret < 0)
return ret;

Expand Down