Linux filesystem development
 help / color / mirror / Atom feed
From: Viacheslav Dubeyko <Slava.Dubeyko@ibm.com>
To: "contact@gvernon.com" <contact@gvernon.com>,
	"penguin-kernel@I-love.SAKURA.ne.jp"
	<penguin-kernel@I-love.SAKURA.ne.jp>
Cc: "glaubitz@physik.fu-berlin.de" <glaubitz@physik.fu-berlin.de>,
	"frank.li@vivo.com" <frank.li@vivo.com>,
	"syzbot+97e301b4b82ae803d21b@syzkaller.appspotmail.com"
	<syzbot+97e301b4b82ae803d21b@syzkaller.appspotmail.com>,
	"slava@dubeyko.com" <slava@dubeyko.com>,
	"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
	"linux-fsdevel@vger.kernel.org" <linux-fsdevel@vger.kernel.org>
Subject: Re: [PATCH v7] hfs: validate record ID against requested CNID in hfs_cat_find_brec()
Date: Fri, 15 May 2026 21:10:27 +0000	[thread overview]
Message-ID: <5ff5f107e5a8588367b3af77748369c166f16cc7.camel@ibm.com> (raw)
In-Reply-To: <c80f3c36-4c66-4e51-ab3e-e83d37b60131@I-love.SAKURA.ne.jp>

On Thu, 2026-05-14 at 16:34 +0900, Tetsuo Handa wrote:
> syzbot is reporting that BUG() in hfs_write_inode() fires upon unmount
> operation when the inode number of the record retrieved as a result of
> hfs_cat_find_brec(HFS_ROOT_CNID) is not HFS_ROOT_CNID, for
> commit b905bafdea21 ("hfs: Sanity check the root record") checked
> the record size and the record type but did not check the inode number.
> 
> Initially, Viacheslav Dubeyko was assuming that we can fix this problem
> by adding validation to hfs_read_inode(), and George Anthony Vernon is
> proposing a patch that adds validation to hfs_read_inode().
> 

We can fix the problem in by adding validation to hfs_read_inode().

> While I am not against adding validation to hfs_read_inode(), treating
> an inode which is not the root inode as if the root inode is a logical
> error which should be rejected regardless of whether we hit BUG() or not.
> And we confirmed that we can't fix this logical error by adding validation
> to hfs_read_inode().
> 

We haven't confirmed it. The issue can be fixed by adding validation to
hfs_read_inode().

> Since hfs_brec_read() doesn't receive which type of struct (one of "struct
> hfs_cat_file", "struct hfs_cat_dir" or "struct hfs_cat_thread") does the
> caller of hfs_brec_read() want to read as function argument, currently
> it is impossible for hfs_brec_read() to return 0 only when the retrieved
> record is what the caller wants, despite the HFS's on-disk layout includes
> type of struct within the retrieved record.

The hfs_brec_read() is called with arguments [1]:

int hfs_brec_read(struct hfs_find_data *fd, void *rec, u32 rec_len);

So, we have void *rec as a buffer for read. The hfs_brec_read() is called to
extract the b-tree record, for example [2-4]:

int hfs_cat_find_brec(struct super_block *sb, u32 cnid,
		      struct hfs_find_data *fd)
{
	hfs_cat_rec rec;

<skipped>

	res = hfs_brec_read(fd, &rec, sizeof(rec));
	if (res)
		return res;

<skipped>
}

So, the goal of this function is to extract the hfs_cat_rec [5]:

/* A catalog tree record */
typedef union hfs_cat_rec {
	s8 type;			/* The type of entry */
	struct hfs_cat_file file;
	struct hfs_cat_dir dir;
	struct hfs_cat_thread thread;
} hfs_cat_rec;

It is possible to see that hfs_cat_rec starts from type field [6]. This type
field can be checked to make a conclusion which type of record was read by
hfs_brec_read(). Technically speaking, we can change void *rec on hfs_cat_rec
*rec:

int hfs_brec_read(struct hfs_find_data *fd, hfs_cat_rec *rec, u32 rec_len);

or we can cast void *rec into hfs_cat_rec *rec. Also, we can introduce
specialized hfs_brec_read() for Catalog File. So, I don't see any problem to
check the type of the record in the hfs_brec_read().

Also, we have struct hfs_find_data as an input argument:

struct hfs_find_data {
	btree_key *key;
	btree_key *search_key;
	struct hfs_btree *tree;
	struct hfs_bnode *bnode;
	int record;
	int keyoffset, keylength;
	int entryoffset, entrylength;
};

