DF-3006 / leak.c
#include <sys/ioctl.h> #include <stdio.h> #include <string.h> #include <fcntl.h> #include <unistd.h> #include <stdlib.h> #define PATHMAX 1024 struct devfs_rule_ioctl { unsigned long rule_type; unsigned long rule_cmd; char mntpoint[PATHMAX]; char name[PATHMAX]; char linkname[PATHMAX]; unsigned long dev_type; unsigned short mode; unsigned int uid; unsigned int gid; }; #define DEVFS_RULE_NAME 0x01 #define DEVFS_RULE_LINK 0x01 #define DEVFS_RULE_ADD _IOWR('d', 221, struct devfs_rule_ioctl) #define DEVFS_RULE_APPLY _IOWR('d', 222, struct devfs_rule_ioctl) #define DEVFS_RULE_CLEAR _IOWR('d', 223, struct devfs_rule_ioctl) #define DEVFS_RULE_RESET _IOWR('d', 224, struct devfs_rule_ioctl) static void fill(struct devfs_rule_ioctl *r, const char *mnt, const char *name, const char *link) { memset(r, 0, sizeof(*r)); strlcpy(r->mntpoint, mnt, sizeof(r->mntpoint)); strlcpy(r->name, name, sizeof(r->name)); strlcpy(r->linkname, link, sizeof(r->linkname)); } int main(int argc, char **argv) { struct devfs_rule_ioctl r; int fd, i, iters, mode; const char *mnt = "/mnt/dt"; iters = (argc > 1) ? atoi(argv[1]) : 300; mode = (argc > 2) ? atoi(argv[2]) : 1; /* 1 = with RESET (bug), 0 = control */ fd = open("/dev/devfs", O_RDWR); if (fd < 0) { perror("open /dev/devfs"); return 1; } /* add a link rule: on mount /mnt/dt, node "vn0" gets a link "leaklink" */ fill(&r, mnt, "vn0", "leaklink"); r.rule_type = DEVFS_RULE_NAME; r.rule_cmd = DEVFS_RULE_LINK; if (ioctl(fd, DEVFS_RULE_ADD, &r)) { perror("ADD"); return 1; } for (i = 0; i < iters; i++) { /* * mount: node creation auto-applies the rule -> Nlink created, * target->nlinks = 1 */ if (system("mount -t devfs df3006 /mnt/dt 2>/dev/null") != 0) { perror("mount"); return 1; } if (mode) { /* * reset: devfs_rule_reset_node does --nlinks (1->0), * then devfs_gc->devfs_unlinkp does nlinks-- (0->SIZE_MAX) */ if (ioctl(fd, DEVFS_RULE_RESET, &r)) { perror("RESET"); return 1; } } /* * umount: reaper calls devfs_freep(vn0 node); nlinks != 0 * -> DEVFS_NLINKSWAIT -> node + name leaked forever */ if (system("umount /mnt/dt 2>/dev/null") != 0) { perror("umount"); return 1; } } /* clean the rule out of the kernel's rule list */ fill(&r, mnt, "vn0", "leaklink"); if (ioctl(fd, DEVFS_RULE_CLEAR, &r)) { perror("CLEAR"); return 1; } return 0; } |