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:06:49 +0300
commit4bcd792194c23fd73912a567101af5fda6e860da (patch)
treee45bef29dbfe031a6abb5360c72b183177858856 /src/io.c
parent1b954e4120c1565134e9d81296e4fec3ce8e7a7c (diff)
downloadapk-tools-4bcd792194c23fd73912a567101af5fda6e860da.tar.gz
apk-tools-4bcd792194c23fd73912a567101af5fda6e860da.tar.bz2
apk-tools-4bcd792194c23fd73912a567101af5fda6e860da.tar.xz
apk-tools-4bcd792194c23fd73912a567101af5fda6e860da.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 682c6b6..10ab836 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. */
@@ -1099,6 +1101,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
@@ -1116,8 +1131,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);
@@ -1158,8 +1173,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);