]>
git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - db/fuzz.c
2 * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc.
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation.
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
37 static int fuzz_f(int argc
, char **argv
);
38 static void fuzz_help(void);
40 static const cmdinfo_t fuzz_cmd
=
41 { "fuzz", NULL
, fuzz_f
, 0, -1, 0, N_("[-c] [-d] field fuzzcmd..."),
42 N_("fuzz values on disk"), fuzz_help
};
50 add_command(&fuzz_cmd
);
59 " The 'fuzz' command fuzzes fields in any on-disk data structure. For\n"
60 " block fuzzing, see the 'blocktrash' or 'write' commands."
63 " Struct mode: 'fuzz core.uid zeroes' - set an inode uid field to 0.\n"
64 " 'fuzz crc ones' - set a crc filed to all ones.\n"
65 " 'fuzz bno[11] firstbit' - set the high bit of a block array.\n"
66 " 'fuzz keys[5].startblock add' - increase a btree key value.\n"
67 " 'fuzz uuid random' - randomize the superblock uuid.\n"
69 " Type 'fuzz' by itself for a list of specific commands.\n\n"
70 " Specifying the -c option will allow writes of invalid (corrupt) data with\n"
71 " an invalid CRC. Specifying the -d option will allow writes of invalid data,\n"
72 " but still recalculate the CRC so we are forced to check and detect the\n"
73 " invalid data appropriately.\n\n"
84 extern char *progname
;
86 bool corrupt
= false; /* Allow write of bad data w/ invalid CRC */
87 bool invalid_data
= false; /* Allow write of bad data w/ valid CRC */
88 struct xfs_buf_ops local_ops
;
89 const struct xfs_buf_ops
*stashed_ops
= NULL
;
91 if (x
.isreadonly
& LIBXFS_ISREADONLY
) {
92 dbprintf(_("%s started in read only mode, fuzzing disabled\n"),
97 if (cur_typ
== NULL
) {
98 dbprintf(_("no current type\n"));
104 dbprintf(_("no handler function for type %s, fuzz unsupported.\n"),
109 while ((c
= getopt(argc
, argv
, "cd")) != EOF
) {
118 dbprintf(_("bad option for fuzz command\n"));
123 if (corrupt
&& invalid_data
) {
124 dbprintf(_("Cannot specify both -c and -d options\n"));
128 if (invalid_data
&& iocur_top
->typ
->crc_off
== TYP_F_NO_CRC_OFF
) {
129 dbprintf(_("Cannot recalculate CRCs on this type of object\n"));
137 * If the buffer has no verifier or we are using standard verifier
138 * paths, then just fuzz it and return
140 if (!iocur_top
->bp
->b_ops
||
141 !(corrupt
|| invalid_data
)) {
142 (*pf
)(DB_FUZZ
, cur_typ
->fields
, argc
, argv
);
147 /* Temporarily remove write verifier to write bad data */
148 stashed_ops
= iocur_top
->bp
->b_ops
;
149 local_ops
.verify_read
= stashed_ops
->verify_read
;
150 iocur_top
->bp
->b_ops
= &local_ops
;
153 local_ops
.verify_write
= xfs_dummy_verify
;
154 dbprintf(_("Allowing fuzz of corrupted data and bad CRC\n"));
155 } else if (iocur_top
->typ
->crc_off
== TYP_F_CRC_FUNC
) {
156 local_ops
.verify_write
= iocur_top
->typ
->set_crc
;
157 dbprintf(_("Allowing fuzz of corrupted data with good CRC\n"));
158 } else { /* invalid data */
159 local_ops
.verify_write
= xfs_verify_recalc_crc
;
160 dbprintf(_("Allowing fuzz of corrupted data with good CRC\n"));
163 (*pf
)(DB_FUZZ
, cur_typ
->fields
, argc
, argv
);
165 iocur_top
->bp
->b_ops
= stashed_ops
;
170 /* Write zeroes to the field */
180 if (bitoff
% NBBY
|| nbits
% NBBY
) {
181 for (bit
= 0; bit
< nbits
; bit
++)
182 setbit_l(out
, bit
+ bitoff
, 0);
184 memset(out
+ byteize(bitoff
), 0, byteize(nbits
));
188 /* Write ones to the field */
198 if (bitoff
% NBBY
|| nbits
% NBBY
) {
199 for (bit
= 0; bit
< nbits
; bit
++)
200 setbit_l(out
, bit
+ bitoff
, 1);
202 memset(out
+ byteize(bitoff
), 0xFF, byteize(nbits
));
206 /* Flip the high bit in the (presumably big-endian) field */
213 setbit_l((char *)buf
, bitoff
, !getbit_l((char *)buf
, bitoff
));
217 /* Flip the low bit in the (presumably big-endian) field */
224 setbit_l((char *)buf
, bitoff
+ nbits
- 1,
225 !getbit_l((char *)buf
, bitoff
));
229 /* Flip the middle bit in the (presumably big-endian) field */
236 setbit_l((char *)buf
, bitoff
+ nbits
/ 2,
237 !getbit_l((char *)buf
, bitoff
));
241 /* Format and shift a number into a buffer for setbitval. */
249 char *rbuf
= (char *)out
;
252 * If the length of the field is not a multiple of a byte, push
253 * the bits up in the field, so the most signicant field bit is
254 * the most significant bit in the byte:
257 * val |----|----|----|----|----|--MM|mmmm|llll|
259 * val |----|----|----|----|----|MMmm|mmll|ll00|
261 offset
= bit_length
% NBBY
;
263 val
<<= (NBBY
- offset
);
266 * convert to big endian and copy into the array
267 * rbuf |----|----|----|----|----|MMmm|mmll|ll00|
269 *out
= cpu_to_be64(val
);
272 * Align the array to point to the field in the array.
273 * rbuf = |MMmm|mmll|ll00|
275 offset
= sizeof(__be64
) - 1 - ((bit_length
- 1) / sizeof(__be64
));
276 return rbuf
+ offset
;
279 /* Increase the value by some small prime number. */
293 val
= getbitval(buf
, bitoff
, nbits
, BVUNSIGNED
);
294 val
+= (nbits
> 8 ? 2017 : 137);
295 b
= format_number(val
, &out
, nbits
);
296 setbitval(buf
, bitoff
, nbits
, b
);
301 /* Decrease the value by some small prime number. */
315 val
= getbitval(buf
, bitoff
, nbits
, BVUNSIGNED
);
316 val
-= (nbits
> 8 ? 2017 : 137);
317 b
= format_number(val
, &out
, nbits
);
318 setbitval(buf
, bitoff
, nbits
, b
);
323 /* Randomize the field. */
333 bytes
= byteize_up(nbits
);
334 rbuf
= b
= malloc(bytes
);
336 perror("fuzz_random");
340 for (i
= 0; i
< bytes
; i
++)
341 *b
++ = (char)lrand48();
343 setbitval(buf
, bitoff
, nbits
, rbuf
);
351 bool (*fn
)(void *buf
, int bitoff
, int nbits
);
354 /* Keep these verbs in sync with enum fuzzcmds. */
355 static struct fuzzcmd fuzzverbs
[] = {
356 {"zeroes", fuzz_zeroes
},
358 {"firstbit", fuzz_firstbit
},
359 {"middlebit", fuzz_middlebit
},
360 {"lastbit", fuzz_lastbit
},
363 {"random", fuzz_random
},
370 const field_t
*fields
,
383 dbprintf(_("Usage: fuzz fieldname fuzzcmd\n"));
384 dbprintf("Fuzz commands: %s", fuzzverbs
->verb
);
385 for (fc
= fuzzverbs
+ 1; fc
->verb
!= NULL
; fc
++)
386 dbprintf(", %s", fc
->verb
);
391 fl
= flist_scan(argv
[0]);
393 dbprintf(_("unable to parse '%s'.\n"), argv
[0]);
397 /* Find our fuzz verb */
398 for (fc
= fuzzverbs
; fc
->verb
!= NULL
; fc
++)
399 if (!strcmp(fc
->verb
, argv
[1]))
401 if (fc
->fn
== NULL
) {
402 dbprintf(_("Unknown fuzz command '%s'.\n"), argv
[1]);
406 /* if we're a root field type, go down 1 layer to get field list */
407 if (fields
->name
[0] == '\0') {
408 fa
= &ftattrtab
[fields
->ftyp
];
409 ASSERT(fa
->ftyp
== fields
->ftyp
);
413 /* run down the field list and set offsets into the data */
414 if (!flist_parse(fields
, fl
, iocur_top
->data
, 0)) {
415 dbprintf(_("parsing error\n"));
422 parentoffset
= sfl
->offset
;
427 * For structures, fsize * fcount tells us the size of the region we are
428 * modifying, which is usually a single structure member and is pointed
429 * to by the last child in the list.
431 * However, if the base structure is an array and we have a direct index
432 * into the array (e.g. write bno[5]) then we are returned a single
433 * flist object with the offset pointing directly at the location we
434 * need to modify. The length of the object we are modifying is then
435 * determined by the size of the individual array entry (fsize) and the
436 * indexes defined in the object, not the overall size of the array
437 * (which is what fcount returns).
439 bit_length
= fsize(sfl
->fld
, iocur_top
->data
, parentoffset
, 0);
440 if (sfl
->fld
->flags
& FLD_ARRAY
)
441 bit_length
*= sfl
->high
- sfl
->low
+ 1;
443 bit_length
*= fcount(sfl
->fld
, iocur_top
->data
, parentoffset
);
446 success
= fc
->fn(iocur_top
->data
, sfl
->offset
, bit_length
);
448 dbprintf(_("unable to fuzz field '%s'\n"), argv
[0]);
452 /* Write the fuzzed value back */