summaryrefslogtreecommitdiff
path: root/src/io.c
diff options
context:
space:
mode:
authorTimo Teräs <timo.teras@iki.fi>2021-04-11 15:01:52 +0300
committerTimo Teräs <timo.teras@iki.fi>2021-04-11 15:01:52 +0300
commit3c339a74d1b9dba23d60d6c769d99227d75cc6dc (patch)
tree209a057ea7727597ce469f2a5aa6268b1b7e0ce9 /src/io.c
parent2752816f0b48a3053b501fb727dbf303a0d9a5f0 (diff)
downloadapk-tools-3c339a74d1b9dba23d60d6c769d99227d75cc6dc.tar.gz
apk-tools-3c339a74d1b9dba23d60d6c769d99227d75cc6dc.tar.bz2
apk-tools-3c339a74d1b9dba23d60d6c769d99227d75cc6dc.tar.xz
apk-tools-3c339a74d1b9dba23d60d6c769d99227d75cc6dc.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.
Diffstat (limited to 'src/io.c')
-rw-r--r--src/io.c25
1 files 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);