Version in base suite: 2022.10.3-5+deb13u1 Base version: ntfs-3g_2022.10.3-5+deb13u1 Target version: ntfs-3g_2022.10.3-5+deb13u2 Base file: /srv/ftp-master.debian.org/ftp/pool/main/n/ntfs-3g/ntfs-3g_2022.10.3-5+deb13u1.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/n/ntfs-3g/ntfs-3g_2022.10.3-5+deb13u2.dsc changelog | 9 patches/CVE-2026-42616.patch | 44 + patches/CVE-2026-42617_CVE-2026-46572_CVE-2026-56136.patch | 130 ++++ patches/CVE-2026-42618.patch | 361 +++++++++++++ patches/CVE-2026-46569.patch | 39 + patches/CVE-2026-46570.patch | 18 patches/CVE-2026-46571.patch | 27 patches/CVE-2026-56135.patch | 151 +++++ patches/series | 7 9 files changed, 786 insertions(+) dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmplk48zedk/ntfs-3g_2022.10.3-5+deb13u1.dsc: no acceptable signature found dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmplk48zedk/ntfs-3g_2022.10.3-5+deb13u2.dsc: no acceptable signature found diff -Nru ntfs-3g-2022.10.3/debian/changelog ntfs-3g-2022.10.3/debian/changelog --- ntfs-3g-2022.10.3/debian/changelog 2026-04-16 21:27:17.000000000 +0000 +++ ntfs-3g-2022.10.3/debian/changelog 2026-07-15 05:02:26.000000000 +0000 @@ -1,3 +1,12 @@ +ntfs-3g (1:2022.10.3-5+deb13u2) trixie-security; urgency=high + + * Non-maintainer upload by the Security Team. + * Fix multiple vulnerabilities (CVE-2026-42616, CVE-2026-42617, + CVE-2026-42618, CVE-2026-46569, CVE-2026-46570, CVE-2026-46571, + CVE-2026-46572, CVE-2026-56135, CVE-2026-56136) + + -- Salvatore Bonaccorso Wed, 15 Jul 2026 07:02:26 +0200 + ntfs-3g (1:2022.10.3-5+deb13u1) trixie-security; urgency=high * Non-maintainer upload by the Security Team. diff -Nru ntfs-3g-2022.10.3/debian/patches/CVE-2026-42616.patch ntfs-3g-2022.10.3/debian/patches/CVE-2026-42616.patch --- ntfs-3g-2022.10.3/debian/patches/CVE-2026-42616.patch 1970-01-01 00:00:00.000000000 +0000 +++ ntfs-3g-2022.10.3/debian/patches/CVE-2026-42616.patch 2026-07-09 04:34:54.000000000 +0000 @@ -0,0 +1,44 @@ +diff --git a/ntfsprogs/ntfscat.c b/ntfsprogs/ntfscat.c +index b8af25033..0f711815a 100644 +--- a/ntfsprogs/ntfscat.c ++++ b/ntfsprogs/ntfscat.c +@@ -334,22 +334,17 @@ static int index_get_size(ntfs_inode *inode) + static int cat(ntfs_volume *vol, ntfs_inode *inode, ATTR_TYPES type, + ntfschar *name, int namelen) + { +- const int bufsize = 4096; + char *buffer; + ntfs_attr *attr; + s64 bytes_read, written; + s64 offset; + u32 block_size; +- +- buffer = malloc(bufsize); +- if (!buffer) +- return 1; ++ u32 bufsize = 4096; + + attr = ntfs_attr_open(inode, type, name, namelen); + if (!attr) { + ntfs_log_error("Cannot find attribute type 0x%x.\n", + le32_to_cpu(type)); +- free(buffer); + return 1; + } + +@@ -360,6 +355,15 @@ static int cat(ntfs_volume *vol, ntfs_inode *inode, ATTR_TYPES type, + else + block_size = 0; + ++ if (bufsize < block_size) { ++ bufsize = block_size; ++ } ++ ++ buffer = malloc(bufsize); ++ if (!buffer) { ++ return 1; ++ } ++ + offset = 0; + for (;;) { + if (!opts.raw && block_size > 0) { diff -Nru ntfs-3g-2022.10.3/debian/patches/CVE-2026-42617_CVE-2026-46572_CVE-2026-56136.patch ntfs-3g-2022.10.3/debian/patches/CVE-2026-42617_CVE-2026-46572_CVE-2026-56136.patch --- ntfs-3g-2022.10.3/debian/patches/CVE-2026-42617_CVE-2026-46572_CVE-2026-56136.patch 1970-01-01 00:00:00.000000000 +0000 +++ ntfs-3g-2022.10.3/debian/patches/CVE-2026-42617_CVE-2026-46572_CVE-2026-56136.patch 2026-07-09 04:34:54.000000000 +0000 @@ -0,0 +1,130 @@ +diff --git a/include/ntfs-3g/index.h b/include/ntfs-3g/index.h +index d001863ae..1d5845d47 100644 +--- a/include/ntfs-3g/index.h ++++ b/include/ntfs-3g/index.h +@@ -143,6 +143,7 @@ extern int ntfs_index_block_inconsistent(const INDEX_BLOCK *ib, u32 block_size, + u64 inum, VCN vcn); + extern int ntfs_index_entry_inconsistent(const INDEX_ENTRY *ie, + COLLATION_RULES collation_rule, u64 inum); ++extern int ntfs_ie_stream_inconsistent(const INDEX_HEADER *ih, u64 inum); + extern int ntfs_index_lookup(const void *key, const int key_len, + ntfs_index_context *ictx) __attribute_warn_unused_result__; + +diff --git a/libntfs-3g/attrib.c b/libntfs-3g/attrib.c +index efb919438..cfc2446e3 100644 +--- a/libntfs-3g/attrib.c ++++ b/libntfs-3g/attrib.c +@@ -3528,6 +3528,10 @@ int ntfs_attr_inconsistent(const ATTR_RECORD *a, const MFT_REF mref) + if (a->non_resident + || (le32_to_cpu(a->value_length) + < offsetof(INDEX_ROOT, index.reserved)) ++ || (le32_to_cpu(ir->index_block_size) ++ < NTFS_BLOCK_SIZE) ++ || (le32_to_cpu(ir->index_block_size) ++ & (le32_to_cpu(ir->index_block_size) - 1)) + || (le32_to_cpu(ir->index.entries_offset) + < sizeof(INDEX_HEADER)) + || (le32_to_cpu(ir->index.index_length) +@@ -3542,6 +3546,9 @@ int ntfs_attr_inconsistent(const ATTR_RECORD *a, const MFT_REF mref) + (long long)inum); + errno = EIO; + ret = -1; ++ } else if (ntfs_ie_stream_inconsistent(&ir->index, inum)) { ++ errno = EIO; ++ ret = -1; + } + break; + case AT_STANDARD_INFORMATION : +diff --git a/libntfs-3g/index.c b/libntfs-3g/index.c +index e48d6aafb..c9651a62c 100644 +--- a/libntfs-3g/index.c ++++ b/libntfs-3g/index.c +@@ -504,6 +504,8 @@ int ntfs_index_block_inconsistent(const INDEX_BLOCK *ib, u32 block_size, + (unsigned long long)inum); + return -1; + } ++ if (ntfs_ie_stream_inconsistent(&ib->index, inum)) ++ return -1; + + return (0); + } +@@ -560,7 +562,40 @@ int ntfs_index_entry_inconsistent(const INDEX_ENTRY *ie, + return (ret); + } + +-/** ++int ntfs_ie_stream_inconsistent(const INDEX_HEADER *ih, u64 inum) ++{ ++ const u8 *ies_start = (const u8 *)ih + le32_to_cpu(ih->entries_offset); ++ const u8 *ies_end = (const u8 *)ih + le32_to_cpu(ih->index_length); ++ const u8 *ie; ++ ++ ntfs_log_trace("Entering\n"); ++ ++ for (ie = ies_start; ie < ies_end; ) { ++ u32 len; ++ const INDEX_ENTRY *ent = (const INDEX_ENTRY *)ie; ++ ++ if ((size_t)(ies_end - ie) < sizeof(INDEX_ENTRY_HEADER)) ++ goto err; ++ len = le16_to_cpu(ent->length); ++ if (len < sizeof(INDEX_ENTRY_HEADER) || (len & 7)) ++ goto err; ++ if ((size_t)(ies_end - ie) < len) ++ goto err; ++ if (ent->ie_flags & INDEX_ENTRY_END) { ++ /* END must terminate the stream exactly. */ ++ if (ie + len != ies_end) ++ goto err; ++ return 0; ++ } ++ ie += len; ++ } ++err: ++ ntfs_log_error("Corrupt index entry stream in inode %lld\n", ++ (long long)inum); ++ return -1; ++} ++ ++/** + * Find a key in the index block. + * + * Return values: +@@ -1091,14 +1126,16 @@ out: + + static INDEX_BLOCK *ntfs_ir_to_ib(INDEX_ROOT *ir, VCN ib_vcn) + { ++ u32 ib_size; + INDEX_BLOCK *ib; + INDEX_ENTRY *ie_last; + char *ies_start, *ies_end; + int i; + + ntfs_log_trace("Entering\n"); +- +- ib = ntfs_ib_alloc(ib_vcn, le32_to_cpu(ir->index_block_size), LEAF_NODE); ++ ++ ib_size = le32_to_cpu(ir->index_block_size); ++ ib = ntfs_ib_alloc(ib_vcn, ib_size, LEAF_NODE); + if (!ib) + return NULL; + +@@ -1110,6 +1147,18 @@ static INDEX_BLOCK *ntfs_ir_to_ib(INDEX_ROOT *ir, VCN ib_vcn) + * as well, which can never have any data. + */ + i = (char *)ie_last - ies_start + le16_to_cpu(ie_last->length); ++ ++ if (offsetof(INDEX_BLOCK, index) + le32_to_cpu(ib->index.entries_offset) ++ + i > ib_size) ++ { ++ ntfs_log_error("Last entry in index root overflows the index " ++ "block size: %d (index block size: %lu)\n", ++ i, (unsigned long)ib_size); ++ free(ib); ++ errno = EIO; ++ return NULL; ++ } ++ + memcpy(ntfs_ie_get_first(&ib->index), ies_start, i); + + ib->index.ih_flags = ir->index.ih_flags; diff -Nru ntfs-3g-2022.10.3/debian/patches/CVE-2026-42618.patch ntfs-3g-2022.10.3/debian/patches/CVE-2026-42618.patch --- ntfs-3g-2022.10.3/debian/patches/CVE-2026-42618.patch 1970-01-01 00:00:00.000000000 +0000 +++ ntfs-3g-2022.10.3/debian/patches/CVE-2026-42618.patch 2026-07-09 04:34:54.000000000 +0000 @@ -0,0 +1,361 @@ +diff --git a/libntfs-3g/compress.c b/libntfs-3g/compress.c +index 390b2d97d..50d9daf32 100644 +--- a/libntfs-3g/compress.c ++++ b/libntfs-3g/compress.c +@@ -459,7 +459,8 @@ static unsigned int ntfs_compress_block(const char *inbuf, const int bufsize, + * @cb_start is a pointer to the compression block which needs decompressing + * and @cb_size is the size of @cb_start in bytes (8-64kiB). + * +- * Return 0 if success or -EOVERFLOW on error in the compressed stream. ++ * Return 0 on success. On error in the compressed stream, set errno to ++ * EOVERFLOW and return -1. + */ + static int ntfs_decompress(u8 *dest, const u32 dest_size, + u8 *const cb_start, const u32 cb_size) +@@ -479,153 +480,211 @@ static int ntfs_decompress(u8 *dest, const u32 dest_size, + /* Variables for tag and token parsing. */ + u8 tag; /* Current tag. */ + int token; /* Loop counter for the eight tokens in tag. */ ++ u16 hdr; /* Current sub-block header. */ + + ntfs_log_trace("Entering, cb_size = 0x%x.\n", (unsigned)cb_size); + do_next_sb: +- ntfs_log_debug("Beginning sub-block at offset = %d in the cb.\n", +- (int)(cb - cb_start)); +- /* +- * Have we reached the end of the compression block or the end of the +- * decompressed data? The latter can happen for example if the current +- * position in the compression block is one byte before its end so the +- * first two checks do not detect it. +- */ +- if (cb == cb_end || !le16_to_cpup((le16*)cb) || dest == dest_end) { +- if (dest_end > dest) +- memset(dest, 0, dest_end - dest); +- ntfs_log_debug("Completed. Returning success (0).\n"); +- return 0; +- } +- /* Setup offset for the current sub-block destination. */ +- dest_sb_start = dest; +- dest_sb_end = dest + NTFS_SB_SIZE; +- /* Check that we are still within allowed boundaries. */ +- if (dest_sb_end > dest_end) +- goto return_overflow; +- /* Does the minimum size of a compressed sb overflow valid range? */ +- if (cb + 6 > cb_end) +- goto return_overflow; +- /* Setup the current sub-block source pointers and validate range. */ +- cb_sb_start = cb; +- cb_sb_end = cb_sb_start + (le16_to_cpup((le16*)cb) & NTFS_SB_SIZE_MASK) +- + 3; +- if (cb_sb_end > cb_end) +- goto return_overflow; +- /* Now, we are ready to process the current sub-block (sb). */ +- if (!(le16_to_cpup((le16*)cb) & NTFS_SB_IS_COMPRESSED)) { +- ntfs_log_debug("Found uncompressed sub-block.\n"); +- /* This sb is not compressed, just copy it into destination. */ +- /* Advance source position to first data byte. */ +- cb += 2; +- /* An uncompressed sb must be full size. */ +- if (cb_sb_end - cb != NTFS_SB_SIZE) +- goto return_overflow; +- /* Copy the block and advance the source position. */ +- memcpy(dest, cb, NTFS_SB_SIZE); +- cb += NTFS_SB_SIZE; +- /* Advance destination position to next sub-block. */ +- dest += NTFS_SB_SIZE; +- goto do_next_sb; +- } +- ntfs_log_debug("Found compressed sub-block.\n"); +- /* This sb is compressed, decompress it into destination. */ +- /* Forward to the first tag in the sub-block. */ +- cb += 2; +-do_next_tag: +- if (cb == cb_sb_end) { +- /* Check if the decompressed sub-block was not full-length. */ +- if (dest < dest_sb_end) { +- int nr_bytes = dest_sb_end - dest; +- +- ntfs_log_debug("Filling incomplete sub-block with zeroes.\n"); +- /* Zero remainder and update destination position. */ +- memset(dest, 0, nr_bytes); +- dest += nr_bytes; +- } +- /* We have finished the current sub-block. */ +- goto do_next_sb; +- } +- /* Check we are still in range. */ +- if (cb > cb_sb_end || dest > dest_sb_end) +- goto return_overflow; +- /* Get the next tag and advance to first token. */ +- tag = *cb++; +- /* Parse the eight tokens described by the tag. */ +- for (token = 0; token < 8; token++, tag >>= 1) { +- u16 lg, pt, length, max_non_overlap; +- register u16 i; +- u8 *dest_back_addr; +- +- /* Check if we are done / still in range. */ +- if (cb >= cb_sb_end || dest > dest_sb_end) +- break; +- /* Determine token type and parse appropriately.*/ +- if ((tag & NTFS_TOKEN_MASK) == NTFS_SYMBOL_TOKEN) { +- /* +- * We have a symbol token, copy the symbol across, and +- * advance the source and destination positions. +- */ +- *dest++ = *cb++; +- /* Continue with the next token. */ +- continue; +- } ++ { ++ ntfs_log_debug("Beginning sub-block at offset = %d in the " ++ "cb.\n", ++ (int)(cb - cb_start)); + /* +- * We have a phrase token. Make sure it is not the first tag in +- * the sb as this is illegal and would confuse the code below. ++ * Have we reached the end of the compression block or the end ++ * of the decompressed data? ++ * ++ * Check dest == dest_end before reading the next two-byte sub- ++ * block header. The compressed pointer can legally be near the ++ * end of the buffer when the requested output has already been ++ * produced. + */ +- if (dest == dest_sb_start) ++ if (cb == cb_end || dest == dest_end) ++ goto complete; ++ /* A sub-block header is two bytes. */ ++ if ((size_t)(cb_end - cb) < 2) + goto return_overflow; +- /* +- * Determine the number of bytes to go back (p) and the number +- * of bytes to copy (l). We use an optimized algorithm in which +- * we first calculate log2(current destination position in sb), +- * which allows determination of l and p in O(1) rather than +- * O(n). We just need an arch-optimized log2() function now. +- */ +- lg = 0; +- for (i = dest - dest_sb_start - 1; i >= 0x10; i >>= 1) +- lg++; +- /* Get the phrase token into i. */ +- pt = le16_to_cpup((le16*)cb); +- /* +- * Calculate starting position of the byte sequence in +- * the destination using the fact that p = (pt >> (12 - lg)) + 1 +- * and make sure we don't go too far back. +- */ +- dest_back_addr = dest - (pt >> (12 - lg)) - 1; +- if (dest_back_addr < dest_sb_start) ++ hdr = le16_to_cpup((le16*)cb); ++ if (!hdr) ++ goto complete; ++ /* Setup offset for the current sub-block destination. */ ++ dest_sb_start = dest; ++ dest_sb_end = dest + NTFS_SB_SIZE; ++ /* Check that we are still within allowed boundaries. */ ++ if (dest_sb_end > dest_end) + goto return_overflow; +- /* Now calculate the length of the byte sequence. */ +- length = (pt & (0xfff >> lg)) + 3; +- /* Verify destination is in range. */ +- if (dest + length > dest_sb_end) ++ /* Does the minimum size of a compressed sb overflow valid ++ * range? */ ++ if ((size_t)(cb_end - cb) < 6) + goto return_overflow; +- /* The number of non-overlapping bytes. */ +- max_non_overlap = dest - dest_back_addr; +- if (length <= max_non_overlap) { +- /* The byte sequence doesn't overlap, just copy it. */ +- memcpy(dest, dest_back_addr, length); +- /* Advance destination pointer. */ +- dest += length; +- } else { ++ /* Setup the current sub-block source pointers and validate ++ * range. */ ++ cb_sb_start = cb; ++ cb_sb_end = cb_sb_start + (hdr & NTFS_SB_SIZE_MASK) + 3; ++ if (cb_sb_end > cb_end) ++ goto return_overflow; ++ /* Now, we are ready to process the current sub-block (sb). */ ++ if (!(hdr & NTFS_SB_IS_COMPRESSED)) { ++ ntfs_log_debug("Found uncompressed sub-block.\n"); ++ /* This sb is not compressed, just copy it into ++ * destination. */ ++ /* Advance source position to first data byte. */ ++ cb += 2; ++ /* An uncompressed sb must be full size. */ ++ if (cb_sb_end - cb != NTFS_SB_SIZE) ++ goto return_overflow; ++ /* Copy the block and advance the source position. */ ++ memcpy(dest, cb, NTFS_SB_SIZE); ++ cb += NTFS_SB_SIZE; ++ /* Advance destination position to next sub-block. */ ++ dest += NTFS_SB_SIZE; ++ goto do_next_sb; ++ } ++ ntfs_log_debug("Found compressed sub-block.\n"); ++ /* This sb is compressed, decompress it into destination. */ ++ /* Forward to the first tag in the sub-block. */ ++ cb += 2; ++do_next_tag: ++ { ++ /* Check we are still in range. */ ++ if (cb > cb_sb_end || dest > dest_sb_end) ++ goto return_overflow; + /* +- * The byte sequence does overlap, copy non-overlapping +- * part and then do a slow byte by byte copy for the +- * overlapping part. Also, advance the destination +- * pointer. ++ * Finish this compressed sub-block when either its ++ * compressed input is exhausted or its 4 KiB output ++ * slot is full. If output becomes full first, skip the ++ * remaining compressed bytes in this sub-block instead ++ * of interpreting them as more tags/tokens. + */ +- memcpy(dest, dest_back_addr, max_non_overlap); +- dest += max_non_overlap; +- dest_back_addr += max_non_overlap; +- length -= max_non_overlap; +- while (length--) +- *dest++ = *dest_back_addr++; ++ if (cb == cb_sb_end || dest == dest_sb_end) ++ goto finish_compressed_sb; ++ /* Get the next tag and advance to first token. */ ++ tag = *cb++; ++ /* Parse the eight tokens described by the tag. */ ++ for (token = 0; token < 8; token++, tag >>= 1) { ++ u16 lg, pt, length, max_non_overlap; ++ register u16 i; ++ u8 *dest_back_addr; ++ ++ /* Check if we are done / still in range. */ ++ if (cb > cb_sb_end || dest > dest_sb_end) ++ goto return_overflow; ++ if (cb == cb_sb_end || dest == dest_sb_end) ++ goto finish_compressed_sb; ++ /* Determine token type and parse ++ * appropriately. */ ++ if ((tag & NTFS_TOKEN_MASK) == ++ NTFS_SYMBOL_TOKEN) ++ { ++ /* ++ * We have a symbol token, copy the ++ * symbol across, and advance the source ++ * and destination positions. ++ */ ++ *dest++ = *cb++; ++ /* Continue with the next token. */ ++ continue; ++ } ++ /* ++ * We have a phrase token. Make sure it is not ++ * the first token in the sb as this is illegal ++ * and would confuse the code below. ++ */ ++ if (dest == dest_sb_start) ++ goto return_overflow; ++ /* ++ * A phrase token is a two-byte compressed word. ++ * The generic token check above only proves ++ * that at least one byte remains, which is ++ * enough for a symbol token but not for a ++ * phrase token. ++ */ ++ if ((size_t)(cb_sb_end - cb) < 2) ++ goto return_overflow; ++ /* ++ * Determine the number of bytes to go back (p) ++ * and the number of bytes to copy (l). We use ++ * an optimized algorithm in which we first ++ * calculate log2(current destination position ++ * in sb), which allows determination of l and p ++ * in O(1) rather than O(n). We just need an ++ * arch-optimized log2() function now. ++ */ ++ lg = 0; ++ for (i = dest - dest_sb_start - 1; i >= 0x10; ++ i >>= 1) ++ { ++ lg++; ++ } ++ /* Get the phrase token into i. */ ++ pt = le16_to_cpup((le16*)cb); ++ /* ++ * Calculate starting position of the byte ++ * sequence in the destination using the fact ++ * that p = (pt >> (12 - lg)) + 1 and make sure ++ * we don't go too far back. ++ */ ++ dest_back_addr = dest - (pt >> (12 - lg)) - 1; ++ if (dest_back_addr < dest_sb_start) ++ goto return_overflow; ++ /* Now calculate the length of the byte ++ * sequence. */ ++ length = (pt & (0xfff >> lg)) + 3; ++ /* Verify destination is in range. */ ++ if (dest + length > dest_sb_end) ++ goto return_overflow; ++ /* The number of non-overlapping bytes. */ ++ max_non_overlap = dest - dest_back_addr; ++ if (length <= max_non_overlap) { ++ /* The byte sequence doesn't overlap, ++ * just copy it. */ ++ memcpy(dest, dest_back_addr, length); ++ /* Advance destination pointer. */ ++ dest += length; ++ } else { ++ /* ++ * The byte sequence does overlap, copy ++ * non-overlapping part and then do a ++ * slow byte by byte copy for the ++ * overlapping part. Also, advance the ++ * destination pointer. ++ */ ++ memcpy(dest, dest_back_addr, ++ max_non_overlap); ++ dest += max_non_overlap; ++ dest_back_addr += max_non_overlap; ++ length -= max_non_overlap; ++ while (length--) ++ *dest++ = *dest_back_addr++; ++ } ++ /* Advance source position and continue with the ++ * next token. */ ++ cb += 2; ++ } ++ /* No tokens left in the current tag. Continue with the ++ * next tag. */ ++ goto do_next_tag; + } +- /* Advance source position and continue with the next token. */ +- cb += 2; + } +- /* No tokens left in the current tag. Continue with the next tag. */ +- goto do_next_tag; ++finish_compressed_sb: ++ /* Check if the decompressed sub-block was not full-length. */ ++ if (dest < dest_sb_end) { ++ size_t nr_bytes = dest_sb_end - dest; ++ ++ ntfs_log_debug("Filling incomplete sub-block with zeroes.\n"); ++ /* Zero remainder and update destination position. */ ++ memset(dest, 0, nr_bytes); ++ dest += nr_bytes; ++ } ++ /* ++ * If the output sub-block filled before the compressed sub-block input ++ * was exhausted, skip the remaining compressed bytes in this sub-block. ++ */ ++ cb = cb_sb_end; ++ goto do_next_sb; ++complete: ++ if (dest_end > dest) ++ memset(dest, 0, dest_end - dest); ++ ntfs_log_debug("Completed. Returning success (0).\n"); ++ return 0; + return_overflow: + errno = EOVERFLOW; + ntfs_log_perror("Failed to decompress file"); diff -Nru ntfs-3g-2022.10.3/debian/patches/CVE-2026-46569.patch ntfs-3g-2022.10.3/debian/patches/CVE-2026-46569.patch --- ntfs-3g-2022.10.3/debian/patches/CVE-2026-46569.patch 1970-01-01 00:00:00.000000000 +0000 +++ ntfs-3g-2022.10.3/debian/patches/CVE-2026-46569.patch 2026-07-09 04:34:54.000000000 +0000 @@ -0,0 +1,39 @@ +diff --git a/libntfs-3g/index.c b/libntfs-3g/index.c +index e48d6aafb..6ebaa2e4a 100644 +--- a/libntfs-3g/index.c ++++ b/libntfs-3g/index.c +@@ -1144,7 +1144,7 @@ static int ntfs_ib_copy_tail(ntfs_index_context *icx, INDEX_BLOCK *src, + { + u8 *ies_end; + INDEX_ENTRY *ie_head; /* first entry after the median */ +- int tail_size, ret; ++ int tail_size, dst_capacity, ret; + INDEX_BLOCK *dst; + + ntfs_log_trace("Entering\n"); +@@ -1158,6 +1158,25 @@ static int ntfs_ib_copy_tail(ntfs_index_context *icx, INDEX_BLOCK *src, + + ies_end = (u8 *)ntfs_ie_get_end(&src->index); + tail_size = ies_end - (u8 *)ie_head; ++ dst_capacity = (int)(le32_to_cpu(dst->index.allocated_size) ++ - le32_to_cpu(dst->index.entries_offset)); ++ ++ /* ++ * src->index.entries_offset (on-disk, only required to be >= ++ * sizeof(INDEX_HEADER) by ntfs_index_block_inconsistent) may be smaller ++ * than dst's, which ntfs_ib_alloc fixes (40 on a 4 KiB block). When ++ * the median lands near the start of the source stream the gap lets ++ * tail_size exceed dst's usable space. The < 0 guard catches a ++ * negative tail_size before memcpy sign-extends it into a huge size_t. ++ */ ++ if (tail_size < 0 || tail_size > dst_capacity) { ++ ntfs_log_error("Invalid tail_size %d (dst capacity %d) in " ++ "ntfs_ib_copy_tail\n", tail_size, dst_capacity); ++ free(dst); ++ errno = EIO; ++ return STATUS_ERROR; ++ } ++ + memcpy(ntfs_ie_get_first(&dst->index), ie_head, tail_size); + + dst->index.index_length = cpu_to_le32(tail_size + diff -Nru ntfs-3g-2022.10.3/debian/patches/CVE-2026-46570.patch ntfs-3g-2022.10.3/debian/patches/CVE-2026-46570.patch --- ntfs-3g-2022.10.3/debian/patches/CVE-2026-46570.patch 1970-01-01 00:00:00.000000000 +0000 +++ ntfs-3g-2022.10.3/debian/patches/CVE-2026-46570.patch 2026-07-09 04:34:54.000000000 +0000 @@ -0,0 +1,18 @@ +diff --git a/libntfs-3g/index.c b/libntfs-3g/index.c +index e48d6aafb..4768128d2 100644 +--- a/libntfs-3g/index.c ++++ b/libntfs-3g/index.c +@@ -2056,6 +2056,13 @@ static INDEX_ENTRY *ntfs_index_walk_down(INDEX_ENTRY *ie, + /* down from non-zero level */ + + ictx->pindex++; ++ if (ictx->pindex >= MAX_PARENT_VCN) { ++ errno = EOPNOTSUPP; ++ ntfs_log_perror("Index is over %d level deep", ++ MAX_PARENT_VCN); ++ entry = (INDEX_ENTRY*)NULL; ++ break; ++ } + } + ictx->parent_pos[ictx->pindex] = 0; + ictx->parent_vcn[ictx->pindex] = vcn; diff -Nru ntfs-3g-2022.10.3/debian/patches/CVE-2026-46571.patch ntfs-3g-2022.10.3/debian/patches/CVE-2026-46571.patch --- ntfs-3g-2022.10.3/debian/patches/CVE-2026-46571.patch 1970-01-01 00:00:00.000000000 +0000 +++ ntfs-3g-2022.10.3/debian/patches/CVE-2026-46571.patch 2026-07-09 04:34:54.000000000 +0000 @@ -0,0 +1,27 @@ +diff --git a/libntfs-3g/reparse.c b/libntfs-3g/reparse.c +index 76dbe2f1b..54858caa7 100644 +--- a/libntfs-3g/reparse.c ++++ b/libntfs-3g/reparse.c +@@ -196,11 +196,19 @@ static u64 ntfs_fix_file_name(ntfs_inode *dir_ni, ntfschar *uname, + lemref = entry->indexed_file; + mref = le64_to_cpu(lemref); + if (NVolCaseSensitive(vol) || !vol->locase) { +- for (i=0; ifile_name_length; i++) ++ for (i=0; ifile_name_length; ++ i++) + uname[i] = found->file_name[i]; + } else { +- for (i=0; ifile_name_length; i++) +- uname[i] = vol->locase[le16_to_cpu(found->file_name[i])]; ++ for (i=0; ifile_name_length; ++ i++) { ++ u16 u = le16_to_cpu(found-> ++ file_name[i]); ++ uname[i] = (u < vol->upcase_len) ++ ? vol->locase[u] ++ : found-> ++ file_name[i]; ++ } + } + } + } diff -Nru ntfs-3g-2022.10.3/debian/patches/CVE-2026-56135.patch ntfs-3g-2022.10.3/debian/patches/CVE-2026-56135.patch --- ntfs-3g-2022.10.3/debian/patches/CVE-2026-56135.patch 1970-01-01 00:00:00.000000000 +0000 +++ ntfs-3g-2022.10.3/debian/patches/CVE-2026-56135.patch 2026-07-09 04:34:54.000000000 +0000 @@ -0,0 +1,151 @@ +diff --git a/include/ntfs-3g/acls.h b/include/ntfs-3g/acls.h +index 932791e97..4f36389c5 100644 +--- a/include/ntfs-3g/acls.h ++++ b/include/ntfs-3g/acls.h +@@ -168,6 +168,8 @@ char *ntfs_build_descr_posix(struct MAPPING* const mapping[], + + #endif /* POSIXACLS */ + ++int ntfs_inherit_acl_extra_size(const ACL *acl, const SID *usid, ++ const SID *gsid); + int ntfs_inherit_acl(const ACL *oldacl, ACL *newacl, + const SID *usid, const SID *gsid, + BOOL fordir, le16 inherited); +diff --git a/libntfs-3g/acls.c b/libntfs-3g/acls.c +index 9f16fecd0..f9ed58f40 100644 +--- a/libntfs-3g/acls.c ++++ b/libntfs-3g/acls.c +@@ -560,7 +560,9 @@ static BOOL valid_acl(const ACL *pacl, unsigned int end) + pace = (const ACCESS_ALLOWED_ACE*) + &((const char*)pacl)[offace]; + acesz = le16_to_cpu(pace->size); +- switch (pace->type) { ++ if (acesz < sizeof(ACE_HEADER)) ++ ok = FALSE; ++ else switch (pace->type) { + case ACCESS_ALLOWED_ACE_TYPE : + case ACCESS_DENIED_ACE_TYPE : + wantsz = ntfs_sid_size(&pace->sid) + 8; +@@ -681,6 +683,87 @@ BOOL ntfs_valid_descr(const char *securattr, unsigned int attrsz) + return (ok); + } + ++/** ++ * ntfs_inherit_acl_extra_size: compute creator SID inheritance slack ++ * @acl: ACL to scan ++ * @usid: owner SID to substitute for CREATOR_OWNER ++ * @gsid: group SID to substitute for CREATOR_GROUP ++ * ++ * Walks @acl bounded by acl->size, adding slack for ALLOW and DENY ACEs ++ * whose SID matches either creator placeholder. ntfs_inherit_acl() can ++ * replace those placeholders by @usid or @gsid and, for directories, can ++ * also keep a verbatim copy for child inheritance. Count the worst-case ++ * extra bytes so the inherited descriptor allocation cannot be overrun. ++ * ++ * Return: extra bytes needed, or 0 if @acl is NULL or structurally rejected. ++ */ ++ ++int ntfs_inherit_acl_extra_size(const ACL *acl, ++ const SID *usid, const SID *gsid) ++{ ++ const ACCESS_ALLOWED_ACE *ace; ++ unsigned int off; ++ unsigned int acl_size; ++ unsigned int acesz; ++ unsigned int sidsz; ++ int usidsz; ++ int gsidsz; ++ int ownersidsz; ++ int groupsidsz; ++ int oldcnt; ++ int nace; ++ int extra; ++ BOOL usid_is_group_sid; ++ ++ extra = 0; ++ if (!acl || !usid || !gsid) ++ return (0); ++ acl_size = le16_to_cpu(acl->size); ++ if (acl_size < sizeof(ACL)) ++ return (0); ++ oldcnt = le16_to_cpu(acl->ace_count); ++ usidsz = ntfs_sid_size(usid); ++ gsidsz = ntfs_sid_size(gsid); ++ ownersidsz = sizeof(ownersidbytes); ++ groupsidsz = sizeof(groupsidbytes); ++ usid_is_group_sid = ntfs_same_sid(usid, groupsid); ++ off = sizeof(ACL); ++ for (nace = 0; nace < oldcnt; nace++) { ++ if (off + 8 > acl_size) ++ break; ++ ace = (const ACCESS_ALLOWED_ACE*)((const char*)acl + off); ++ acesz = le16_to_cpu(ace->size); ++ if (acesz < 8 || acesz > acl_size - off) ++ break; ++ switch (ace->type) { ++ case ACCESS_ALLOWED_ACE_TYPE : ++ case ACCESS_DENIED_ACE_TYPE : ++ if ((acesz >= 8 + sizeof(ownersidbytes)) ++ && ntfs_valid_sid(&ace->sid)) { ++ sidsz = ntfs_sid_size(&ace->sid); ++ if (sidsz <= acesz - 8) { ++ if (ntfs_same_sid(&ace->sid, ownersid)) ++ { ++ extra += usidsz - ownersidsz + ++ 20; ++ if (usid_is_group_sid) ++ extra += gsidsz - ++ groupsidsz + 20; ++ } ++ if (ntfs_same_sid(&ace->sid, groupsid)) ++ extra += gsidsz - groupsidsz + ++ 20; ++ } ++ } ++ break; ++ default : ++ break; ++ } ++ off += acesz; ++ } ++ return extra; ++} ++ + /* + * Copy the inheritable parts of an ACL + * +diff --git a/libntfs-3g/security.c b/libntfs-3g/security.c +index acee0a5ed..d0e030e19 100644 +--- a/libntfs-3g/security.c ++++ b/libntfs-3g/security.c +@@ -3944,6 +3944,30 @@ static le32 build_inherited_id(struct SECURITY_CONTEXT *scx, + usidsz = ntfs_sid_size(usid); + gsidsz = ntfs_sid_size(gsid); + newattrsz = parentattrsz + 3*usidsz + 3*gsidsz; ++ /* ++ * The +3*usidsz + 3*gsidsz slack above only covers a few creator SID ++ * expansions during ntfs_inherit_acl(). Add worst-case slack for every ++ * ALLOW/DENY creator-owner and creator-group ACE in both the parent ++ * DACL and SACL. ++ */ ++ if (pphead->dacl) { ++ offpacl = le32_to_cpu(pphead->dacl); ++ if ((unsigned int)offpacl + sizeof(ACL) <= ++ (unsigned int)parentattrsz) { ++ ppacl = (const ACL*)&parentattr[offpacl]; ++ newattrsz += ntfs_inherit_acl_extra_size(ppacl, ++ usid, gsid); ++ } ++ } ++ if (pphead->sacl) { ++ offpacl = le32_to_cpu(pphead->sacl); ++ if ((unsigned int)offpacl + sizeof(ACL) <= ++ (unsigned int)parentattrsz) { ++ ppacl = (const ACL*)&parentattr[offpacl]; ++ newattrsz += ntfs_inherit_acl_extra_size(ppacl, ++ usid, gsid); ++ } ++ } + if (fordir) + newattrsz *= 2; + newattr = (char*)ntfs_malloc(newattrsz); diff -Nru ntfs-3g-2022.10.3/debian/patches/series ntfs-3g-2022.10.3/debian/patches/series --- ntfs-3g-2022.10.3/debian/patches/series 2026-04-16 21:25:43.000000000 +0000 +++ ntfs-3g-2022.10.3/debian/patches/series 2026-07-15 04:59:36.000000000 +0000 @@ -1,2 +1,9 @@ Fix_use-after-free_in_ntfs_uppercase_mbs.patch ntfs-3g_2022.10.3-cve_2026-02.patch +CVE-2026-42618.patch +CVE-2026-42616.patch +CVE-2026-42617_CVE-2026-46572_CVE-2026-56136.patch +CVE-2026-46569.patch +CVE-2026-46571.patch +CVE-2026-46570.patch +CVE-2026-56135.patch