diff options
author | Timo Teräs <timo.teras@iki.fi> | 2021-04-11 15:01:52 +0300 |
---|---|---|
committer | Timo Teräs <timo.teras@iki.fi> | 2021-04-11 15:08:17 +0300 |
commit | 6552a1d3f8126d858d64c75fa3c1eb049d8bf235 (patch) | |
tree | 95ab25d8881aaafff88b11c2511c57f7e0a16fa2 | |
parent | 1096e3ce154e0a702ca7fdec783452b96b79d78c (diff) | |
download | apk-tools-6552a1d3f8126d858d64c75fa3c1eb049d8bf235.tar.gz apk-tools-6552a1d3f8126d858d64c75fa3c1eb049d8bf235.tar.bz2 apk-tools-6552a1d3f8126d858d64c75fa3c1eb049d8bf235.tar.xz apk-tools-6552a1d3f8126d858d64c75fa3c1eb049d8bf235.zip |
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.
(cherry picked from commit 3c339a74d1b9dba23d60d6c769d99227d75cc6dc)
-rw-r--r-- | src/io.c | 25 |
1 files changed, 20 insertions, 5 deletions
@@ -725,8 +725,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. */ @@ -1012,6 +1014,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 @@ -1030,8 +1045,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); @@ -1073,8 +1088,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); |