All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH resend 0/2] btrfs: fix races between exec and defrag
@ 2018-07-17 22:05 Adam Borowski
  2018-07-17 22:08 ` [PATCH resend 1/2] btrfs: allow defrag on a file opened ro that has rw permissions Adam Borowski
  0 siblings, 1 reply; 6+ messages in thread
From: Adam Borowski @ 2018-07-17 22:05 UTC (permalink / raw)
  To: linux-btrfs, David Sterba, Mark Fasheh

[-- Attachment #1: Type: text/plain, Size: 949 bytes --]

Hi!
Here's a ping for a patch to fix ETXTBSY races between defrag and exec, just
like the dedupe counterpart.  Unlike that one which is shared to multiple
filesystems and thus lives in Al Viro's land, it is btrfs only.

Attached: a simple tool to fragment a file, by ten O_SYNC rewrites of length
1 at random positions; racey vs concurrent writes or execs but shouldn't
damage the file otherwise.

Also attached: a preliminary patch for -progs; it yet lacks a check for the
kernel version, but to add such a check we'd need to know which kernels
actually permit ro defrag for non-root.

No man page patch -- there's no man page to be patched...


Meow!
-- 
// If you believe in so-called "intellectual property", please immediately
// cease using counterfeit alphabets.  Instead, contact the nearest temple
// of Amon, whose priests will provide you with scribal services for all
// your writing needs, for Reasonable And Non-Discriminatory prices.

[-- Attachment #2: fragme.c --]
[-- Type: text/x-csrc, Size: 1363 bytes --]

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdarg.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/syscall.h>

static void die(const char *txt, ...) __attribute__((format (printf, 1, 2)));
static void die(const char *txt, ...)
{
    fprintf(stderr, "fragme: ");

    va_list ap;
    va_start(ap, txt);
    vfprintf(stderr, txt, ap);
    va_end(ap);

    exit(1);
}

static uint64_t rnd(uint64_t max)
{
    __uint128_t r;
    if (syscall(SYS_getrandom, &r, sizeof(r), 0)==-1)
        die("getrandom(): %m\n");
    return r%max;
}

int main(int argc, char **argv)
{
    if (argc!=2)
        die("Usage: fragme <file>\n");

    int fd = open(argv[1], O_RDWR|O_SYNC);
    if (fd == -1)
        die("open(\"%s\"): %m\n", argv[1]);
    off_t size = lseek(fd, 0, SEEK_END);
    if (size == -1)
        die("lseek(SEEK_END): %m\n");

    for (int i=0; i<10; ++i)
    {
        off_t off = rnd(size);
        char b;
        if (lseek(fd, off, SEEK_SET) != off)
            die("lseek for read: %m\n");
        if (read(fd, &b, 1) != 1)
            die("read(%lu): %m\n", off);
        if (lseek(fd, off, SEEK_SET) != off)
            die("lseek for write: %m\n");
        if (write(fd, &b, 1) != 1)
            die("write: %m\n");
    }

    return 0;
}

[-- Attachment #3: 0001-defrag-open-files-RO.patch --]
[-- Type: text/x-diff, Size: 1140 bytes --]

>From d040af09adb03daadbba4336700f40425a860320 Mon Sep 17 00:00:00 2001
From: Adam Borowski <kilobyte@angband.pl>
Date: Tue, 28 Nov 2017 01:00:21 +0100
Subject: [PATCH] defrag: open files RO

NOT FOR MERGING -- requires kernel versioning

Fixes EXTXBSY races.

Signed-off-by: Adam Borowski <kilobyte@angband.pl>
---
 cmds-filesystem.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/cmds-filesystem.c b/cmds-filesystem.c
index 30a50bf5..7eb6b7bb 100644
--- a/cmds-filesystem.c
+++ b/cmds-filesystem.c
@@ -876,7 +876,7 @@ static int defrag_callback(const char *fpath, const struct stat *sb,
 	if ((typeflag == FTW_F) && S_ISREG(sb->st_mode)) {
 		if (defrag_global_verbose)
 			printf("%s\n", fpath);
-		fd = open(fpath, O_RDWR);
+		fd = open(fpath, O_RDONLY);
 		if (fd < 0) {
 			goto error;
 		}
@@ -1012,7 +1012,7 @@ static int cmd_filesystem_defrag(int argc, char **argv)
 		int defrag_err = 0;
 
 		dirstream = NULL;
-		fd = open_file_or_dir(argv[i], &dirstream);
+		fd = open_file_or_dir3(argv[i], &dirstream, O_RDONLY);
 		if (fd < 0) {
 			error("cannot open %s: %m", argv[i]);
 			ret = -errno;
-- 
2.18.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH resend 1/2] btrfs: allow defrag on a file opened ro that has rw permissions
  2018-07-17 22:05 [PATCH resend 0/2] btrfs: fix races between exec and defrag Adam Borowski
@ 2018-07-17 22:08 ` Adam Borowski
  2018-07-17 22:09   ` [PATCH resend 2/2] btrfs: defrag: return EPERM not EINVAL when only permissions fail Adam Borowski
  2018-07-23 15:26   ` [PATCH resend 1/2] btrfs: allow defrag on a file opened ro that has rw permissions David Sterba
  0 siblings, 2 replies; 6+ messages in thread
