2 * e2fuzz.c -- Fuzz an ext4 image, for testing purposes.
4 * Copyright (C) 2014 Oracle.
7 * This file may be redistributed under the terms of the GNU Library
8 * General Public License, version 2.
11 #define _XOPEN_SOURCE 600
12 #define _FILE_OFFSET_BITS 64
13 #define _LARGEFILE64_SOURCE 1
17 #include <sys/types.h>
25 #include "ext2fs/ext2_fs.h"
26 #include "ext2fs/ext2fs.h"
28 static int dryrun
= 0;
29 static int verbose
= 0;
30 static int metadata_only
= 1;
31 static unsigned long long user_corrupt_bytes
= 0;
32 static double user_corrupt_pct
= 0.0;
39 fd
= open("/dev/urandom", O_RDONLY
);
44 read(fd
, &r
, sizeof(r
));
51 ext2fs_block_bitmap bmap
;
52 struct ext2_inode
*inode
;
53 blk64_t corrupt_blocks
;
56 int find_block_helper(ext2_filsys fs
, blk64_t
*blocknr
, e2_blkcnt_t blockcnt
,
57 blk64_t ref_blk
, int ref_offset
, void *priv_data
)
59 struct find_block
*fb
= (struct find_block
*)priv_data
;
61 if (S_ISDIR(fb
->inode
->i_mode
) || !metadata_only
|| blockcnt
< 0) {
62 ext2fs_mark_block_bitmap2(fb
->bmap
, *blocknr
);
69 errcode_t
find_metadata_blocks(ext2_filsys fs
, ext2fs_block_bitmap bmap
,
73 blk64_t b
, c
, d
, j
, old_desc_blocks
;
76 struct ext2_inode inode
;
81 fb
.corrupt_blocks
= 0;
82 if (EXT2_HAS_INCOMPAT_FEATURE(fs
->super
,
83 EXT2_FEATURE_INCOMPAT_META_BG
))
84 old_desc_blocks
= fs
->super
->s_first_meta_bg
;
86 old_desc_blocks
= fs
->desc_blocks
+
87 fs
->super
->s_reserved_gdt_blocks
;
89 /* Construct bitmaps of super/descriptor blocks */
90 for (i
= 0; i
< fs
->group_desc_count
; i
++) {
91 ext2fs_reserve_super_and_bgd(fs
, i
, bmap
);
93 /* bitmaps and inode table */
94 b
= ext2fs_block_bitmap_loc(fs
, i
);
95 ext2fs_mark_block_bitmap2(bmap
, b
);
98 b
= ext2fs_inode_bitmap_loc(fs
, i
);
99 ext2fs_mark_block_bitmap2(bmap
, b
);
102 c
= ext2fs_inode_table_loc(fs
, i
);
103 ext2fs_mark_block_bitmap_range2(bmap
, c
,
104 fs
->inode_blocks_per_group
);
105 fb
.corrupt_blocks
+= fs
->inode_blocks_per_group
;
111 memset(&inode
, 0, sizeof(inode
));
112 retval
= ext2fs_open_inode_scan(fs
, 0, &scan
);
116 retval
= ext2fs_get_next_inode_full(scan
, &ino
, &inode
, sizeof(inode
));
120 if (inode
.i_links_count
== 0)
123 b
= ext2fs_file_acl_block(fs
, &inode
);
125 ext2fs_mark_block_bitmap2(bmap
, b
);
130 * Inline data, sockets, devices, and symlinks have
131 * no blocks to iterate.
133 if ((inode
.i_flags
& EXT4_INLINE_DATA_FL
) ||
134 S_ISLNK(inode
.i_mode
) || S_ISFIFO(inode
.i_mode
) ||
135 S_ISCHR(inode
.i_mode
) || S_ISBLK(inode
.i_mode
) ||
136 S_ISSOCK(inode
.i_mode
))
139 retval
= ext2fs_block_iterate3(fs
, ino
, BLOCK_FLAG_READ_ONLY
,
140 NULL
, find_block_helper
, &fb
);
144 retval
= ext2fs_get_next_inode_full(scan
, &ino
, &inode
,
150 ext2fs_close_inode_scan(scan
);
153 *corrupt_bytes
= fb
.corrupt_blocks
* fs
->blocksize
;
157 uint64_t rand_num(uint64_t min
, uint64_t max
)
161 uint8_t *px
= (uint8_t *)&x
;
163 for (i
= 0; i
< sizeof(x
); i
++)
166 return min
+ (uint64_t)((double)(max
- min
) * (x
/ (UINT64_MAX
+ 1.0)));
169 int process_fs(const char *fsname
)
173 ext2_filsys fs
= NULL
;
174 ext2fs_block_bitmap corrupt_map
;
175 off_t hsize
, count
, off
, offset
, corrupt_bytes
;
179 /* If mounted rw, force dryrun mode */
180 ret
= ext2fs_check_if_mounted(fsname
, &flags
);
182 fprintf(stderr
, "%s: failed to determine filesystem mount "
187 if (!dryrun
&& (flags
& EXT2_MF_MOUNTED
) &&
188 !(flags
& EXT2_MF_READONLY
)) {
189 fprintf(stderr
, "%s: is mounted rw, performing dry run.\n",
194 /* Ensure the fs is clean and does not have errors */
195 ret
= ext2fs_open(fsname
, EXT2_FLAG_64BITS
, 0, 0, unix_io_manager
,
198 fprintf(stderr
, "%s: failed to open filesystem.\n",
203 if ((fs
->super
->s_state
& EXT2_ERROR_FS
)) {
204 fprintf(stderr
, "%s: errors detected, run fsck.\n",
209 if (!dryrun
&& (fs
->super
->s_state
& EXT2_VALID_FS
) == 0) {
210 fprintf(stderr
, "%s: unclean shutdown, performing dry run.\n",
215 /* Construct a bitmap of whatever we're corrupting */
216 if (!metadata_only
) {
217 /* Load block bitmap */
218 ret
= ext2fs_read_block_bitmap(fs
);
220 fprintf(stderr
, "%s: error while reading block bitmap\n",
224 corrupt_map
= fs
->block_map
;
225 corrupt_bytes
= (ext2fs_blocks_count(fs
->super
) -
226 ext2fs_free_blocks_count(fs
->super
)) *
229 ret
= ext2fs_allocate_block_bitmap(fs
, "metadata block map",
232 fprintf(stderr
, "%s: unable to create block bitmap\n",
237 /* Iterate everything... */
238 ret
= find_metadata_blocks(fs
, corrupt_map
, &corrupt_bytes
);
240 fprintf(stderr
, "%s: while finding metadata\n",
246 /* Run around corrupting things */
247 fd
= open(fsname
, O_RDWR
);
253 hsize
= fs
->blocksize
* ext2fs_blocks_count(fs
->super
);
254 if (user_corrupt_bytes
> 0)
255 count
= user_corrupt_bytes
;
256 else if (user_corrupt_pct
> 0.0)
257 count
= user_corrupt_pct
* corrupt_bytes
/ 100;
259 count
= rand_num(0, corrupt_bytes
/ 100);
260 offset
= 4096; /* never corrupt superblock */
261 for (i
= 0; i
< count
; i
++) {
263 off
= rand_num(offset
, hsize
);
264 while (!ext2fs_test_block_bitmap2(corrupt_map
,
265 off
/ fs
->blocksize
));
267 if ((rand() % 2) && c
< 128)
270 printf("Corrupting byte %jd in block %jd to 0x%x\n",
271 off
% fs
->blocksize
, off
/ fs
->blocksize
, c
);
274 if (pwrite64(fd
, &c
, sizeof(c
), off
) != sizeof(c
)) {
282 ret
= ext2fs_close(fs
);
285 fprintf(stderr
, "%s: error while closing filesystem\n",
294 if (corrupt_map
!= fs
->block_map
)
295 ext2fs_free_block_bitmap(corrupt_map
);
302 void print_help(const char *progname
)
304 printf("Usage: %s OPTIONS device\n", progname
);
305 printf("-b: Corrupt this many bytes.\n");
306 printf("-d: Fuzz data blocks too.\n");
307 printf("-n: Dry run only.\n");
308 printf("-v: Verbose output.\n");
312 int main(int argc
, char *argv
[])
316 while ((c
= getopt(argc
, argv
, "b:dnv")) != -1) {
319 if (optarg
[strlen(optarg
) - 1] == '%') {
320 user_corrupt_pct
= strtod(optarg
, NULL
);
321 if (user_corrupt_pct
> 100 ||
322 user_corrupt_pct
< 0) {
323 fprintf(stderr
, "%s: Invalid percentage.\n",
328 user_corrupt_bytes
= strtoull(optarg
, NULL
, 0);
348 for (c
= optind
; c
< argc
; c
++)
349 if (process_fs(argv
[c
]))