X-Git-Url: https://wimlib.net/git/?a=blobdiff_plain;f=src%2Fdentry.c;h=db333849584c8e8641b317a1d5db882f09258654;hb=9f56f9f091155065173712c3f254945fd8224511;hp=4f842eaa6a413d3588be38f1a58f85ef2600429c;hpb=d5975da32eacd99a3211b6158da2e487cb5a5713;p=wimlib diff --git a/src/dentry.c b/src/dentry.c index 4f842eaa..db333849 100644 --- a/src/dentry.c +++ b/src/dentry.c @@ -3,7 +3,7 @@ */ /* - * Copyright (C) 2012, 2013, 2014, 2015 Eric Biggers + * Copyright (C) 2012-2016 Eric Biggers * * This file is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free @@ -92,10 +92,10 @@ struct wim_dentry_on_disk { le32 attributes; /* A value that specifies the security descriptor for this file or - * directory. If -1, the file or directory has no security descriptor. - * Otherwise, it is a 0-based index into the WIM image's table of - * security descriptors (see: `struct wim_security_data') */ - sle32 security_id; + * directory. If 0xFFFFFFFF, the file or directory has no security + * descriptor. Otherwise, it is a 0-based index into the WIM image's + * table of security descriptors (see: `struct wim_security_data') */ + le32 security_id; /* Offset, in bytes, from the start of the uncompressed metadata * resource of this directory's child directory entries, or 0 if this @@ -358,7 +358,8 @@ dentry_out_total_length(const struct wim_dentry *dentry) dentry->d_short_name_nbytes); len = ALIGN(len, 8); - len += ALIGN(inode->i_extra_size, 8); + if (inode->i_extra) + len += ALIGN(inode->i_extra->size, 8); if (!(inode->i_attributes & FILE_ATTRIBUTE_ENCRYPTED)) { /* @@ -503,7 +504,8 @@ calculate_dentry_full_path(struct wim_dentry *dentry) d = dentry; do { p -= d->d_name_nbytes / sizeof(utf16lechar); - memcpy(p, d->d_name, d->d_name_nbytes); + if (d->d_name_nbytes) + memcpy(p, d->d_name, d->d_name_nbytes); *--p = cpu_to_le16(WIM_PATH_SEPARATOR); d = d->d_parent; /* assumes d == d->d_parent for root */ } while (!dentry_is_root(d)); @@ -1187,10 +1189,12 @@ read_extra_data(const u8 *p, const u8 *end, struct wim_inode *inode) p++; if (unlikely(p < end)) { - inode->i_extra = memdup(p, end - p); + inode->i_extra = MALLOC(sizeof(struct wim_inode_extra) + + end - p); if (!inode->i_extra) return WIMLIB_ERR_NOMEM; - inode->i_extra_size = end - p; + inode->i_extra->size = end - p; + memcpy(inode->i_extra->data, p, end - p); } return 0; } @@ -1394,7 +1398,7 @@ read_dentry(const u8 * restrict buf, size_t buf_len, u64 calculated_size; int ret; - BUILD_BUG_ON(sizeof(struct wim_dentry_on_disk) != WIM_DENTRY_DISK_SIZE); + STATIC_ASSERT(sizeof(struct wim_dentry_on_disk) == WIM_DENTRY_DISK_SIZE); /* Before reading the whole dentry, we need to read just the length. * This is because a dentry of length 8 (that is, just the length field) @@ -1528,7 +1532,6 @@ err_free_dentry: return ret; } -/* Is the dentry named "." or ".." ? */ static bool dentry_is_dot_or_dotdot(const struct wim_dentry *dentry) { @@ -1545,6 +1548,46 @@ dentry_is_dot_or_dotdot(const struct wim_dentry *dentry) return false; } +static bool +dentry_contains_embedded_null(const struct wim_dentry *dentry) +{ + for (unsigned i = 0; i < dentry->d_name_nbytes / 2; i++) + if (dentry->d_name[i] == cpu_to_le16('\0')) + return true; + return false; +} + +static bool +should_ignore_dentry(struct wim_dentry *dir, const struct wim_dentry *dentry) +{ + /* All dentries except the root must be named. */ + if (!dentry_has_long_name(dentry)) { + WARNING("Ignoring unnamed file in directory \"%"TS"\"", + dentry_full_path(dir)); + return true; + } + + /* Don't allow files named "." or "..". Such filenames could be used in + * path traversal attacks. */ + if (dentry_is_dot_or_dotdot(dentry)) { + WARNING("Ignoring file named \".\" or \"..\" in directory " + "\"%"TS"\"", dentry_full_path(dir)); + return true; + } + + /* Don't allow filenames containing embedded null characters. Although + * the null character is already considered an unsupported character for + * extraction by all targets, it is probably a good idea to just forbid + * such names entirely. */ + if (dentry_contains_embedded_null(dentry)) { + WARNING("Ignoring filename with embedded null character in " + "directory \"%"TS"\"", dentry_full_path(dir)); + return true; + } + + return false; +} + static int read_dentry_tree_recursive(const u8 * restrict buf, size_t buf_len, struct wim_dentry * restrict dir, unsigned depth) @@ -1571,18 +1614,8 @@ read_dentry_tree_recursive(const u8 * restrict buf, size_t buf_len, if (child == NULL) return 0; - /* All dentries except the root should be named. */ - if (unlikely(!dentry_has_long_name(child))) { - WARNING("Ignoring unnamed dentry in " - "directory \"%"TS"\"", dentry_full_path(dir)); - free_dentry(child); - continue; - } - - /* Don't allow files named "." or "..". */ - if (unlikely(dentry_is_dot_or_dotdot(child))) { - WARNING("Ignoring file named \".\" or \"..\"; " - "potentially malicious archive!!!"); + /* Ignore dentries with bad names. */ + if (unlikely(should_ignore_dentry(dir, child))) { free_dentry(child); continue; } @@ -1774,9 +1807,9 @@ write_dentry(const struct wim_dentry * restrict dentry, u8 * restrict p) while ((uintptr_t)p & 7) *p++ = 0; - if (inode->i_extra_size) { + if (inode->i_extra) { /* Extra tagged items --- not usually present. */ - p = mempcpy(p, inode->i_extra, inode->i_extra_size); + p = mempcpy(p, inode->i_extra->data, inode->i_extra->size); /* Align to 8-byte boundary */ while ((uintptr_t)p & 7)