From: Adam Borowski @ 2018-07-17 22:08 UTC (permalink / raw)
  To: David Sterba, Mark Fasheh, linux-btrfs; +Cc: Adam Borowski

Requiring a rw descriptor conflicts both ways with exec, returning ETXTBSY
whenever you try to defrag a program that's currently being run, or
causing intermittent exec failures on a live system being defragged.

As defrag doesn't change the file's contents in any way, there's no reason
to consider it a rw operation.  Thus, let's check only whether the file
could have been opened rw.  Such access control is still needed as
currently defrag can use extra disk space, and might trigger bugs.

Signed-off-by: Adam Borowski <kilobyte@angband.pl>
---
 fs/btrfs/ioctl.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 43ecbe620dea..01c150b6ab62 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -2941,7 +2941,8 @@ static int btrfs_ioctl_defrag(struct file *file, void __user *argp)
 		ret = btrfs_defrag_root(root);
 		break;
 	case S_IFREG:
-		if (!(file->f_mode & FMODE_WRITE)) {
+		if (!capable(CAP_SYS_ADMIN) &&
+		    inode_permission(inode, MAY_WRITE)) {
 			ret = -EINVAL;
 			goto out;
 		}
-- 
2.18.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH resend 2/2] btrfs: defrag: return EPERM not EINVAL when only permissions fail
  2018-07-17 22:08 ` [PATCH resend 1/2] btrfs: allow defrag on a file opened ro that has rw permissions Adam Borowski
@ 2018-07-17 22:09   ` Adam Borowski
  2018-07-23 15:26   ` [PATCH resend 1/2] btrfs: allow defrag on a file opened ro that has rw permissions David Sterba
  1 sibling, 0 replies; 6+ messages in thread
From: Adam Borowski @ 2018-07-17 22:09 UTC (permalink / raw)
  To: David Sterba, Mark Fasheh, linux-btrfs; +Cc: Adam Borowski

We give EINVAL when the request is invalid; here it's ok but merely the
user has insufficient privileges.  Thus, this return value reflects the
error better -- as discussed in the identical case for dedupe.

According to codesearch.debian.net, no userspace program distinguishes
these values beyond strerror().

Signed-off-by: Adam Borowski <kilobyte@angband.pl>
---
 fs/btrfs/ioctl.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 01c150b6ab62..e96e3c3caca1 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -2943,7 +2943,7 @@ static int btrfs_ioctl_defrag(struct file *file, void __user *argp)
 	case S_IFREG:
 		if (!capable(CAP_SYS_ADMIN) &&
 		    inode_permission(inode, MAY_WRITE)) {
-			ret = -EINVAL;
+			ret = -EPERM;
 			goto out;
 		}
 
-- 
2.18.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH resend 1/2] btrfs: allow defrag on a file opened ro that has rw permissions
  2018-07-17 22:08 ` [PATCH resend 1/2] btrfs: allow defrag on a file opened ro that has rw permissions Adam Borowski
  2018-07-17 22:09   ` [PATCH resend 2/2] btrfs: defrag: return EPERM not EINVAL when only permissions fail Adam Borowski
@ 2018-07-23 15:26   ` David Sterba
  2018-07-24 20:35     ` Adam Borowski
  1 sibling, 1 reply; 6+ messages in thread
From: David Sterba @ 2018-07-23 15:26 UTC (permalink / raw)
  To: Adam Borowski; +Cc: David Sterba, Mark Fasheh, linux-btrfs

On Wed, Jul 18, 2018 at 12:08:59AM +0200, Adam Borowski wrote:
> Requiring a rw descriptor conflicts both ways with exec, returning ETXTBSY
> whenever you try to defrag a program that's currently being run, or
> causing intermittent exec failures on a live system being defragged.
> 
> As defrag doesn't change the file's contents in any way, there's no reason
> to consider it a rw operation.  Thus, let's check only whether the file
> could have been opened rw.  Such access control is still needed as
> currently defrag can use extra disk space, and might trigger bugs.
> 
> Signed-off-by: Adam Borowski <kilobyte@angband.pl>
> ---
>  fs/btrfs/ioctl.c | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
> index 43ecbe620dea..01c150b6ab62 100644
> --- a/fs/btrfs/ioctl.c
> +++ b/fs/btrfs/ioctl.c
> @@ -2941,7 +2941,8 @@ static int btrfs_ioctl_defrag(struct file *file, void __user *argp)
>  		ret = btrfs_defrag_root(root);
>  		break;
>  	case S_IFREG:
> -		if (!(file->f_mode & FMODE_WRITE)) {
> +		if (!capable(CAP_SYS_ADMIN) &&
> +		    inode_permission(inode, MAY_WRITE)) {

The dedupe ioctl does the admin check or the FMODE_WRITE, which means
admin can dedupe anything but user has to have the file write open.
Doing the same for defrag should be ok for same reasons it is for
dedupe.

I'm not sure about using plain inode_permissions here, though it looks
correct and I'm not able to see inode vs file descriptor issues that
could cause trouble here. There are uid/gid, rws, acl, immutable,
capabilities, namespace aware checks, security hooks.

So, I'll add the patch to 4.19 queue. It's small and isolated change so
a revert would be easy in case we find something bad. The 2nd patch
should be IMHO part of this change as it's logical to return the error
code in the patch that modifies the user visible behaviour.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH resend 1/2] btrfs: allow defrag on a file opened ro that has rw permissions
  2018-07-23 15:26   ` [PATCH resend 1/2] btrfs: allow defrag on a file opened ro that has rw permissions David Sterba
