Fix memory leak due to not freeing each dirent pointer in the namelist
array.

Signed-off-by: Tyler Hicks <[email protected]>
---
 libraries/libapparmor/src/private.c | 31 +++++++++++++++++++------------
 1 file changed, 19 insertions(+), 12 deletions(-)

diff --git a/libraries/libapparmor/src/private.c 
b/libraries/libapparmor/src/private.c
index f164ccb..4769f34 100644
--- a/libraries/libapparmor/src/private.c
+++ b/libraries/libapparmor/src/private.c
@@ -207,7 +207,7 @@ int _aa_dirat_for_each(int dirfd, const char *name, void 
*data,
 {
        autofree struct dirent **namelist = NULL;
        autoclose int cb_dirfd = -1;
-       int i, ret;
+       int i, num_dirs, rc;
 
        if (!cb || !name) {
                errno = EINVAL;
@@ -220,27 +220,34 @@ int _aa_dirat_for_each(int dirfd, const char *name, void 
*data,
                return -1;
        }
 
-       ret = scandirat(cb_dirfd, ".", &namelist, dot_or_dot_dot_filter, NULL);
-       if (ret == -1) {
+       num_dirs = scandirat(cb_dirfd, ".", &namelist,
+                            dot_or_dot_dot_filter, NULL);
+       if (num_dirs == -1) {
                PDEBUG("scandirat of directory '%s' failed: %m\n", name);
                return -1;
        }
 
-       for (i = 0; i < ret; i++) {
+       for (rc = 0, i = 0; i < num_dirs; i++) {
+               /* Must cycle through all dirs so that each one is autofreed */
+               autofree struct dirent *dir = namelist[i];
                struct stat my_stat;
 
-               if (fstatat(cb_dirfd, namelist[i]->d_name, &my_stat, 0)) {
-                       PDEBUG("stat failed for '%s': %m\n",
-                              namelist[i]->d_name);
-                       return -1;
+               if (rc)
+                       continue;
+
+               if (fstatat(cb_dirfd, dir->d_name, &my_stat, 0)) {
+                       PDEBUG("stat failed for '%s': %m\n", dir->d_name);
+                       rc = -1;
+                       continue;
                }
 
-               if (cb(cb_dirfd, namelist[i]->d_name, &my_stat, data)) {
+               if (cb(cb_dirfd, dir->d_name, &my_stat, data)) {
                        PDEBUG("dir_for_each callback failed for '%s'\n",
-                              namelist[i]->d_name);
-                       return -1;
+                              dir->d_name);
+                       rc = -1;
+                       continue;
                }
        }
 
-       return 0;
+       return rc;
 }
-- 
2.1.4


-- 
AppArmor mailing list
[email protected]
Modify settings or unsubscribe at: 
https://lists.ubuntu.com/mailman/listinfo/apparmor

Reply via email to