Skip to content

Commit fa86ac6

Browse files
tytsoBrian Maly
authored andcommitted
ext4: use atomic64_t for the per-flexbg free_clusters count
Orabug: 17488415 commit 90ba983 upstream. A user who was using a 8TB+ file system and with a very large flexbg size (> 65536) could cause the atomic_t used in the struct flex_groups to overflow. This was detected by PaX security patchset: http://forums.grsecurity.net/viewtopic.php?f=3&t=3289&p=12551#p12551 This bug was introduced in commit 9f24e42, so it's been around since 2.6.30. :-( Fix this by using an atomic64_t for struct orlav_stats's free_clusters. [Backported for 3.0-stable. Renamed free_clusters back to free_blocks; fixed a few more atomic_read's of free_blocks left in 3.0.] Signed-off-by: "Theodore Ts'o" <[email protected]> Reviewed-by: Lukas Czerner <[email protected]> Signed-off-by: Lingzhu Xiang <[email protected]> Reviewed-by: CAI Qian <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]> (cherry picked from commit 503f4bdcc078e7abee273a85ce322de81b18a224) Signed-off-by: Todd Vierling <[email protected]> Acked-by: John Haxby <[email protected]> Signed-off-by: Brian Maly <[email protected]>
1 parent 9776b65 commit fa86ac6

File tree

5 files changed

+21
-21
lines changed

5 files changed

+21
-21
lines changed

fs/ext4/ext4.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -289,9 +289,9 @@ struct ext4_group_desc
289289
*/
290290

291291
struct flex_groups {
292-
atomic_t free_inodes;
293-
atomic_t free_blocks;
294-
atomic_t used_dirs;
292+
atomic64_t free_blocks;
293+
atomic_t free_inodes;
294+
atomic_t used_dirs;
295295
};
296296

297297
#define EXT4_BG_INODE_UNINIT 0x0001 /* Inode table/bitmap not in use */

