Skip to content

Commit

Permalink
aio: fix async fsync creds
Browse files Browse the repository at this point in the history
Avi Kivity reports that on fuse filesystems running in a user namespace
asyncronous fsync fails with EOVERFLOW.

The reason is that f_ops->fsync() is called with the creds of the kthread
performing aio work instead of the creds of the process originally
submitting IOCB_CMD_FSYNC.

Fuse sends the creds of the caller in the request header and it needs to
translate the uid and gid into the server's user namespace.  Since the
kthread is running in init_user_ns, the translation will fail and the
operation returns an error.

It can be argued that fsync doesn't actually need any creds, but just
zeroing out those fields in the header (as with requests that currently
don't take creds) is a backward compatibility risk.

Instead of working around this issue in fuse, solve the core of the problem
by calling the filesystem with the proper creds.

Reported-by: Avi Kivity <[email protected]>
Tested-by: Giuseppe Scrivano <[email protected]>
Fixes: c9582eb ("fuse: Fail all requests with invalid uids or gids")
Cc: [email protected]  # 4.18+
Signed-off-by: Miklos Szeredi <[email protected]>
Reviewed-by: Christoph Hellwig <[email protected]>
  • Loading branch information
Miklos Szeredi committed May 14, 2020
1 parent a3c751a commit 530f32f
Showing 1 changed file with 8 additions and 0 deletions.
8 changes: 8 additions & 0 deletions fs/aio.c
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ struct fsync_iocb {
struct file *file;
struct work_struct work;
bool datasync;
struct cred *creds;
};

struct poll_iocb {
Expand Down Expand Up @@ -1589,8 +1590,11 @@ static int aio_write(struct kiocb *req, const struct iocb *iocb,
static void aio_fsync_work(struct work_struct *work)
{
struct aio_kiocb *iocb = container_of(work, struct aio_kiocb, fsync.work);
const struct cred *old_cred = override_creds(iocb->fsync.creds);

iocb->ki_res.res = vfs_fsync(iocb->fsync.file, iocb->fsync.datasync);
revert_creds(old_cred);
put_cred(iocb->fsync.creds);
iocb_put(iocb);
}

Expand All @@ -1604,6 +1608,10 @@ static int aio_fsync(struct fsync_iocb *req, const struct iocb *iocb,
if (unlikely(!req->file->f_op->fsync))
return -EINVAL;

req->creds = prepare_creds();
if (!req->creds)
return -ENOMEM;

req->datasync = datasync;
INIT_WORK(&req->work, aio_fsync_work);
schedule_work(&req->work);
Expand Down

0 comments on commit 530f32f

Please sign in to comment.