Whamcloud - gitweb
e2fsck: fix f_baddotdir failure on big-endian systems
authorTheodore Ts'o <tytso@mit.edu>
Wed, 28 Jul 2021 17:51:13 +0000 (13:51 -0400)
committerTheodore Ts'o <tytso@mit.edu>
Wed, 28 Jul 2021 18:40:49 +0000 (14:40 -0400)
Commit 63f44aafb1f2 ("e2fsck: fix ".." more gracefully if possible")
changed the check_dot() function to try to avoid resetting the '..'
entry when the '.' entry is too large..  But if we do that, then on
big-endian systems, we need to try byte swapping the rest of the
directory entries, or else the f_baddotdir test will fail on
big-endian systems.

Also add a check to avoid UBSAN warning when there is not enough space
at the end of the directory block for a directory entry, and so we can
potentially overflow some pointer arithmetic when trying to byte swap
the remainder of the (negative) space in the directory block.

Fixes: 63f44aafb1f2 ("e2fsck: fix ".." more gracefully if possible")
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
e2fsck/pass2.c

index f00cb40..bd974c5 100644 (file)
@@ -458,6 +458,12 @@ static int check_dot(e2fsck_t ctx,
                                        ext2fs_dirent_set_name_len(nextdir, 0);
                                        ext2fs_dirent_set_file_type(nextdir,
                                                                    ftype);
+#ifdef WORDS_BIGENDIAN
+                               } else {
+                                       (void) ext2fs_dirent_swab_in2(ctx->fs,
+                                               (char *) nextdir,
+                                               ctx->fs->blocksize - 12, 0);
+#endif
                                }
                                status = 1;
                        }
@@ -1370,12 +1376,14 @@ skip_checksum:
                                                          hash_in_dirent);
 #ifdef WORDS_BIGENDIAN
                                        if (need_reswab) {
+                                               unsigned int len;
+
                                                (void) ext2fs_get_rec_len(fs,
-                                                       dirent, &rec_len);
-                                               ext2fs_dirent_swab_in2(fs,
-                                                       ((char *)dirent) + offset + rec_len,
-                                                       max_block_size - offset - rec_len,
-                                                       0);
+                                                       dirent, &len);
+                                               len += offset;
+                                               if (max_block_size > len)
+                                                       ext2fs_dirent_swab_in2(fs,
+                               ((char *)dirent) + len, max_block_size - len, 0);
                                        }
 #endif
                                        dir_modified++;