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