shithub: gefs

Download patch

ref: 1d8fed57471bb32dd0ed4a6558fcb1e725203380
parent: ca1920836657ca041cd032e87cf80522187ea629
author: Michael Forney <mforney@mforney.org>
date: Thu Mar 24 01:08:07 EDT 2022

fs: fix some memory and lock leaks

getdent:
Unlock dtablk if malloc or packdkey fail.
Free Dent if packdkey fails.

clunkmount:
Free mount name.

clunkdent:
Handle nil and QTAUTH Dents (now necessary for certain cleanup paths).

dupfid:
Don't increase Mount/Dent ref count until we know dupfid will
succeed. Currently the only failure case involves an abort, but
when this is eventually removed, we'd leak references.

fsauth:
Initialize Dent ref count to 0 so that it's 1 after the dupfid.
Free Dent if dupfid fails.

fsattach:
Clunk Mount and Dent (if they were acquired) on all exit paths, and
remove Dent ref manipulation trick.
Close snap before checking newsnap result to prevent leaking snap
reference.

--- a/fs.c
+++ b/fs.c
@@ -343,20 +343,22 @@
 	for(de = fs->dtab[h]; de != nil; de = de->next){
 		if(de->qid.path == d->qid.path){
 			ainc(&de->ref);
-			unlock(&fs->dtablk);
-			return de;
+			goto Out;
 		}
 	}
 
 	if((de = mallocz(sizeof(Dent), 1)) == nil)
-		return nil;
+		goto Out;
 	de->Xdir = *d;
 	de->ref = 1;
 	de->qid = d->qid;
 	de->length = d->length;
 
-	if((e = packdkey(de->buf, sizeof(de->buf), pqid, d->name)) == nil)
-		return nil;
+	if((e = packdkey(de->buf, sizeof(de->buf), pqid, d->name)) == nil){
+		free(de);
+		de = nil;
+		goto Out;
+	}
 	de->k = de->buf;
 	de->nk = e - de->buf;
 	de->name = de->buf + 11;
@@ -363,6 +365,7 @@
 	de->next = fs->dtab[h];
 	fs->dtab[h] = de;
 
+Out:
 	unlock(&fs->dtablk);
 	return de;
 }
@@ -370,8 +373,10 @@
 static void
 clunkmount(Mount *mnt)
 {
-	if(mnt != nil && adec(&mnt->ref) == 0)
+	if(mnt != nil && adec(&mnt->ref) == 0){
+		free(mnt->name);
 		free(mnt);
+	}
 }
 
 static void
@@ -380,6 +385,12 @@
 	Dent *e, **pe;
 	u32int h;
 
+	if(de == nil)
+		return;
+	if(de->qid.type == QTAUTH && adec(&de->ref) == 0){
+		free(de);
+		return;
+	}
 	lock(&fs->dtablk);
 	if(adec(&de->ref) != 0)
 		goto Out;
@@ -460,11 +471,8 @@
 	n->ref = 2; /* one for dup, one for clunk */
 	n->mode = -1;
 	n->next = nil;
-	if(n->mnt != nil)
-		ainc(&n->mnt->ref);
 
 	lock(&c->fidtablk);
-	ainc(&n->dent->ref);
 	for(o = c->fidtab[h]; o != nil; o = o->next)
 		if(o->fid == new)
 			break;
@@ -480,6 +488,9 @@
 		free(n);
 		return nil;
 	}
+	if(n->mnt != nil)
+		ainc(&n->mnt->ref);
+	ainc(&n->dent->ref);
 	return n;
 }
 
@@ -615,7 +626,7 @@
 		return;
 	}
 	memset(de, 0, sizeof(Dent));
-	de->ref = 1;
+	de->ref = 0;
 	de->qid.type = QTAUTH;
 	de->qid.path = inc64(&fs->nextqid, 1);
 	de->qid.vers = 0;
@@ -638,6 +649,7 @@
 	f.auth = authnew();
 	if(dupfid(m->conn, m->afid, &f) == nil){
 		rerror(m, Enomem);
+		free(de);
 		return;
 	}
 	r.type = Rauth;
@@ -740,22 +752,25 @@
 	Tree *t;
 	int uid;
 
+	de = nil;
 	if((mnt = mallocz(sizeof(Mount), 1)) == nil){
 		rerror(m, Enomem);
-		return;
+		goto Out;
 	}
+	mnt->ref = 1;
 	if(m->aname[0] == '\0')
 		m->aname = "main";
 	if((mnt->name = strdup(m->aname)) == nil){
 		rerror(m, Enomem);
-		return;
+		goto Out;
 	}
+
 	rlock(&fs->userlk);
 	n = (forceuser == nil) ? m->uname : forceuser;
 	if((u = name2user(n)) == nil){
-		rerror(m, Enouser);
 		runlock(&fs->userlk);
-		return;
+		rerror(m, Enouser);
+		goto Out;
 	}
 	uid = u->id;
 	runlock(&fs->userlk);
@@ -762,41 +777,34 @@
 
 	if((t = openlabel(m->aname)) == nil){
 		rerror(m, Enosnap);
-		return;
+		goto Out;
 	}
-	if((mnt->root = newsnap(t)) == nil){
+	mnt->root = newsnap(t);
+	closesnap(t);
+	if(mnt->root == nil){
 		rerror(m, Enomem);
-		return;
+		goto Out;
 	}
-	closesnap(t);
 
 	if((p = packdkey(dbuf, sizeof(dbuf), -1ULL, "")) == nil){
 		rerror(m, Elength);
-		return;
+		goto Out;
 	}
 	dk.k = dbuf;
 	dk.nk = p - dbuf;
 	if((e = btlookup(mnt->root, &dk, &kv, kvbuf, sizeof(kvbuf))) != nil){
 		rerror(m, e);
-		return;
+		goto Out;
 	}
 	if(kv2dir(&kv, &d) == -1){
 		rerror(m, Efs);
-		return;
+		goto Out;
 	}
 	if((de = getdent(-1, &d)) == nil){
 		rerror(m, Efs);
-		return;
+		goto Out;
 	}
 
-	/*
-	 * A bit of a hack; we're duping a fid
-	 * that doesn't exist, so we'd be off
-	 * by one on the refcount. Adjust to
-	 * compensate for the dup.
-	 */
-	adec(&de->ref);
-
 	memset(&f, 0, sizeof(Fid));
 	f.fid = NOFID;
 	f.mnt = mnt;
@@ -811,7 +819,7 @@
 	f.dmode = d.mode;
 	if(dupfid(m->conn, m->fid, &f) == nil){
 		rerror(m, Enomem);
-		return;
+		goto Out;
 	}
 
 	mnt->next = fs->mounts;
@@ -819,6 +827,10 @@
 	r.type = Rattach;
 	r.qid = d.qid;
 	respond(m, &r);
+
+Out:
+	clunkdent(de);
+	clunkmount(mnt);
 }
 
 static char*