Skip to content

Commit f5a44db

Browse files
committed
ext4: add explicit casts when masking cluster sizes
The missing casts can cause the high 64-bits of the physical blocks to be lost. Set up new macros which allows us to make sure the right thing happen, even if at some point we end up supporting larger logical block numbers. Thanks to the Emese Revfy and the PaX security team for reporting this issue. Reported-by: PaX Team <[email protected]> Reported-by: Emese Revfy <[email protected]> Signed-off-by: "Theodore Ts'o" <[email protected]> Cc: [email protected]
1 parent 34cf865 commit f5a44db

File tree

3 files changed

+25
-17
lines changed

3 files changed

+25
-17
lines changed

fs/ext4/ext4.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,16 @@ struct ext4_io_submit {
268268
/* Translate # of blks to # of clusters */
269269
#define EXT4_NUM_B2C(sbi, blks) (((blks) + (sbi)->s_cluster_ratio - 1) >> \
270270
(sbi)->s_cluster_bits)
271+
/* Mask out the low bits to get the starting block of the cluster */
272+
#define EXT4_PBLK_CMASK(s, pblk) ((pblk) & \
273+
~((ext4_fsblk_t) (s)->s_cluster_ratio - 1))
274+
#define EXT4_LBLK_CMASK(s, lblk) ((lblk) & \
275+
~((ext4_lblk_t) (s)->s_cluster_ratio - 1))
276+
/* Get the cluster offset */
277+
#define EXT4_PBLK_COFF(s, pblk) ((pblk) & \
278+
((ext4_fsblk_t) (s)->s_cluster_ratio - 1))
279+
#define EXT4_LBLK_COFF(s, lblk) ((lblk) & \
280+
((ext4_lblk_t) (s)->s_cluster_ratio - 1))
271281

