*/
/*
- * 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
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
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)) {
/*
calculate_dentry_full_path(struct wim_dentry *dentry)
{
size_t ulen;
- size_t dummy;
const struct wim_dentry *d;
if (dentry->d_full_path)
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));
wimlib_assert(p == ubuf);
return utf16le_to_tstr(ubuf, ulen * sizeof(utf16lechar),
- &dentry->d_full_path, &dummy);
+ &dentry->d_full_path, NULL);
}
/*
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;
}
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)
return ret;
}
-/* Is the dentry named "." or ".." ? */
static bool
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)
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;
}
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)