From: Jaroslav Rohel Date: Tue, 30 Mar 2021 06:42:31 +0000 (+0200) Subject: Fix: zchunkopen: resources leaks, don't close supplied fd X-Git-Tag: 0.7.19~2^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=725778574dda14dfa646f9a3f97568b15cdcbb2e;p=thirdparty%2Flibsolv.git Fix: zchunkopen: resources leaks, don't close supplied fd System variant: - resource leaks when `zck_init_read` or `zck_init_write` fails - supplied fd will be closed if `zck_create` fails Libsolv limited zchunk implementation: - resource leak when `strcmp(mode, "r") != 0` - supplied fd will be closed if `solv_zchunk_open` fails (Fix is thread unsafe. However the original version caused a double-close in the caller function and was thread unsafe too.) --- diff --git a/ext/solv_xfopen.c b/ext/solv_xfopen.c index 4258fac1..7dca41f0 100644 --- a/ext/solv_xfopen.c +++ b/ext/solv_xfopen.c @@ -548,9 +548,9 @@ static void *zchunkopen(const char *path, const char *mode, int fd) { zckCtx *f; - if (!path && fd < 0) + if ((!path && fd < 0) || (path && fd >= 0)) return 0; - if (fd == -1) + if (path) { if (*mode != 'w') fd = open(path, O_RDONLY); @@ -562,18 +562,29 @@ static void *zchunkopen(const char *path, const char *mode, int fd) f = zck_create(); if (!f) { - close(fd); + if (path) + close(fd); return 0; } if (*mode != 'w') { if(!zck_init_read(f, fd)) - return 0; + { + zck_free(&f); + if (path) + close(fd); + return 0; + } } else { if(!zck_init_write(f, fd)) - return 0; + { + zck_free(&f); + if (path) + close(fd); + return 0; + } } return cookieopen(f, mode, cookie_zckread, cookie_zckwrite, cookie_zckclose); } @@ -587,19 +598,32 @@ static void *zchunkopen(const char *path, const char *mode, int fd) { FILE *fp; void *f; - if (!path && fd < 0) + int tmpfd; + if ((!path && fd < 0) || (path && fd >= 0)) return 0; - if (fd != -1) + if (strcmp(mode, "r") != 0) + return 0; + if (!path) fp = fdopen(fd, mode); else fp = fopen(path, mode); if (!fp) return 0; - if (strcmp(mode, "r") != 0) - return 0; f = solv_zchunk_open(fp, 1); if (!f) - fclose(fp); + { + /* When 0 is returned, fd passed by user must not be closed! */ + /* Dup (save) the original fd to a temporary variable and then back. */ + /* It is ugly and thread unsafe hack (non atomical sequence fclose dup2). */ + if (!path) + tmpfd = dup(fd); + fclose(fp); + if (!path) + { + dup2(tmpfd, fd); + close(tmpfd); + } + } return cookieopen(f, mode, (ssize_t (*)(void *, char *, size_t))solv_zchunk_read, 0, (int (*)(void *))solv_zchunk_close); }