From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-yb1-f176.google.com (mail-yb1-f176.google.com [209.85.219.176]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9C70585C49 for ; Wed, 24 Jan 2024 17:19:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.219.176 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706116777; cv=none; b=fvdMs5bjMp9aV4pRLdpxbUTOnN2K9madJ/g0YzSotW/ytw8Zth+UphbsjwIUfCfQR44UKeunZpdn3bPBtOJJoN9oR6ClDY/cadgmM7SHBwj7jpSw12QqYTUzpOgwxra7C+LnJuWgPW5ZJR+bPmf51HuvUOUK5sBTvUrRqAonca0= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1706116777; c=relaxed/simple; bh=Y42fGFl4F/pGNE1FifNlRyw6w7kTHKoaQmFNSt1rUuI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=eZPM/lIxk0giDdv+je6VuHPWkhpvcjP8GZdwgYy3P/jdV0CnkoS/XbnEYs/wd2x2Rbuyl9dAUJe5mOMnpeHjbOnkQw5+SMNY1LRHd+LCl8d0wlbHWRIzK4x45iiHxtZNV55bH3mxC3Kl5pTboGjNHIdIC5X0DyNlUv4HO34SerQ= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=toxicpanda.com; spf=none smtp.mailfrom=toxicpanda.com; dkim=pass (2048-bit key) header.d=toxicpanda-com.20230601.gappssmtp.com header.i=@toxicpanda-com.20230601.gappssmtp.com header.b=s98Qm8gX; arc=none smtp.client-ip=209.85.219.176 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=toxicpanda.com Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=toxicpanda.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=toxicpanda-com.20230601.gappssmtp.com header.i=@toxicpanda-com.20230601.gappssmtp.com header.b="s98Qm8gX" Received: by mail-yb1-f176.google.com with SMTP id 3f1490d57ef6-dc227feab99so5588733276.2 for ; Wed, 24 Jan 2024 09:19:35 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=toxicpanda-com.20230601.gappssmtp.com; s=20230601; t=1706116774; x=1706721574; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=21xp00Q4FaE/AFbkjfhFZh6BgtFKeSZkw8ipfChaXro=; b=s98Qm8gXPg8Oqk95QLtqMtBONlO8Y7NN5rTvR82iBGY3yIrdWQHdcYU9jX4tIbchx4 v7TA1cL7q1RGzkR6BQvsa9p0156oksxb5BoVrFQXOk+MkNSaqN7GbbTckiYsS7ekY2GN IT3/k8VN/6Xu6WwCrA3gSWpliAmW+7fCE/Q9kPEirJRwsYKTiUNS3tERlAvKOwCz6BDs lwch559LMM91KKlgNgU5agQWHUTFsEeeN8qqTaL6xt43o5s8OjG3LQlZMxZnP6m1SpMJ ROUTXTYfu3/AHuaixDe0yuUFA+2Yiw2Cll2g0fq2cCxvQkZCKrN3zH5mvIvmnuBLIqe8 TuyA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1706116774; x=1706721574; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=21xp00Q4FaE/AFbkjfhFZh6BgtFKeSZkw8ipfChaXro=; b=w3sQ0JCneqa0BM+eL2U3iSIe0p5jPEhw6JThhduFuZPOOerQUiStwC5eJeHgSkGBeK 7o07JxW0KSYKPRG8b0mJ0gvPQGCX52B0Oqch/U/TWUC4bBRwvuMc3OZno1co8i375Iru OoOsn8zl7TAlZ2S1YhdELQpxCJMsiQtasSZg75nkYklKckbwNdrSTJM2en9hmTmccWB8 hia2iQQeq27LnVm4VebyQvur6wbBJd7hRykqdNip6+bQIhbwhfm3E/xyX3j/B+Ong4ry gZRvVC5ALxnYTu7lDbVf8hUAQde1dVYwIARF/HldPZmJc2gFHn+mTewRPQUzJKduwfiZ N4tQ== X-Gm-Message-State: AOJu0YxBIuq3wUelAK9Q0KperGkzUM437elo8dvCiemxtHdZOwEkHtJn ITpsmGz1AL5KQwvtqw4fvRTqiVggiBTmtBU3qiZawT8M1Tl8D5EbjQ0Jr0fp9YhmbS0DEwvMCby c X-Google-Smtp-Source: AGHT+IH1pqnImgL7kLTAuR7UcvCmuU2OD5/8qf1epxJCvZFirtODcHZTVErakCdPI9QZxo2N7bMUhA== X-Received: by 2002:a5b:a0a:0:b0:dc2:46cd:eeef with SMTP id k10-20020a5b0a0a000000b00dc246cdeeefmr822515ybq.130.1706116774230; Wed, 24 Jan 2024 09:19:34 -0800 (PST) Received: from localhost (076-182-020-124.res.spectrum.com. [76.182.20.124]) by smtp.gmail.com with ESMTPSA id g9-20020a5b0709000000b00dc23af43ff3sm2872016ybq.14.2024.01.24.09.19.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 24 Jan 2024 09:19:33 -0800 (PST) From: Josef Bacik To: linux-btrfs@vger.kernel.org, kernel-team@fb.com Cc: Omar Sandoval , Sweet Tea Dorminy Subject: [PATCH v5 13/52] btrfs: add inode encryption contexts Date: Wed, 24 Jan 2024 12:18:35 -0500 Message-ID: <5a88efb484b0874a7430b83bc6e5f6b9aa5858d5.1706116485.git.josef@toxicpanda.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-btrfs@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: Omar Sandoval fscrypt stores a context item with encrypted inodes that contains the related encryption information. fscrypt provides an arbitrary blob for the filesystem to store, and it does not clearly fit into an existing structure, so this goes in a new item type. Signed-off-by: Omar Sandoval Signed-off-by: Sweet Tea Dorminy Signed-off-by: Josef Bacik --- fs/btrfs/fscrypt.c | 117 ++++++++++++++++++++++++++++++++ fs/btrfs/fscrypt.h | 2 + fs/btrfs/inode.c | 19 ++++++ fs/btrfs/ioctl.c | 8 ++- include/uapi/linux/btrfs_tree.h | 10 +++ 5 files changed, 154 insertions(+), 2 deletions(-) diff --git a/fs/btrfs/fscrypt.c b/fs/btrfs/fscrypt.c index 48ab99dfe48d..3f82352662e6 100644 --- a/fs/btrfs/fscrypt.c +++ b/fs/btrfs/fscrypt.c @@ -1,7 +1,124 @@ // SPDX-License-Identifier: GPL-2.0 +#include #include "ctree.h" +#include "accessors.h" +#include "btrfs_inode.h" +#include "disk-io.h" +#include "fs.h" #include "fscrypt.h" +#include "ioctl.h" +#include "messages.h" +#include "transaction.h" +#include "xattr.h" + +static int btrfs_fscrypt_get_context(struct inode *inode, void *ctx, size_t len) +{ + struct btrfs_key key = { + .objectid = btrfs_ino(BTRFS_I(inode)), + .type = BTRFS_FSCRYPT_INODE_CTX_ITEM_KEY, + .offset = 0, + }; + struct btrfs_path *path; + struct extent_buffer *leaf; + unsigned long ptr; + int ret; + + + path = btrfs_alloc_path(); + if (!path) + return -ENOMEM; + + ret = btrfs_search_slot(NULL, BTRFS_I(inode)->root, &key, path, 0, 0); + if (ret) { + len = -ENOENT; + goto out; + } + + leaf = path->nodes[0]; + ptr = btrfs_item_ptr_offset(leaf, path->slots[0]); + /* fscrypt provides max context length, but it could be less */ + len = min_t(size_t, len, btrfs_item_size(leaf, path->slots[0])); + read_extent_buffer(leaf, ctx, ptr, len); + +out: + btrfs_free_path(path); + return len; +} + +static int btrfs_fscrypt_set_context(struct inode *inode, const void *ctx, + size_t len, void *fs_data) +{ + struct btrfs_trans_handle *trans = fs_data; + struct btrfs_key key = { + .objectid = btrfs_ino(BTRFS_I(inode)), + .type = BTRFS_FSCRYPT_INODE_CTX_ITEM_KEY, + .offset = 0, + }; + struct btrfs_path *path = NULL; + struct extent_buffer *leaf; + unsigned long ptr; + int ret; + + if (!trans) + trans = btrfs_start_transaction(BTRFS_I(inode)->root, 2); + if (IS_ERR(trans)) + return PTR_ERR(trans); + + path = btrfs_alloc_path(); + if (!path) { + ret = -ENOMEM; + goto out_err; + } + + ret = btrfs_search_slot(trans, BTRFS_I(inode)->root, &key, path, 0, 1); + if (ret < 0) + goto out_err; + + if (ret > 0) { + btrfs_release_path(path); + ret = btrfs_insert_empty_item(trans, BTRFS_I(inode)->root, path, &key, len); + if (ret) + goto out_err; + } + + leaf = path->nodes[0]; + ptr = btrfs_item_ptr_offset(leaf, path->slots[0]); + + len = min_t(size_t, len, btrfs_item_size(leaf, path->slots[0])); + write_extent_buffer(leaf, ctx, ptr, len); + btrfs_mark_buffer_dirty(trans, leaf); + btrfs_release_path(path); + + if (fs_data) + return ret; + + BTRFS_I(inode)->flags |= BTRFS_INODE_ENCRYPT; + btrfs_sync_inode_flags_to_i_flags(inode); + inode_inc_iversion(inode); + inode_set_ctime_current(inode); + ret = btrfs_update_inode(trans, BTRFS_I(inode)); + if (ret) + goto out_abort; + btrfs_free_path(path); + btrfs_end_transaction(trans); + return 0; +out_abort: + btrfs_abort_transaction(trans, ret); +out_err: + if (!fs_data) + btrfs_end_transaction(trans); + btrfs_free_path(path); + return ret; +} + +static bool btrfs_fscrypt_empty_dir(struct inode *inode) +{ + return inode->i_size == BTRFS_EMPTY_DIR_SIZE; +} const struct fscrypt_operations btrfs_fscrypt_ops = { + .get_context = btrfs_fscrypt_get_context, + .set_context = btrfs_fscrypt_set_context, + .empty_dir = btrfs_fscrypt_empty_dir, }; diff --git a/fs/btrfs/fscrypt.h b/fs/btrfs/fscrypt.h index 7f4e6888bd43..80adb7e56826 100644 --- a/fs/btrfs/fscrypt.h +++ b/fs/btrfs/fscrypt.h @@ -5,6 +5,8 @@ #include +#include "fs.h" + extern const struct fscrypt_operations btrfs_fscrypt_ops; #endif /* BTRFS_FSCRYPT_H */ diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 5f682a7aa761..4999ae1db2a3 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -62,6 +62,7 @@ #include "defrag.h" #include "dir-item.h" #include "file-item.h" +#include "fscrypt.h" #include "uuid-tree.h" #include "ioctl.h" #include "file.h" @@ -6102,6 +6103,9 @@ int btrfs_new_inode_prepare(struct btrfs_new_inode_args *args, struct inode *inode = args->inode; int ret; + if (fscrypt_is_nokey_name(args->dentry)) + return -ENOKEY; + if (!args->orphan) { ret = fscrypt_setup_filename(dir, &args->dentry->d_name, 0, &args->fname); @@ -6137,6 +6141,9 @@ int btrfs_new_inode_prepare(struct btrfs_new_inode_args *args, if (dir->i_security) (*trans_num_items)++; #endif + /* 1 to add fscrypt item */ + if (args->encrypt) + (*trans_num_items)++; if (args->orphan) { /* 1 to add orphan item */ (*trans_num_items)++; @@ -6322,6 +6329,11 @@ int btrfs_create_new_inode(struct btrfs_trans_handle *trans, BTRFS_I(inode)->i_otime_sec = ts.tv_sec; BTRFS_I(inode)->i_otime_nsec = ts.tv_nsec; + if (args->encrypt) { + BTRFS_I(inode)->flags |= BTRFS_INODE_ENCRYPT; + btrfs_sync_inode_flags_to_i_flags(inode); + } + /* * We're going to fill the inode item now, so at this point the inode * must be fully initialized. @@ -6396,6 +6408,13 @@ int btrfs_create_new_inode(struct btrfs_trans_handle *trans, goto discard; } } + if (args->encrypt) { + ret = fscrypt_set_context(inode, trans); + if (ret) { + btrfs_abort_transaction(trans, ret); + goto discard; + } + } inode_tree_add(BTRFS_I(inode)); diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 3d476decde52..c333a49e5bad 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -156,6 +156,8 @@ static unsigned int btrfs_inode_flags_to_fsflags(struct btrfs_inode *binode) iflags |= FS_DIRSYNC_FL; if (flags & BTRFS_INODE_NODATACOW) iflags |= FS_NOCOW_FL; + if (flags & BTRFS_INODE_ENCRYPT) + iflags |= FS_ENCRYPT_FL; if (ro_flags & BTRFS_INODE_RO_VERITY) iflags |= FS_VERITY_FL; @@ -185,12 +187,14 @@ void btrfs_sync_inode_flags_to_i_flags(struct inode *inode) new_fl |= S_NOATIME; if (binode->flags & BTRFS_INODE_DIRSYNC) new_fl |= S_DIRSYNC; + if (binode->flags & BTRFS_INODE_ENCRYPT) + new_fl |= S_ENCRYPTED; if (binode->ro_flags & BTRFS_INODE_RO_VERITY) new_fl |= S_VERITY; set_mask_bits(&inode->i_flags, S_SYNC | S_APPEND | S_IMMUTABLE | S_NOATIME | S_DIRSYNC | - S_VERITY, new_fl); + S_VERITY | S_ENCRYPTED, new_fl); } /* @@ -203,7 +207,7 @@ static int check_fsflags(unsigned int old_flags, unsigned int flags) FS_NOATIME_FL | FS_NODUMP_FL | \ FS_SYNC_FL | FS_DIRSYNC_FL | \ FS_NOCOMP_FL | FS_COMPR_FL | - FS_NOCOW_FL)) + FS_NOCOW_FL | FS_ENCRYPT_FL)) return -EOPNOTSUPP; /* COMPR and NOCOMP on new/old are valid */ diff --git a/include/uapi/linux/btrfs_tree.h b/include/uapi/linux/btrfs_tree.h index d24e8e121507..f3fcca1c9449 100644 --- a/include/uapi/linux/btrfs_tree.h +++ b/include/uapi/linux/btrfs_tree.h @@ -164,6 +164,8 @@ #define BTRFS_VERITY_DESC_ITEM_KEY 36 #define BTRFS_VERITY_MERKLE_ITEM_KEY 37 +#define BTRFS_FSCRYPT_INODE_CTX_ITEM_KEY 41 + #define BTRFS_ORPHAN_ITEM_KEY 48 /* reserve 2-15 close to the inode for later flexibility */ @@ -424,6 +426,7 @@ static inline __u8 btrfs_dir_flags_to_ftype(__u8 flags) #define BTRFS_INODE_NOATIME (1U << 9) #define BTRFS_INODE_DIRSYNC (1U << 10) #define BTRFS_INODE_COMPRESS (1U << 11) +#define BTRFS_INODE_ENCRYPT (1U << 12) #define BTRFS_INODE_ROOT_ITEM_INIT (1U << 31) @@ -440,6 +443,7 @@ static inline __u8 btrfs_dir_flags_to_ftype(__u8 flags) BTRFS_INODE_NOATIME | \ BTRFS_INODE_DIRSYNC | \ BTRFS_INODE_COMPRESS | \ + BTRFS_INODE_ENCRYPT | \ BTRFS_INODE_ROOT_ITEM_INIT) #define BTRFS_INODE_RO_VERITY (1U << 0) @@ -1069,6 +1073,12 @@ enum { BTRFS_NR_FILE_EXTENT_TYPES = 3, }; +enum btrfs_encryption_type { + BTRFS_ENCRYPTION_NONE, + BTRFS_ENCRYPTION_FSCRYPT, + BTRFS_NR_ENCRYPTION_TYPES, +}; + struct btrfs_file_extent_item { /* * transaction id that created this extent -- 2.43.0