]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - repair/attr_repair.c
xfs: don't treat unknown di_flags2 as corruption in scrub
[thirdparty/xfsprogs-dev.git] / repair / attr_repair.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (c) 2000-2002,2004-2005 Silicon Graphics, Inc.
4 * All Rights Reserved.
5 */
6
7 #include "libxfs.h"
8 #include "globals.h"
9 #include "err_protos.h"
10 #include "attr_repair.h"
11 #include "dinode.h"
12 #include "bmap.h"
13 #include "protos.h"
14 #include "dir2.h"
15 #include "da_util.h"
16
17 static int xfs_acl_valid(struct xfs_mount *mp, struct xfs_acl *daclp);
18 static int xfs_mac_valid(xfs_mac_label_t *lp);
19
20 /*
21 * da node check/verify functions that the attribute tree relies on are first in
22 * the file before the actual attribute code. This used to be shared with the
23 * dir v1 code, but that format is no longer supported yb the userspace
24 * utilities and hence is now specific to the attribute tree implementation.
25 */
26
27 typedef unsigned char da_freemap_t;
28
29 /*
30 * Allocate a freespace map for directory or attr leaf blocks (1 bit per byte)
31 * 1 == used, 0 == free.
32 */
33 static da_freemap_t *
34 alloc_da_freemap(struct xfs_mount *mp)
35 {
36 return calloc(1, mp->m_sb.sb_blocksize / NBBY);
37 }
38
39 /*
40 * Set the he range [start, stop) in the directory freemap.
41 *
42 * Returns 1 if there is a conflict or 0 if everything's good.
43 *
44 * Within a char, the lowest bit of the char represents the byte with
45 * the smallest address
46 */
47 static int
48 set_da_freemap(xfs_mount_t *mp, da_freemap_t *map, int start, int stop)
49 {
50 const da_freemap_t mask = 0x1;
51 int i;
52
53 if (start > stop) {
54 /*
55 * allow == relation since [x, x) claims 1 byte
56 */
57 do_warn(_("bad range claimed [%d, %d) in da block\n"),
58 start, stop);
59 return(1);
60 }
61
62 if (stop > mp->m_sb.sb_blocksize) {
63 do_warn(
64 _("byte range end [%d %d) in da block larger than blocksize %d\n"),
65 start, stop, mp->m_sb.sb_blocksize);
66 return(1);
67 }
68
69 for (i = start; i < stop; i ++) {
70 if (map[i / NBBY] & (mask << i % NBBY)) {
71 do_warn(_("multiply claimed byte %d in da block\n"), i);
72 return(1);
73 }
74 map[i / NBBY] |= (mask << i % NBBY);
75 }
76
77 return(0);
78 }
79
80 /*
81 * For attribute repair, there are 3 formats to worry about. First, is
82 * shortform attributes which reside in the inode. Second is the leaf
83 * form, and lastly the btree. Much of this models after the directory
84 * structure so code resembles the directory repair cases.
85 * For shortform case, if an attribute looks corrupt, it is removed.
86 * If that leaves the shortform down to 0 attributes, it's okay and
87 * will appear to just have a null attribute fork. Some checks are done
88 * for validity of the value field based on what the security needs are.
89 * Calls will be made to xfs_mac_valid or xfs_acl_valid routines if the
90 * security attributes exist. They will be cleared if invalid.
91 * No other values will be checked. The DMF folks do not have current
92 * requirements, but may in the future.
93 *
94 * For leaf block attributes, it requires more processing. One sticky
95 * point is that the attributes can be local (within the leaf) or
96 * remote (outside the leaf in other blocks). Thinking of local only
97 * if you get a bad attribute, and want to delete just one, it's a-okay
98 * if it remains large enough to still be a leaf block attribute. Otherwise,
99 * it may have to be converted to shortform. How to convert this and when
100 * is an issue. This call is happening in Phase3. Phase5 will capture empty
101 * blocks, but Phase6 allows you to use the libxfs library which knows
102 * how to handle attributes in the kernel for converting formats. What we
103 * could do is mark an attribute to be cleared now, but in phase6 somehow
104 * have it cleared for real and then the format changed to shortform if
105 * applicable. Since this requires more work than I anticipate can be
106 * accomplished for the next release, we will instead just say any bad
107 * attribute in the leaf block will make the entire attribute fork be
108 * cleared. The simplest way to do that is to ignore the leaf format, and
109 * call clear_dinode_attr to just make a shortform attribute fork with
110 * zero entries.
111 *
112 * Another issue with handling repair on leaf attributes is the remote
113 * blocks. To make sure that they look good and are not used multiple times
114 * by the attribute fork, some mechanism to keep track of all them is necessary.
115 * Do this in the future, time permitting. For now, note that there is no
116 * check for remote blocks and their allocations.
117 *
118 * For btree formatted attributes, the model can follow directories. That
119 * would mean go down the tree to the leftmost leaf. From there moving down
120 * the links and processing each. They would call back up the tree, to verify
121 * that the tree structure is okay. Any problems will result in the attribute
122 * fork being emptied and put in shortform format.
123 */
124
125 /*
126 * This routine just checks what security needs are for attribute values
127 * only called when root flag is set, otherwise these names could exist in
128 * in user attribute land without a conflict.
129 * If value is non-zero, then a remote attribute is being passed in
130 */
131 static int
132 valuecheck(
133 struct xfs_mount *mp,
134 char *namevalue,
135 char *value,
136 int namelen,
137 int valuelen)
138 {
139 /* for proper alignment issues, get the structs and memmove the values */
140 xfs_mac_label_t macl;
141 void *valuep;
142 int clearit = 0;
143
144 if ((namelen == SGI_ACL_FILE_SIZE &&
145 strncmp(namevalue, SGI_ACL_FILE, SGI_ACL_FILE_SIZE) == 0) ||
146 (namelen == SGI_ACL_DEFAULT_SIZE &&
147 strncmp(namevalue, SGI_ACL_DEFAULT, SGI_ACL_DEFAULT_SIZE) == 0)) {
148 if (value == NULL) {
149 valuep = malloc(valuelen);
150 if (!valuep)
151 do_error(_("No memory for ACL check!\n"));
152 memcpy(valuep, namevalue + namelen, valuelen);
153 } else
154 valuep = value;
155
156 if (xfs_acl_valid(mp, valuep) != 0) {
157 clearit = 1;
158 do_warn(
159 _("entry contains illegal value in attribute named SGI_ACL_FILE "
160 "or SGI_ACL_DEFAULT\n"));
161 }
162
163 if (valuep != value)
164 free(valuep);
165
166 } else if (strncmp(namevalue, SGI_MAC_FILE, SGI_MAC_FILE_SIZE) == 0) {
167 if (value == NULL) {
168 memset(&macl, 0, sizeof(xfs_mac_label_t));
169 memmove(&macl, namevalue+namelen, valuelen);
170 valuep = &macl;
171 } else
172 valuep = value;
173
174 if (xfs_mac_valid((xfs_mac_label_t *)valuep) != 1) { /* 1 is valid */
175 /*
176 * if sysconf says MAC enabled,
177 * temp = mac_from_text("msenhigh/mintlow", NULL)
178 * copy it to value, update valuelen, totsize
179 * This causes pushing up or down of all following
180 * attributes, forcing a attribute format change!!
181 * else clearit = 1;
182 */
183 clearit = 1;
184 do_warn(
185 _("entry contains illegal value in attribute named SGI_MAC_LABEL\n"));
186 }
187 } else if (strncmp(namevalue, SGI_CAP_FILE, SGI_CAP_FILE_SIZE) == 0) {
188 if ( valuelen != sizeof(xfs_cap_set_t)) {
189 clearit = 1;
190 do_warn(
191 _("entry contains illegal value in attribute named SGI_CAP_FILE\n"));
192 }
193 }
194
195 return(clearit);
196 }
197
198
199 /*
200 * this routine validates the attributes in shortform format.
201 * a non-zero return repair value means certain attributes are bogus
202 * and were cleared if possible. Warnings do not generate error conditions
203 * if you cannot modify the structures. repair is set to 1, if anything
204 * was fixed.
205 */
206 static int
207 process_shortform_attr(
208 struct xfs_mount *mp,
209 xfs_ino_t ino,
210 xfs_dinode_t *dip,
211 int *repair)
212 {
213 xfs_attr_shortform_t *asf;
214 xfs_attr_sf_entry_t *currententry, *nextentry, *tempentry;
215 int i, junkit;
216 int currentsize, remainingspace;
217
218 *repair = 0;
219
220 asf = (xfs_attr_shortform_t *) XFS_DFORK_APTR(dip);
221
222 /* Assumption: hdr.totsize is less than a leaf block and was checked
223 * by lclinode for valid sizes. Check the count though.
224 */
225 if (asf->hdr.count == 0)
226 /* then the total size should just be the header length */
227 if (be16_to_cpu(asf->hdr.totsize) != sizeof(xfs_attr_sf_hdr_t)) {
228 /* whoops there's a discrepancy. Clear the hdr */
229 if (!no_modify) {
230 do_warn(
231 _("there are no attributes in the fork for inode %" PRIu64 "\n"),
232 ino);
233 asf->hdr.totsize =
234 cpu_to_be16(sizeof(xfs_attr_sf_hdr_t));
235 *repair = 1;
236 return(1);
237 } else {
238 do_warn(
239 _("would junk the attribute fork since count is 0 for inode %" PRIu64 "\n"),
240 ino);
241 return(1);
242 }
243 }
244
245 currentsize = sizeof(xfs_attr_sf_hdr_t);
246 remainingspace = be16_to_cpu(asf->hdr.totsize) - currentsize;
247 nextentry = &asf->list[0];
248 for (i = 0; i < asf->hdr.count; i++) {
249 currententry = nextentry;
250 junkit = 0;
251
252 /* don't go off the end if the hdr.count was off */
253 if ((currentsize + (sizeof(xfs_attr_sf_entry_t) - 1)) >
254 be16_to_cpu(asf->hdr.totsize))
255 break; /* get out and reset count and totSize */
256
257 /* if the namelen is 0, can't get to the rest of the entries */
258 if (currententry->namelen == 0) {
259 do_warn(_("zero length name entry in attribute fork,"));
260 if (!no_modify) {
261 do_warn(
262 _(" truncating attributes for inode %" PRIu64 " to %d\n"), ino, i);
263 *repair = 1;
264 break; /* and then update hdr fields */
265 } else {
266 do_warn(
267 _(" would truncate attributes for inode %" PRIu64 " to %d\n"), ino, i);
268 break;
269 }
270 } else {
271 /* It's okay to have a 0 length valuelen, but do a
272 * rough check to make sure we haven't gone outside of
273 * totsize.
274 */
275 if (remainingspace < currententry->namelen ||
276 ((remainingspace - currententry->
277 namelen) < currententry->valuelen)) {
278 do_warn(
279 _("name or value attribute lengths are too large,\n"));
280 if (!no_modify) {
281 do_warn(
282 _(" truncating attributes for inode %" PRIu64 " to %d\n"),
283 ino, i);
284 *repair = 1;
285 break; /* and then update hdr fields */
286 } else {
287 do_warn(
288 _(" would truncate attributes for inode %" PRIu64 " to %d\n"),
289 ino, i);
290 break;
291 }
292 }
293 }
294
295 /* namecheck checks for / and null terminated for file names.
296 * attributes names currently follow the same rules.
297 */
298 if (namecheck((char *)&currententry->nameval[0],
299 currententry->namelen)) {
300 do_warn(
301 _("entry contains illegal character in shortform attribute name\n"));
302 junkit = 1;
303 }
304
305 if (currententry->flags & XFS_ATTR_INCOMPLETE) {
306 do_warn(
307 _("entry has INCOMPLETE flag on in shortform attribute\n"));
308 junkit = 1;
309 }
310
311 /* Only check values for root security attributes */
312 if (currententry->flags & XFS_ATTR_ROOT)
313 junkit |= valuecheck(mp,
314 (char *)&currententry->nameval[0],
315 NULL, currententry->namelen,
316 currententry->valuelen);
317
318 remainingspace = remainingspace -
319 XFS_ATTR_SF_ENTSIZE(currententry);
320
321 if (junkit) {
322 if (!no_modify) {
323 /* get rid of only this entry */
324 do_warn(
325 _("removing attribute entry %d for inode %" PRIu64 "\n"),
326 i, ino);
327 tempentry = (xfs_attr_sf_entry_t *)
328 ((intptr_t) currententry +
329 XFS_ATTR_SF_ENTSIZE(currententry));
330 memmove(currententry,tempentry,remainingspace);
331 asf->hdr.count -= 1;
332 i--; /* no worries, it will wrap back to 0 */
333 *repair = 1;
334 continue; /* go back up now */
335 } else {
336 do_warn(
337 _("would remove attribute entry %d for inode %" PRIu64 "\n"),
338 i, ino);
339 }
340 }
341
342 /* Let's get ready for the next entry... */
343 nextentry = (xfs_attr_sf_entry_t *)((intptr_t) nextentry +
344 XFS_ATTR_SF_ENTSIZE(currententry));
345 currentsize = currentsize + XFS_ATTR_SF_ENTSIZE(currententry);
346
347 } /* end the loop */
348
349 if (asf->hdr.count != i) {
350 if (no_modify) {
351 do_warn(
352 _("would have corrected attribute entry count in inode %" PRIu64 " from %d to %d\n"),
353 ino, asf->hdr.count, i);
354 } else {
355 do_warn(
356 _("corrected attribute entry count in inode %" PRIu64 ", was %d, now %d\n"),
357 ino, asf->hdr.count, i);
358 asf->hdr.count = i;
359 *repair = 1;
360 }
361 }
362
363 /* ASSUMPTION: currentsize <= totsize */
364 if (be16_to_cpu(asf->hdr.totsize) != currentsize) {
365 if (no_modify) {
366 do_warn(
367 _("would have corrected attribute totsize in inode %" PRIu64 " from %d to %d\n"),
368 ino, be16_to_cpu(asf->hdr.totsize),
369 currentsize);
370 } else {
371 do_warn(
372 _("corrected attribute entry totsize in inode %" PRIu64 ", was %d, now %d\n"),
373 ino, be16_to_cpu(asf->hdr.totsize),
374 currentsize);
375 asf->hdr.totsize = cpu_to_be16(currentsize);
376 *repair = 1;
377 }
378 }
379
380 return(*repair);
381 }
382
383 /* This routine brings in blocks from disk one by one and assembles them
384 * in the value buffer. If get_bmapi gets smarter later to return an extent
385 * or list of extents, that would be great. For now, we don't expect too
386 * many blocks per remote value, so one by one is sufficient.
387 */
388 static int
389 rmtval_get(xfs_mount_t *mp, xfs_ino_t ino, blkmap_t *blkmap,
390 xfs_dablk_t blocknum, int valuelen, char* value)
391 {
392 xfs_fsblock_t bno;
393 xfs_buf_t *bp;
394 int clearit = 0, i = 0, length = 0, amountdone = 0;
395 int hdrsize = 0;
396
397 if (xfs_sb_version_hascrc(&mp->m_sb))
398 hdrsize = sizeof(struct xfs_attr3_rmt_hdr);
399
400 /* ASSUMPTION: valuelen is a valid number, so use it for looping */
401 /* Note that valuelen is not a multiple of blocksize */
402 while (amountdone < valuelen) {
403 bno = blkmap_get(blkmap, blocknum + i);
404 if (bno == NULLFSBLOCK) {
405 do_warn(
406 _("remote block for attributes of inode %" PRIu64 " is missing\n"), ino);
407 clearit = 1;
408 break;
409 }
410 bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, bno),
411 XFS_FSB_TO_BB(mp, 1), 0,
412 &xfs_attr3_rmt_buf_ops);
413 if (!bp) {
414 do_warn(
415 _("can't read remote block for attributes of inode %" PRIu64 "\n"), ino);
416 clearit = 1;
417 break;
418 }
419
420 if (bp->b_error == -EFSBADCRC || bp->b_error == -EFSCORRUPTED) {
421 do_warn(
422 _("Corrupt remote block for attributes of inode %" PRIu64 "\n"), ino);
423 libxfs_putbuf(bp);
424 clearit = 1;
425 break;
426 }
427
428 ASSERT(mp->m_sb.sb_blocksize == bp->b_bcount);
429
430 length = min(bp->b_bcount - hdrsize, valuelen - amountdone);
431 memmove(value, bp->b_addr + hdrsize, length);
432 amountdone += length;
433 value += length;
434 i++;
435 libxfs_putbuf(bp);
436 }
437 return (clearit);
438 }
439
440 /* The block is read in. The magic number and forward / backward
441 * links are checked by the caller process_leaf_attr.
442 * If any problems occur the routine returns with non-zero. In
443 * this case the next step is to clear the attribute fork, by
444 * changing it to shortform and zeroing it out. Forkoff need not
445 * be changed.
446 */
447
448 static int
449 process_leaf_attr_local(
450 struct xfs_mount *mp,
451 xfs_attr_leafblock_t *leaf,
452 int i,
453 xfs_attr_leaf_entry_t *entry,
454 xfs_dahash_t last_hashval,
455 xfs_dablk_t da_bno,
456 xfs_ino_t ino)
457 {
458 xfs_attr_leaf_name_local_t *local;
459
460 local = xfs_attr3_leaf_name_local(leaf, i);
461 if (local->namelen == 0 || namecheck((char *)&local->nameval[0],
462 local->namelen)) {
463 do_warn(
464 _("attribute entry %d in attr block %u, inode %" PRIu64 " has bad name (namelen = %d)\n"),
465 i, da_bno, ino, local->namelen);
466 return -1;
467 }
468
469 /* Check on the hash value. Checking order of values
470 * is not necessary, since one wrong clears the whole
471 * fork. If the ordering's wrong, it's caught here or
472 * the kernel code has a bug with transaction logging
473 * or attributes itself. Being paranoid, let's check
474 * ordering anyway in case both the name value and the
475 * hashvalue were wrong but matched. Unlikely, however.
476 */
477 if (be32_to_cpu(entry->hashval) != libxfs_da_hashname(
478 &local->nameval[0], local->namelen) ||
479 be32_to_cpu(entry->hashval) < last_hashval) {
480 do_warn(
481 _("bad hashvalue for attribute entry %d in attr block %u, inode %" PRIu64 "\n"),
482 i, da_bno, ino);
483 return -1;
484 }
485
486 /* Only check values for root security attributes */
487 if (entry->flags & XFS_ATTR_ROOT) {
488 if (valuecheck(mp, (char *)&local->nameval[0], NULL,
489 local->namelen, be16_to_cpu(local->valuelen))) {
490 do_warn(
491 _("bad security value for attribute entry %d in attr block %u, inode %" PRIu64 "\n"),
492 i, da_bno, ino);
493 return -1;
494 }
495 }
496 return xfs_attr_leaf_entsize_local(local->namelen,
497 be16_to_cpu(local->valuelen));
498 }
499
500 static int
501 process_leaf_attr_remote(
502 xfs_attr_leafblock_t *leaf,
503 int i,
504 xfs_attr_leaf_entry_t *entry,
505 xfs_dahash_t last_hashval,
506 xfs_dablk_t da_bno,
507 xfs_ino_t ino,
508 xfs_mount_t *mp,
509 blkmap_t *blkmap)
510 {
511 xfs_attr_leaf_name_remote_t *remotep;
512 char* value;
513
514 remotep = xfs_attr3_leaf_name_remote(leaf, i);
515
516 if (remotep->namelen == 0 || namecheck((char *)&remotep->name[0],
517 remotep->namelen) ||
518 be32_to_cpu(entry->hashval) !=
519 libxfs_da_hashname((unsigned char *)&remotep->name[0],
520 remotep->namelen) ||
521 be32_to_cpu(entry->hashval) < last_hashval ||
522 be32_to_cpu(remotep->valueblk) == 0) {
523 do_warn(
524 _("inconsistent remote attribute entry %d in attr block %u, ino %" PRIu64 "\n"), i, da_bno, ino);
525 return -1;
526 }
527
528 value = malloc(be32_to_cpu(remotep->valuelen));
529 if (value == NULL) {
530 do_warn(
531 _("cannot malloc enough for remotevalue attribute for inode %" PRIu64 "\n"),
532 ino);
533 do_warn(_("SKIPPING this remote attribute\n"));
534 goto out;
535 }
536 if (rmtval_get(mp, ino, blkmap, be32_to_cpu(remotep->valueblk),
537 be32_to_cpu(remotep->valuelen), value)) {
538 do_warn(
539 _("remote attribute get failed for entry %d, inode %" PRIu64 "\n"),
540 i, ino);
541 goto bad_free_out;
542 }
543 if ((entry->flags & XFS_ATTR_ROOT) &&
544 valuecheck(mp, (char *)&remotep->name[0], value, remotep->namelen,
545 be32_to_cpu(remotep->valuelen))) {
546 do_warn(
547 _("remote attribute value check failed for entry %d, inode %" PRIu64 "\n"),
548 i, ino);
549 goto bad_free_out;
550 }
551 free(value);
552 out:
553 return xfs_attr_leaf_entsize_remote(remotep->namelen);
554
555 bad_free_out:
556 free(value);
557 return -1;
558 }
559
560 static int
561 process_leaf_attr_block(
562 xfs_mount_t *mp,
563 xfs_attr_leafblock_t *leaf,
564 xfs_dablk_t da_bno,
565 xfs_ino_t ino,
566 blkmap_t *blkmap,
567 xfs_dahash_t last_hashval,
568 xfs_dahash_t *current_hashval,
569 int *repair)
570 {
571 xfs_attr_leaf_entry_t *entry;
572 int i, start, stop, clearit, usedbs, firstb, thissize;
573 da_freemap_t *attr_freemap;
574 struct xfs_attr3_icleaf_hdr leafhdr;
575
576 xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf);
577 clearit = usedbs = 0;
578 firstb = mp->m_sb.sb_blocksize;
579 stop = xfs_attr3_leaf_hdr_size(leaf);
580
581 /* does the count look sorta valid? */
582 if (!leafhdr.count ||
583 leafhdr.count * sizeof(xfs_attr_leaf_entry_t) + stop >
584 mp->m_sb.sb_blocksize) {
585 do_warn(
586 _("bad attribute count %d in attr block %u, inode %" PRIu64 "\n"),
587 leafhdr.count, da_bno, ino);
588 return 1;
589 }
590
591 attr_freemap = alloc_da_freemap(mp);
592 (void) set_da_freemap(mp, attr_freemap, 0, stop);
593
594 /* go thru each entry checking for problems */
595 for (i = 0, entry = xfs_attr3_leaf_entryp(leaf);
596 i < leafhdr.count; i++, entry++) {
597
598 /* check if index is within some boundary. */
599 if (be16_to_cpu(entry->nameidx) > mp->m_sb.sb_blocksize) {
600 do_warn(
601 _("bad attribute nameidx %d in attr block %u, inode %" PRIu64 "\n"),
602 be16_to_cpu(entry->nameidx), da_bno, ino);
603 clearit = 1;
604 break;
605 }
606
607 if (entry->flags & XFS_ATTR_INCOMPLETE) {
608 /* we are inconsistent state. get rid of us */
609 do_warn(
610 _("attribute entry #%d in attr block %u, inode %" PRIu64 " is INCOMPLETE\n"),
611 i, da_bno, ino);
612 clearit = 1;
613 break;
614 }
615
616 /* mark the entry used */
617 start = (intptr_t)entry - (intptr_t)leaf;
618 stop = start + sizeof(xfs_attr_leaf_entry_t);
619 if (set_da_freemap(mp, attr_freemap, start, stop)) {
620 do_warn(
621 _("attribute entry %d in attr block %u, inode %" PRIu64 " claims already used space\n"),
622 i, da_bno, ino);
623 clearit = 1;
624 break; /* got an overlap */
625 }
626
627 if (entry->flags & XFS_ATTR_LOCAL)
628 thissize = process_leaf_attr_local(mp, leaf, i, entry,
629 last_hashval, da_bno, ino);
630 else
631 thissize = process_leaf_attr_remote(leaf, i, entry,
632 last_hashval, da_bno, ino,
633 mp, blkmap);
634 if (thissize < 0) {
635 clearit = 1;
636 break;
637 }
638
639 *current_hashval = last_hashval = be32_to_cpu(entry->hashval);
640
641 if (set_da_freemap(mp, attr_freemap, be16_to_cpu(entry->nameidx),
642 be16_to_cpu(entry->nameidx) + thissize)) {
643 do_warn(
644 _("attribute entry %d in attr block %u, inode %" PRIu64 " claims used space\n"),
645 i, da_bno, ino);
646 clearit = 1;
647 break; /* got an overlap */
648 }
649 usedbs += thissize;
650 if (be16_to_cpu(entry->nameidx) < firstb)
651 firstb = be16_to_cpu(entry->nameidx);
652
653 } /* end the loop */
654
655 if (!clearit) {
656 /* verify the header information is correct */
657
658 /* if the holes flag is set, don't reset first_used unless it's
659 * pointing to used bytes. we're being conservative here
660 * since the block will get compacted anyhow by the kernel.
661 */
662
663 if ((leafhdr.holes == 0 &&
664 firstb != leafhdr.firstused) ||
665 leafhdr.firstused > firstb) {
666 if (!no_modify) {
667 do_warn(
668 _("- resetting first used heap value from %d to %d in "
669 "block %u of attribute fork of inode %" PRIu64 "\n"),
670 leafhdr.firstused,
671 firstb, da_bno, ino);
672 leafhdr.firstused = firstb;
673 *repair = 1;
674 } else {
675 do_warn(
676 _("- would reset first used value from %d to %d in "
677 "block %u of attribute fork of inode %" PRIu64 "\n"),
678 leafhdr.firstused,
679 firstb, da_bno, ino);
680 }
681 }
682
683 if (usedbs != leafhdr.usedbytes) {
684 if (!no_modify) {
685 do_warn(
686 _("- resetting usedbytes cnt from %d to %d in "
687 "block %u of attribute fork of inode %" PRIu64 "\n"),
688 leafhdr.usedbytes,
689 usedbs, da_bno, ino);
690 leafhdr.usedbytes = usedbs;
691 *repair = 1;
692 } else {
693 do_warn(
694 _("- would reset usedbytes cnt from %d to %d in "
695 "block %u of attribute fork of %" PRIu64 "\n"),
696 leafhdr.usedbytes,
697 usedbs, da_bno, ino);
698 }
699 }
700
701 /* there's a lot of work in process_leaf_dir_block to go thru
702 * checking for holes and compacting if appropiate. I don't think
703 * attributes need all that, so let's just leave the holes. If
704 * we discover later that this is a good place to do compaction
705 * we can add it then.
706 */
707 }
708 /*
709 * If we're just going to zap the block, don't pretend like we
710 * repaired it, because repairing the block stops the clear
711 * operation.
712 */
713 if (clearit)
714 *repair = 0;
715 if (*repair)
716 xfs_attr3_leaf_hdr_to_disk(mp->m_attr_geo, leaf, &leafhdr);
717
718 free(attr_freemap);
719 return (clearit); /* and repair */
720 }
721
722
723 /*
724 * returns 0 if the attribute fork is ok, 1 if it has to be junked.
725 */
726 static int
727 process_leaf_attr_level(xfs_mount_t *mp,
728 da_bt_cursor_t *da_cursor)
729 {
730 int repair;
731 xfs_attr_leafblock_t *leaf;
732 xfs_buf_t *bp;
733 xfs_ino_t ino;
734 xfs_fsblock_t dev_bno;
735 xfs_dablk_t da_bno;
736 xfs_dablk_t prev_bno;
737 xfs_dahash_t current_hashval = 0;
738 xfs_dahash_t greatest_hashval;
739 struct xfs_attr3_icleaf_hdr leafhdr;
740
741 da_bno = da_cursor->level[0].bno;
742 ino = da_cursor->ino;
743 /*
744 * 0 is the root block and no block
745 * pointer can point to the root block of the btree
746 */
747 if (da_bno == 0) {
748 do_warn(
749 _("btree cycle detected in attribute fork for inode %" PRIu64 "\n"),
750 ino);
751 goto error_out;
752 }
753
754 prev_bno = 0;
755
756 do {
757 repair = 0;
758 dev_bno = blkmap_get(da_cursor->blkmap, da_bno);
759 if (dev_bno == NULLFSBLOCK) {
760 do_warn(
761 _("can't map block %u for attribute fork for inode %" PRIu64 "\n"),
762 da_bno, ino);
763 goto error_out;
764 }
765
766 bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, dev_bno),
767 XFS_FSB_TO_BB(mp, 1), 0,
768 &xfs_attr3_leaf_buf_ops);
769 if (!bp) {
770 do_warn(
771 _("can't read file block %u (fsbno %" PRIu64 ") for attribute fork of inode %" PRIu64 "\n"),
772 da_bno, dev_bno, ino);
773 goto error_out;
774 }
775
776 leaf = bp->b_addr;
777 xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf);
778
779 /* check magic number for leaf directory btree block */
780 if (!(leafhdr.magic == XFS_ATTR_LEAF_MAGIC ||
781 leafhdr.magic == XFS_ATTR3_LEAF_MAGIC)) {
782 do_warn(
783 _("bad attribute leaf magic %#x for inode %" PRIu64 "\n"),
784 leafhdr.magic, ino);
785 libxfs_putbuf(bp);
786 goto error_out;
787 }
788
789 /*
790 * for each block, process the block, verify its path,
791 * then get next block. update cursor values along the way
792 */
793 if (process_leaf_attr_block(mp, leaf, da_bno, ino,
794 da_cursor->blkmap, current_hashval,
795 &greatest_hashval, &repair)) {
796 libxfs_putbuf(bp);
797 goto error_out;
798 }
799
800 /*
801 * index can be set to hdr.count so match the
802 * indexes of the interior blocks -- which at the
803 * end of the block will point to 1 after the final
804 * real entry in the block
805 */
806 da_cursor->level[0].hashval = greatest_hashval;
807 da_cursor->level[0].bp = bp;
808 da_cursor->level[0].bno = da_bno;
809 da_cursor->level[0].index = leafhdr.count;
810 da_cursor->level[0].dirty = repair;
811
812 if (leafhdr.back != prev_bno) {
813 do_warn(
814 _("bad sibling back pointer for block %u in attribute fork for inode %" PRIu64 "\n"),
815 da_bno, ino);
816 libxfs_putbuf(bp);
817 goto error_out;
818 }
819
820 prev_bno = da_bno;
821 da_bno = leafhdr.forw;
822
823 if (da_bno != 0) {
824 if (verify_da_path(mp, da_cursor, 0, XFS_ATTR_FORK)) {
825 libxfs_putbuf(bp);
826 goto error_out;
827 }
828 }
829
830 current_hashval = greatest_hashval;
831 /*
832 * If block looks ok but CRC didn't match, make sure to
833 * recompute it.
834 */
835 if (!no_modify && bp->b_error == -EFSBADCRC)
836 repair++;
837
838 if (repair && !no_modify)
839 libxfs_writebuf(bp, 0);
840 else
841 libxfs_putbuf(bp);
842 } while (da_bno != 0);
843
844 if (verify_final_da_path(mp, da_cursor, 0, XFS_ATTR_FORK)) {
845 /*
846 * verify the final path up (right-hand-side) if still ok
847 */
848 do_warn(
849 _("bad hash path in attribute fork for inode %" PRIu64 "\n"),
850 da_cursor->ino);
851 goto error_out;
852 }
853
854 /* releases all buffers holding interior btree blocks */
855 release_da_cursor(mp, da_cursor, 0);
856 return(0);
857
858 error_out:
859 /* release all buffers holding interior btree blocks */
860 err_release_da_cursor(mp, da_cursor, 0);
861 return(1);
862 }
863
864
865 /*
866 * a node directory is a true btree -- where the attribute fork
867 * has gotten big enough that it is represented as a non-trivial (e.g.
868 * has more than just a block) btree.
869 *
870 * Note that if we run into any problems, we will trash the attribute fork.
871 *
872 * returns 0 if things are ok, 1 if bad
873 * Note this code has been based off process_node_dir.
874 */
875 static int
876 process_node_attr(
877 xfs_mount_t *mp,
878 xfs_ino_t ino,
879 xfs_dinode_t *dip,
880 blkmap_t *blkmap)
881 {
882 xfs_dablk_t bno;
883 int error = 0;
884 da_bt_cursor_t da_cursor;
885
886 /*
887 * try again -- traverse down left-side of tree until we hit
888 * the left-most leaf block setting up the btree cursor along
889 * the way. Then walk the leaf blocks left-to-right, calling
890 * a parent-verification routine each time we traverse a block.
891 */
892 memset(&da_cursor, 0, sizeof(da_bt_cursor_t));
893 da_cursor.active = 0;
894 da_cursor.ino = ino;
895 da_cursor.dip = dip;
896 da_cursor.greatest_bno = 0;
897 da_cursor.blkmap = blkmap;
898
899 /*
900 * now process interior node. don't have any buffers held in this path.
901 */
902 error = traverse_int_dablock(mp, &da_cursor, &bno, XFS_ATTR_FORK);
903 if (error == 0)
904 return(1); /* 0 means unsuccessful */
905
906 /*
907 * now pass cursor and bno into leaf-block processing routine
908 * the leaf dir level routine checks the interior paths
909 * up to the root including the final right-most path.
910 */
911
912 return (process_leaf_attr_level(mp, &da_cursor));
913 }
914
915 /* check v5 metadata */
916 static int
917 __check_attr_header(
918 struct xfs_mount *mp,
919 struct xfs_buf *bp,
920 xfs_ino_t ino)
921 {
922 struct xfs_da3_blkinfo *info = bp->b_addr;
923
924 if (info->hdr.magic != cpu_to_be16(XFS_ATTR3_LEAF_MAGIC) &&
925 info->hdr.magic != cpu_to_be16(XFS_DA3_NODE_MAGIC))
926 return 0;
927
928 /* verify owner */
929 if (be64_to_cpu(info->owner) != ino) {
930 do_warn(
931 _("expected owner inode %" PRIu64 ", got %llu, attr block %" PRIu64 "\n"),
932 ino, (unsigned long long)be64_to_cpu(info->owner),
933 bp->b_bn);
934 return 1;
935 }
936 /* verify block number */
937 if (be64_to_cpu(info->blkno) != bp->b_bn) {
938 do_warn(
939 _("expected block %" PRIu64 ", got %llu, inode %" PRIu64 "attr block\n"),
940 bp->b_bn, (unsigned long long)be64_to_cpu(info->blkno),
941 ino);
942 return 1;
943 }
944 /* verify uuid */
945 if (platform_uuid_compare(&info->uuid, &mp->m_sb.sb_meta_uuid) != 0) {
946 do_warn(
947 _("wrong FS UUID, inode %" PRIu64 " attr block %" PRIu64 "\n"),
948 ino, bp->b_bn);
949 return 1;
950 }
951
952 return 0;
953 }
954
955 /*
956 * Start processing for a leaf or fuller btree.
957 * A leaf directory is one where the attribute fork is too big for
958 * the inode but is small enough to fit into one btree block
959 * outside the inode. This code is modelled after process_leaf_dir_block.
960 *
961 * returns 0 if things are ok, 1 if bad (attributes needs to be junked)
962 * repair is set, if anything was changed, but attributes can live thru it
963 */
964 static int
965 process_longform_attr(
966 xfs_mount_t *mp,
967 xfs_ino_t ino,
968 xfs_dinode_t *dip,
969 blkmap_t *blkmap,
970 int *repair) /* out - 1 if something was fixed */
971 {
972 xfs_attr_leafblock_t *leaf;
973 xfs_fsblock_t bno;
974 xfs_buf_t *bp;
975 xfs_dahash_t next_hashval;
976 int repairlinks = 0;
977 struct xfs_attr3_icleaf_hdr leafhdr;
978 int error;
979
980 *repair = 0;
981
982 bno = blkmap_get(blkmap, 0);
983
984 if ( bno == NULLFSBLOCK ) {
985 if (dip->di_aformat == XFS_DINODE_FMT_EXTENTS &&
986 be16_to_cpu(dip->di_anextents) == 0)
987 return(0); /* the kernel can handle this state */
988 do_warn(
989 _("block 0 of inode %" PRIu64 " attribute fork is missing\n"),
990 ino);
991 return(1);
992 }
993 /* FIX FOR bug 653709 -- EKN */
994 if (mp->m_sb.sb_agcount < XFS_FSB_TO_AGNO(mp, bno)) {
995 do_warn(
996 _("agno of attribute fork of inode %" PRIu64 " out of regular partition\n"), ino);
997 return(1);
998 }
999
1000 bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, bno),
1001 XFS_FSB_TO_BB(mp, 1), 0, &xfs_da3_node_buf_ops);
1002 if (!bp) {
1003 do_warn(
1004 _("can't read block 0 of inode %" PRIu64 " attribute fork\n"),
1005 ino);
1006 return(1);
1007 }
1008 if (bp->b_error == -EFSBADCRC)
1009 (*repair)++;
1010
1011 /* is this block sane? */
1012 if (__check_attr_header(mp, bp, ino)) {
1013 *repair = 0;
1014 libxfs_putbuf(bp);
1015 return 1;
1016 }
1017
1018 /* verify leaf block */
1019 leaf = bp->b_addr;
1020 xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf);
1021
1022 /* check sibling pointers in leaf block or root block 0 before
1023 * we have to release the btree block
1024 */
1025 if (leafhdr.forw != 0 || leafhdr.back != 0) {
1026 if (!no_modify) {
1027 do_warn(
1028 _("clearing forw/back pointers in block 0 for attributes in inode %" PRIu64 "\n"),
1029 ino);
1030 repairlinks = 1;
1031 leafhdr.forw = 0;
1032 leafhdr.back = 0;
1033 xfs_attr3_leaf_hdr_to_disk(mp->m_attr_geo,
1034 leaf, &leafhdr);
1035 } else {
1036 do_warn(
1037 _("would clear forw/back pointers in block 0 for attributes in inode %" PRIu64 "\n"), ino);
1038 }
1039 }
1040
1041 /*
1042 * use magic number to tell us what type of attribute this is.
1043 * it's possible to have a node or leaf attribute in either an
1044 * extent format or btree format attribute fork.
1045 */
1046 switch (leafhdr.magic) {
1047 case XFS_ATTR_LEAF_MAGIC: /* leaf-form attribute */
1048 case XFS_ATTR3_LEAF_MAGIC:
1049 if (process_leaf_attr_block(mp, leaf, 0, ino, blkmap,
1050 0, &next_hashval, repair)) {
1051 *repair = 0;
1052 /* the block is bad. lose the attribute fork. */
1053 libxfs_putbuf(bp);
1054 return(1);
1055 }
1056 *repair = *repair || repairlinks;
1057 break;
1058
1059 case XFS_DA_NODE_MAGIC: /* btree-form attribute */
1060 case XFS_DA3_NODE_MAGIC:
1061 /* must do this now, to release block 0 before the traversal */
1062 if ((*repair || repairlinks) && !no_modify) {
1063 *repair = 1;
1064 libxfs_writebuf(bp, 0);
1065 } else
1066 libxfs_putbuf(bp);
1067 error = process_node_attr(mp, ino, dip, blkmap); /* + repair */
1068 if (error)
1069 *repair = 0;
1070 return error;
1071 default:
1072 do_warn(
1073 _("bad attribute leaf magic # %#x for dir ino %" PRIu64 "\n"),
1074 be16_to_cpu(leaf->hdr.info.magic), ino);
1075 libxfs_putbuf(bp);
1076 *repair = 0;
1077 return(1);
1078 }
1079
1080 if (*repair && !no_modify)
1081 libxfs_writebuf(bp, 0);
1082 else
1083 libxfs_putbuf(bp);
1084
1085 return(0); /* repair may be set */
1086 }
1087
1088
1089 static int
1090 xfs_acl_from_disk(
1091 struct xfs_mount *mp,
1092 struct xfs_icacl **aclp,
1093 struct xfs_acl *dacl)
1094 {
1095 struct xfs_icacl *acl;
1096 struct xfs_icacl_entry *ace;
1097 struct xfs_acl_entry *dace;
1098 int count;
1099 int i;
1100
1101 count = be32_to_cpu(dacl->acl_cnt);
1102 if (count > XFS_ACL_MAX_ENTRIES(mp)) {
1103 do_warn(_("Too many ACL entries, count %d\n"), count);
1104 *aclp = NULL;
1105 return EINVAL;
1106 }
1107
1108
1109 acl = malloc(sizeof(struct xfs_icacl) +
1110 count * sizeof(struct xfs_icacl_entry));
1111 if (!acl) {
1112 do_warn(_("cannot malloc enough for ACL attribute\n"));
1113 do_warn(_("SKIPPING this ACL\n"));
1114 *aclp = NULL;
1115 return ENOMEM;
1116 }
1117
1118 acl->acl_cnt = count;
1119 for (i = 0; i < count; i++) {
1120 ace = &acl->acl_entry[i];
1121 dace = &dacl->acl_entry[i];
1122
1123 ace->ae_tag = be32_to_cpu(dace->ae_tag);
1124 ace->ae_id = be32_to_cpu(dace->ae_id);
1125 ace->ae_perm = be16_to_cpu(dace->ae_perm);
1126 }
1127
1128 *aclp = acl;
1129 return 0;
1130 }
1131
1132 /*
1133 * returns 1 if attributes got cleared
1134 * and 0 if things are ok.
1135 */
1136 int
1137 process_attributes(
1138 xfs_mount_t *mp,
1139 xfs_ino_t ino,
1140 xfs_dinode_t *dip,
1141 blkmap_t *blkmap,
1142 int *repair) /* returned if we did repair */
1143 {
1144 int err;
1145 __u8 aformat = dip->di_aformat;
1146 #ifdef DEBUG
1147 xfs_attr_shortform_t *asf;
1148
1149 asf = (xfs_attr_shortform_t *) XFS_DFORK_APTR(dip);
1150 #endif
1151
1152 if (aformat == XFS_DINODE_FMT_LOCAL) {
1153 ASSERT(be16_to_cpu(asf->hdr.totsize) <=
1154 XFS_DFORK_ASIZE(dip, mp));
1155 err = process_shortform_attr(mp, ino, dip, repair);
1156 } else if (aformat == XFS_DINODE_FMT_EXTENTS ||
1157 aformat == XFS_DINODE_FMT_BTREE) {
1158 err = process_longform_attr(mp, ino, dip, blkmap,
1159 repair);
1160 /* if err, convert this to shortform and clear it */
1161 /* if repair and no error, it's taken care of */
1162 } else {
1163 do_warn(_("illegal attribute format %d, ino %" PRIu64 "\n"),
1164 aformat, ino);
1165 err = 1;
1166 }
1167 return (err); /* and repair */
1168 }
1169
1170 /*
1171 * Validate an ACL
1172 */
1173 static int
1174 xfs_acl_valid(
1175 struct xfs_mount *mp,
1176 struct xfs_acl *daclp)
1177 {
1178 struct xfs_icacl *aclp = NULL;
1179 struct xfs_icacl_entry *entry, *e;
1180 int user = 0, group = 0, other = 0, mask = 0, mask_required = 0;
1181 int i, j;
1182
1183 if (daclp == NULL)
1184 goto acl_invalid;
1185
1186 switch (xfs_acl_from_disk(mp, &aclp, daclp)) {
1187 case ENOMEM:
1188 return 0;
1189 case EINVAL:
1190 goto acl_invalid;
1191 default:
1192 break;
1193 }
1194
1195 for (i = 0; i < aclp->acl_cnt; i++) {
1196 entry = &aclp->acl_entry[i];
1197 if (entry->ae_perm & ~(ACL_READ|ACL_WRITE|ACL_EXECUTE))
1198 goto acl_invalid;
1199 switch (entry->ae_tag) {
1200 case ACL_USER_OBJ:
1201 if (user++)
1202 goto acl_invalid;
1203 break;
1204 case ACL_GROUP_OBJ:
1205 if (group++)
1206 goto acl_invalid;
1207 break;
1208 case ACL_OTHER:
1209 if (other++)
1210 goto acl_invalid;
1211 break;
1212 case ACL_USER:
1213 case ACL_GROUP:
1214 for (j = i + 1; j < aclp->acl_cnt; j++) {
1215 e = &aclp->acl_entry[j];
1216 if (e->ae_id == entry->ae_id &&
1217 e->ae_tag == entry->ae_tag)
1218 goto acl_invalid;
1219 }
1220 mask_required++;
1221 break;
1222 case ACL_MASK:
1223 if (mask++)
1224 goto acl_invalid;
1225 break;
1226 default:
1227 goto acl_invalid;
1228 }
1229 }
1230 if (!user || !group || !other || (mask_required && !mask))
1231 goto acl_invalid;
1232 free(aclp);
1233 return 0;
1234 acl_invalid:
1235 free(aclp);
1236 errno = EINVAL;
1237 return (-1);
1238 }
1239
1240 /*
1241 * Check a category or division set to ensure that all values are in
1242 * ascending order and each division or category appears only once.
1243 */
1244 static int
1245 __check_setvalue(const unsigned short *list, unsigned short count)
1246 {
1247 unsigned short i;
1248
1249 for (i = 1; i < count ; i++)
1250 if (list[i] <= list[i-1])
1251 return -1;
1252 return 0;
1253 }
1254
1255 /*
1256 * xfs_mac_valid(lp)
1257 * Check the validity of a MAC label.
1258 */
1259 static int
1260 xfs_mac_valid(xfs_mac_label_t *lp)
1261 {
1262 if (lp == NULL)
1263 return (0);
1264
1265 /*
1266 * if the total category set and division set is greater than 250
1267 * report error
1268 */
1269 if ((lp->ml_catcount + lp->ml_divcount) > XFS_MAC_MAX_SETS)
1270 return(0);
1271
1272 /*
1273 * check whether the msentype value is valid, and do they have
1274 * appropriate level, category association.
1275 */
1276 switch (lp->ml_msen_type) {
1277 case XFS_MSEN_ADMIN_LABEL:
1278 case XFS_MSEN_EQUAL_LABEL:
1279 case XFS_MSEN_HIGH_LABEL:
1280 case XFS_MSEN_MLD_HIGH_LABEL:
1281 case XFS_MSEN_LOW_LABEL:
1282 case XFS_MSEN_MLD_LOW_LABEL:
1283 if (lp->ml_level != 0 || lp->ml_catcount > 0 )
1284 return (0);
1285 break;
1286 case XFS_MSEN_TCSEC_LABEL:
1287 case XFS_MSEN_MLD_LABEL:
1288 if (lp->ml_catcount > 0 &&
1289 __check_setvalue(lp->ml_list,
1290 lp->ml_catcount) == -1)
1291 return (0);
1292 break;
1293 case XFS_MSEN_UNKNOWN_LABEL:
1294 default:
1295 return (0);
1296 }
1297
1298 /*
1299 * check whether the minttype value is valid, and do they have
1300 * appropriate grade, division association.
1301 */
1302 switch (lp->ml_mint_type) {
1303 case XFS_MINT_BIBA_LABEL:
1304 if (lp->ml_divcount > 0 &&
1305 __check_setvalue(lp->ml_list + lp->ml_catcount,
1306 lp->ml_divcount) == -1)
1307 return(0);
1308 break;
1309 case XFS_MINT_EQUAL_LABEL:
1310 case XFS_MINT_HIGH_LABEL:
1311 case XFS_MINT_LOW_LABEL:
1312 if (lp->ml_grade != 0 || lp->ml_divcount > 0 )
1313 return(0);
1314 break;
1315 default:
1316 return(0);
1317 }
1318
1319 return (1);
1320 }