From 3c339a74d1b9dba23d60d6c769d99227d75cc6dc Mon Sep 17 00:00:00 2001 From: Timo Teräs Date: Sun, 11 Apr 2021 15:01:52 +0300 Subject: io: fix fd leak in error handling paths apk_dir_foreach_file and apk_resolve_[ug]id needs to free the fd in case fdopen/fdopendir fails. Additionally this does not rely on fdopen to fail if openat() returned -1, making sure that we don't call any syscalls with invalid file handle. --- src/io.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/io.c b/src/io.c index 08aee5c..6a4e568 100644 --- a/src/io.c +++ b/src/io.c @@ -808,8 +808,10 @@ int apk_dir_foreach_file(int dirfd, apk_dir_file_cb cb, void *ctx) return -1; dir = fdopendir(dirfd); - if (dir == NULL) + if (!dir) { + close(dirfd); return -1; + } /* We get called here with dup():ed fd. Since they all refer to * same object, we need to rewind so subsequent calls work. */ @@ -1095,6 +1097,19 @@ void apk_id_cache_reset(struct apk_id_cache *idc) idc->genid = 1; } +static FILE *fopenat(int dirfd, const char *pathname) +{ + FILE *f; + int fd; + + fd = openat(dirfd, pathname, O_RDONLY|O_CLOEXEC); + if (fd < 0) return NULL; + + f = fdopen(fd, "r"); + if (!f) close(fd); + return f; +} + uid_t apk_resolve_uid(struct apk_id_cache *idc, const char *username, uid_t default_uid) { #ifdef HAVE_FGETPWENT_R @@ -1113,8 +1128,8 @@ uid_t apk_resolve_uid(struct apk_id_cache *idc, const char *username, uid_t defa ci->genid = idc->genid; ci->uid = -1; - in = fdopen(openat(idc->root_fd, "etc/passwd", O_RDONLY|O_CLOEXEC), "r"); - if (in != NULL) { + in = fopenat(idc->root_fd, "etc/passwd"); + if (in) { do { #ifdef HAVE_FGETPWENT_R fgetpwent_r(in, &pwent, buf, sizeof(buf), &pwd); @@ -1156,8 +1171,8 @@ uid_t apk_resolve_gid(struct apk_id_cache *idc, const char *groupname, uid_t def ci->genid = idc->genid; ci->gid = -1; - in = fdopen(openat(idc->root_fd, "etc/group", O_RDONLY|O_CLOEXEC), "r"); - if (in != NULL) { + in = fopenat(idc->root_fd, "etc/group"); + if (in) { do { #ifdef HAVE_FGETGRENT_R fgetgrent_r(in, &grent, buf, sizeof(buf), &grp); -- cgit v1.2.3-70-g09d2