I've been dealing for some weeks now with having my system unexpectedly lock up and be unreachable via Ctrl-Alt-Esc, and tracked it down as far as "the daily script" or "trying to relabel the entire filesystem" until recently. Imagine my relief when rwatson suggests to try using the serial console instead. I sez, "You're nuts! Why would the serial console make any difference from the syscons for trying to break to the debugger? This is definitely a hard lock-up," I sez to Robert. Lo and behold, I try it, and in fact I _can_ break to the debugger over the serial console! I find out that I'm in ffs_findextattr() and in an infinite loop. Upon further investigation, I discover that (long story short) I have three files on my system which have completely invalid extents: one has 48 bytes of gibberish (not just a few bytes being corrupt) and two have 48 bytes of 0s. I'm not going to wonder too hard about how they got there since I had bad RAM in the laptop for a while, but I did go ahead and fix FFS to be more resilient. Here are my changes to just return EIO instead of looping infinitely. Does it seem to be correct? I've also got a change to fsck in the trustedbsd_mac which detects and dumps corrupt extents, but I don't have it clearing and fixing them yet. I think both are probably important to have :)
==== //depot/projects/trustedbsd/mac/sys/ufs/ffs/ffs_vnops.c#15 (text+ko) - //depot/projects/trustedbsd/mac/sys/ufs/ffs/ffs_vnops.c#17 (text+ko) ==== content @@ -1324,11 +1324,12 @@ * the length of the EA, and possibly the pointer to the entry and to the data. */ static int -ffs_findextattr(u_char *ptr, uint length, int nspace, const char *name, u_char **eap, u_char **eac) +ffs_findextattr(u_char *ptr, uint length, int nspace, const char *name, + int *ealenp, u_char **eap, u_char **eac) { u_char *p, *pe, *pn, *p0; - int eapad1, eapad2, ealength, ealen, nlen; - uint32_t ul; + int eapad1, ealength, ealen, nlen; + uint32_t ul, eapad2; pe = ptr + length; nlen = strlen(name); @@ -1339,16 +1340,23 @@ pn = p + ul; /* make sure this entry is complete */ if (pn > pe) - break; + return (EIO); + /* don't loop forever on a corrupt entry */ + if (pn <= p) + return (EIO); p += sizeof(uint32_t); if (*p != nspace) continue; p++; eapad2 = *p++; + /* padding is at most 7 bytes */ + if (eapad2 >= 8) + return (EIO); if (*p != nlen) continue; p++; - if (bcmp(p, name, nlen)) + /* compare only up to the end of this attribute */ + if (p + nlen > pn || bcmp(p, name, nlen)) continue; ealength = sizeof(uint32_t) + 3 + nlen; eapad1 = 8 - (ealength % 8); @@ -1361,9 +1369,10 @@ *eap = p0; if (eac != NULL) *eac = p; - return (ealen); + *ealenp = ealen; + return (0); } - return(-1); + return (ENOATTR); } static int @@ -1597,16 +1606,13 @@ eae = ip->i_ea_area; easize = ip->i_ea_len; if (strlen(ap->a_name) > 0) { - ealen = ffs_findextattr(eae, easize, - ap->a_attrnamespace, ap->a_name, NULL, &p); - if (ealen >= 0) { - error = 0; + error = ffs_findextattr(eae, easize, + ap->a_attrnamespace, ap->a_name, &ealen, NULL, &p); + if (error == 0) { if (ap->a_size != NULL) *ap->a_size = ealen; else if (ap->a_uio != NULL) error = uiomove(p, ealen, ap->a_uio); - } else { - error = ENOATTR; } } else { error = 0; @@ -1711,16 +1717,16 @@ bcopy(ip->i_ea_area, eae, ip->i_ea_len); easize = ip->i_ea_len; - olen = ffs_findextattr(eae, easize, - ap->a_attrnamespace, ap->a_name, &p, NULL); - if (olen == -1 && ealength == 0) { - /* delete but nonexistent */ + error = ffs_findextattr(eae, easize, + ap->a_attrnamespace, ap->a_name, &olen, &p, NULL); + if ((error == ENOATTR && ealength == 0) || /* delete but nonexistent */ + (error != 0 && error != ENOATTR)) { /* corrupted? */ free(eae, M_TEMP); if (stand_alone) ffs_close_ea(ap->a_vp, 0, ap->a_cred, ap->a_td); - return(ENOATTR); + return (error); } - if (olen == -1) { + if (error == ENOATTR) { /* new, append at end */ p = eae + easize; easize += ealength; -- Brian Fundakowski Feldman \'[ FreeBSD ]''''''''''\ <> [EMAIL PROTECTED] <> [EMAIL PROTECTED] \ The Power to Serve! \ Opinions expressed are my own. \,,,,,,,,,,,,,,,,,,,,,,\ To Unsubscribe: send mail to [EMAIL PROTECTED] with "unsubscribe freebsd-current" in the body of the message