From owner-freebsd-current Fri Nov 8 11: 8:58 2002 Delivered-To: freebsd-current@freebsd.org Received: from green.bikeshed.org (freefall.freebsd.org [216.136.204.21]) by hub.freebsd.org (Postfix) with ESMTP id F364E37B401; Fri, 8 Nov 2002 11:08:54 -0800 (PST) Received: from green.bikeshed.org (g7gt404ga38o9j03@green.bikeshed.org [10.0.0.1] (may be forged)) by green.bikeshed.org (8.12.6/8.12.6) with ESMTP id gA8J8s56058920; Fri, 8 Nov 2002 14:08:54 -0500 (EST) (envelope-from green@green.bikeshed.org) Received: from localhost (green@localhost) by green.bikeshed.org (8.12.6/8.12.6/Submit) with ESMTP id gA8J8s06058917; Fri, 8 Nov 2002 14:08:54 -0500 (EST) Message-Id: <200211081908.gA8J8s06058917@green.bikeshed.org> X-Mailer: exmh version 2.5 07/13/2001 with nmh-1.0.4 To: current@FreeBSD.org Cc: phk@FreeBSD.org, mckusick@FreeBSD.org Subject: UFS2 extended attribute corruption woes From: Brian Fundakowski Feldman Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Date: Fri, 08 Nov 2002 14:08:53 -0500 Sender: owner-freebsd-current@FreeBSD.ORG Precedence: bulk List-ID: List-Archive: (Web Archive) List-Help: (List Instructions) List-Subscribe: List-Unsubscribe: X-Loop: FreeBSD.ORG 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 ]''''''''''\ <> green@FreeBSD.org <> bfeldman@tislabs.com \ The Power to Serve! \ Opinions expressed are my own. \,,,,,,,,,,,,,,,,,,,,,,\ To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-current" in the body of the message