xfstest splats

OGAWA Hirofumi hirofumi at mail.parknet.co.jp
Tue Apr 29 04:56:04 PDT 2014


"Darrick J. Wong" <darrick.wong at oracle.com> writes:

> Hi all,
>
> I ran xfstests against tux3 on 3.15-rc3, with default options (primarily
> because I don't know what options exist anyway).  xfstest generic/310 spit out
> this:
>
>  TUX3-fs error (sda): tux_readdir:398: zero length entry at inum 8192, block 15

This bug was by wrong dir f_pos from 310, and current tux3 behavior is
error=panic. As a result, it caused of BUG().

Well, this patch checks pos, and dir entry more (from ext4 checker). And
additionally, checks f_pos alignment is valid at first.

And finally, convert from error=panic to just error message if
readdir().

[FIXME: If f_pos is invalid, SuSv4 says unspecified behavior. and now,
skips that block, and continue at next block. What is good behavior?]

Thanks.

Signed-off-by: OGAWA Hirofumi <hirofumi at mail.parknet.co.jp>
---

 user/kernel/dir.c  |   47 +++++++++++++++++++++++++++++++++++++++++++----
 user/kernel/tux3.h |    6 ++++--
 user/tux3user.h    |    6 ++++--
 3 files changed, 51 insertions(+), 8 deletions(-)

diff -puN user/kernel/dir.c~dir-make-robust user/kernel/dir.c
--- tux3/user/kernel/dir.c~dir-make-robust	2014-04-29 17:56:00.268760455 +0900
+++ tux3-hirofumi/user/kernel/dir.c	2014-04-29 18:58:44.666310736 +0900
@@ -363,6 +363,39 @@ static unsigned char filetype[TUX_TYPES]
 	[TUX_LNK] = DT_LNK,
 };
 
+/*
+ * Return 0 if the directory entry is OK, and 1 if there is a problem
+ */
+static int __check_dir_entry(const char *func, int line, struct inode *dir,
+			     struct buffer_head *buffer, tux_dirent *entry)
+{
+	struct sb *sb = tux_sb(dir->i_sb);
+	const char *error_msg = NULL;
+	const void *base = bufdata(buffer);
+	const int off = (void *)entry - base;
+	const int rlen = tux_rec_len_from_disk(entry->rec_len);
+
+	if (unlikely(rlen < TUX_REC_LEN(1)))
+		error_msg = "rec_len is smaller than minimal";
+	else if (unlikely(rlen % TUX_DIR_ALIGN != 0))
+		error_msg = "rec_len alignment error";
+	else if (unlikely(rlen < TUX_REC_LEN(entry->name_len)))
+		error_msg = "rec_len is too small for name_len";
+	else if (unlikely(off + rlen > sb->blocksize))
+		error_msg = "directory entry across range";
+	else
+		return 0;
+
+	__tux3_err(sb, func, line,
+		   "bad entry: %s: inum %Lu, block %Lu, off %d, rec_len %d",
+		   error_msg, tux_inode(dir)->inum, bufindex(buffer),
+		   off, rlen);
+
+	return 1;
+}
+#define check_dir_entry(d, b, e)		\
+	__check_dir_entry(__func__, __LINE__, d, b, e)
+
 int tux_readdir(struct file *file, struct dir_context *ctx)
 {
 	struct inode *dir = file_inode(file);
@@ -374,6 +407,12 @@ int tux_readdir(struct file *file, struc
 
 	assert(!(dir->i_size & sb->blockmask));
 
+	if (offset % TUX_DIR_ALIGN) {
+		/* Invalid offset, skip to next block */
+		ctx->pos = (ctx->pos | (sb->blocksize - 1)) + 1;
+		offset = 0;
+	}
+
 	for (block = ctx->pos >> blockbits; block < blocks; block++) {
 		struct buffer_head *buffer = blockread(mapping(dir), block);
 		if (!buffer)
@@ -393,10 +432,10 @@ int tux_readdir(struct file *file, struc
 		}
 		tux_dirent *limit = base + sb->blocksize - TUX_REC_LEN(1);
 		for (tux_dirent *entry = base + offset; entry <= limit; entry = next_entry(entry)) {
-			if (entry->rec_len == 0) {
-				blockput(buffer);
-				tux_zero_len_error(dir, block);
-				return -EIO;
+			if (check_dir_entry(dir, buffer, entry)) {
+				/* On error, skip to next block */
+				ctx->pos = (ctx->pos | (sb->blocksize - 1)) + 1;
+				break;
 			}
 			if (!is_deleted(entry)) {
 				unsigned type = (entry->type < TUX_TYPES) ? filetype[entry->type] : DT_UNKNOWN;
diff -puN user/kernel/tux3.h~dir-make-robust user/kernel/tux3.h
--- tux3/user/kernel/tux3.h~dir-make-robust	2014-04-29 18:42:30.553071700 +0900
+++ tux3-hirofumi/user/kernel/tux3.h	2014-04-29 18:51:29.007547097 +0900
@@ -704,9 +704,11 @@ int blockio_vec(int rw, struct bufvec *b
 
 #define tux3_msg(sb, fmt, ...)						\
 	__tux3_msg(sb, KERN_INFO, "", fmt, ##__VA_ARGS__)
-#define tux3_err(sb, fmt, ...)						\
+#define __tux3_err(sb, func, line, fmt, ...)				\
 	__tux3_msg(sb, KERN_ERR, " error",				\
-		   "%s:%d: " fmt, __func__, __LINE__, ##__VA_ARGS__)
+		   "%s:%d: " fmt, func, line, ##__VA_ARGS__)
+#define tux3_err(sb, fmt, ...)						\
+	__tux3_err(sb, __func__, __LINE__, fmt, ##__VA_ARGS__)
 #define tux3_warn(sb, fmt, ...)					\
 	__tux3_msg(sb, KERN_WARNING, " warning", fmt, ##__VA_ARGS__)
 
diff -puN user/tux3user.h~dir-make-robust user/tux3user.h
--- tux3/user/tux3user.h~dir-make-robust	2014-04-29 18:43:13.460952866 +0900
+++ tux3-hirofumi/user/tux3user.h	2014-04-29 18:49:57.279807808 +0900
@@ -143,9 +143,11 @@ int blockio_vec(int rw, struct bufvec *b
 
 #define tux3_msg(sb, fmt, ...)						\
 	__tux3_msg(sb, "", "", fmt "\n", ##__VA_ARGS__)
-#define tux3_err(sb, fmt, ...)						\
+#define __tux3_err(sb, func, line, fmt, ...)				\
 	__tux3_msg(sb, "", "",						\
-		   "Error: %s:%d: " fmt "\n", __func__, __LINE__, ##__VA_ARGS__)
+		   "Error: %s:%d: " fmt "\n", func, line, ##__VA_ARGS__)
+#define tux3_err(sb, fmt, ...)						\
+	__tux3_err(sb, __func__, __LINE__, fmt, ##__VA_ARGS__)
 #define tux3_warn(sb, fmt, ...)					\
 	__tux3_msg(sb, "", "", "Warning: " fmt "\n", ##__VA_ARGS__)
 
_
-- 
OGAWA Hirofumi <hirofumi at mail.parknet.co.jp>



More information about the Tux3 mailing list