fs/ext4/ialloc.c

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -345,8 +345,8 @@ static int find_group_flex(struct super_block *sb, struct inode *parent,
345345
ext4_group_t ngroups = ext4_get_groups_count(sb);
346346
int flex_size = ext4_flex_bg_size(sbi);
347347
ext4_group_t best_flex = parent_fbg_group;
348-
int blocks_per_flex = sbi->s_blocks_per_group * flex_size;
349-
int flexbg_free_blocks;
348+
ext4_fsblk_t blocks_per_flex = sbi->s_blocks_per_group * flex_size;
349+
ext4_fsblk_t flexbg_free_blocks;
350350
int flex_freeb_ratio;
351351
ext4_group_t n_fbg_groups;
352352
ext4_group_t i;
@@ -355,7 +355,7 @@ static int find_group_flex(struct super_block *sb, struct inode *parent,
355355
sbi->s_log_groups_per_flex;
356356

357357
find_close_to_parent:
358-
flexbg_free_blocks = atomic_read(&flex_group[best_flex].free_blocks);
358+
flexbg_free_blocks = atomic64_read(&flex_group[best_flex].free_blocks);
359359
flex_freeb_ratio = flexbg_free_blocks * 100 / blocks_per_flex;
360360
if (atomic_read(&flex_group[best_flex].free_inodes) &&
361361
flex_freeb_ratio > free_block_ratio)
@@ -370,7 +370,7 @@ static int find_group_flex(struct super_block *sb, struct inode *parent,
370370
if (i == parent_fbg_group || i == parent_fbg_group - 1)
371371
continue;
372372

373-
flexbg_free_blocks = atomic_read(&flex_group[i].free_blocks);
373+
flexbg_free_blocks = atomic64_read(&flex_group[i].free_blocks);
374374
flex_freeb_ratio = flexbg_free_blocks * 100 / blocks_per_flex;
375375

376376
if (flex_freeb_ratio > free_block_ratio &&
@@ -380,14 +380,14 @@ static int find_group_flex(struct super_block *sb, struct inode *parent,
380380
}
381381

382382
if ((atomic_read(&flex_group[best_flex].free_inodes) == 0) ||
383-
((atomic_read(&flex_group[i].free_blocks) >
384-
atomic_read(&flex_group[best_flex].free_blocks)) &&
383+
((atomic64_read(&flex_group[i].free_blocks) >
384+
atomic64_read(&flex_group[best_flex].free_blocks)) &&
385385
atomic_read(&flex_group[i].free_inodes)))
386386
best_flex = i;
387387
}
388388

389389
if (!atomic_read(&flex_group[best_flex].free_inodes) ||
390-
!atomic_read(&flex_group[best_flex].free_blocks))
390+
!atomic64_read(&flex_group[best_flex].free_blocks))
391391
return -1;
392392

393393
found_flexbg:
@@ -406,8 +406,8 @@ static int find_group_flex(struct super_block *sb, struct inode *parent,
406406
}
407407

408408
struct orlov_stats {
409+
__u64 free_blocks;
409410
__u32 free_inodes;
410-
__u32 free_blocks;
411411
__u32 used_dirs;
412412
};
413413

@@ -424,7 +424,7 @@ static void get_orlov_stats(struct super_block *sb, ext4_group_t g,
424424

425425
if (flex_size > 1) {
426426
stats->free_inodes = atomic_read(&flex_group[g].free_inodes);
427-
stats->free_blocks = atomic_read(&flex_group[g].free_blocks);
427+
stats->free_blocks = atomic64_read(&flex_group[g].free_blocks);
428428
stats->used_dirs = atomic_read(&flex_group[g].used_dirs);
429429
return;
430430
}

fs/ext4/mballoc.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2814,8 +2814,8 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,
28142814
if (sbi->s_log_groups_per_flex) {
28152815
ext4_group_t flex_group = ext4_flex_group(sbi,
28162816
ac->ac_b_ex.fe_group);
2817-
atomic_sub(ac->ac_b_ex.fe_len,
2818-
&sbi->s_flex_groups[flex_group].free_blocks);
2817+
atomic64_sub(ac->ac_b_ex.fe_len,
2818+
&sbi->s_flex_groups[flex_group].free_blocks);
28192819
}
28202820

28212821
err = ext4_handle_dirty_metadata(handle, NULL, bitmap_bh);
@@ -4614,7 +4614,7 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode,
46144614

46154615
if (sbi->s_log_groups_per_flex) {
46164616
ext4_group_t flex_group = ext4_flex_group(sbi, block_group);
4617-
atomic_add(count, &sbi->s_flex_groups[flex_group].free_blocks);
4617+
atomic64_add(count, &sbi->s_flex_groups[flex_group].free_blocks);
46184618
}
46194619

46204620
ext4_mb_unload_buddy(&e4b);
@@ -4745,8 +4745,8 @@ void ext4_add_groupblocks(handle_t *handle, struct super_block *sb,
47454745

47464746
if (sbi->s_log_groups_per_flex) {
47474747
ext4_group_t flex_group = ext4_flex_group(sbi, block_group);
4748-
atomic_add(blocks_freed,
4749-
&sbi->s_flex_groups[flex_group].free_blocks);
4748+
atomic64_add(blocks_freed,
4749+
&sbi->s_flex_groups[flex_group].free_blocks);
47504750
}
47514751

47524752
ext4_mb_unload_buddy(&e4b);

fs/ext4/resize.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -929,8 +929,8 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input)
929929
sbi->s_log_groups_per_flex) {
930930
ext4_group_t flex_group;
931931
flex_group = ext4_flex_group(sbi, input->group);
932-
atomic_add(input->free_blocks_count,
933-
&sbi->s_flex_groups[flex_group].free_blocks);
932+
atomic64_add(input->free_blocks_count,
933+
&sbi->s_flex_groups[flex_group].free_blocks);
934934
atomic_add(EXT4_INODES_PER_GROUP(sb),
935935
&sbi->s_flex_groups[flex_group].free_inodes);
936936
}

fs/ext4/super.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1992,8 +1992,8 @@ static int ext4_fill_flex_info(struct super_block *sb)
19921992
flex_group = ext4_flex_group(sbi, i);
19931993
atomic_add(ext4_free_inodes_count(sb, gdp),
19941994
&sbi->s_flex_groups[flex_group].free_inodes);
1995-
atomic_add(ext4_free_blks_count(sb, gdp),
1996-
&sbi->s_flex_groups[flex_group].free_blocks);
1995+
atomic64_add(ext4_free_blks_count(sb, gdp),
1996+
&sbi->s_flex_groups[flex_group].free_blocks);
19971997
atomic_add(ext4_used_dirs_count(sb, gdp),
19981998
&sbi->s_flex_groups[flex_group].used_dirs);
19991999
}

0 commit comments

Comments
 (0)