DF-3130 / remount_leak.c
/* * DF-3130: drive msdosfs_mount(MNT_UPDATE) with args.fspec != NULL and the * KICONV flag set, in a loop. update_mp() (msdosfs_vfsops.c:115-133) * re-opens all four iconv handles (pm_w2u/pm_u2w/pm_u2d/pm_d2u) on every * call and overwrites the pm_* pointers without closing the previous ones * -> 4 leaked converter handles per remount until unmount. * * Mirrors mount_msdos(8): same header (<vfs/msdosfs/msdosfsmount.h>), same * kiconv_add_xlat16_cspairs() pre-registration of the conversion pairs. * * usage: remount_leak <device> <mountpoint> <iterations> [cs_local cs_dos] */ #include <stdio.h> #include <err.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <unistd.h> #include <sys/param.h> #include <sys/mount.h> #include <sys/iconv.h> #include <sys/linker.h> #include <sys/module.h> #include <vfs/msdosfs/msdosfsmount.h> int main(int argc, char **argv) { struct msdosfs_args args; const char *cs_local = "zh_CN.GB18030"; const char *cs_dos = "GB18030"; int i, n, ok = 0, fail = 0; if (argc < 4) { fprintf(stderr, "usage: remount_leak <device> <mountpoint> <iterations> [cs_local cs_dos]\n"); return 2; } if (argc >= 6) { cs_local = argv[4]; cs_dos = argv[5]; } n = atoi(argv[3]); /* * No userland kiconv registration needed: pm_flags retains * MSDOSFSMNT_KICONV from the initial mount_msdos -L call (sticky, * msdosfs_vfsops.c:113), and the conversion tables registered by the * CLI are still in the kernel, so update_mp() re-opens the four * handles on every MNT_UPDATE even without KICONV in *these* args. */ for (i = 0; i < n; i++) { memset(&args, 0, sizeof(args)); args.fspec = argv[1]; args.uid = 0; args.gid = 0; args.mask = 0755; args.dirmask = 0755; args.flags = MSDOSFSMNT_LONGNAME; snprintf(args.cs_local, sizeof(args.cs_local), "%s", cs_local); snprintf(args.cs_dos, sizeof(args.cs_dos), "%s", cs_dos); if (mount("msdos", argv[2], MNT_UPDATE, &args) == 0) ok++; else { fail++; if (fail <= 3) fprintf(stderr, "mount UPDATE failed: %s\n", strerror(errno)); } } printf("remounts: ok=%d failed=%d\n", ok, fail); return 0; } |