272282
/*
273283
* Structure of a blocks group descriptor

fs/ext4/extents.c

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1851,8 +1851,7 @@ static unsigned int ext4_ext_check_overlap(struct ext4_sb_info *sbi,
18511851
depth = ext_depth(inode);
18521852
if (!path[depth].p_ext)
18531853
goto out;
1854-
b2 = le32_to_cpu(path[depth].p_ext->ee_block);
1855-
b2 &= ~(sbi->s_cluster_ratio - 1);
1854+
b2 = EXT4_LBLK_CMASK(sbi, le32_to_cpu(path[depth].p_ext->ee_block));
18561855

18571856
/*
18581857
* get the next allocated block if the extent in the path
@@ -1862,7 +1861,7 @@ static unsigned int ext4_ext_check_overlap(struct ext4_sb_info *sbi,
18621861
b2 = ext4_ext_next_allocated_block(path);
18631862
if (b2 == EXT_MAX_BLOCKS)
18641863
goto out;
1865-
b2 &= ~(sbi->s_cluster_ratio - 1);
1864+
b2 = EXT4_LBLK_CMASK(sbi, b2);
18661865
}
18671866

18681867
/* check for wrap through zero on extent logical start block*/
@@ -2521,7 +2520,7 @@ static int ext4_remove_blocks(handle_t *handle, struct inode *inode,
25212520
* extent, we have to mark the cluster as used (store negative
25222521
* cluster number in partial_cluster).
25232522
*/
2524-
unaligned = pblk & (sbi->s_cluster_ratio - 1);
2523+
unaligned = EXT4_PBLK_COFF(sbi, pblk);
25252524
if (unaligned && (ee_len == num) &&
25262525
(*partial_cluster != -((long long)EXT4_B2C(sbi, pblk))))
25272526
*partial_cluster = EXT4_B2C(sbi, pblk);
@@ -2615,7 +2614,7 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
26152614
* accidentally freeing it later on
26162615
*/
26172616
pblk = ext4_ext_pblock(ex);
2618-
if (pblk & (sbi->s_cluster_ratio - 1))
2617+
if (EXT4_PBLK_COFF(sbi, pblk))
26192618
*partial_cluster =
26202619
-((long long)EXT4_B2C(sbi, pblk));
26212620
ex--;
@@ -3770,7 +3769,7 @@ int ext4_find_delalloc_cluster(struct inode *inode, ext4_lblk_t lblk)
37703769
{
37713770
struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
37723771
ext4_lblk_t lblk_start, lblk_end;
3773-
lblk_start = lblk & (~(sbi->s_cluster_ratio - 1));
3772+
lblk_start = EXT4_LBLK_CMASK(sbi, lblk);
37743773
lblk_end = lblk_start + sbi->s_cluster_ratio - 1;
37753774

37763775
return ext4_find_delalloc_range(inode, lblk_start, lblk_end);
@@ -3829,17 +3828,17 @@ get_reserved_cluster_alloc(struct inode *inode, ext4_lblk_t lblk_start,
38293828
trace_ext4_get_reserved_cluster_alloc(inode, lblk_start, num_blks);
38303829

38313830
/* Check towards left side */
3832-
c_offset = lblk_start & (sbi->s_cluster_ratio - 1);
3831+
c_offset = EXT4_LBLK_COFF(sbi, lblk_start);
38333832
if (c_offset) {
3834-
lblk_from = lblk_start & (~(sbi->s_cluster_ratio - 1));
3833+
lblk_from = EXT4_LBLK_CMASK(sbi, lblk_start);
38353834
lblk_to = lblk_from + c_offset - 1;
38363835

38373836
if (ext4_find_delalloc_range(inode, lblk_from, lblk_to))
38383837
allocated_clusters--;
38393838
}
38403839

38413840
/* Now check towards right. */
3842-
c_offset = (lblk_start + num_blks) & (sbi->s_cluster_ratio - 1);
3841+
c_offset = EXT4_LBLK_COFF(sbi, lblk_start + num_blks);
38433842
if (allocated_clusters && c_offset) {
38443843
lblk_from = lblk_start + num_blks;
38453844
lblk_to = lblk_from + (sbi->s_cluster_ratio - c_offset) - 1;
@@ -4047,7 +4046,7 @@ static int get_implied_cluster_alloc(struct super_block *sb,
40474046
struct ext4_ext_path *path)
40484047
{
40494048
struct ext4_sb_info *sbi = EXT4_SB(sb);
4050-
ext4_lblk_t c_offset = map->m_lblk & (sbi->s_cluster_ratio-1);
4049+
ext4_lblk_t c_offset = EXT4_LBLK_COFF(sbi, map->m_lblk);
40514050
ext4_lblk_t ex_cluster_start, ex_cluster_end;
40524051
ext4_lblk_t rr_cluster_start;
40534052
ext4_lblk_t ee_block = le32_to_cpu(ex->ee_block);
@@ -4065,8 +4064,7 @@ static int get_implied_cluster_alloc(struct super_block *sb,
40654064
(rr_cluster_start == ex_cluster_start)) {
40664065
if (rr_cluster_start == ex_cluster_end)
40674066
ee_start += ee_len - 1;
4068-
map->m_pblk = (ee_start & ~(sbi->s_cluster_ratio - 1)) +
4069-
c_offset;
4067+
map->m_pblk = EXT4_PBLK_CMASK(sbi, ee_start) + c_offset;
40704068
map->m_len = min(map->m_len,
40714069
(unsigned) sbi->s_cluster_ratio - c_offset);
40724070
/*
@@ -4220,7 +4218,7 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
42204218
*/
42214219
map->m_flags &= ~EXT4_MAP_FROM_CLUSTER;
42224220
newex.ee_block = cpu_to_le32(map->m_lblk);
4223-
cluster_offset = map->m_lblk & (sbi->s_cluster_ratio-1);
4221+
cluster_offset = EXT4_LBLK_CMASK(sbi, map->m_lblk);
42244222

42254223
/*
42264224
* If we are doing bigalloc, check to see if the extent returned
@@ -4288,7 +4286,7 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
42884286
* needed so that future calls to get_implied_cluster_alloc()
42894287
* work correctly.
42904288
*/
4291-
offset = map->m_lblk & (sbi->s_cluster_ratio - 1);
4289+
offset = EXT4_LBLK_COFF(sbi, map->m_lblk);
42924290
ar.len = EXT4_NUM_B2C(sbi, offset+allocated);
42934291
ar.goal -= offset;
42944292
ar.logical -= offset;

fs/ext4/mballoc.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4126,7 +4126,7 @@ ext4_mb_initialize_context(struct ext4_allocation_context *ac,
41264126
ext4_get_group_no_and_offset(sb, goal, &group, &block);
41274127

41284128
/* set up allocation goals */
4129-
ac->ac_b_ex.fe_logical = ar->logical & ~(sbi->s_cluster_ratio - 1);
4129+
ac->ac_b_ex.fe_logical = EXT4_LBLK_CMASK(sbi, ar->logical);
41304130
ac->ac_status = AC_STATUS_CONTINUE;
41314131
ac->ac_sb = sb;
41324132
ac->ac_inode = ar->inode;
@@ -4668,7 +4668,7 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode,
46684668
* blocks at the beginning or the end unless we are explicitly
46694669
* requested to avoid doing so.
46704670
*/
4671-
overflow = block & (sbi->s_cluster_ratio - 1);
4671+
overflow = EXT4_PBLK_COFF(sbi, block);
46724672
if (overflow) {
46734673
if (flags & EXT4_FREE_BLOCKS_NOFREE_FIRST_CLUSTER) {
46744674
overflow = sbi->s_cluster_ratio - overflow;
@@ -4682,7 +4682,7 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode,
46824682
count += overflow;
46834683
}
46844684
}
4685-
overflow = count & (sbi->s_cluster_ratio - 1);
4685+
overflow = EXT4_LBLK_COFF(sbi, count);
46864686
if (overflow) {
46874687
if (flags & EXT4_FREE_BLOCKS_NOFREE_LAST_CLUSTER) {
46884688
if (count > overflow)

0 commit comments

Comments
 (0)