Test to trace kernel bug in fsconfig(2) with btrfs

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



I've attached a test program 'fsmount.c'. This can be used along with
the test script below to show a kernel bug when calling fsconfig(2)
with security options on a btrfs filesystem.

This problem only occurs using fsconfig(2) when attempting to add
security options. Setting a native btrfs option (e.g. flushoncommit)
works.

Copy the statements below into test.sh and run with the fs name. Other
fs will work such as ext4, xfs. Only btrfs will fail.

#!/bin/sh
fs_name=$1

mkdir -p /mnt/selinux-testsuite
dd if=/dev/zero of=./fstest bs=4096 count=27904
dev=`losetup -f`
losetup $dev ./fstest
mkfs.$fs_name $dev
/usr/bin/systemctl stop udisks2 # Stops crap appearing in journal log
# mount(2) works:
#mount -t $fs_name -o "rootcontext=system_u:object_r:unconfined_t:s0"
$dev /mnt/selinux-testsuite
# This native btrfs "flushoncommit" option will work with fsconfig(2):
#./fsmount $fs_name $dev  /mnt/selinux-testsuite "flushoncommit"
# This will not:
./fsmount $fs_name $dev  /mnt/selinux-testsuite
"rootcontext=system_u:object_r:unconfined_t:s0"
# rootcontext fails with journal entry: SELinux: mount invalid.
#    Same superblock, different security settings for (dev loop0, type
btrfs)
umount /mnt/selinux-testsuite
losetup -d $dev
/usr/bin/systemctl start udisks2
rm -f ./fstest

/* cc fsmount.c -o fsmount -Wall */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/prctl.h>
#include <linux/mount.h>
#include <linux/unistd.h>

int fsopen(const char *fs_name, unsigned int flags)
{
	return syscall(__NR_fsopen, fs_name, flags);
}

int fsconfig(int fsfd, unsigned int cmd, const char *key,
	     const void *val, int aux)
{
	return syscall(__NR_fsconfig, fsfd, cmd, key, val, aux);
}

int fsmount(int fsfd, unsigned int flags, unsigned int ms_flags)
{
	return syscall(__NR_fsmount, fsfd, flags, ms_flags);
}

int move_mount(int from_dfd, const char *from_pathname, int to_dfd,
	       const char *to_pathname, unsigned int flags)
{
	return syscall(__NR_move_mount, from_dfd, from_pathname,
		       to_dfd, to_pathname, flags);
}

#define MAX_OPS 10
int fsconfig_opts(int fd, char *src, char *opts)
{
	int ret, i, max_entries = 0;
	int cmd[MAX_OPS];
	char *key[MAX_OPS], *value[MAX_OPS];
	char *src_str = "source";

	cmd[0] = FSCONFIG_SET_STRING;
	key[0] = src_str;
	value[0] = src;

	for (i = 1; i < MAX_OPS; i++) {
		value[i] = strsep(&opts, ",");
		if (!value[i]) {
			max_entries = i + 1;
			break;
		}
		cmd[i] = FSCONFIG_SET_STRING;
	}

	for (i = 1; value[i] != NULL; i++) {
		key[i] = strsep(&value[i], "=");
		if (!value[i])
			cmd[i] = FSCONFIG_SET_FLAG;
	}

	cmd[i] = FSCONFIG_CMD_CREATE;
	key[i] = NULL;
	value[i] = NULL;

	for (i = 0; i != max_entries; i++) {
		printf("fsconfig(0x%x, %s, %s, 0)\n", cmd[i], key[i], value[i]);
		ret = fsconfig(fd, cmd[i], key[i], value[i], 0);
		if (ret < 0) {
			fprintf(stderr, "Failed fsconfig(2): %s\n",
				strerror(errno));
			return -1;
		}
	}
	return 0;
}

int main(int argc, char *argv[])
{
	int ret, fsfd, mfd;
	unsigned int mount_attrs = 0;
	char *opts;

	if (argc != 5) {
		fprintf(stderr, "usage: %s <type> <src> <tgt> <opts>\n", argv[0]);
		return 1;
	}

	fsfd = fsopen(argv[1], 0);
	if (fsfd < 0) {
		fprintf(stderr, "Failed fsopen(2): %s\n", strerror(errno));
		return -1;
	}

	if (!strncmp (argv[1], "nfs", 3))
		mount_attrs = MS_NODEV;

	opts = strdup(argv[4]);

	ret = fsconfig_opts(fsfd, argv[2], opts);
	if (ret < 0) {
		fprintf(stderr, "Failed to add options: %s\n", argv[4]);
		close(fsfd);
		return -1;
	}
	printf("Successfully added options: %s\n", argv[4]);

	mfd = fsmount(fsfd, 0, mount_attrs);
	if (mfd < 0) {
		fprintf(stderr, "Failed fsmount(2): %s\n", strerror(errno));
		return -1;
	}
	close(fsfd);

	ret = move_mount(mfd, "", AT_FDCWD, argv[3], MOVE_MOUNT_F_EMPTY_PATH);
	if (ret < 0) {
		fprintf(stderr, "Failed move_mount(2): %s\n", strerror(errno));
		return -1;
	}
	close(mfd);

	printf("Successfully mounted on: %s\n", argv[3]);

	return 0;
}

[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [Samba]     [Device Mapper]     [CEPH Development]

  Powered by Linux