mirror of
https://git.code.sf.net/p/ntfs-3g/ntfs-3g.git
synced 2024-11-23 10:04:00 +08:00
Corrected validation of multi sector transfer protected records
The validation contained an off-by-one error. The expression '(u32)(usa_ofs + (usa_count * 2)) > size' used 'usa_count' after it had been decremented to skip the update sequence number entry. Consequently, the code could read out of bounds, up to two bytes past the end of the MST-protected record. Furthermore, as documented in the comment in layout.h for "NTFS_RECORD" and also on MSDN for "MULTI_SECTOR_HEADER", the update sequence array must end before the last le16 in the first logical sector --- not merely before the end of the record. Fix the validation and move it into a helper function, as it was done identically in the read and write paths. Signed-off-by: Eric Biggers <ebiggers3@gmail.com>
This commit is contained in:
parent
2840e84a97
commit
f86c4403ed
@ -161,6 +161,12 @@ typedef enum {
|
|||||||
#define ntfs_is_empty_recordp(p) ( ntfs_is_magicp(p, empty) )
|
#define ntfs_is_empty_recordp(p) ( ntfs_is_magicp(p, empty) )
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The size of a logical sector in bytes, used as the sequence number stride for
|
||||||
|
* multi-sector transfers. This is intended to be less than or equal to the
|
||||||
|
* physical sector size, since if this were greater than the physical sector
|
||||||
|
* size, then incomplete multi-sector transfers may not be detected.
|
||||||
|
*/
|
||||||
#define NTFS_BLOCK_SIZE 512
|
#define NTFS_BLOCK_SIZE 512
|
||||||
#define NTFS_BLOCK_SIZE_BITS 9
|
#define NTFS_BLOCK_SIZE_BITS 9
|
||||||
|
|
||||||
|
@ -31,6 +31,21 @@
|
|||||||
#include "mst.h"
|
#include "mst.h"
|
||||||
#include "logging.h"
|
#include "logging.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Basic validation of a NTFS multi-sector record. The record size must be a
|
||||||
|
* multiple of the logical sector size; and the update sequence array must be
|
||||||
|
* properly aligned, of the expected length, and must end before the last le16
|
||||||
|
* in the first logical sector.
|
||||||
|
*/
|
||||||
|
static BOOL
|
||||||
|
is_valid_record(u32 size, u16 usa_ofs, u16 usa_count)
|
||||||
|
{
|
||||||
|
return size % NTFS_BLOCK_SIZE == 0 &&
|
||||||
|
usa_ofs % 2 == 0 &&
|
||||||
|
usa_count == 1 + (size / NTFS_BLOCK_SIZE) &&
|
||||||
|
usa_ofs + ((u32)usa_count * 2) <= NTFS_BLOCK_SIZE - 2;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ntfs_mst_post_read_fixup - deprotect multi sector transfer protected data
|
* ntfs_mst_post_read_fixup - deprotect multi sector transfer protected data
|
||||||
* @b: pointer to the data to deprotect
|
* @b: pointer to the data to deprotect
|
||||||
@ -57,12 +72,9 @@ int ntfs_mst_post_read_fixup_warn(NTFS_RECORD *b, const u32 size,
|
|||||||
|
|
||||||
/* Setup the variables. */
|
/* Setup the variables. */
|
||||||
usa_ofs = le16_to_cpu(b->usa_ofs);
|
usa_ofs = le16_to_cpu(b->usa_ofs);
|
||||||
/* Decrement usa_count to get number of fixups. */
|
usa_count = le16_to_cpu(b->usa_count);
|
||||||
usa_count = le16_to_cpu(b->usa_count) - 1;
|
|
||||||
/* Size and alignment checks. */
|
if (!is_valid_record(size, usa_ofs, usa_count)) {
|
||||||
if (size & (NTFS_BLOCK_SIZE - 1) || usa_ofs & 1 ||
|
|
||||||
(u32)(usa_ofs + (usa_count * 2)) > size ||
|
|
||||||
(size >> NTFS_BLOCK_SIZE_BITS) != usa_count) {
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
if (warn) {
|
if (warn) {
|
||||||
ntfs_log_perror("%s: magic: 0x%08lx size: %ld "
|
ntfs_log_perror("%s: magic: 0x%08lx size: %ld "
|
||||||
@ -91,7 +103,7 @@ int ntfs_mst_post_read_fixup_warn(NTFS_RECORD *b, const u32 size,
|
|||||||
/*
|
/*
|
||||||
* Check for incomplete multi sector transfer(s).
|
* Check for incomplete multi sector transfer(s).
|
||||||
*/
|
*/
|
||||||
while (usa_count--) {
|
while (--usa_count) {
|
||||||
if (*data_pos != usn) {
|
if (*data_pos != usn) {
|
||||||
/*
|
/*
|
||||||
* Incomplete multi sector transfer detected! )-:
|
* Incomplete multi sector transfer detected! )-:
|
||||||
@ -109,10 +121,10 @@ int ntfs_mst_post_read_fixup_warn(NTFS_RECORD *b, const u32 size,
|
|||||||
data_pos += NTFS_BLOCK_SIZE/sizeof(u16);
|
data_pos += NTFS_BLOCK_SIZE/sizeof(u16);
|
||||||
}
|
}
|
||||||
/* Re-setup the variables. */
|
/* Re-setup the variables. */
|
||||||
usa_count = le16_to_cpu(b->usa_count) - 1;
|
usa_count = le16_to_cpu(b->usa_count);
|
||||||
data_pos = (u16*)b + NTFS_BLOCK_SIZE/sizeof(u16) - 1;
|
data_pos = (u16*)b + NTFS_BLOCK_SIZE/sizeof(u16) - 1;
|
||||||
/* Fixup all sectors. */
|
/* Fixup all sectors. */
|
||||||
while (usa_count--) {
|
while (--usa_count) {
|
||||||
/*
|
/*
|
||||||
* Increment position in usa and restore original data from
|
* Increment position in usa and restore original data from
|
||||||
* the usa into the data buffer.
|
* the usa into the data buffer.
|
||||||
@ -171,12 +183,9 @@ int ntfs_mst_pre_write_fixup(NTFS_RECORD *b, const u32 size)
|
|||||||
}
|
}
|
||||||
/* Setup the variables. */
|
/* Setup the variables. */
|
||||||
usa_ofs = le16_to_cpu(b->usa_ofs);
|
usa_ofs = le16_to_cpu(b->usa_ofs);
|
||||||
/* Decrement usa_count to get number of fixups. */
|
usa_count = le16_to_cpu(b->usa_count);
|
||||||
usa_count = le16_to_cpu(b->usa_count) - 1;
|
|
||||||
/* Size and alignment checks. */
|
if (!is_valid_record(size, usa_ofs, usa_count)) {
|
||||||
if (size & (NTFS_BLOCK_SIZE - 1) || usa_ofs & 1 ||
|
|
||||||
(u32)(usa_ofs + (usa_count * 2)) > size ||
|
|
||||||
(size >> NTFS_BLOCK_SIZE_BITS) != usa_count) {
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
ntfs_log_perror("%s", __FUNCTION__);
|
ntfs_log_perror("%s", __FUNCTION__);
|
||||||
return -1;
|
return -1;
|
||||||
@ -195,7 +204,7 @@ int ntfs_mst_pre_write_fixup(NTFS_RECORD *b, const u32 size)
|
|||||||
/* Position in data of first le16 that needs fixing up. */
|
/* Position in data of first le16 that needs fixing up. */
|
||||||
data_pos = (le16*)b + NTFS_BLOCK_SIZE/sizeof(le16) - 1;
|
data_pos = (le16*)b + NTFS_BLOCK_SIZE/sizeof(le16) - 1;
|
||||||
/* Fixup all sectors. */
|
/* Fixup all sectors. */
|
||||||
while (usa_count--) {
|
while (--usa_count) {
|
||||||
/*
|
/*
|
||||||
* Increment the position in the usa and save the
|
* Increment the position in the usa and save the
|
||||||
* original data from the data buffer into the usa.
|
* original data from the data buffer into the usa.
|
||||||
@ -223,7 +232,7 @@ void ntfs_mst_post_write_fixup(NTFS_RECORD *b)
|
|||||||
u16 *usa_pos, *data_pos;
|
u16 *usa_pos, *data_pos;
|
||||||
|
|
||||||
u16 usa_ofs = le16_to_cpu(b->usa_ofs);
|
u16 usa_ofs = le16_to_cpu(b->usa_ofs);
|
||||||
u16 usa_count = le16_to_cpu(b->usa_count) - 1;
|
u16 usa_count = le16_to_cpu(b->usa_count);
|
||||||
|
|
||||||
ntfs_log_trace("Entering\n");
|
ntfs_log_trace("Entering\n");
|
||||||
|
|
||||||
@ -234,7 +243,7 @@ void ntfs_mst_post_write_fixup(NTFS_RECORD *b)
|
|||||||
data_pos = (u16*)b + NTFS_BLOCK_SIZE/sizeof(u16) - 1;
|
data_pos = (u16*)b + NTFS_BLOCK_SIZE/sizeof(u16) - 1;
|
||||||
|
|
||||||
/* Fixup all sectors. */
|
/* Fixup all sectors. */
|
||||||
while (usa_count--) {
|
while (--usa_count) {
|
||||||
/*
|
/*
|
||||||
* Increment position in usa and restore original data from
|
* Increment position in usa and restore original data from
|
||||||
* the usa into the data buffer.
|
* the usa into the data buffer.
|
||||||
|
Loading…
Reference in New Issue
Block a user