We build the key before the search:

int hfs_cat_find_brec(struct super_block *sb, u32 cnid,
		      struct hfs_find_data *fd)
{
	hfs_cat_rec rec;
	int res, len, type;

	hfs_cat_build_key(sb, fd->search_key, cnid, NULL);
	res = hfs_brec_read(fd, &rec, sizeof(rec));
	if (res)
		return res;

	type = rec.type;
	if (type != HFS_CDR_THD && type != HFS_CDR_FTH) {
		pr_err("found bad thread record in catalog\n");
		return -EIO;
	}

	fdsearch_key->cat.ParID = rec.thread.ParID;
	len = fd->search_key->cat.CName.len = rec.thread.CName.len;
	if (len > HFS_NAMELEN) {
		pr_err("bad catalog namelength\n");
		return -EIO;
	}
	memcpy(fd->search_key->cat.CName.name, rec.thread.CName.name, len);
	return hfs_brec_find(fd);
}

void hfs_cat_build_key(struct super_block *sb, btree_key *key, u32 parent, const
struct qstr *name)
{
	key->cat.reserved = 0;
	key->cat.ParID = cpu_to_be32(parent);
	if (name) {
		hfs_asc2mac(sb, &key->cat.CName, name);
		key->key_len = 6 + key->cat.CName.len;
	} else {
		memset(&key->cat.CName, 0, sizeof(struct hfs_name));
		key->key_len = 6;
	}
}

So, we keep CNID in the key->cat.ParID. As far as I can see, we have everything
for check. We have the pointer on tree in struct hfs_find_data and we can make
conclusion which key need to be used based on tree type.

Thanks,
Slava.

[1] https://elixir.bootlin.com/linux/v7.1-rc3/source/fs/hfs/bfind.c#L170
[2] https://elixir.bootlin.com/linux/v7.1-rc3/source/fs/hfs/catalog.c#L187
[3] https://elixir.bootlin.com/linux/v7.1-rc3/source/fs/hfs/dir.c#L20
[4] https://elixir.bootlin.com/linux/v7.1-rc3/source/fs/hfs/inode.c#L544
[5]
https://elixir.bootlin.com/linux/v7.1-rc3/source/include/linux/hfs_common.h#L447
[6]
https://elixir.bootlin.com/linux/v7.1-rc3/source/include/linux/hfs_common.h#L89


  reply	other threads:[~2026-05-15 21:10 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-03-11 21:13 [PATCH v4] hfs: Validate CNIDs in hfs_read_inode George Anthony Vernon
2026-03-12 10:45 ` Tetsuo Handa
2026-03-12 23:13   ` Viacheslav Dubeyko
2026-03-13 11:03     ` Tetsuo Handa
2026-03-13 18:40       ` Viacheslav Dubeyko
2026-03-14  6:35         ` Tetsuo Handa
2026-03-16 21:50           ` Viacheslav Dubeyko
2026-03-18  0:37             ` George Anthony Vernon
2026-03-18  2:02               ` Viacheslav Dubeyko
2026-03-18 22:49                 ` George Anthony Vernon
2026-03-19  9:57                   ` Tetsuo Handa
2026-03-19 12:26                     ` George Vernon
2026-03-20  0:32                       ` Tetsuo Handa
2026-05-14  7:34                         ` [PATCH v7] hfs: validate record ID against requested CNID in hfs_cat_find_brec() Tetsuo Handa
2026-05-15 21:10                           ` Viacheslav Dubeyko [this message]
2026-05-16  6:17                             ` Tetsuo Handa
2026-05-19 21:09                               ` Viacheslav Dubeyko
2026-03-18 10:42             ` [PATCH v4] hfs: Validate CNIDs in hfs_read_inode Tetsuo Handa
2026-03-18  0:10   ` George Anthony Vernon
2026-03-18  8:16     ` Tetsuo Handa
2026-03-12 23:07 ` Viacheslav Dubeyko

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=5ff5f107e5a8588367b3af77748369c166f16cc7.camel@ibm.com \
    --to=slava.dubeyko@ibm.com \
    --cc=contact@gvernon.com \
    --cc=frank.li@vivo.com \
    --cc=glaubitz@physik.fu-berlin.de \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=penguin-kernel@I-love.SAKURA.ne.jp \
    --cc=slava@dubeyko.com \
    --cc=syzbot+97e301b4b82ae803d21b@syzkaller.appspotmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox