diff --git a/configure.ac b/configure.ac index 029b334fdc9847148fa9bab6f577af7e98e31568..9aa25bd593dbd1cb451ae740991df9b5a857efc1 100644 --- a/configure.ac +++ b/configure.ac @@ -24,7 +24,7 @@ # Autoconf AC_PREREQ(2.59) -AC_INIT([ntfs-3g],[2021.8.22],[ntfs-3g-devel@lists.sf.net]) +AC_INIT([ntfs-3g],[2022.5.17],[ntfs-3g-devel@lists.sf.net]) LIBNTFS_3G_VERSION="89" AC_CONFIG_SRCDIR([src/ntfs-3g.c]) diff --git a/libfuse-lite/fuse.c b/libfuse-lite/fuse.c index 6f9242b776b6c7a88a1b1ee27f03a8fe6714a248..3d653e634b93cfb8443fffc496bc843e9780c9db 100644 --- a/libfuse-lite/fuse.c +++ b/libfuse-lite/fuse.c @@ -2223,7 +2223,7 @@ static void fuse_lib_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, } } if (dh->filled) { - if (off < dh->len) { + if ((off >= 0) && (off < dh->len)) { if (off + size > dh->len) size = dh->len - off; } else diff --git a/libfuse-lite/mount.c b/libfuse-lite/mount.c index 64adee7d858033c121409a9e1696cf86d3df9dd3..6ae29d8c3191d6845f5be462078c033a22a932f8 100644 --- a/libfuse-lite/mount.c +++ b/libfuse-lite/mount.c @@ -670,11 +670,10 @@ int fuse_kern_mount(const char *mountpoint, struct fuse_args *args) fprintf(stderr, "fuse: 'allow_other' and 'allow_root' options are mutually exclusive\n"); goto out; } - res = 0; + res = -1; if (mo.ishelp) goto out; - res = -1; if (get_mnt_flag_opts(&mnt_opts, mo.flags) == -1) goto out; #ifndef __SOLARIS__ diff --git a/libntfs-3g/attrib.c b/libntfs-3g/attrib.c index e8d6fafb8242cca0c4c11c941a6a2423e6cfd903..efb91943810a734c5103978da8319793e7040813 100644 --- a/libntfs-3g/attrib.c +++ b/libntfs-3g/attrib.c @@ -216,6 +216,7 @@ s64 ntfs_get_attribute_value(const ntfs_volume *vol, if (total + (rl[i].length << vol->cluster_size_bits) >= sle64_to_cpu(a->data_size)) { unsigned char *intbuf = NULL; + s64 intlth; /* * We have reached the last run so we were going to * overflow when executing the ntfs_pread() which is @@ -229,8 +230,18 @@ s64 ntfs_get_attribute_value(const ntfs_volume *vol, * We have reached the end of data size so we were * going to overflow in the same fashion. * Temporary fix: same as above. + * + * For safety, limit the amount to read to the + * needed size, knowing that the whole attribute + * size has been checked to be <= 0x40000. */ - intbuf = ntfs_malloc(rl[i].length << vol->cluster_size_bits); + intlth = (sle64_to_cpu(a->data_size) - total + + vol->cluster_size - 1) + >> vol->cluster_size_bits; + if (rl[i].length < intlth) + intlth = rl[i].length; + intbuf = (u8*)ntfs_malloc(intlth + << vol->cluster_size_bits); if (!intbuf) { free(rl); return 0; @@ -246,14 +257,15 @@ s64 ntfs_get_attribute_value(const ntfs_volume *vol, * - Yes we can, in sparse files! But not necessarily * size of 16, just run length. */ - r = ntfs_pread(vol->dev, rl[i].lcn << - vol->cluster_size_bits, rl[i].length << - vol->cluster_size_bits, intbuf); - if (r != rl[i].length << vol->cluster_size_bits) { + r = ntfs_pread(vol->dev, + rl[i].lcn << vol->cluster_size_bits, + intlth << vol->cluster_size_bits, + intbuf); + if (r != intlth << vol->cluster_size_bits) { #define ESTR "Error reading attribute value" if (r == -1) ntfs_log_perror(ESTR); - else if (r < rl[i].length << + else if (r < intlth << vol->cluster_size_bits) { ntfs_log_debug(ESTR ": Ran out of input data.\n"); errno = EIO; @@ -414,7 +426,15 @@ ntfs_attr *ntfs_attr_open(ntfs_inode *ni, const ATTR_TYPES type, na = ntfs_calloc(sizeof(ntfs_attr)); if (!na) goto out; + if (!name_len) + name = (ntfschar*)NULL; if (name && name != AT_UNNAMED && name != NTFS_INDEX_I30) { + /* A null char leads to a short name and unallocated bytes */ + if (ntfs_ucsnlen(name, name_len) != name_len) { + ntfs_log_error("Null character in attribute name" + " of inode %lld\n",(long long)ni->mft_no); + goto err_out; + } name = ntfs_ucsndup(name, name_len); if (!name) goto err_out; @@ -432,8 +452,19 @@ ntfs_attr *ntfs_attr_open(ntfs_inode *ni, const ATTR_TYPES type, if (!name) { if (a->name_length) { - name = ntfs_ucsndup((ntfschar*)((u8*)a + le16_to_cpu( - a->name_offset)), a->name_length); + ntfschar *attr_name; + + attr_name = (ntfschar*)((u8*)a + + le16_to_cpu(a->name_offset)); + /* A null character leads to illegal memory access */ + if (ntfs_ucsnlen(attr_name, a->name_length) + != a->name_length) { + ntfs_log_error("Null character in attribute" + " name in inode %lld\n", + (long long)ni->mft_no); + goto put_err_out; + } + name = ntfs_ucsndup(attr_name, a->name_length); if (!name) goto put_err_out; newname = name; diff --git a/libntfs-3g/logfile.c b/libntfs-3g/logfile.c index adc0557f580bbdc9ce5cb8e4163cf33a57f468c1..c0ba09b528e4c890845c3ccb7a19efd0ee346716 100644 --- a/libntfs-3g/logfile.c +++ b/libntfs-3g/logfile.c @@ -287,9 +287,19 @@ static BOOL ntfs_check_log_client_array(RESTART_PAGE_HEADER *rp) LOG_CLIENT_RECORD *ca, *cr; u16 nr_clients, idx; BOOL in_free_list, idx_is_first; + u32 offset_clients; ntfs_log_trace("Entering.\n"); + /* The restart area must be fully within page */ + if ((le16_to_cpu(rp->restart_area_offset) + sizeof(RESTART_AREA)) + > le32_to_cpu(rp->system_page_size)) + goto err_out; ra = (RESTART_AREA*)((u8*)rp + le16_to_cpu(rp->restart_area_offset)); + offset_clients = le16_to_cpu(rp->restart_area_offset) + + le16_to_cpu(ra->client_array_offset); + /* The clients' records must begin within page */ + if (offset_clients >= le32_to_cpu(rp->system_page_size)) + goto err_out; ca = (LOG_CLIENT_RECORD*)((u8*)ra + le16_to_cpu(ra->client_array_offset)); /* @@ -308,6 +318,10 @@ check_list: idx = le16_to_cpu(cr->next_client)) { if (!nr_clients || idx >= le16_to_cpu(ra->log_clients)) goto err_out; + /* The client record must be fully within page */ + if ((offset_clients + (idx + 1)*sizeof(LOG_CLIENT_RECORD)) + > le32_to_cpu(rp->system_page_size)) + goto err_out; /* Set @cr to the current log client record. */ cr = ca + idx; /* The first log client record must not have a prev_client. */ @@ -380,7 +394,14 @@ static int ntfs_check_and_load_restart_page(ntfs_attr *log_na, /* * Allocate a buffer to store the whole restart page so we can multi * sector transfer deprotect it. + * For safety, make sure this is consistent with the usa_count + * and shorter than the full log size */ + if ((le32_to_cpu(rp->system_page_size) + > (u32)(le16_to_cpu(rp->usa_count) - 1)*NTFS_BLOCK_SIZE) + || (le32_to_cpu(rp->system_page_size) + > le64_to_cpu(log_na->data_size))) + return (EINVAL); trp = ntfs_malloc(le32_to_cpu(rp->system_page_size)); if (!trp) return errno; diff --git a/libntfs-3g/mft.c b/libntfs-3g/mft.c index d0a601ffa17d3df56e64dc9746173bafbbf2d4a8..a880e1ea98835761f897676cb75e372816b2e399 100644 --- a/libntfs-3g/mft.c +++ b/libntfs-3g/mft.c @@ -5,7 +5,7 @@ * Copyright (c) 2004-2005 Richard Russon * Copyright (c) 2004-2008 Szabolcs Szakacsits * Copyright (c) 2005 Yura Pakhuchiy - * Copyright (c) 2014-2018 Jean-Pierre Andre + * Copyright (c) 2014-2021 Jean-Pierre Andre * * This program/include file is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as published @@ -1529,8 +1529,17 @@ found_free_rec: goto undo_mftbmp_alloc; } + /* + * Retrieve the former seq_no and usn so that the new record + * cannot be mistaken for the former one. + * However the original record may just be garbage, so + * use some sensible value when they cannot be retrieved. + */ seq_no = m->sequence_number; - usn = *(le16*)((u8*)m + le16_to_cpu(m->usa_ofs)); + if (le16_to_cpu(m->usa_ofs) <= (NTFS_BLOCK_SIZE - 2)) + usn = *(le16*)((u8*)m + (le16_to_cpu(m->usa_ofs) & -2)); + else + usn = const_cpu_to_le16(1); if (ntfs_mft_record_layout(vol, bit, m)) { ntfs_log_error("Failed to re-format mft record.\n"); free(m); diff --git a/ntfsprogs/ntfsck.c b/ntfsprogs/ntfsck.c index d49f3f96c4997bb2d2639f2f84af35869d6a37d1..8c1264112e6baec9d0715f9870198f7426dcc95a 100644 --- a/ntfsprogs/ntfsck.c +++ b/ntfsprogs/ntfsck.c @@ -616,7 +616,8 @@ static BOOL check_file_record(u8 *buffer, u16 buflen) // Remove update seq & check it. usa = *(u16*)(buffer+usa_ofs); // The value that should be at the end of every sector. - assert_u32_equal(usa_count-1, buflen/NTFS_BLOCK_SIZE, "USA length"); + if (assert_u32_equal(usa_count-1, buflen/NTFS_BLOCK_SIZE, "USA length")) + return (1); for (i=1;iname); diff --git a/src/ntfs-3g_common.h b/src/ntfs-3g_common.h index 4ed256a319ba5279aea8190b0946f77d4e9b5400..8ead5107bebf4e8f4f7a9dd8d533d8105fab9787 100644 --- a/src/ntfs-3g_common.h +++ b/src/ntfs-3g_common.h @@ -94,6 +94,8 @@ enum { OPT_EFS_RAW, OPT_POSIX_NLINK, OPT_SPECIAL_FILES, + OPT_HELP, + OPT_VERSION, } ; /* Option flags */