@ 2018-07-24 20:35     ` Adam Borowski
  2018-08-01 13:03       ` David Sterba
  0 siblings, 1 reply; 6+ messages in thread
From: Adam Borowski @ 2018-07-24 20:35 UTC (permalink / raw)
  To: dsterba, Mark Fasheh, linux-btrfs

On Mon, Jul 23, 2018 at 05:26:24PM +0200, David Sterba wrote:
> On Wed, Jul 18, 2018 at 12:08:59AM +0200, Adam Borowski wrote:
(Combined with as-folded)

| | btrfs: allow defrag on a file opened read-only that has rw permissions
| |
> > Requiring a rw descriptor conflicts both ways with exec, returning ETXTBSY
> > whenever you try to defrag a program that's currently being run, or
> > causing intermittent exec failures on a live system being defragged.
> > 
> > As defrag doesn't change the file's contents in any way, there's no reason
> > to consider it a rw operation.  Thus, let's check only whether the file
> > could have been opened rw.  Such access control is still needed as
> > currently defrag can use extra disk space, and might trigger bugs.
<-----
| | We give EINVAL when the request is invalid; here it's ok but merely the
| | user has insufficient privileges.  Thus, this return value reflects the
| | error better -- as discussed in the identical case for dedupe.
| |
| | According to codesearch.debian.net, no userspace program distinguishes
| | these values beyond strerror().
| |
| | Signed-off-by: Adam Borowski <kilobyte@angband.pl>
| | Reviewed-by: David Sterba <dsterba@suse.com>
| | [ fold the EPERM patch from Adam ]
| | Signed-off-by: David Sterba <dsterba@suse.com>

