On Thu, Sep 01, 2011 at 05:18:38PM +0800, Jeff Liu wrote:
> Hi Hugo,
>
> On 09/01/2011 05:00 PM, Hugo Mills wrote:
> >On Thu, Sep 01, 2011 at 04:47:47PM +0800, Jeff Liu wrote:
> >>Hello,
> >>
> >>I'd like to introduce a new ioctl to set file system label.
> >>With this feature, we can execute `btrfs filesystem label [label]
> >>[path]` through btrfs tools to set or change the label.
> >>
> >> Signed-off-by: Jie Liu<jeff.liu@xxxxxxxxxx>
> >>
> >>---
> >> fs/btrfs/ctree.h | 6 ++++++
> >> fs/btrfs/ioctl.c | 37 +++++++++++++++++++++++++++++++++++++
> >> fs/btrfs/ioctl.h | 2 ++
> >> 3 files changed, 45 insertions(+), 0 deletions(-)
> >>
> >>diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
> >>index 03912c5..2889b5e 100644
> >>--- a/fs/btrfs/ctree.h
> >>+++ b/fs/btrfs/ctree.h
> >>@@ -1259,6 +1259,12 @@ struct btrfs_ioctl_defrag_range_args {
> >> };
> >>
> >>
> >>+struct btrfs_ioctl_fs_label_args {
> >>+ /* label length in bytes */
> >>+ __u32 len;
> >>+ char label[BTRFS_LABEL_SIZE];
> >>+};
> > Why do we need to provide a length here? Simply force a zero byte
> >at the end of the string when you copy it into kernel space, and then
> >use strcpy(). Then you have no need to test for length at all.
> At first, I am afraid if an evil user may input an unexpected label
> string with huge bytes to consume memory.
That's why you force a known 0 byte at the end of the string when
you do the copy. (See below) Note also that the evil user can't
consume more than sizeof(btrfs_ioctl_fs_label_args) anyway, because
that's how much you're memdup()ing. The only issue is dealing with an
unterminated string... which you can fix by explicitly terminating it.
> >> /*
> >> * inode items have the data typically returned from stat and store other
> >> * info about object characteristics. There is one for every file
> >>and dir in
> >>diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
> >>index 970977a..9e01628 100644
> >>--- a/fs/btrfs/ioctl.c
> >>+++ b/fs/btrfs/ioctl.c
> >>@@ -268,6 +268,41 @@ static int btrfs_ioctl_getversion(struct file
> >>*file, int __user *arg)
> >> return put_user(inode->i_generation, arg);
> >> }
> >>
> >>+static int btrfs_ioctl_fs_setlabel(struct btrfs_root *root, void
> >>__user *arg)
> >>+{
> >>+ struct btrfs_super_block *super_block =&(root->fs_info->super_copy);
> >>+ struct btrfs_ioctl_fs_label_args *label_args;
> >>+ struct btrfs_trans_handle *trans;
> >>+
> >>+ if (!capable(CAP_SYS_ADMIN))
> >>+ return -EPERM;
> >>+
> >>+ if (btrfs_root_readonly(root))
> >>+ return -EROFS;
> >>+
> >>+ label_args = memdup_user(arg, sizeof(*label_args));
> >>+ if (IS_ERR(label_args))
> >>+ return PTR_ERR(label_args);
label_args->label[BTRFS_LABEL_SIZE-1] = 0;
This guarantees that the string is no longer than
BTRFS_LABEL_SIZE-1 bytes long.
> >>+ if (label_args->len>= sizeof(label_args->label))
> >>+ return -EINVAL;
Having ensured that the string is no longer than our buffers, we
don't need this.
> > Memory leak... you're not freeing label_args
> >>+ mutex_lock(&root->fs_info->volume_mutex);
> >>+ trans = btrfs_start_transaction(root, 0);
> >>+ if (IS_ERR(trans))
> >>+ return PTR_ERR(trans);
> > and here -- and you're leaving the mutex locked
> >
> >>+ if (snprintf(super_block->label, BTRFS_LABEL_SIZE, "%s",
> >>+ label_args->label) != label_args->len)
It's now safe to use strcpy() here, since we know that the string
*must* be zero terminated at or before BTRFS_LABEL_SIZE.
> >>+ return -EFAULT;
> > and here -- plus the transaction is still running
> Sorry for my stupid mistake and thanks for pointing those out!
> >>+ btrfs_end_transaction(trans, root);
> >>+ mutex_unlock(&root->fs_info->volume_mutex);
> >>+
> >>+ kfree(label_args);
> >>+ return 0;
> >>+}
> >>+
> >> static noinline int btrfs_ioctl_fitrim(struct file *file, void
> >>__user *arg)
> >> {
> >> struct btrfs_root *root = fdentry(file)->d_sb->s_fs_info;
> >>@@ -2876,6 +2911,8 @@ long btrfs_ioctl(struct file *file, unsigned int
> >> return btrfs_ioctl_fs_info(root, argp);
> >> case BTRFS_IOC_DEV_INFO:
> >> return btrfs_ioctl_dev_info(root, argp);
> >>+ case BTRFS_IOC_FS_SETLABEL:
> >>+ return btrfs_ioctl_fs_setlabel(root, argp);
> >> case BTRFS_IOC_BALANCE:
> >> return btrfs_balance(root->fs_info->dev_root);
> >> case BTRFS_IOC_CLONE:
> >>diff --git a/fs/btrfs/ioctl.h b/fs/btrfs/ioctl.h
> >>index ad1ea78..1e0ca2a 100644
> >>--- a/fs/btrfs/ioctl.h
> >>+++ b/fs/btrfs/ioctl.h
> >>@@ -248,4 +248,6 @@ struct btrfs_ioctl_space_args {
> >> struct btrfs_ioctl_dev_info_args)
> >> #define BTRFS_IOC_FS_INFO _IOR(BTRFS_IOCTL_MAGIC, 31, \
> >> struct btrfs_ioctl_fs_info_args)
> >>+#define BTRFS_IOC_FS_SETLABEL _IOW(BTRFS_IOCTL_MAGIC, 32, \
> >>+ struct btrfs_ioctl_fs_label_args)
> > Could you use an unassigned number from [1], and update the wiki
> >page, please? (The page only went up yesterday, but it's been needed
> >for a while).
> Ok, looks number 5 is free. :)
> I'll update the wiki later.
>
>
> Regards,
> -Jeff
> >> #endif
> > Will there be a userspace patch for this along shortly?
> >
> > Hugo.
> >
> >[1] https://btrfs.wiki.kernel.org/index.php/Project_ideas#Development_notes.2C_please_read
> >
>
--
=== Hugo Mills: hugo@... carfax.org.uk | darksatanic.net | lug.org.uk ===
PGP key: 515C238D from wwwkeys.eu.pgp.net or http://www.carfax.org.uk
--- He's playing Schubert. I think Schubert is losing. ---
Attachment:
signature.asc
Description: Digital signature
