From: Nikolaus Rath Date: Tue, 27 Nov 2018 20:58:36 +0000 (+0000) Subject: Fix fd/inode leak X-Git-Tag: fuse-3.4.1~1 X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=d4a7ba44b022e3b63fc215374d87ed9e930d9974;p=qemu-gpiodev%2Flibfuse.git Fix fd/inode leak If do_readdir() calls do_lookup(), but the latter fails, we still have to return any entries that we already stored in the readdir buffer to avoid leaking inodes. do_lookup() may fail if e.g. we reach the file descriptor limit. --- diff --git a/example/passthrough_ll.c b/example/passthrough_ll.c index eadad3a..5364b97 100644 --- a/example/passthrough_ll.c +++ b/example/passthrough_ll.c @@ -666,22 +666,23 @@ static void lo_do_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, struct lo_dirp *d = lo_dirp(fi); char *buf; char *p; - size_t rem; + size_t rem = size; int err; (void) ino; buf = calloc(1, size); - if (!buf) - return (void) fuse_reply_err(req, ENOMEM); + if (!buf) { + err = ENOMEM; + goto error; + } + p = buf; if (offset != d->offset) { seekdir(d->dp, offset); d->entry = NULL; d->offset = offset; } - p = buf; - rem = size; while (1) { size_t entsize; off_t nextoff; @@ -691,11 +692,12 @@ static void lo_do_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, errno = 0; d->entry = readdir(d->dp); if (!d->entry) { - if (errno && rem == size) { + if (errno) { // Error err = errno; goto error; + } else { // End of stream + break; } - break; } } nextoff = d->entry->d_off; @@ -738,13 +740,17 @@ static void lo_do_readdir(fuse_req_t req, fuse_ino_t ino, size_t size, d->offset = nextoff; } - fuse_reply_buf(req, buf, size - rem); - free(buf); - return; - + err = 0; error: - free(buf); - fuse_reply_err(req, err); + // If there's an error, we can only signal it if we haven't stored + // any entries yet - otherwise we'd end up with wrong lookup + // counts for the entries that are already in the buffer. So we + // return what we've collected until that point. + if (err && rem == size) + fuse_reply_err(req, err); + else + fuse_reply_buf(req, buf, size - rem); + free(buf); } static void lo_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,