[...]
> So, I'll add the patch to 4.19 queue. It's small and isolated change so
> a revert would be easy in case we find something bad. The 2nd patch
> should be IMHO part of this change as it's logical to return the error
> code in the patch that modifies the user visible behaviour.

A nitpick: the new commit message has a dangling pointer "this" to the title
of the commit that was squashed.  It was:

| btrfs: defrag: return EPERM not EINVAL when only permissions fail

It'd be nice if it could be inserted in some form in the place I marked with
an arrow.

But then, commit messages are not vital.  The actual functionality patch has
been applied correctly.  And thanks for adding the comment.


Meow!
-- 
// If you believe in so-called "intellectual property", please immediately
// cease using counterfeit alphabets.  Instead, contact the nearest temple
// of Amon, whose priests will provide you with scribal services for all
// your writing needs, for Reasonable And Non-Discriminatory prices.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH resend 1/2] btrfs: allow defrag on a file opened ro that has rw permissions
  2018-07-24 20:35     ` Adam Borowski
@ 2018-08-01 13:03       ` David Sterba
  0 siblings, 0 replies; 6+ messages in thread
From: David Sterba @ 2018-08-01 13:03 UTC (permalink / raw)
  To: Adam Borowski; +Cc: dsterba, Mark Fasheh, linux-btrfs

On Tue, Jul 24, 2018 at 10:35:28PM +0200, Adam Borowski wrote:
> On Mon, Jul 23, 2018 at 05:26:24PM +0200, David Sterba wrote:
> > On Wed, Jul 18, 2018 at 12:08:59AM +0200, Adam Borowski wrote:
> (Combined with as-folded)
> 
> | | btrfs: allow defrag on a file opened read-only that has rw permissions
> | |
> > > Requiring a rw descriptor conflicts both ways with exec, returning ETXTBSY
> > > whenever you try to defrag a program that's currently being run, or
> > > causing intermittent exec failures on a live system being defragged.
> > > 
> > > As defrag doesn't change the file's contents in any way, there's no reason
> > > to consider it a rw operation.  Thus, let's check only whether the file
> > > could have been opened rw.  Such access control is still needed as
> > > currently defrag can use extra disk space, and might trigger bugs.
> <-----
> | | We give EINVAL when the request is invalid; here it's ok but merely the
> | | user has insufficient privileges.  Thus, this return value reflects the
> | | error better -- as discussed in the identical case for dedupe.
> | |
> | | According to codesearch.debian.net, no userspace program distinguishes
> | | these values beyond strerror().
> | |
> | | Signed-off-by: Adam Borowski <kilobyte@angband.pl>
> | | Reviewed-by: David Sterba <dsterba@suse.com>
> | | [ fold the EPERM patch from Adam ]
> | | Signed-off-by: David Sterba <dsterba@suse.com>
> 
> [...]
> > So, I'll add the patch to 4.19 queue. It's small and isolated change so
> > a revert would be easy in case we find something bad. The 2nd patch
> > should be IMHO part of this change as it's logical to return the error
> > code in the patch that modifies the user visible behaviour.
> 
> A nitpick: the new commit message has a dangling pointer "this" to the title
> of the commit that was squashed.  It was:
> 
> | btrfs: defrag: return EPERM not EINVAL when only permissions fail
> 
> It'd be nice if it could be inserted in some form in the place I marked with
> an arrow.

Right. I've replaced 'this' with 'EPERM', thanks for catching it.

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2018-08-01 14:49 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-07-17 22:05 [PATCH resend 0/2] btrfs: fix races between exec and defrag Adam Borowski
2018-07-17 22:08 ` [PATCH resend 1/2] btrfs: allow defrag on a file opened ro that has rw permissions Adam Borowski
2018-07-17 22:09   ` [PATCH resend 2/2] btrfs: defrag: return EPERM not EINVAL when only permissions fail Adam Borowski
2018-07-23 15:26   ` [PATCH resend 1/2] btrfs: allow defrag on a file opened ro that has rw permissions David Sterba
2018-07-24 20:35     ` Adam Borowski
2018-08-01 13:03       ` David Sterba

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.