From nobody Mon May 11 04:12:40 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9955EC433F5 for ; Thu, 14 Apr 2022 15:19:52 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1349789AbiDNPQT (ORCPT ); Thu, 14 Apr 2022 11:16:19 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43374 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1347657AbiDNN7Z (ORCPT ); Thu, 14 Apr 2022 09:59:25 -0400 Received: from smtp-out1.suse.de (smtp-out1.suse.de [195.135.220.28]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 293CB338AB; Thu, 14 Apr 2022 06:51:01 -0700 (PDT) Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out1.suse.de (Postfix) with ESMTPS id DA51121613; Thu, 14 Apr 2022 13:50:59 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1649944259; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=w48CeVx/KrAp2wYmVlzeqrFMXv/esKDNwCLFBwxR02s=; b=uaeMI/WNT2E/95xcEZ4JcQ06Tm3X0TddvO3ah9jLlN9Oyu476ryR9nE/gc0hsoQMF9Xwet 42oI+/ew7Nt4soJEztWKc0aUUJgjzRCuWPMawiC+Zip4wPYybteVu1qcHlzXuqwFUSBR5f QkCHiQFPi3/MVQY1tUAblYHf2Cb8UKg= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1649944259; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=w48CeVx/KrAp2wYmVlzeqrFMXv/esKDNwCLFBwxR02s=; b=eatG4gJ5bW2m1wSrnnkUmuPzvJUWTkADZ8rmg6fn0riFO4RrBXCPQqc8ISHqJQUVX8puMA +oACCwSr942bhbCw== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id 6A822132C0; Thu, 14 Apr 2022 13:50:59 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id yBMNF8MmWGJnTgAAMHmgww (envelope-from ); Thu, 14 Apr 2022 13:50:59 +0000 Received: from localhost (brahms.olymp [local]) by brahms.olymp (OpenSMTPD) with ESMTPA id 527b0df8; Thu, 14 Apr 2022 13:51:24 +0000 (UTC) From: =?UTF-8?q?Lu=C3=ADs=20Henriques?= To: Jeff Layton , Xiubo Li , Ilya Dryomov Cc: ceph-devel@vger.kernel.org, linux-kernel@vger.kernel.org, =?UTF-8?q?Lu=C3=ADs=20Henriques?= Subject: [PATCH v4 1/4] ceph: add support for encrypted snapshot names Date: Thu, 14 Apr 2022 14:51:19 +0100 Message-Id: <20220414135122.26821-2-lhenriques@suse.de> In-Reply-To: <20220414135122.26821-1-lhenriques@suse.de> References: <20220414135122.26821-1-lhenriques@suse.de> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Since filenames in encrypted directories are already encrypted and shown as a base64-encoded string when the directory is locked, snapshot names should show a similar behaviour. Signed-off-by: Lu=C3=ADs Henriques Reviewed-by: Xiubo Li --- fs/ceph/inode.c | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index fa0d3018d981..8e97efa2b1a7 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -91,9 +91,15 @@ struct inode *ceph_new_inode(struct inode *dir, struct d= entry *dentry, if (err < 0) goto out_err; =20 - err =3D ceph_fscrypt_prepare_context(dir, inode, as_ctx); - if (err) - goto out_err; + /* + * We'll skip setting fscrypt context for snapshots, leaving that for + * the handle_reply(). + */ + if (ceph_snap(dir) !=3D CEPH_SNAPDIR) { + err =3D ceph_fscrypt_prepare_context(dir, inode, as_ctx); + if (err) + goto out_err; + } =20 return inode; out_err: @@ -157,6 +163,7 @@ struct inode *ceph_get_snapdir(struct inode *parent) }; struct inode *inode =3D ceph_get_inode(parent->i_sb, vino, NULL); struct ceph_inode_info *ci =3D ceph_inode(inode); + int ret =3D -ENOTDIR; =20 if (IS_ERR(inode)) return inode; @@ -182,6 +189,22 @@ struct inode *ceph_get_snapdir(struct inode *parent) ci->i_rbytes =3D 0; ci->i_btime =3D ceph_inode(parent)->i_btime; =20 + /* if encrypted, just borrow fscrypt_auth from parent */ + if (IS_ENCRYPTED(parent)) { + struct ceph_inode_info *pci =3D ceph_inode(parent); + + ci->fscrypt_auth =3D kmemdup(pci->fscrypt_auth, + pci->fscrypt_auth_len, + GFP_KERNEL); + if (ci->fscrypt_auth) { + inode->i_flags |=3D S_ENCRYPTED; + ci->fscrypt_auth_len =3D pci->fscrypt_auth_len; + } else { + dout("Failed to alloc snapdir fscrypt_auth\n"); + ret =3D -ENOMEM; + goto err; + } + } if (inode->i_state & I_NEW) { inode->i_op =3D &ceph_snapdir_iops; inode->i_fop =3D &ceph_snapdir_fops; @@ -195,7 +218,7 @@ struct inode *ceph_get_snapdir(struct inode *parent) discard_new_inode(inode); else iput(inode); - return ERR_PTR(-ENOTDIR); + return ERR_PTR(ret); } =20 const struct inode_operations ceph_file_iops =3D { From nobody Mon May 11 04:12:40 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0B680C4332F for ; Thu, 14 Apr 2022 15:20:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1343548AbiDNPUl (ORCPT ); Thu, 14 Apr 2022 11:20:41 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43260 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1347659AbiDNN7Z (ORCPT ); Thu, 14 Apr 2022 09:59:25 -0400 Received: from smtp-out1.suse.de (smtp-out1.suse.de [195.135.220.28]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id BD4C547077; Thu, 14 Apr 2022 06:51:01 -0700 (PDT) Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out1.suse.de (Postfix) with ESMTPS id 60E2A21614; Thu, 14 Apr 2022 13:51:00 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1649944260; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=cu68SN1IUUySsr+jjj2rTCf7GS5VCe8GS76dH2LjJMQ=; b=HioUu2WvUe871Ds3nmVxrSjTDE0a+pfdtbfxnKgJXk8tyXZmy8M8JumL/HwaVeA/Bd4IXm kWZoxsDN0ehte/ZncUsnl/RJ2a2P0yCKrrsnPIfed4HsL8PqLVkf7kawVu74vZbs2du5OO zQeYIghnz879DYb9kyLwBiEMabi+/XY= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1649944260; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=cu68SN1IUUySsr+jjj2rTCf7GS5VCe8GS76dH2LjJMQ=; b=grlvI+pMcA3Tql4WjhMQjd4SFHrVS6ASHMl2gWk8RSIFZjFec5STGiDebEtBy0Xvu//DMD H3lCmqWkA9o0moCg== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id ED5E7132C0; Thu, 14 Apr 2022 13:50:59 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id kOMYN8MmWGJnTgAAMHmgww (envelope-from ); Thu, 14 Apr 2022 13:50:59 +0000 Received: from localhost (brahms.olymp [local]) by brahms.olymp (OpenSMTPD) with ESMTPA id bc9f9603; Thu, 14 Apr 2022 13:51:24 +0000 (UTC) From: =?UTF-8?q?Lu=C3=ADs=20Henriques?= To: Jeff Layton , Xiubo Li , Ilya Dryomov Cc: ceph-devel@vger.kernel.org, linux-kernel@vger.kernel.org, =?UTF-8?q?Lu=C3=ADs=20Henriques?= Subject: [PATCH v4 2/4] ceph: add support for handling encrypted snapshot names Date: Thu, 14 Apr 2022 14:51:20 +0100 Message-Id: <20220414135122.26821-3-lhenriques@suse.de> In-Reply-To: <20220414135122.26821-1-lhenriques@suse.de> References: <20220414135122.26821-1-lhenriques@suse.de> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org When creating a snapshot, the .snap directories for every subdirectory will show the snapshot name in the "long format": # mkdir .snap/my-snap # ls my-dir/.snap/ _my-snap_1099511627782 Encrypted snapshots will need to be able to handle these snapshot names by encrypting/decrypting only the snapshot part of the string ('my-snap'). Also, since the MDS prevents snapshot names to be bigger than 240 characters it is necessary to adapt CEPH_NOHASH_NAME_MAX to accommodate this extra limitation. Signed-off-by: Lu=C3=ADs Henriques Reviewed-by: Xiubo Li --- fs/ceph/crypto.c | 190 ++++++++++++++++++++++++++++++++++++++++------- fs/ceph/crypto.h | 11 ++- 2 files changed, 170 insertions(+), 31 deletions(-) diff --git a/fs/ceph/crypto.c b/fs/ceph/crypto.c index e24e61c51118..1fa9dd634a6f 100644 --- a/fs/ceph/crypto.c +++ b/fs/ceph/crypto.c @@ -129,16 +129,100 @@ void ceph_fscrypt_as_ctx_to_req(struct ceph_mds_requ= est *req, struct ceph_acl_se swap(req->r_fscrypt_auth, as->fscrypt_auth); } =20 -int ceph_encode_encrypted_dname(const struct inode *parent, struct qstr *d= _name, char *buf) +/* + * User-created snapshots can't start with '_'. Snapshots that start with= this + * character are special (hint: there aren't real snapshots) and use the + * following format: + * + * __ + * + * where: + * - - the real snapshot name that may need to be decrypt= ed, + * - - the inode number for the actual snapshot + * + * This function parses these snapshot names and returns the inode + * . 'name_len' will also bet set with the + * length. + */ +static struct inode *parse_longname(const struct inode *parent, const char= *name, + int *name_len) { + struct inode *dir =3D NULL; + struct ceph_vino vino =3D { .snap =3D CEPH_NOSNAP }; + char *inode_number; + char *name_end; + int orig_len =3D *name_len; + int ret =3D -EIO; + + /* Skip initial '_' */ + name++; + name_end =3D strrchr(name, '_'); + if (!name_end) { + dout("Failed to parse long snapshot name: %s\n", name); + return ERR_PTR(-EIO); + } + *name_len =3D (name_end - name); + if (*name_len <=3D 0) { + pr_err("Failed to parse long snapshot name\n"); + return ERR_PTR(-EIO); + } + + /* Get the inode number */ + inode_number =3D kmemdup_nul(name_end + 1, + orig_len - *name_len - 2, + GFP_KERNEL); + if (!inode_number) + return ERR_PTR(-ENOMEM); + ret =3D kstrtou64(inode_number, 0, &vino.ino); + if (ret) { + dout("Failed to parse inode number: %s\n", name); + dir =3D ERR_PTR(ret); + goto out; + } + + /* And finally the inode */ + dir =3D ceph_find_inode(parent->i_sb, vino); + if (!dir) { + /* This can happen if we're not mounting cephfs on the root */ + dir =3D ceph_get_inode(parent->i_sb, vino, NULL); + if (!dir) + dir =3D ERR_PTR(-ENOENT); + } + if (IS_ERR(dir)) + dout("Can't find inode %s (%s)\n", inode_number, name); + +out: + kfree(inode_number); + return dir; +} + +int ceph_encode_encrypted_dname(struct inode *parent, struct qstr *d_name,= char *buf) +{ + struct inode *dir =3D parent; + struct qstr iname; u32 len; + int name_len; int elen; int ret; - u8 *cryptbuf; + u8 *cryptbuf =3D NULL; + + iname.name =3D d_name->name; + name_len =3D d_name->len; + + /* Handle the special case of snapshot names that start with '_' */ + if ((ceph_snap(dir) =3D=3D CEPH_SNAPDIR) && (name_len > 0) && + (iname.name[0] =3D=3D '_')) { + dir =3D parse_longname(parent, iname.name, &name_len); + if (IS_ERR(dir)) + return PTR_ERR(dir); + iname.name++; /* skip initial '_' */ + } + iname.len =3D name_len; =20 - if (!fscrypt_has_encryption_key(parent)) { + if (!fscrypt_has_encryption_key(dir)) { memcpy(buf, d_name->name, d_name->len); - return d_name->len; + elen =3D d_name->len; + goto out; } =20 /* @@ -147,18 +231,22 @@ int ceph_encode_encrypted_dname(const struct inode *p= arent, struct qstr *d_name, * * See: fscrypt_setup_filename */ - if (!fscrypt_fname_encrypted_size(parent, d_name->len, NAME_MAX, &len)) - return -ENAMETOOLONG; + if (!fscrypt_fname_encrypted_size(dir, iname.len, NAME_MAX, &len)) { + elen =3D -ENAMETOOLONG; + goto out; + } =20 /* Allocate a buffer appropriate to hold the result */ cryptbuf =3D kmalloc(len > CEPH_NOHASH_NAME_MAX ? NAME_MAX : len, GFP_KER= NEL); - if (!cryptbuf) - return -ENOMEM; + if (!cryptbuf) { + elen =3D -ENOMEM; + goto out; + } =20 - ret =3D fscrypt_fname_encrypt(parent, d_name, cryptbuf, len); + ret =3D fscrypt_fname_encrypt(dir, &iname, cryptbuf, len); if (ret) { - kfree(cryptbuf); - return ret; + elen =3D ret; + goto out; } =20 /* hash the end if the name is long enough */ @@ -174,12 +262,30 @@ int ceph_encode_encrypted_dname(const struct inode *p= arent, struct qstr *d_name, =20 /* base64 encode the encrypted name */ elen =3D fscrypt_base64url_encode(cryptbuf, len, buf); - kfree(cryptbuf); dout("base64-encoded ciphertext name =3D %.*s\n", elen, buf); + + /* To understand the 240 limit, see CEPH_NOHASH_NAME_MAX comments */ + WARN_ON(elen > 240); + if ((elen > 0) && (dir !=3D parent)) { + char tmp_buf[NAME_MAX]; + + elen =3D snprintf(tmp_buf, sizeof(tmp_buf), "_%.*s_%ld", + elen, buf, dir->i_ino); + memcpy(buf, tmp_buf, elen); + } + +out: + kfree(cryptbuf); + if (dir !=3D parent) { + if ((dir->i_state & I_NEW)) + discard_new_inode(dir); + else + iput(dir); + } return elen; } =20 -int ceph_encode_encrypted_fname(const struct inode *parent, struct dentry = *dentry, char *buf) +int ceph_encode_encrypted_fname(struct inode *parent, struct dentry *dentr= y, char *buf) { WARN_ON_ONCE(!fscrypt_has_encryption_key(parent)); =20 @@ -204,29 +310,42 @@ int ceph_encode_encrypted_fname(const struct inode *p= arent, struct dentry *dentr int ceph_fname_to_usr(const struct ceph_fname *fname, struct fscrypt_str *= tname, struct fscrypt_str *oname, bool *is_nokey) { - int ret; + struct inode *dir =3D fname->dir; struct fscrypt_str _tname =3D FSTR_INIT(NULL, 0); struct fscrypt_str iname; - - if (!IS_ENCRYPTED(fname->dir)) { - oname->name =3D fname->name; - oname->len =3D fname->name_len; - return 0; - } + char *name =3D fname->name; + int name_len =3D fname->name_len; + int ret; =20 /* Sanity check that the resulting name will fit in the buffer */ if (fname->name_len > NAME_MAX || fname->ctext_len > NAME_MAX) return -EIO; =20 - ret =3D __fscrypt_prepare_readdir(fname->dir); + /* Handle the special case of snapshot names that start with '_' */ + if ((ceph_snap(dir) =3D=3D CEPH_SNAPDIR) && (name_len > 0) && + (name[0] =3D=3D '_')) { + dir =3D parse_longname(dir, name, &name_len); + if (IS_ERR(dir)) + return PTR_ERR(dir); + name++; /* skip initial '_' */ + } + + if (!IS_ENCRYPTED(dir)) { + oname->name =3D fname->name; + oname->len =3D fname->name_len; + ret =3D 0; + goto out_inode; + } + + ret =3D __fscrypt_prepare_readdir(dir); if (ret) - return ret; + goto out_inode; =20 /* * Use the raw dentry name as sent by the MDS instead of * generating a nokey name via fscrypt. */ - if (!fscrypt_has_encryption_key(fname->dir)) { + if (!fscrypt_has_encryption_key(dir)) { if (fname->no_copy) oname->name =3D fname->name; else @@ -234,7 +353,8 @@ int ceph_fname_to_usr(const struct ceph_fname *fname, s= truct fscrypt_str *tname, oname->len =3D fname->name_len; if (is_nokey) *is_nokey =3D true; - return 0; + ret =3D 0; + goto out_inode; } =20 if (fname->ctext_len =3D=3D 0) { @@ -243,11 +363,11 @@ int ceph_fname_to_usr(const struct ceph_fname *fname,= struct fscrypt_str *tname, if (!tname) { ret =3D fscrypt_fname_alloc_buffer(NAME_MAX, &_tname); if (ret) - return ret; + goto out_inode; tname =3D &_tname; } =20 - declen =3D fscrypt_base64url_decode(fname->name, fname->name_len, tname-= >name); + declen =3D fscrypt_base64url_decode(name, name_len, tname->name); if (declen <=3D 0) { ret =3D -EIO; goto out; @@ -259,9 +379,25 @@ int ceph_fname_to_usr(const struct ceph_fname *fname, = struct fscrypt_str *tname, iname.len =3D fname->ctext_len; } =20 - ret =3D fscrypt_fname_disk_to_usr(fname->dir, 0, 0, &iname, oname); + ret =3D fscrypt_fname_disk_to_usr(dir, 0, 0, &iname, oname); + if (!ret && (dir !=3D fname->dir)) { + char tmp_buf[FSCRYPT_BASE64URL_CHARS(NAME_MAX)]; + + name_len =3D snprintf(tmp_buf, sizeof(tmp_buf), "_%.*s_%ld", + oname->len, oname->name, dir->i_ino); + memcpy(oname->name, tmp_buf, name_len); + oname->len =3D name_len; + } + out: fscrypt_fname_free_buffer(&_tname); +out_inode: + if ((dir !=3D fname->dir) && !IS_ERR(dir)) { + if ((dir->i_state & I_NEW)) + discard_new_inode(dir); + else + iput(dir); + } return ret; } =20 diff --git a/fs/ceph/crypto.h b/fs/ceph/crypto.h index 0cf526f07567..0e10f934af5c 100644 --- a/fs/ceph/crypto.h +++ b/fs/ceph/crypto.h @@ -78,13 +78,16 @@ static inline u32 ceph_fscrypt_auth_len(struct ceph_fsc= rypt_auth *fa) * struct fscrypt_ceph_nokey_name { * u8 bytes[157]; * u8 sha256[SHA256_DIGEST_SIZE]; - * }; // 189 bytes =3D> 252 bytes base64-encoded, which is <=3D NAME_MAX (= 255) + * }; // 180 bytes =3D> 240 bytes base64-encoded, which is <=3D NAME_MAX (= 255) + * + * (240 bytes is the maximum size allowed for snapshot names to take into + * account the format: '__'.) * * Note that for long names that end up having their tail portion hashed, = we * must also store the full encrypted name (in the dentry's alternate_name * field). */ -#define CEPH_NOHASH_NAME_MAX (189 - SHA256_DIGEST_SIZE) +#define CEPH_NOHASH_NAME_MAX (180 - SHA256_DIGEST_SIZE) =20 void ceph_fscrypt_set_ops(struct super_block *sb); =20 @@ -93,8 +96,8 @@ void ceph_fscrypt_free_dummy_policy(struct ceph_fs_client= *fsc); int ceph_fscrypt_prepare_context(struct inode *dir, struct inode *inode, struct ceph_acl_sec_ctx *as); void ceph_fscrypt_as_ctx_to_req(struct ceph_mds_request *req, struct ceph_= acl_sec_ctx *as); -int ceph_encode_encrypted_dname(const struct inode *parent, struct qstr *d= _name, char *buf); -int ceph_encode_encrypted_fname(const struct inode *parent, struct dentry = *dentry, char *buf); +int ceph_encode_encrypted_dname(struct inode *parent, struct qstr *d_name,= char *buf); +int ceph_encode_encrypted_fname(struct inode *parent, struct dentry *dentr= y, char *buf); =20 static inline int ceph_fname_alloc_buffer(struct inode *parent, struct fsc= rypt_str *fname) { From nobody Mon May 11 04:12:40 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0BA52C433F5 for ; Thu, 14 Apr 2022 15:20:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1354744AbiDNPS1 (ORCPT ); Thu, 14 Apr 2022 11:18:27 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43372 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1347662AbiDNN70 (ORCPT ); Thu, 14 Apr 2022 09:59:26 -0400 Received: from smtp-out2.suse.de (smtp-out2.suse.de [195.135.220.29]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 46BE24707A; Thu, 14 Apr 2022 06:51:02 -0700 (PDT) Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id D7A0E1F748; Thu, 14 Apr 2022 13:51:00 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1649944260; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=8zj/qp1HcgBQX+/4vlQAgG9P0stPwQSdbGTrHMd1YsE=; b=bTcgkcf8ztn4CmqvW/jNOBLqNRtzRP+RDN6cNUaEQs/bH5zU27ADWbcilPDEAzR2Yz2fAD BZEM4XIC1h4TocI9fay50TaVF8su17gJWfB11TGgluQuLIyK0jwfzMkFttthzHNH2ckBTH qOrcpF4CY5APr2Fr01DyqqbKUg1/eo8= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1649944260; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=8zj/qp1HcgBQX+/4vlQAgG9P0stPwQSdbGTrHMd1YsE=; b=1x3CnwOTKE5IX0W9CQhhgzPTP+mIgsHI7jW9usVyMLgN2LfoUmjieYzKPvIrYklIASKj03 nhUml7p89qGXefBg== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id 731A2132C0; Thu, 14 Apr 2022 13:51:00 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id UAcwGcQmWGJnTgAAMHmgww (envelope-from ); Thu, 14 Apr 2022 13:51:00 +0000 Received: from localhost (brahms.olymp [local]) by brahms.olymp (OpenSMTPD) with ESMTPA id c633f8db; Thu, 14 Apr 2022 13:51:24 +0000 (UTC) From: =?UTF-8?q?Lu=C3=ADs=20Henriques?= To: Jeff Layton , Xiubo Li , Ilya Dryomov Cc: ceph-devel@vger.kernel.org, linux-kernel@vger.kernel.org, =?UTF-8?q?Lu=C3=ADs=20Henriques?= Subject: [PATCH v4 3/4] ceph: update documentation regarding snapshot naming limitations Date: Thu, 14 Apr 2022 14:51:21 +0100 Message-Id: <20220414135122.26821-4-lhenriques@suse.de> In-Reply-To: <20220414135122.26821-1-lhenriques@suse.de> References: <20220414135122.26821-1-lhenriques@suse.de> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Signed-off-by: Lu=C3=ADs Henriques Reviewed-by: Xiubo Li --- Documentation/filesystems/ceph.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Documentation/filesystems/ceph.rst b/Documentation/filesystems= /ceph.rst index 4942e018db85..d487cabe792d 100644 --- a/Documentation/filesystems/ceph.rst +++ b/Documentation/filesystems/ceph.rst @@ -57,6 +57,16 @@ a snapshot on any subdirectory (and its nested contents)= in the system. Snapshot creation and deletion are as simple as 'mkdir .snap/foo' and 'rmdir .snap/foo'. =20 +Snapshot names have two limitations: + +* They can not start with an underscore ('_'), as these names are reserved + for internal usage by the MDS. +* They can not exceed 240 characters in size. This is because the MDS mak= es + use of long snapshot names internally, which follow the format: + `__`. Since filenames in general can't have + more than 255 characters, and `` takes 13 characters, the long + snapshot names can take as much as 255 - 1 - 1 - 13 =3D 240. + Ceph also provides some recursive accounting on directories for nested files and bytes. That is, a 'getfattr -d foo' on any directory in the system will reveal the total number of nested regular files and From nobody Mon May 11 04:12:40 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A665AC433F5 for ; Thu, 14 Apr 2022 15:20:11 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1356060AbiDNPSa (ORCPT ); Thu, 14 Apr 2022 11:18:30 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43414 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1347667AbiDNN70 (ORCPT ); Thu, 14 Apr 2022 09:59:26 -0400 Received: from smtp-out1.suse.de (smtp-out1.suse.de [195.135.220.28]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AFECF4707F; Thu, 14 Apr 2022 06:51:02 -0700 (PDT) Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out1.suse.de (Postfix) with ESMTPS id 5AE2A21615; Thu, 14 Apr 2022 13:51:01 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1649944261; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=dYu8vIYx3wq/1oLGXfYf1q5L4rYJ/h1RWxYRhBgaOaI=; b=nSNFWtCWGsgU2i333wP83WKVbq6mXMux4ySlC/iJnBopR6jAdOGpE3BEV16w3rdyfj6l7x HvA5jO54f4V6xcfNtvDZz03xtviqi9ZSvJnZguW9UIX7URb6U4a0KYCToOTI5j7u+EEZ6r fMLl5ppXBi/lw4zyMNvcaJJrCnnIoDs= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1649944261; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=dYu8vIYx3wq/1oLGXfYf1q5L4rYJ/h1RWxYRhBgaOaI=; b=s8qiFMJDSx2Kl/uVuz0kHJgJvH6hKF/Zwm9eIrCyDjgDDdy0g444QHix3TiRD+gj6dF8/I 1U2FPkocLdicipAA== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id EA5AB132C0; Thu, 14 Apr 2022 13:51:00 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id 8EJLNsQmWGJnTgAAMHmgww (envelope-from ); Thu, 14 Apr 2022 13:51:00 +0000 Received: from localhost (brahms.olymp [local]) by brahms.olymp (OpenSMTPD) with ESMTPA id 4d1c80aa; Thu, 14 Apr 2022 13:51:24 +0000 (UTC) From: =?UTF-8?q?Lu=C3=ADs=20Henriques?= To: Jeff Layton , Xiubo Li , Ilya Dryomov Cc: ceph-devel@vger.kernel.org, linux-kernel@vger.kernel.org, =?UTF-8?q?Lu=C3=ADs=20Henriques?= Subject: [PATCH v4 4/4] ceph: replace base64url by the encoding used for mailbox names Date: Thu, 14 Apr 2022 14:51:22 +0100 Message-Id: <20220414135122.26821-5-lhenriques@suse.de> In-Reply-To: <20220414135122.26821-1-lhenriques@suse.de> References: <20220414135122.26821-1-lhenriques@suse.de> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The base64url encoding includes the '_' character, which may cause problems in snapshot names (if the name starts with '_'). Thus, use the base64 encoding defined for IMAP mailbox names (RFC 3501), which uses '+' and ',' instead of '-' and '_'. Signed-off-by: Lu=C3=ADs Henriques Reviewed-by: Xiubo Li --- fs/ceph/crypto.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++-- fs/ceph/crypto.h | 3 +++ fs/ceph/dir.c | 2 +- fs/ceph/inode.c | 2 +- 4 files changed, 67 insertions(+), 4 deletions(-) diff --git a/fs/ceph/crypto.c b/fs/ceph/crypto.c index 1fa9dd634a6f..1adf97b00a4f 100644 --- a/fs/ceph/crypto.c +++ b/fs/ceph/crypto.c @@ -1,4 +1,11 @@ // SPDX-License-Identifier: GPL-2.0 +/* + * The base64 encode/decode code was copied from fscrypt: + * Copyright (C) 2015, Google, Inc. + * Copyright (C) 2015, Motorola Mobility + * Written by Uday Savagaonkar, 2014. + * Modified by Jaegeuk Kim, 2015. + */ #include #include #include @@ -8,6 +15,59 @@ #include "mds_client.h" #include "crypto.h" =20 +/* + * The base64url encoding used by fscrypt includes the '_' character, whic= h may + * cause problems in snapshot names (which can not starts with '_'). Thus= , we + * used the base64 encoding defined for IMAP mailbox names (RFC 3501) inst= ead, + * which replaces '-' and '_' by '+' and ','. + */ +static const char base64_table[65] =3D + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,"; + +int ceph_base64_encode(const u8 *src, int srclen, char *dst) +{ + u32 ac =3D 0; + int bits =3D 0; + int i; + char *cp =3D dst; + + for (i =3D 0; i < srclen; i++) { + ac =3D (ac << 8) | src[i]; + bits +=3D 8; + do { + bits -=3D 6; + *cp++ =3D base64_table[(ac >> bits) & 0x3f]; + } while (bits >=3D 6); + } + if (bits) + *cp++ =3D base64_table[(ac << (6 - bits)) & 0x3f]; + return cp - dst; +} + +int ceph_base64_decode(const char *src, int srclen, u8 *dst) +{ + u32 ac =3D 0; + int bits =3D 0; + int i; + u8 *bp =3D dst; + + for (i =3D 0; i < srclen; i++) { + const char *p =3D strchr(base64_table, src[i]); + + if (p =3D=3D NULL || src[i] =3D=3D 0) + return -1; + ac =3D (ac << 6) | (p - base64_table); + bits +=3D 6; + if (bits >=3D 8) { + bits -=3D 8; + *bp++ =3D (u8)(ac >> bits); + } + } + if (ac & ((1 << bits) - 1)) + return -1; + return bp - dst; +} + static int ceph_crypt_get_context(struct inode *inode, void *ctx, size_t l= en) { struct ceph_inode_info *ci =3D ceph_inode(inode); @@ -261,7 +321,7 @@ int ceph_encode_encrypted_dname(struct inode *parent, s= truct qstr *d_name, char } =20 /* base64 encode the encrypted name */ - elen =3D fscrypt_base64url_encode(cryptbuf, len, buf); + elen =3D ceph_base64_encode(cryptbuf, len, buf); dout("base64-encoded ciphertext name =3D %.*s\n", elen, buf); =20 /* To understand the 240 limit, see CEPH_NOHASH_NAME_MAX comments */ @@ -367,7 +427,7 @@ int ceph_fname_to_usr(const struct ceph_fname *fname, s= truct fscrypt_str *tname, tname =3D &_tname; } =20 - declen =3D fscrypt_base64url_decode(name, name_len, tname->name); + declen =3D ceph_base64_decode(name, name_len, tname->name); if (declen <=3D 0) { ret =3D -EIO; goto out; diff --git a/fs/ceph/crypto.h b/fs/ceph/crypto.h index 0e10f934af5c..63fb230fcb41 100644 --- a/fs/ceph/crypto.h +++ b/fs/ceph/crypto.h @@ -89,6 +89,9 @@ static inline u32 ceph_fscrypt_auth_len(struct ceph_fscry= pt_auth *fa) */ #define CEPH_NOHASH_NAME_MAX (180 - SHA256_DIGEST_SIZE) =20 +int ceph_base64_encode(const u8 *src, int srclen, char *dst); +int ceph_base64_decode(const char *src, int srclen, u8 *dst); + void ceph_fscrypt_set_ops(struct super_block *sb); =20 void ceph_fscrypt_free_dummy_policy(struct ceph_fs_client *fsc); diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 5ccf6453f02f..f48f1ff20927 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c @@ -966,7 +966,7 @@ static int prep_encrypted_symlink_target(struct ceph_md= s_request *req, const cha goto out; } =20 - len =3D fscrypt_base64url_encode(osd_link.name, osd_link.len, req->r_path= 2); + len =3D ceph_base64_encode(osd_link.name, osd_link.len, req->r_path2); req->r_path2[len] =3D '\0'; out: fscrypt_fname_free_buffer(&osd_link); diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 8e97efa2b1a7..1df2eab767ef 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -876,7 +876,7 @@ static int decode_encrypted_symlink(const char *encsym,= int enclen, u8 **decsym) if (!sym) return -ENOMEM; =20 - declen =3D fscrypt_base64url_decode(encsym, enclen, sym); + declen =3D ceph_base64_decode(encsym, enclen, sym); if (declen < 0) { pr_err("%s: can't decode symlink (%d). Content: %.*s\n", __func__, declen, enclen, encsym); From nobody Mon May 11 04:12:40 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id AA989C3527C for ; Mon, 18 Apr 2022 14:17:02 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1345102AbiDROSs (ORCPT ); Mon, 18 Apr 2022 10:18:48 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56522 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S244924AbiDRN6F (ORCPT ); Mon, 18 Apr 2022 09:58:05 -0400 Received: from smtp-out2.suse.de (smtp-out2.suse.de [195.135.220.29]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6C31726D9; Mon, 18 Apr 2022 06:08:15 -0700 (PDT) Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id D29A81F381; Mon, 18 Apr 2022 13:08:13 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1650287293; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=iBYQm7Rp5LG8jKxerzOsfwWsTzE/H7NffrHSL2IyD+s=; b=TocHSoPX9e5EcicfNhzjUIFR8D2OXV/K3lKZJSWWVrMF+nTO7p7lqWZukGYiNMgRhCcI2S HJTiKL4rTD0OvGEQAOmlFBlwQU9KUgEqfF2NSk75WGi21Uhzu2sWGHOdZf5AjIbAxK3aiV lCTohJTbyaE21PBqte+yxlpTjKOPTik= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1650287293; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=iBYQm7Rp5LG8jKxerzOsfwWsTzE/H7NffrHSL2IyD+s=; b=xGtN1dHwZEvL/X5HVK+Vrt3cgkkqhFrdYXZs9AO3qJxgafORU/jLMoBegjJTpsRHqcEzFE xlEstEnrU2eBGDAg== Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id 68C5D13ACB; Mon, 18 Apr 2022 13:08:13 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id Dj9SFr1iXWLcLwAAMHmgww (envelope-from ); Mon, 18 Apr 2022 13:08:13 +0000 Received: from localhost (brahms.olymp [local]) by brahms.olymp (OpenSMTPD) with ESMTPA id 150a3546; Mon, 18 Apr 2022 13:08:40 +0000 (UTC) From: =?UTF-8?q?Lu=C3=ADs=20Henriques?= To: Jeff Layton , Xiubo Li , Ilya Dryomov Cc: ceph-devel@vger.kernel.org, linux-kernel@vger.kernel.org, =?UTF-8?q?Lu=C3=ADs=20Henriques?= Subject: [PATCH] ceph: prevent snapshots to be created in encrypted locked directories Date: Mon, 18 Apr 2022 14:08:39 +0100 Message-Id: <20220418130839.9862-1-lhenriques@suse.de> In-Reply-To: <20220414135122.26821-1-lhenriques@suse.de> References: <20220414135122.26821-1-lhenriques@suse.de> MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org With snapshot names encryption we can not allow snapshots to be created in locked directories because the names wouldn't be encrypted. This patch forces the directory to be unlocked to allow a snapshot to be created. Signed-off-by: Lu=C3=ADs Henriques Reviewed-by: Xiubo Li --- fs/ceph/dir.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index f48f1ff20927..93e2f08102a1 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c @@ -1071,6 +1071,10 @@ static int ceph_mkdir(struct user_namespace *mnt_use= rns, struct inode *dir, err =3D -EDQUOT; goto out; } + if ((op =3D=3D CEPH_MDS_OP_MKSNAP) && !fscrypt_has_encryption_key(dir)) { + err =3D -ENOKEY; + goto out; + } =20 =20 req =3D ceph_mdsc_create_request(mdsc, op, USE_AUTH_MDS);