lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Message-Id: <20250918120304.1578406-1-zhouyuhang1010@163.com>
Date: Thu, 18 Sep 2025 20:03:04 +0800
From: zhouyuhang <zhouyuhang1010@....com>
To: raven@...maw.net,
	brauner@...nel.org
Cc: autofs@...r.kernel.org,
	linux-kernel@...r.kernel.org,
	Zhou Yuhang <zhouyuhang@...inos.cn>
Subject: [PATCH] autofs: avoid memleak when autofs_fill_super() fails

From: Zhou Yuhang <zhouyuhang@...inos.cn>

When autofs_fill_super() fails, kmemleak may detect memleak
with output similar to the following:

unreferenced object 0xffff8c3e83e1abe0 (size 616):
  comm "a.out", pid 1451, jiffies 4294715113
  hex dump (first 32 bytes):
    80 11 04 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
    ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  ................
  backtrace (crc f623388e):
    kmem_cache_alloc_lru_noprof+0x32c/0x440
    alloc_inode+0x84/0x110
    create_pipe_files+0x2b/0x290
    do_pipe2+0x56/0x110
    __x64_sys_pipe2+0x18/0x20
    do_syscall_64+0x7f/0x2c0
    entry_SYSCALL_64_after_hwframe+0x76/0x7e
unreferenced object 0xffff8c3e8cf5e000 (size 72):
  comm "a.out", pid 1451, jiffies 4294715113
  hex dump (first 32 bytes):
    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
    00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  backtrace (crc 494f173f):
    kmem_cache_alloc_noprof+0x31f/0x410
    security_inode_alloc+0x45/0x140
    inode_init_always_gfp+0x20a/0x240
    alloc_inode+0x42/0x110
    create_pipe_files+0x2b/0x290
    do_pipe2+0x56/0x110
    __x64_sys_pipe2+0x18/0x20
    do_syscall_64+0x7f/0x2c0
    entry_SYSCALL_64_after_hwframe+0x76/0x7e

The memleak occurs because when autofs_fill_super() fails,
the AUTOFS_SBI_CATATONIC flag is not cleared, which prevents
autofs_kill_sb()->autofs_catatonic_mode() from cleaning up
the pipe resources. Additionally, fc->s_fs_info has already been
set to NULL in sget_fc(), so autofs_free_fc() cannot clean up the
pipe resources either. Therefore, add explicit cleanup of pipe
resources in the error paths of autofs_fill_super() to prevent memleak.

Signed-off-by: Zhou Yuhang <zhouyuhang@...inos.cn>
---
The following test code can reproduce the issue:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>

int main() {
    int pipefd[2];
    if (pipe(pipefd) == -1) {
        perror("pipe creation failed");
        return 1;
    }
    printf("Created anonymous pipe: read fd=%d, write fd=%d\n", pipefd[0], pipefd[1]);

    int dup_write_fd = dup(pipefd[1]);
    if (dup_write_fd == -1) {
        perror("dup write fd failed");
        close(pipefd[0]);
        close(pipefd[1]);
        return 1;
    }
    printf("Duplicated write fd: %d\n", dup_write_fd);

    const char *mount_point = "/mnt/autofs_test";
    if (mkdir(mount_point, 0755) == -1 && errno != EEXIST) {
        perror("mkdir mount point failed");
        close(pipefd[0]);
        close(pipefd[1]);
        close(dup_write_fd);
        return 1;
    }

    char opts[128];
    snprintf(opts, sizeof(opts), "fd=%d,pgrp=99999", dup_write_fd);
    printf("Mount options: %s\n", opts);

    int ret = mount("none", mount_point, "autofs", 0, opts);
    if (ret == -1) {
        perror("mount system call failed");
    } else {
        printf("Mount succeeded (unexpected)\n");
        umount(mount_point);
    }

    close(dup_write_fd);
    close(pipefd[1]);
    close(pipefd[0]);
    printf("Closed all fds\n");

    return ret;
}
---
 fs/autofs/inode.c | 24 ++++++++++++++++++------
 1 file changed, 18 insertions(+), 6 deletions(-)

diff --git a/fs/autofs/inode.c b/fs/autofs/inode.c
index f5c16ffba013..7a2ae9d33096 100644
--- a/fs/autofs/inode.c
+++ b/fs/autofs/inode.c
@@ -303,6 +303,7 @@ static int autofs_fill_super(struct super_block *s, struct fs_context *fc)
 	struct autofs_sb_info *sbi = s->s_fs_info;
 	struct inode *root_inode;
 	struct autofs_info *ino;
+	int ret = -ENOMEM;
 
 	pr_debug("starting up, sbi = %p\n", sbi);
 
@@ -319,11 +320,11 @@ static int autofs_fill_super(struct super_block *s, struct fs_context *fc)
 	 */
 	ino = autofs_new_ino(sbi);
 	if (!ino)
-		return -ENOMEM;
+		goto out;
 
 	root_inode = autofs_get_inode(s, S_IFDIR | 0755);
 	if (!root_inode)
-		return -ENOMEM;
+		goto out_free_ino;
 
 	root_inode->i_uid = ctx->uid;
 	root_inode->i_gid = ctx->gid;
@@ -332,16 +333,17 @@ static int autofs_fill_super(struct super_block *s, struct fs_context *fc)
 
 	s->s_root = d_make_root(root_inode);
 	if (unlikely(!s->s_root)) {
-		autofs_free_ino(ino);
-		return -ENOMEM;
+		goto out_free_ino;
 	}
 	s->s_root->d_fsdata = ino;
 
 	if (ctx->pgrp_set) {
 		sbi->oz_pgrp = find_get_pid(ctx->pgrp);
-		if (!sbi->oz_pgrp)
-			return invalf(fc, "Could not find process group %d",
+		if (!sbi->oz_pgrp) {
+			ret = invalf(fc, "Could not find process group %d",
 				      ctx->pgrp);
+			goto out;
+		}
 	} else
 		sbi->oz_pgrp = get_task_pid(current, PIDTYPE_PGID);
 
@@ -357,6 +359,16 @@ static int autofs_fill_super(struct super_block *s, struct fs_context *fc)
 
 	sbi->flags &= ~AUTOFS_SBI_CATATONIC;
 	return 0;
+
+out_free_ino:
+	autofs_free_ino(ino);
+out:
+	if (sbi->pipe) {
+		fput(sbi->pipe);
+		sbi->pipe = NULL;
+		sbi->pipefd = -1;
+	}
+	return ret;
 }
 
 /*
-- 
2.27.0


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