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  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Sun, 10 Oct 2021 21:06:52 +0900
From:   OGAWA Hirofumi <hirofumi@...l.parknet.co.jp>
To:     Martin Kepplinger <martink@...teo.de>
Cc:     angus@...ea.ca, linux-kernel@...r.kernel.org, kay.sievers@...y.org,
        lennart@...ttering.net, harald@...hat.com,
        gregkh@...uxfoundation.org, david@...ar.dk, tytso@....edu,
        alan@...rguk.ukuu.org.uk, akpm@...ux-foundation.org,
        pali.rohar@...il.com
Subject: Re: [PATCH] fs: fat: Make the volume label writable when mounted

Martin Kepplinger <martink@...teo.de> writes:

> The motivation for this change (probably) has its origin in a whishlist
> for the kernel that popped up in 2011, see
> https://lore.kernel.org/lkml/1319135973.1020.9.camel@mop/

I'm ok this patch if some userspace wants to use in real world.

The whole point of this should be to provide access without any race,
however this looks like broken many ways.

> +/* protect access to the FAT fs label */
> +DEFINE_MUTEX(label_mutex);

nothing reason to be global lock (iow, should be per-sb)?

> +	/* code found in inode.c */
> +	fat_get_blknr_offset(sbi, i_pos, &blocknr, &offset);
> +	bh = sb_bread(sb, blocknr);
> +	if (!bh) {
> +		fat_msg(sb, KERN_ERR,
> +			"unable to read inode block for updating (i_pos %lld)",
> +			i_pos);
> +		return -EIO;
> +	}

reading dir block manually, this can read full of dir blocks for fat32?

> +	de = NULL;
> +	err = fat_get_label_entry(root_inode, &bh, &de);
> +	if (err)
> +		return err;
> +
> +	if (label) {
> +		fat_msg(sb, KERN_INFO,
> +			"rename directory label from %.11s to %.11s",
> +			de->name, label);
> +		mutex_lock(&label_mutex);
> +		strncpy(de->name, label, MSDOS_NAME);
> +		mark_buffer_dirty(bh);
> +		sync_dirty_buffer(bh);
> +		brelse(bh);
> +		mutex_unlock(&label_mutex);

race with normal dir operations?

> +	if (sbi->fat_bits == 32) {
> +		if (label) {
> +			fat_msg(sb, KERN_INFO,
> +				"rename partition label from %.11s to %.11s",
> +				b->fat32.vol_label, label);

nothing reason to output message for user input.

> +			mutex_lock(&MSDOS_SB(sb)->s_lock);
> +			b->fat32.state |= FAT_STATE_DIRTY;
> +			memcpy(b->fat32.vol_label, label, MSDOS_NAME);
> +			mutex_unlock(&MSDOS_SB(sb)->s_lock);
> +		} else {
> +			b->fat32.state &= ~FAT_STATE_DIRTY;
> +			fat_msg(sb, KERN_INFO, "partition label is %.11s",
> +				b->fat32.vol_label);
> +		}

why do you touch dirty state?

> +	} else {
> +		if (label) {
> +			fat_msg(sb, KERN_INFO,
> +				"rename partition label from %.11s to %.11s ",
> +				b->fat16.vol_label, label);
> +
> +			mutex_lock(&MSDOS_SB(sb)->s_lock);
> +			b->fat32.state |= FAT_STATE_DIRTY;
> +			memcpy(b->fat32.vol_label, label, MSDOS_NAME);
> +			mutex_unlock(&MSDOS_SB(sb)->s_lock);
> +		} else {
> +			b->fat32.state &= ~FAT_STATE_DIRTY;
> +			fat_msg(sb, KERN_INFO, "partition label is %.11s",
> +				b->fat16.vol_label);
> +		}
> +	}

ditto

> +	mark_buffer_dirty(bh);
> +	sync_dirty_buffer(bh);
> +	brelse(bh);

why need to sync here?

> +	if (!user_attr) {
> +		label = NULL;
> +		goto print_only;

This outputs only label to dmesg, too strange syscall design. Probably,
we would be better to delete label or such for NULL.

> +	label = newlabel;
> +	err = copy_from_user(label, (void *)user_attr, MSDOS_NAME);

do we need cast here?

> +	if (err) {
> +		fat_msg(sb, KERN_ERR,
> +			"copy_from_user failed %d bytes not copied\n", err);
> +		return -EFAULT;

user fault should not output message basically.

> +		for (i = 0; i < len; i++) {
> +			c = label[i];
> +			if ((c < 'a' || c > 'z') && (c < 'A' || c > 'Z')) {
> +				if ((c < '0' || c > '9') && c != 0x20)
> +					return -EINVAL;

IIRC, label allows much more characters.

> +	err = fat_set_directory_volume_label(file, label);
> +	if (err == -ENOENT) {
> +		fat_msg(sb, KERN_ERR, "no label entry. please reformat\n");
> +		strncpy(label, "NO NAME    ", MSDOS_NAME);

no label entry should be normal state, and should not output message

> +	} else if (err) {
> +		fat_msg(sb, KERN_ERR, "error setting directory label\n");
> +		return err;
> +	}
> +
> +	err = fat_set_partition_volume_label(file, label);
> +	if (err) {
> +		fat_msg(sb, KERN_ERR, "error setting partition label\n");
> +		return err;
> +	}

strange messages, how interacting with the user should be basically the
job of userspace tools.

> diff --git a/include/uapi/linux/msdos_fs.h b/include/uapi/linux/msdos_fs.h
> index a5773899f4d9..b666bca09238 100644
> --- a/include/uapi/linux/msdos_fs.h
> +++ b/include/uapi/linux/msdos_fs.h
> @@ -104,6 +104,7 @@ struct __fat_dirent {
>  #define FAT_IOCTL_SET_ATTRIBUTES	_IOW('r', 0x11, __u32)
>  /*Android kernel has used 0x12, so we use 0x13*/
>  #define FAT_IOCTL_GET_VOLUME_ID		_IOR('r', 0x13, __u32)
> +#define VFAT_IOCTL_SET_LABEL		_IOW('r', 0x14, __u32)

maybe FAT_IOCTL_SET_LABEL is better.
-- 
OGAWA Hirofumi <hirofumi@...l.parknet.co.jp>

Powered by blists - more mailing lists