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