xref: /linux/fs/xfs/scrub/listxattr.c (revision da5b2ad1c2f18834cb1ce429e2e5a5cf5cbdf21b)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2022-2024 Oracle.  All Rights Reserved.
4  * Author: Darrick J. Wong <djwong@kernel.org>
5  */
6 #include "xfs.h"
7 #include "xfs_fs.h"
8 #include "xfs_shared.h"
9 #include "xfs_format.h"
10 #include "xfs_log_format.h"
11 #include "xfs_trans_resv.h"
12 #include "xfs_mount.h"
13 #include "xfs_inode.h"
14 #include "xfs_da_format.h"
15 #include "xfs_da_btree.h"
16 #include "xfs_attr.h"
17 #include "xfs_attr_leaf.h"
18 #include "xfs_attr_sf.h"
19 #include "xfs_trans.h"
20 #include "scrub/scrub.h"
21 #include "scrub/bitmap.h"
22 #include "scrub/dab_bitmap.h"
23 #include "scrub/listxattr.h"
24 
25 /* Call a function for every entry in a shortform xattr structure. */
26 STATIC int
27 xchk_xattr_walk_sf(
28 	struct xfs_scrub		*sc,
29 	struct xfs_inode		*ip,
30 	xchk_xattr_fn			attr_fn,
31 	void				*priv)
32 {
33 	struct xfs_attr_sf_hdr		*hdr = ip->i_af.if_data;
34 	struct xfs_attr_sf_entry	*sfe;
35 	unsigned int			i;
36 	int				error;
37 
38 	sfe = xfs_attr_sf_firstentry(hdr);
39 	for (i = 0; i < hdr->count; i++) {
40 		error = attr_fn(sc, ip, sfe->flags, sfe->nameval, sfe->namelen,
41 				&sfe->nameval[sfe->namelen], sfe->valuelen,
42 				priv);
43 		if (error)
44 			return error;
45 
46 		sfe = xfs_attr_sf_nextentry(sfe);
47 	}
48 
49 	return 0;
50 }
51 
52 /* Call a function for every entry in this xattr leaf block. */
53 STATIC int
54 xchk_xattr_walk_leaf_entries(
55 	struct xfs_scrub		*sc,
56 	struct xfs_inode		*ip,
57 	xchk_xattr_fn			attr_fn,
58 	struct xfs_buf			*bp,
59 	void				*priv)
60 {
61 	struct xfs_attr3_icleaf_hdr	ichdr;
62 	struct xfs_mount		*mp = sc->mp;
63 	struct xfs_attr_leafblock	*leaf = bp->b_addr;
64 	struct xfs_attr_leaf_entry	*entry;
65 	unsigned int			i;
66 	int				error;
67 
68 	xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &ichdr, leaf);
69 	entry = xfs_attr3_leaf_entryp(leaf);
70 
71 	for (i = 0; i < ichdr.count; entry++, i++) {
72 		void			*value;
73 		unsigned char		*name;
74 		unsigned int		namelen, valuelen;
75 
76 		if (entry->flags & XFS_ATTR_LOCAL) {
77 			struct xfs_attr_leaf_name_local		*name_loc;
78 
79 			name_loc = xfs_attr3_leaf_name_local(leaf, i);
80 			name = name_loc->nameval;
81 			namelen = name_loc->namelen;
82 			value = &name_loc->nameval[name_loc->namelen];
83 			valuelen = be16_to_cpu(name_loc->valuelen);
84 		} else {
85 			struct xfs_attr_leaf_name_remote	*name_rmt;
86 
87 			name_rmt = xfs_attr3_leaf_name_remote(leaf, i);
88 			name = name_rmt->name;
89 			namelen = name_rmt->namelen;
90 			value = NULL;
91 			valuelen = be32_to_cpu(name_rmt->valuelen);
92 		}
93 
94 		error = attr_fn(sc, ip, entry->flags, name, namelen, value,
95 				valuelen, priv);
96 		if (error)
97 			return error;
98 
99 	}
100 
101 	return 0;
102 }
103 
104 /*
105  * Call a function for every entry in a leaf-format xattr structure.  Avoid
106  * memory allocations for the loop detector since there's only one block.
107  */
108 STATIC int
109 xchk_xattr_walk_leaf(
110 	struct xfs_scrub		*sc,
111 	struct xfs_inode		*ip,
112 	xchk_xattr_fn			attr_fn,
113 	void				*priv)
114 {
115 	struct xfs_buf			*leaf_bp;
116 	int				error;
117 
118 	error = xfs_attr3_leaf_read(sc->tp, ip, ip->i_ino, 0, &leaf_bp);
119 	if (error)
120 		return error;
121 
122 	error = xchk_xattr_walk_leaf_entries(sc, ip, attr_fn, leaf_bp, priv);
123 	xfs_trans_brelse(sc->tp, leaf_bp);
124 	return error;
125 }
126 
127 /* Find the leftmost leaf in the xattr dabtree. */
128 STATIC int
129 xchk_xattr_find_leftmost_leaf(
130 	struct xfs_scrub		*sc,
131 	struct xfs_inode		*ip,
132 	struct xdab_bitmap		*seen_dablks,
133 	struct xfs_buf			**leaf_bpp)
134 {
135 	struct xfs_da3_icnode_hdr	nodehdr;
136 	struct xfs_mount		*mp = sc->mp;
137 	struct xfs_trans		*tp = sc->tp;
138 	struct xfs_da_intnode		*node;
139 	struct xfs_da_node_entry	*btree;
140 	struct xfs_buf			*bp;
141 	xfs_failaddr_t			fa;
142 	xfs_dablk_t			blkno = 0;
143 	unsigned int			expected_level = 0;
144 	int				error;
145 
146 	for (;;) {
147 		xfs_extlen_t		len = 1;
148 		uint16_t		magic;
149 
150 		/* Make sure we haven't seen this new block already. */
151 		if (xdab_bitmap_test(seen_dablks, blkno, &len))
152 			return -EFSCORRUPTED;
153 
154 		error = xfs_da3_node_read(tp, ip, blkno, &bp, XFS_ATTR_FORK);
155 		if (error)
156 			return error;
157 
158 		node = bp->b_addr;
159 		magic = be16_to_cpu(node->hdr.info.magic);
160 		if (magic == XFS_ATTR_LEAF_MAGIC ||
161 		    magic == XFS_ATTR3_LEAF_MAGIC)
162 			break;
163 
164 		error = -EFSCORRUPTED;
165 		if (magic != XFS_DA_NODE_MAGIC &&
166 		    magic != XFS_DA3_NODE_MAGIC)
167 			goto out_buf;
168 
169 		fa = xfs_da3_node_header_check(bp, ip->i_ino);
170 		if (fa)
171 			goto out_buf;
172 
173 		xfs_da3_node_hdr_from_disk(mp, &nodehdr, node);
174 
175 		if (nodehdr.count == 0 || nodehdr.level >= XFS_DA_NODE_MAXDEPTH)
176 			goto out_buf;
177 
178 		/* Check the level from the root node. */
179 		if (blkno == 0)
180 			expected_level = nodehdr.level - 1;
181 		else if (expected_level != nodehdr.level)
182 			goto out_buf;
183 		else
184 			expected_level--;
185 
186 		/* Remember that we've seen this node. */
187 		error = xdab_bitmap_set(seen_dablks, blkno, 1);
188 		if (error)
189 			goto out_buf;
190 
191 		/* Find the next level towards the leaves of the dabtree. */
192 		btree = nodehdr.btree;
193 		blkno = be32_to_cpu(btree->before);
194 		xfs_trans_brelse(tp, bp);
195 	}
196 
197 	error = -EFSCORRUPTED;
198 	fa = xfs_attr3_leaf_header_check(bp, ip->i_ino);
199 	if (fa)
200 		goto out_buf;
201 
202 	if (expected_level != 0)
203 		goto out_buf;
204 
205 	/* Remember that we've seen this leaf. */
206 	error = xdab_bitmap_set(seen_dablks, blkno, 1);
207 	if (error)
208 		goto out_buf;
209 
210 	*leaf_bpp = bp;
211 	return 0;
212 
213 out_buf:
214 	xfs_trans_brelse(tp, bp);
215 	return error;
216 }
217 
218 /* Call a function for every entry in a node-format xattr structure. */
219 STATIC int
220 xchk_xattr_walk_node(
221 	struct xfs_scrub		*sc,
222 	struct xfs_inode		*ip,
223 	xchk_xattr_fn			attr_fn,
224 	xchk_xattrleaf_fn		leaf_fn,
225 	void				*priv)
226 {
227 	struct xfs_attr3_icleaf_hdr	leafhdr;
228 	struct xdab_bitmap		seen_dablks;
229 	struct xfs_mount		*mp = sc->mp;
230 	struct xfs_attr_leafblock	*leaf;
231 	struct xfs_buf			*leaf_bp;
232 	int				error;
233 
234 	xdab_bitmap_init(&seen_dablks);
235 
236 	error = xchk_xattr_find_leftmost_leaf(sc, ip, &seen_dablks, &leaf_bp);
237 	if (error)
238 		goto out_bitmap;
239 
240 	for (;;) {
241 		xfs_extlen_t	len;
242 
243 		error = xchk_xattr_walk_leaf_entries(sc, ip, attr_fn, leaf_bp,
244 				priv);
245 		if (error)
246 			goto out_leaf;
247 
248 		/* Find the right sibling of this leaf block. */
249 		leaf = leaf_bp->b_addr;
250 		xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf);
251 		if (leafhdr.forw == 0)
252 			goto out_leaf;
253 
254 		xfs_trans_brelse(sc->tp, leaf_bp);
255 
256 		if (leaf_fn) {
257 			error = leaf_fn(sc, priv);
258 			if (error)
259 				goto out_bitmap;
260 		}
261 
262 		/* Make sure we haven't seen this new leaf already. */
263 		len = 1;
264 		if (xdab_bitmap_test(&seen_dablks, leafhdr.forw, &len)) {
265 			error = -EFSCORRUPTED;
266 			goto out_bitmap;
267 		}
268 
269 		error = xfs_attr3_leaf_read(sc->tp, ip, ip->i_ino,
270 				leafhdr.forw, &leaf_bp);
271 		if (error)
272 			goto out_bitmap;
273 
274 		/* Remember that we've seen this new leaf. */
275 		error = xdab_bitmap_set(&seen_dablks, leafhdr.forw, 1);
276 		if (error)
277 			goto out_leaf;
278 	}
279 
280 out_leaf:
281 	xfs_trans_brelse(sc->tp, leaf_bp);
282 out_bitmap:
283 	xdab_bitmap_destroy(&seen_dablks);
284 	return error;
285 }
286 
287 /*
288  * Call a function for every extended attribute in a file.
289  *
290  * Callers must hold the ILOCK.  No validation or cursor restarts allowed.
291  * Returns -EFSCORRUPTED on any problem, including loops in the dabtree.
292  */
293 int
294 xchk_xattr_walk(
295 	struct xfs_scrub	*sc,
296 	struct xfs_inode	*ip,
297 	xchk_xattr_fn		attr_fn,
298 	xchk_xattrleaf_fn	leaf_fn,
299 	void			*priv)
300 {
301 	int			error;
302 
303 	xfs_assert_ilocked(ip, XFS_ILOCK_SHARED | XFS_ILOCK_EXCL);
304 
305 	if (!xfs_inode_hasattr(ip))
306 		return 0;
307 
308 	if (ip->i_af.if_format == XFS_DINODE_FMT_LOCAL)
309 		return xchk_xattr_walk_sf(sc, ip, attr_fn, priv);
310 
311 	/* attr functions require that the attr fork is loaded */
312 	error = xfs_iread_extents(sc->tp, ip, XFS_ATTR_FORK);
313 	if (error)
314 		return error;
315 
316 	if (xfs_attr_is_leaf(ip))
317 		return xchk_xattr_walk_leaf(sc, ip, attr_fn, priv);
318 
319 	return xchk_xattr_walk_node(sc, ip, attr_fn, leaf_fn, priv);
320 }
321