Hi,

it is possible to trigger a floating point exception in df when it is
used to retrieve information from a raw device with a broken ext2
file system.

These are steps to prepare a file system with an invalid entry for
"e2fs_log_bsize" (0xFFFFFF):

$ dd if=/dev/zero of=ext2.fs bs=1K count=1440
# vnconfig vnd0c ext2.fs
# newfs_ext2fs -I vnd0c
$ dd if=/dev/zero bs=1 count=4 | tr '\0' '\777' | \
>    dd of=ext2.fs conv=notrunc seek=1048 bs=1 count=4

If this raw device is accessed with df, the call will result in a
floating point exception:

$ df /dev/vnd0c
Floating point exception (core dumped)

With applied diff, the raw device is considered invalid, which leads to
same behavior as with unknown file systems:

$ /usr/obj/bin/df/df /dev/vnd0c
$ echo $?
1

The fix is simple: Avoid division by zero by explicitly checking that
we won't divide by zero. The results can always be weird with broken
file systems, but at least df won't crash.


Tobias

Index: ext2fs_df.c
===================================================================
RCS file: /cvs/src/bin/df/ext2fs_df.c,v
retrieving revision 1.12
diff -u -p -r1.12 ext2fs_df.c
--- bin/df/ext2fs_df.c  16 Jan 2015 06:39:31 -0000      1.12
+++ bin/df/ext2fs_df.c  1 Mar 2015 11:09:42 -0000
@@ -77,8 +77,9 @@ e2fs_df(int rfd, char *file, struct stat
        sfsp->f_bsize = 1024 << sblock.e2fs_log_bsize;
        sfsp->f_iosize = 1024 << sblock.e2fs_log_bsize;
 
-       ipb = sfsp->f_bsize / sizeof(struct ext2fs_dinode);
-       itpg = sblock.e2fs_ipg/ipb;
+       if ((ipb = sfsp->f_bsize / sizeof(struct ext2fs_dinode)) == 0)
+               return (-1);
+       itpg = sblock.e2fs_ipg / ipb;
 
        ncg = howmany(sblock.e2fs_bcount - sblock.e2fs_first_dblock,
                sblock.e2fs_bpg);

Reply via email to