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