From: Greg Kroah-Hartman Date: Thu, 18 Jun 2020 14:54:20 +0000 (+0200) Subject: 4.9-stable patches X-Git-Tag: v4.4.228~57 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=fc2fb41c46ab0f441f73df5ecb4fb2f9095962ba;p=thirdparty%2Fkernel%2Fstable-queue.git 4.9-stable patches added patches: btrfs-send-emit-file-capabilities-after-chown.patch --- diff --git a/queue-4.9/btrfs-send-emit-file-capabilities-after-chown.patch b/queue-4.9/btrfs-send-emit-file-capabilities-after-chown.patch new file mode 100644 index 00000000000..003cf02b979 --- /dev/null +++ b/queue-4.9/btrfs-send-emit-file-capabilities-after-chown.patch @@ -0,0 +1,154 @@ +From 89efda52e6b6930f80f5adda9c3c9edfb1397191 Mon Sep 17 00:00:00 2001 +From: Marcos Paulo de Souza +Date: Sun, 10 May 2020 23:15:07 -0300 +Subject: btrfs: send: emit file capabilities after chown + +From: Marcos Paulo de Souza + +commit 89efda52e6b6930f80f5adda9c3c9edfb1397191 upstream. + +Whenever a chown is executed, all capabilities of the file being touched +are lost. When doing incremental send with a file with capabilities, +there is a situation where the capability can be lost on the receiving +side. The sequence of actions bellow shows the problem: + + $ mount /dev/sda fs1 + $ mount /dev/sdb fs2 + + $ touch fs1/foo.bar + $ setcap cap_sys_nice+ep fs1/foo.bar + $ btrfs subvolume snapshot -r fs1 fs1/snap_init + $ btrfs send fs1/snap_init | btrfs receive fs2 + + $ chgrp adm fs1/foo.bar + $ setcap cap_sys_nice+ep fs1/foo.bar + + $ btrfs subvolume snapshot -r fs1 fs1/snap_complete + $ btrfs subvolume snapshot -r fs1 fs1/snap_incremental + + $ btrfs send fs1/snap_complete | btrfs receive fs2 + $ btrfs send -p fs1/snap_init fs1/snap_incremental | btrfs receive fs2 + +At this point, only a chown was emitted by "btrfs send" since only the +group was changed. This makes the cap_sys_nice capability to be dropped +from fs2/snap_incremental/foo.bar + +To fix that, only emit capabilities after chown is emitted. The current +code first checks for xattrs that are new/changed, emits them, and later +emit the chown. Now, __process_new_xattr skips capabilities, letting +only finish_inode_if_needed to emit them, if they exist, for the inode +being processed. + +This behavior was being worked around in "btrfs receive" side by caching +the capability and only applying it after chown. Now, xattrs are only +emmited _after_ chown, making that workaround not needed anymore. + +Link: https://github.com/kdave/btrfs-progs/issues/202 +CC: stable@vger.kernel.org # 4.4+ +Suggested-by: Filipe Manana +Reviewed-by: Filipe Manana +Signed-off-by: Marcos Paulo de Souza +Signed-off-by: David Sterba +Signed-off-by: Greg Kroah-Hartman + +--- + fs/btrfs/send.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 67 insertions(+) + +--- a/fs/btrfs/send.c ++++ b/fs/btrfs/send.c +@@ -35,6 +35,7 @@ + #include "btrfs_inode.h" + #include "transaction.h" + #include "compression.h" ++#include "xattr.h" + + /* + * Maximum number of references an extent can have in order for us to attempt to +@@ -4368,6 +4369,10 @@ static int __process_new_xattr(int num, + struct fs_path *p; + struct posix_acl_xattr_header dummy_acl; + ++ /* Capabilities are emitted by finish_inode_if_needed */ ++ if (!strncmp(name, XATTR_NAME_CAPS, name_len)) ++ return 0; ++ + p = fs_path_alloc(); + if (!p) + return -ENOMEM; +@@ -4904,6 +4909,64 @@ static int send_extent_data(struct send_ + return 0; + } + ++/* ++ * Search for a capability xattr related to sctx->cur_ino. If the capability is ++ * found, call send_set_xattr function to emit it. ++ * ++ * Return 0 if there isn't a capability, or when the capability was emitted ++ * successfully, or < 0 if an error occurred. ++ */ ++static int send_capabilities(struct send_ctx *sctx) ++{ ++ struct fs_path *fspath = NULL; ++ struct btrfs_path *path; ++ struct btrfs_dir_item *di; ++ struct extent_buffer *leaf; ++ unsigned long data_ptr; ++ char *buf = NULL; ++ int buf_len; ++ int ret = 0; ++ ++ path = alloc_path_for_send(); ++ if (!path) ++ return -ENOMEM; ++ ++ di = btrfs_lookup_xattr(NULL, sctx->send_root, path, sctx->cur_ino, ++ XATTR_NAME_CAPS, strlen(XATTR_NAME_CAPS), 0); ++ if (!di) { ++ /* There is no xattr for this inode */ ++ goto out; ++ } else if (IS_ERR(di)) { ++ ret = PTR_ERR(di); ++ goto out; ++ } ++ ++ leaf = path->nodes[0]; ++ buf_len = btrfs_dir_data_len(leaf, di); ++ ++ fspath = fs_path_alloc(); ++ buf = kmalloc(buf_len, GFP_KERNEL); ++ if (!fspath || !buf) { ++ ret = -ENOMEM; ++ goto out; ++ } ++ ++ ret = get_cur_path(sctx, sctx->cur_ino, sctx->cur_inode_gen, fspath); ++ if (ret < 0) ++ goto out; ++ ++ data_ptr = (unsigned long)(di + 1) + btrfs_dir_name_len(leaf, di); ++ read_extent_buffer(leaf, buf, data_ptr, buf_len); ++ ++ ret = send_set_xattr(sctx, fspath, XATTR_NAME_CAPS, ++ strlen(XATTR_NAME_CAPS), buf, buf_len); ++out: ++ kfree(buf); ++ fs_path_free(fspath); ++ btrfs_free_path(path); ++ return ret; ++} ++ + static int clone_range(struct send_ctx *sctx, + struct clone_root *clone_root, + const u64 disk_byte, +@@ -5615,6 +5678,10 @@ static int finish_inode_if_needed(struct + goto out; + } + ++ ret = send_capabilities(sctx); ++ if (ret < 0) ++ goto out; ++ + /* + * If other directory inodes depended on our current directory + * inode's move/rename, now do their move/rename operations. diff --git a/queue-4.9/series b/queue-4.9/series index 1aa8ea637d9..ca980c0e058 100644 --- a/queue-4.9/series +++ b/queue-4.9/series @@ -94,3 +94,4 @@ ixgbe-fix-signed-integer-overflow-warning.patch mmc-sdhci-esdhc-imx-fix-the-mask-for-tuning-start-po.patch spi-dw-return-any-value-retrieved-from-the-dma_trans.patch cpuidle-fix-three-reference-count-leaks.patch +btrfs-send-emit-file-capabilities-after-chown.patch