From: Sebastien Buisson Date: Mon, 8 Jul 2019 14:51:39 +0000 (+0000) Subject: LU-12275 sec: enable client side encryption X-Git-Tag: 2.13.55~169 X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=commitdiff_plain;h=28be31137cd22223113e461f74098c92ba6d71e4 LU-12275 sec: enable client side encryption Enable client side encryption. By default it is activated, letting user specifies actual encryption policy to use on a per-directory basis. It is possible to deactivate client side encryption by using the 'noencrypt' mount option. Also add the test dummy encryption mode option to ease testing. Signed-off-by: Sebastien Buisson Change-Id: I0e8d4db7ab8a77aba0600788cca9403f7c50f8a6 Reviewed-on: https://review.whamcloud.com/36143 Reviewed-by: John L. Hammond Reviewed-by: Andreas Dilger Tested-by: jenkins Tested-by: Maloo Reviewed-by: Oleg Drokin --- diff --git a/MAINTAINERS b/MAINTAINERS index 137e272..6ca8902 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -133,9 +133,14 @@ Lustre client side encryption M: Sebastien Buisson S: Maintained F: Documentation/client_side_encryption/*.txt +F: lustre/llite/crypto*.[ch] F: libcfs/libcfs/crypto/*.[ch] F: libcfs/include/libcfs/crypto/*.h F: libcfs/include/uapi/linux/llcrypt.h +F: lustre/include/lustre_crypto.h +K: fscrypt +K: llcrypt +K: HAVE_LUSTRE_CRYPTO Lustre Client VFS Interface R: Oleg Drokin diff --git a/lustre/autoconf/lustre-core.m4 b/lustre/autoconf/lustre-core.m4 index ac986de..4f9ce29 100644 --- a/lustre/autoconf/lustre-core.m4 +++ b/lustre/autoconf/lustre-core.m4 @@ -2655,6 +2655,8 @@ No selinux package found, unable to build selinux enabled tools ]) AC_SUBST(SELINUX) +AC_CHECK_LIB([keyutils], [add_key]) + # Super safe df AC_MSG_CHECKING([whether to report minimum OST free space]) AC_ARG_ENABLE([mindf], diff --git a/lustre/doc/mount.lustre.8 b/lustre/doc/mount.lustre.8 index f2fb607..cc1a25a 100644 --- a/lustre/doc/mount.lustre.8 +++ b/lustre/doc/mount.lustre.8 @@ -221,6 +221,16 @@ Warning! 'network' option is incompatible with LNet Dynamic Peer Discovery. If you want to restrict client NID, please make sure LNet Dynamic Peer Discovery is disabled. .RE +.TP +.BI test_dummy_encryption +Enable test dummy encryption mode. +.RE +.TP +.BI noencrypt +Disable Lustre client-side encryption. By default, Lustre client-side encryption +is enabled, letting users define encryption policies on a per-directory basis. +fscrypt userspace tool can be used for that purpose, see +https://github.com/google/fscrypt .SH SERVER OPTIONS In addition to the standard mount options and backing disk type (e.g. ldiskfs) options listed in diff --git a/lustre/include/Makefile.am b/lustre/include/Makefile.am index 0dcd3c2..16a6cab 100644 --- a/lustre/include/Makefile.am +++ b/lustre/include/Makefile.am @@ -47,6 +47,7 @@ EXTRA_DIST = \ lustre_acl.h \ lustre_barrier.h \ lustre_compat.h \ + lustre_crypto.h \ lustre_debug.h \ lustre_disk.h \ lustre_dlm_flags.h \ diff --git a/lustre/include/lustre_crypto.h b/lustre/include/lustre_crypto.h new file mode 100644 index 0000000..63f7696 --- /dev/null +++ b/lustre/include/lustre_crypto.h @@ -0,0 +1,109 @@ +/* + * GPL HEADER START + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 only, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 for more details (a copy is included + * in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; If not, see + * http://www.gnu.org/licenses/gpl-2.0.html + * + * GPL HEADER END + */ +/* + * Copyright (c) 2019, 2020, Whamcloud. + */ +/* + * This file is part of Lustre, http://www.lustre.org/ + */ + +#ifndef _LUSTRE_CRYPTO_H_ +#define _LUSTRE_CRYPTO_H_ + +struct ll_sb_info; +bool ll_sbi_has_test_dummy_encryption(struct ll_sb_info *sbi); +bool ll_sbi_has_encrypt(struct ll_sb_info *sbi); +void ll_sbi_set_encrypt(struct ll_sb_info *sbi, bool set); + +#ifdef CONFIG_LL_ENCRYPTION +#include +#else /* !CONFIG_LL_ENCRYPTION */ +#ifdef HAVE_LUSTRE_CRYPTO +#define __FS_HAS_ENCRYPTION 1 +#include + +#define llcrypt_operations fscrypt_operations +#define llcrypt_symlink_data fscrypt_symlink_data +#define llcrypt_dummy_context_enabled(inode) \ + fscrypt_dummy_context_enabled(inode) +#define llcrypt_has_encryption_key(inode) fscrypt_has_encryption_key(inode) +#define llcrypt_encrypt_pagecache_blocks(page, len, offs, gfp_flags) \ + fscrypt_encrypt_pagecache_blocks(page, len, offs, gfp_flags) +#define llcrypt_decrypt_pagecache_blocks(page, len, offs) \ + fscrypt_decrypt_pagecache_blocks(page, len, offs) +#define llcrypt_inherit_context(parent, child, fs_data, preload) \ + fscrypt_inherit_context(parent, child, fs_data, preload) +#define llcrypt_get_encryption_info(inode) fscrypt_get_encryption_info(inode) +#define llcrypt_put_encryption_info(inode) fscrypt_put_encryption_info(inode) +#define llcrypt_free_inode(inode) fscrypt_free_inode(inode) +#define llcrypt_finalize_bounce_page(pagep) fscrypt_finalize_bounce_page(pagep) +#define llcrypt_file_open(inode, filp) fscrypt_file_open(inode, filp) +#define llcrypt_ioctl_set_policy(filp, arg) fscrypt_ioctl_set_policy(filp, arg) +#define llcrypt_ioctl_get_policy_ex(filp, arg) \ + fscrypt_ioctl_get_policy_ex(filp, arg) +#define llcrypt_ioctl_add_key(filp, arg) fscrypt_ioctl_add_key(filp, arg) +#define llcrypt_ioctl_remove_key(filp, arg) fscrypt_ioctl_remove_key(filp, arg) +#define llcrypt_ioctl_remove_key_all_users(filp, arg) \ + fscrypt_ioctl_remove_key_all_users(filp, arg) +#define llcrypt_ioctl_get_key_status(filp, arg) \ + fscrypt_ioctl_get_key_status(filp, arg) +#define llcrypt_drop_inode(inode) fscrypt_drop_inode(inode) +#define llcrypt_prepare_rename(olddir, olddentry, newdir, newdentry, flags) \ + fscrypt_prepare_rename(olddir, olddentry, newdir, newdentry, flags) +#define llcrypt_prepare_link(old_dentry, dir, dentry) \ + fscrypt_prepare_link(old_dentry, dir, dentry) +#define llcrypt_prepare_setattr(dentry, attr) \ + fscrypt_prepare_setattr(dentry, attr) +#define llcrypt_set_ops(sb, cop) fscrypt_set_ops(sb, cop) +#else /* !HAVE_LUSTRE_CRYPTO */ +#undef IS_ENCRYPTED +#define IS_ENCRYPTED(x) 0 +#define llcrypt_dummy_context_enabled(inode) NULL +/* copied from include/linux/fscrypt.h */ +#define llcrypt_has_encryption_key(inode) false +#define llcrypt_encrypt_pagecache_blocks(page, len, offs, gfp_flags) \ + ERR_PTR(-EOPNOTSUPP) +#define llcrypt_decrypt_pagecache_blocks(page, len, offs) -EOPNOTSUPP +#define llcrypt_inherit_context(parent, child, fs_data, preload) -EOPNOTSUPP +#define llcrypt_get_encryption_info(inode) -EOPNOTSUPP +#define llcrypt_put_encryption_info(inode) do {} while (0) +#define llcrypt_free_inode(inode) do {} while (0) +#define llcrypt_finalize_bounce_page(pagep) do {} while (0) +static inline int llcrypt_file_open(struct inode *inode, struct file *filp) +{ + return IS_ENCRYPTED(inode) ? -EOPNOTSUPP : 0; +} +#define llcrypt_ioctl_set_policy(filp, arg) -EOPNOTSUPP +#define llcrypt_ioctl_get_policy_ex(filp, arg) -EOPNOTSUPP +#define llcrypt_ioctl_add_key(filp, arg) -EOPNOTSUPP +#define llcrypt_ioctl_remove_key(filp, arg) -EOPNOTSUPP +#define llcrypt_ioctl_remove_key_all_users(filp, arg) -EOPNOTSUPP +#define llcrypt_ioctl_get_key_status(filp, arg) -EOPNOTSUPP +#define llcrypt_drop_inode(inode) 0 +#define llcrypt_prepare_rename(olddir, olddentry, newdir, newdentry, flags) 0 +#define llcrypt_prepare_link(old_dentry, dir, dentry) 0 +#define llcrypt_prepare_setattr(dentry, attr) 0 +#define llcrypt_set_ops(sb, cop) do {} while (0) +#endif /* HAVE_LUSTRE_CRYPTO */ +#endif /* !CONFIG_LL_ENCRYPTION */ + +#endif /* _LUSTRE_CRYPTO_H_ */ diff --git a/lustre/include/obd_support.h b/lustre/include/obd_support.h index d4b3585..e8a99d5 100644 --- a/lustre/include/obd_support.h +++ b/lustre/include/obd_support.h @@ -965,12 +965,14 @@ do { \ static inline int lma_to_lustre_flags(__u32 lma_flags) { - return (lma_flags & LMAI_ORPHAN) ? LUSTRE_ORPHAN_FL : 0; + return (((lma_flags & LMAI_ORPHAN) ? LUSTRE_ORPHAN_FL : 0) | + ((lma_flags & LMAI_ENCRYPT) ? LUSTRE_ENCRYPT_FL : 0)); } static inline int lustre_to_lma_flags(__u32 la_flags) { - return (la_flags & LUSTRE_ORPHAN_FL) ? LMAI_ORPHAN : 0; + return (((la_flags & LUSTRE_ORPHAN_FL) ? LMAI_ORPHAN : 0) | + ((la_flags & LUSTRE_ENCRYPT_FL) ? LMAI_ENCRYPT : 0)); } /* Convert wire LUSTRE_*_FL to corresponding client local VFS S_* values @@ -986,6 +988,9 @@ static inline int ll_ext_to_inode_flags(int flags) ((flags & LUSTRE_NOATIME_FL) ? S_NOATIME : 0) | ((flags & LUSTRE_APPEND_FL) ? S_APPEND : 0) | ((flags & LUSTRE_DIRSYNC_FL) ? S_DIRSYNC : 0) | +#if defined(S_ENCRYPTED) + ((flags & LUSTRE_ENCRYPT_FL) ? S_ENCRYPTED : 0) | +#endif ((flags & LUSTRE_IMMUTABLE_FL) ? S_IMMUTABLE : 0)); } @@ -995,6 +1000,9 @@ static inline int ll_inode_to_ext_flags(int iflags) ((iflags & S_NOATIME) ? LUSTRE_NOATIME_FL : 0) | ((iflags & S_APPEND) ? LUSTRE_APPEND_FL : 0) | ((iflags & S_DIRSYNC) ? LUSTRE_DIRSYNC_FL : 0) | +#if defined(S_ENCRYPTED) + ((iflags & S_ENCRYPTED) ? LUSTRE_ENCRYPT_FL : 0) | +#endif ((iflags & S_IMMUTABLE) ? LUSTRE_IMMUTABLE_FL : 0)); } diff --git a/lustre/include/uapi/linux/lustre/lustre_idl.h b/lustre/include/uapi/linux/lustre/lustre_idl.h index 088dab5..6450380 100644 --- a/lustre/include/uapi/linux/lustre/lustre_idl.h +++ b/lustre/include/uapi/linux/lustre/lustre_idl.h @@ -1199,6 +1199,8 @@ struct lov_mds_md_v1 { /* LOV EA mds/wire data (little-endian) */ #define XATTR_NAME_LFSCK_BITMAP "trusted.lfsck_bitmap" #define XATTR_NAME_DUMMY "trusted.dummy" +#define LL_XATTR_NAME_ENCRYPTION_CONTEXT XATTR_SECURITY_PREFIX"c" + #define XATTR_NAME_LFSCK_NAMESPACE "trusted.lfsck_ns" #define XATTR_NAME_MAX_LEN 32 /* increase this, if there is longer name. */ @@ -1775,8 +1777,9 @@ enum { * stored in LMA. see LMAI_XXXX */ LUSTRE_ORPHAN_FL = 0x00002000, LUSTRE_SET_SYNC_FL = 0x00040000, /* Synchronous setattr on OSTs */ + LUSTRE_ENCRYPT_FL = 0x00800000, /* encrypted file */ - LUSTRE_LMA_FL_MASKS = LUSTRE_ORPHAN_FL, + LUSTRE_LMA_FL_MASKS = LUSTRE_ENCRYPT_FL | LUSTRE_ORPHAN_FL, }; #ifndef FS_XFLAG_SYNC diff --git a/lustre/include/uapi/linux/lustre/lustre_user.h b/lustre/include/uapi/linux/lustre/lustre_user.h index 6e52437..291c70e 100644 --- a/lustre/include/uapi/linux/lustre/lustre_user.h +++ b/lustre/include/uapi/linux/lustre/lustre_user.h @@ -424,8 +424,9 @@ enum lma_incompat { is on the remote MDT */ LMAI_STRIPED = 0x00000008, /* striped directory inode */ LMAI_ORPHAN = 0x00000010, /* inode is orphan */ + LMAI_ENCRYPT = 0x00000020, /* inode is encrypted */ LMA_INCOMPAT_SUPP = (LMAI_AGENT | LMAI_REMOTE_PARENT | \ - LMAI_STRIPED | LMAI_ORPHAN) + LMAI_STRIPED | LMAI_ORPHAN | LMAI_ENCRYPT) }; diff --git a/lustre/llite/Makefile.in b/lustre/llite/Makefile.in index ec5ab34..3a5293f 100644 --- a/lustre/llite/Makefile.in +++ b/lustre/llite/Makefile.in @@ -7,7 +7,7 @@ lustre-objs += glimpse.o lustre-objs += lcommon_cl.o lustre-objs += lcommon_misc.o lustre-objs += vvp_dev.o vvp_page.o vvp_io.o vvp_object.o -lustre-objs += range_lock.o pcc.o +lustre-objs += range_lock.o pcc.o crypto.o EXTRA_DIST := $(lustre-objs:.o=.c) xattr.c rw26.c super25.c EXTRA_DIST += llite_internal.h vvp_internal.h range_lock.h pcc.h diff --git a/lustre/llite/crypto.c b/lustre/llite/crypto.c new file mode 100644 index 0000000..5ccbedf --- /dev/null +++ b/lustre/llite/crypto.c @@ -0,0 +1,153 @@ +/* + * GPL HEADER START + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 only, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License version 2 for more details (a copy is included + * in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; If not, see + * http://www.gnu.org/licenses/gpl-2.0.html + * + * GPL HEADER END + */ +/* + * Copyright (c) 2019, 2020, Whamcloud. + */ +/* + * This file is part of Lustre, http://www.lustre.org/ + */ + +#include "llite_internal.h" + +#ifdef HAVE_LUSTRE_CRYPTO + +static int ll_get_context(struct inode *inode, void *ctx, size_t len) +{ + struct dentry *dentry; + int rc; + + if (hlist_empty(&inode->i_dentry)) + return -ENODATA; + + hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) { + break; + } + + rc = ll_vfs_getxattr(dentry, inode, LL_XATTR_NAME_ENCRYPTION_CONTEXT, + ctx, len); + + return rc; +} + +static int ll_set_context(struct inode *inode, const void *ctx, size_t len, + void *fs_data) +{ + unsigned int ext_flags; + struct dentry *dentry; + struct md_op_data *op_data; + struct ptlrpc_request *req = NULL; + int rc; + + if (inode == NULL) + return 0; + + ext_flags = ll_inode_to_ext_flags(inode->i_flags) | LUSTRE_ENCRYPT_FL; + dentry = (struct dentry *)fs_data; + + /* Encrypting the root directory is not allowed */ + if (inode->i_ino == inode->i_sb->s_root->d_inode->i_ino) + return -EPERM; + + op_data = ll_prep_md_op_data(NULL, inode, NULL, NULL, 0, 0, + LUSTRE_OPC_ANY, NULL); + if (IS_ERR(op_data)) + return PTR_ERR(op_data); + + op_data->op_attr_flags = LUSTRE_ENCRYPT_FL; + op_data->op_xvalid |= OP_XVALID_FLAGS; + rc = md_setattr(ll_i2sbi(inode)->ll_md_exp, op_data, NULL, 0, &req); + ll_finish_md_op_data(op_data); + ptlrpc_req_finished(req); + if (rc) + return rc; + + rc = ll_vfs_setxattr(dentry, inode, LL_XATTR_NAME_ENCRYPTION_CONTEXT, + ctx, len, XATTR_CREATE); + if (rc) + return rc; + + ll_update_inode_flags(inode, ext_flags); + return 0; +} + +inline bool ll_sbi_has_test_dummy_encryption(struct ll_sb_info *sbi) +{ + return unlikely(sbi->ll_flags & LL_SBI_TEST_DUMMY_ENCRYPTION); +} + +static bool ll_dummy_context(struct inode *inode) +{ + struct ll_sb_info *sbi = ll_i2sbi(inode); + + return sbi ? ll_sbi_has_test_dummy_encryption(sbi) : false; +} + +inline bool ll_sbi_has_encrypt(struct ll_sb_info *sbi) +{ + return sbi->ll_flags & LL_SBI_ENCRYPT; +} + +inline void ll_sbi_set_encrypt(struct ll_sb_info *sbi, bool set) +{ + if (set) + sbi->ll_flags |= LL_SBI_ENCRYPT; + else + sbi->ll_flags &= + ~(LL_SBI_ENCRYPT | LL_SBI_TEST_DUMMY_ENCRYPTION); +} + +static bool ll_empty_dir(struct inode *inode) +{ + /* used by llcrypt_ioctl_set_policy(), because a policy can only be set + * on an empty dir. + */ + /* Here we choose to return true, meaning we always call .set_context. + * Then we rely on server side, with mdd_fix_attr() that calls + * mdd_dir_is_empty() when setting encryption flag on directory. + */ + return true; +} + +const struct llcrypt_operations lustre_cryptops = { + .key_prefix = "lustre:", + .get_context = ll_get_context, + .set_context = ll_set_context, + .dummy_context = ll_dummy_context, + .empty_dir = ll_empty_dir, + .max_namelen = NAME_MAX, +}; +#else /* !HAVE_LUSTRE_CRYPTO */ +inline bool ll_sbi_has_test_dummy_encryption(struct ll_sb_info *sbi) +{ + return false; +} + +inline bool ll_sbi_has_encrypt(struct ll_sb_info *sbi) +{ + return false; +} + +inline void ll_sbi_set_encrypt(struct ll_sb_info *sbi, bool set) +{ +} +#endif + diff --git a/lustre/llite/llite_internal.h b/lustre/llite/llite_internal.h index 76db0b0..cb0ebf2 100644 --- a/lustre/llite/llite_internal.h +++ b/lustre/llite/llite_internal.h @@ -45,6 +45,7 @@ #include #include #include +#include #include "vvp_internal.h" #include "range_lock.h" @@ -585,6 +586,8 @@ enum stats_track_type { 2.10, abandoned */ #define LL_SBI_TINY_WRITE 0x2000000 /* tiny write support */ #define LL_SBI_FILE_HEAT 0x4000000 /* file heat support */ +#define LL_SBI_TEST_DUMMY_ENCRYPTION 0x8000000 /* test dummy encryption */ +#define LL_SBI_ENCRYPT 0x10000000 /* client side encryption */ #define LL_SBI_FLAGS { \ "nolck", \ "checksum", \ @@ -613,6 +616,8 @@ enum stats_track_type { "pio", \ "tiny_write", \ "file_heat", \ + "test_dummy_encryption", \ + "noencrypt", \ } /* This is embedded into llite super-blocks to keep track of connect @@ -1639,4 +1644,9 @@ static inline struct pcc_super *ll_info2pccs(struct ll_inode_info *lli) return ll_i2pccs(ll_info2i(lli)); } +#ifdef HAVE_LUSTRE_CRYPTO +/* crypto.c */ +extern const struct llcrypt_operations lustre_cryptops; +#endif + #endif /* LLITE_INTERNAL_H */ diff --git a/lustre/llite/llite_lib.c b/lustre/llite/llite_lib.c index 254a641..78ff536 100644 --- a/lustre/llite/llite_lib.c +++ b/lustre/llite/llite_lib.c @@ -166,6 +166,7 @@ static struct ll_sb_info *ll_init_sbi(void) sbi->ll_flags |= LL_SBI_AGL_ENABLED; sbi->ll_flags |= LL_SBI_FAST_READ; sbi->ll_flags |= LL_SBI_TINY_WRITE; + ll_sbi_set_encrypt(sbi, true); /* root squash */ sbi->ll_squash.rsi_uid = 0; @@ -559,6 +560,9 @@ static int client_common_fill_super(struct super_block *sb, char *md, char *dt) #if THREAD_SIZE >= 8192 /*b=17630*/ sb->s_export_op = &lustre_export_operations; #endif +#ifdef HAVE_LUSTRE_CRYPTO + llcrypt_set_ops(sb, &lustre_cryptops); +#endif /* make root inode * XXX: move this to after cbd setup? */ @@ -944,6 +948,25 @@ static int ll_options(char *options, struct ll_sb_info *sbi) *flags |= tmp; goto next; } + tmp = ll_set_opt("test_dummy_encryption", s1, + LL_SBI_TEST_DUMMY_ENCRYPTION); + if (tmp) { +#ifdef HAVE_LUSTRE_CRYPTO + *flags |= tmp; +#else + LCONSOLE_WARN("Test dummy encryption mount option ignored: encryption not supported\n"); +#endif + goto next; + } + tmp = ll_set_opt("noencrypt", s1, LL_SBI_ENCRYPT); + if (tmp) { +#ifdef HAVE_LUSTRE_CRYPTO + *flags &= ~tmp; +#else + LCONSOLE_WARN("noencrypt mount option ignored: encryption not supported\n"); +#endif + goto next; + } LCONSOLE_ERROR_MSG(0x152, "Unknown option '%s', won't mount.\n", s1); RETURN(-EINVAL); @@ -1635,6 +1658,8 @@ void ll_clear_inode(struct inode *inode) */ cl_inode_fini(inode); + llcrypt_put_encryption_info(inode); + EXIT; } @@ -2042,6 +2067,8 @@ void ll_inode_size_unlock(struct inode *inode) void ll_update_inode_flags(struct inode *inode, int ext_flags) { + /* do not clear encryption flag */ + ext_flags |= ll_inode_to_ext_flags(inode->i_flags) & LUSTRE_ENCRYPT_FL; inode->i_flags = ll_ext_to_inode_flags(ext_flags); if (ext_flags & LUSTRE_PROJINHERIT_FL) ll_file_set_flag(ll_i2info(inode), LLIF_PROJECT_INHERIT); @@ -2793,6 +2820,14 @@ int ll_show_options(struct seq_file *seq, struct dentry *dentry) if (sbi->ll_flags & LL_SBI_ALWAYS_PING) seq_puts(seq, ",always_ping"); + if (ll_sbi_has_test_dummy_encryption(sbi)) + seq_puts(seq, ",test_dummy_encryption"); + + if (ll_sbi_has_encrypt(sbi)) + seq_puts(seq, ",encrypt"); + else + seq_puts(seq, ",noencrypt"); + RETURN(0); } diff --git a/lustre/llite/super25.c b/lustre/llite/super25.c index befd246..30397af 100644 --- a/lustre/llite/super25.c +++ b/lustre/llite/super25.c @@ -61,6 +61,7 @@ static void ll_inode_destroy_callback(struct rcu_head *head) { struct inode *inode = container_of(head, struct inode, i_rcu); struct ll_inode_info *ptr = ll_i2info(inode); + llcrypt_free_inode(inode); OBD_SLAB_FREE_PTR(ptr, ll_inode_cachep); } diff --git a/lustre/mdd/mdd_dir.c b/lustre/mdd/mdd_dir.c index 0006f16..8f45fb9 100644 --- a/lustre/mdd/mdd_dir.c +++ b/lustre/mdd/mdd_dir.c @@ -356,8 +356,7 @@ int mdd_is_subdir(const struct lu_env *env, struct md_object *mo, * -ve other error * */ -static int mdd_dir_is_empty(const struct lu_env *env, - struct mdd_object *dir) +int mdd_dir_is_empty(const struct lu_env *env, struct mdd_object *dir) { struct dt_it *it; struct dt_object *obj; diff --git a/lustre/mdd/mdd_internal.h b/lustre/mdd/mdd_internal.h index a5bc753..5a502f9 100644 --- a/lustre/mdd/mdd_internal.h +++ b/lustre/mdd/mdd_internal.h @@ -312,6 +312,7 @@ int mdd_orphan_declare_insert(const struct lu_env *env, struct mdd_object *obj, umode_t mode, struct thandle *thandle); int mdd_orphan_declare_delete(const struct lu_env *env, struct mdd_object *obj, struct thandle *thandle); +int mdd_dir_is_empty(const struct lu_env *env, struct mdd_object *dir); /* mdd_lproc.c */ int mdd_procfs_init(struct mdd_device *mdd, const char *name); diff --git a/lustre/mdd/mdd_object.c b/lustre/mdd/mdd_object.c index df5bea0..d30599a 100644 --- a/lustre/mdd/mdd_object.c +++ b/lustre/mdd/mdd_object.c @@ -735,8 +735,17 @@ static int mdd_fix_attr(const struct lu_env *env, struct mdd_object *obj, !md_capable(uc, CFS_CAP_LINUX_IMMUTABLE)) RETURN(-EPERM); - if (!S_ISDIR(oattr->la_mode)) + if (!S_ISDIR(oattr->la_mode)) { la->la_flags &= ~(LUSTRE_DIRSYNC_FL | LUSTRE_TOPDIR_FL); + } else if (la->la_flags & LUSTRE_ENCRYPT_FL) { + /* when trying to add encryption flag on dir, + * make sure it is empty + */ + rc = mdd_dir_is_empty(env, obj); + if (rc) + RETURN(rc); + rc = 0; + } } if (oattr->la_flags & (LUSTRE_IMMUTABLE_FL | LUSTRE_APPEND_FL) && diff --git a/lustre/osd-ldiskfs/osd_handler.c b/lustre/osd-ldiskfs/osd_handler.c index 027ded0..88f35766 100644 --- a/lustre/osd-ldiskfs/osd_handler.c +++ b/lustre/osd-ldiskfs/osd_handler.c @@ -2704,6 +2704,10 @@ static int osd_attr_get(const struct lu_env *env, struct dt_object *dt, attr->la_valid |= LA_FLAGS; attr->la_flags |= LUSTRE_ORPHAN_FL; } + if (obj->oo_lma_flags & LUSTRE_ENCRYPT_FL) { + attr->la_valid |= LA_FLAGS; + attr->la_flags |= LUSTRE_ENCRYPT_FL; + } spin_unlock(&obj->oo_guard); if (S_ISDIR(obj->oo_inode->i_mode) && diff --git a/lustre/osd-zfs/osd_internal.h b/lustre/osd-zfs/osd_internal.h index 737ec68..9887b58 100644 --- a/lustre/osd-zfs/osd_internal.h +++ b/lustre/osd-zfs/osd_internal.h @@ -715,6 +715,8 @@ int __osd_xattr_get_large(const struct lu_env *env, struct osd_device *osd, const char *name, int *sizep); int osd_xattr_get_internal(const struct lu_env *env, struct osd_object *obj, struct lu_buf *buf, const char *name, int *sizep); +int osd_xattr_get_lma(const struct lu_env *env, struct osd_object *obj, + struct lu_buf *buf); int osd_xattr_get(const struct lu_env *env, struct dt_object *dt, struct lu_buf *buf, const char *name); int osd_declare_xattr_set(const struct lu_env *env, struct dt_object *dt, diff --git a/lustre/osd-zfs/osd_object.c b/lustre/osd-zfs/osd_object.c index cce661c..8293a01 100644 --- a/lustre/osd-zfs/osd_object.c +++ b/lustre/osd-zfs/osd_object.c @@ -186,9 +186,11 @@ osd_object_sa_bulk_update(struct osd_object *obj, sa_bulk_attr_t *attrs, static int __osd_object_attr_get(const struct lu_env *env, struct osd_device *o, struct osd_object *obj, struct lu_attr *la) { - struct osa_attr *osa = &osd_oti_get(env)->oti_osa; - sa_bulk_attr_t *bulk = osd_oti_get(env)->oti_attr_bulk; - int cnt = 0; + struct osa_attr *osa = &osd_oti_get(env)->oti_osa; + sa_bulk_attr_t *bulk = osd_oti_get(env)->oti_attr_bulk; + struct lustre_mdt_attrs *lma; + struct lu_buf buf; + int cnt = 0; int rc; ENTRY; @@ -244,27 +246,22 @@ static int __osd_object_attr_get(const struct lu_env *env, struct osd_device *o, la->la_flags = attrs_zfs2fs(osa->flags); la->la_size = osa->size; - /* Try to get extra flag from LMA. Right now, only LMAI_ORPHAN - * flags is stored in LMA, and it is only for orphan directory */ - if (S_ISDIR(la->la_mode) && dt_object_exists(&obj->oo_dt)) { - struct osd_thread_info *info = osd_oti_get(env); - struct lustre_mdt_attrs *lma; - struct lu_buf buf; - - lma = (struct lustre_mdt_attrs *)info->oti_buf; - buf.lb_buf = lma; - buf.lb_len = sizeof(info->oti_buf); - rc = osd_xattr_get(env, &obj->oo_dt, &buf, XATTR_NAME_LMA); - if (rc > 0) { - rc = 0; - lma->lma_incompat = le32_to_cpu(lma->lma_incompat); - obj->oo_lma_flags = - lma_to_lustre_flags(lma->lma_incompat); - - } else if (rc == -ENODATA) { - rc = 0; - } + /* Try to get extra flags from LMA */ + lma = (struct lustre_mdt_attrs *)osd_oti_get(env)->oti_buf; + buf.lb_buf = lma; + buf.lb_len = sizeof(osd_oti_get(env)->oti_buf); + down_read(&obj->oo_guard); + rc = osd_xattr_get_lma(env, obj, &buf); + if (!rc) { + lma->lma_incompat = le32_to_cpu(lma->lma_incompat); + obj->oo_lma_flags = + lma_to_lustre_flags(lma->lma_incompat); + } else if (rc == -ENODATA || + !(S_ISDIR(la->la_mode) && + dt_object_exists(&obj->oo_dt))) { + rc = 0; } + up_read(&obj->oo_guard); if (S_ISCHR(la->la_mode) || S_ISBLK(la->la_mode)) { rc = -sa_lookup(obj->oo_sa_hdl, SA_ZPL_RDEV(o), &osa->rdev, 8); @@ -1013,6 +1010,10 @@ static int osd_attr_get(const struct lu_env *env, struct dt_object *dt, attr->la_valid |= LA_FLAGS; attr->la_flags |= LUSTRE_ORPHAN_FL; } + if (obj->oo_lma_flags & LUSTRE_ENCRYPT_FL) { + attr->la_valid |= LA_FLAGS; + attr->la_flags |= LUSTRE_ENCRYPT_FL; + } read_unlock(&obj->oo_attr_lock); if (attr->la_valid & LA_FLAGS && attr->la_flags & LUSTRE_ORPHAN_FL) CDEBUG(D_INFO, "%s: set orphan flag on "DFID" (%llx/%x)\n", @@ -1339,6 +1340,9 @@ static int osd_attr_set(const struct lu_env *env, struct dt_object *dt, CWARN("%s: failed to set LMA flags: rc = %d\n", osd->od_svname, rc); GOTO(out, rc); + } else { + obj->oo_lma_flags = + la->la_flags & LUSTRE_LMA_FL_MASKS; } } } diff --git a/lustre/osd-zfs/osd_xattr.c b/lustre/osd-zfs/osd_xattr.c index 91ed638..e50f23f 100644 --- a/lustre/osd-zfs/osd_xattr.c +++ b/lustre/osd-zfs/osd_xattr.c @@ -223,6 +223,46 @@ int osd_xattr_get_internal(const struct lu_env *env, struct osd_object *obj, buf, name, sizep); } +/** + * Copy LMA extended attribute into provided buffer + * + * Note that no locking is done here. + * + * \param[in] env execution environment + * \param[in] obj object for which to retrieve xattr + * \param[out] buf buffer to store xattr value in + * + * \retval 0 on success + * \retval negative negated errno on failure + */ +int osd_xattr_get_lma(const struct lu_env *env, struct osd_object *obj, + struct lu_buf *buf) +{ + int size = 0; + int rc = -ENOENT; + + if (!buf) + return 0; + + if (unlikely(obj->oo_destroyed)) + goto out_lma; + + /* check SA_ZPL_DXATTR first then fallback to directory xattr */ + rc = __osd_sa_xattr_get(env, obj, buf, XATTR_NAME_LMA, &size); + if (!rc && unlikely(size < sizeof(struct lustre_mdt_attrs))) + rc = -EINVAL; + if (rc != -ENOENT) + goto out_lma; + + rc = __osd_xattr_get_large(env, osd_obj2dev(obj), obj->oo_xattr, + buf, XATTR_NAME_LMA, &size); + if (!rc && unlikely(size < sizeof(struct lustre_mdt_attrs))) + rc = -EINVAL; + +out_lma: + return rc; +} + static int osd_get_pfid_from_lma(const struct lu_env *env, struct osd_object *obj, struct lu_buf *buf, int *sizep) diff --git a/lustre/ptlrpc/wiretest.c b/lustre/ptlrpc/wiretest.c index 019d45e..50cef04 100644 --- a/lustre/ptlrpc/wiretest.c +++ b/lustre/ptlrpc/wiretest.c @@ -451,6 +451,8 @@ void lustre_assert_wire_constants(void) (unsigned)LMAI_STRIPED); LASSERTF(LMAI_ORPHAN == 0x00000010UL, "found 0x%.8xUL\n", (unsigned)LMAI_ORPHAN); + LASSERTF(LMAI_ENCRYPT == 0x00000020UL, "found 0x%.8xUL\n", + (unsigned)LMAI_ENCRYPT); /* Checks for struct lustre_ost_attrs */ LASSERTF((int)sizeof(struct lustre_ost_attrs) == 64, "found %lld\n", @@ -2575,6 +2577,8 @@ void lustre_assert_wire_constants(void) (unsigned)LUSTRE_INLINE_DATA_FL); LASSERTF(LUSTRE_SET_SYNC_FL == 0x00040000UL, "found 0x%.8xUL\n", (unsigned)LUSTRE_SET_SYNC_FL); + LASSERTF(LUSTRE_ENCRYPT_FL == 0x00800000UL, "found 0x%.8xUL\n", + (unsigned)LUSTRE_ENCRYPT_FL); LASSERTF(MDS_INODELOCK_LOOKUP == 0x00000001UL, "found 0x%.8xUL\n", (unsigned)MDS_INODELOCK_LOOKUP); LASSERTF(MDS_INODELOCK_UPDATE == 0x00000002UL, "found 0x%.8xUL\n", diff --git a/lustre/utils/mount_lustre.c b/lustre/utils/mount_lustre.c index 566a8d5..820dc7f 100644 --- a/lustre/utils/mount_lustre.c +++ b/lustre/utils/mount_lustre.c @@ -52,6 +52,9 @@ #include #include #include +#if defined(HAVE_LUSTRE_CRYPTO) && defined(HAVE_LIBKEYUTILS) +#include +#endif #include #include @@ -116,6 +119,12 @@ void usage(FILE *out) "\t\t(no)lazystatfs: disable or enable* statfs to work if OST is unavailable\n" "\t\t32bitapi: return only 32-bit inode numbers to userspace\n" "\t\t(no)verbose: disable or enable* messages at filesystem (un,re)mount\n" +#ifdef HAVE_LUSTRE_CRYPTO +#ifdef HAVE_LIBKEYUTILS + "\t\ttest_dummy_encryption: enable test dummy encryption mode\n" +#endif + "\t\tnoencrypt: disable client side encryption\n" +#endif ); exit((out != stdout) ? EINVAL : 0); } @@ -345,6 +354,52 @@ int parse_options(struct mount_opts *mop, char *orig_options, strncpy(mop->mo_skpath, val + 1, sizeof(mop->mo_skpath) - 1); #endif +#ifdef HAVE_LUSTRE_CRYPTO + } else if (strncmp(arg, "test_dummy_encryption", 21) == 0) { +#ifdef HAVE_LIBKEYUTILS + /* Using dummy encryption mode requires inserting a + * special dummy key into the session keyring. + * Key type is "logon", key description is + * "fscrypt:4242424242424242", and key payload has to be + * in the form , where: + * is "\x00\x00\x00\x00" + * is "$(printf ""\\\\x%02x"" {0..63})" + * is "\x40\x00\x00\x00" for little endian, + * "\x00\x00\x00\x40" for big endian. + */ + char payload[72]; + int *p = (int *)payload; + char *q = (char *)(p + 1); + int i = 0; + key_serial_t key; + + *p = 0; + while (i < 0x40) + *(q++) = i++; + p = (int *)q; + *p = 0x40; + + key = add_key("logon", "fscrypt:4242424242424242", + (const void *)payload, sizeof(payload), + KEY_SPEC_SESSION_KEYRING); + + if (key == -1) { + fprintf(stderr, + "%s: test dummy encryption option ignored: could not insert dummy encryption key into session keyring\n", + progname); + } else { + /* pass this on as an option */ + rc = append_option(options, options_len, opt, + NULL); + if (rc != 0) + goto out_options; + } +#else /* HAVE_LIBKEYUTILS */ + fprintf(stderr, + "%s: test dummy encryption option ignored: Lustre not built with libkeyutils support\n", + progname); +#endif +#endif } else if (parse_one_option(opt, flagp) == 0) { /* pass this on as an option */ rc = append_option(options, options_len, opt, NULL); diff --git a/lustre/utils/wirecheck.c b/lustre/utils/wirecheck.c index c4d5e33..5f200da 100644 --- a/lustre/utils/wirecheck.c +++ b/lustre/utils/wirecheck.c @@ -221,6 +221,7 @@ check_lustre_mdt_attrs(void) CHECK_VALUE_X(LMAI_REMOTE_PARENT); CHECK_VALUE_X(LMAI_STRIPED); CHECK_VALUE_X(LMAI_ORPHAN); + CHECK_VALUE_X(LMAI_ENCRYPT); } static void @@ -1178,6 +1179,7 @@ check_mdt_body(void) CHECK_VALUE_X(LUSTRE_TOPDIR_FL); CHECK_VALUE_X(LUSTRE_INLINE_DATA_FL); CHECK_VALUE_X(LUSTRE_SET_SYNC_FL); + CHECK_VALUE_X(LUSTRE_ENCRYPT_FL); CHECK_VALUE_X(MDS_INODELOCK_LOOKUP); CHECK_VALUE_X(MDS_INODELOCK_UPDATE); diff --git a/lustre/utils/wiretest.c b/lustre/utils/wiretest.c index 3c9d0a4..6ff30e6 100644 --- a/lustre/utils/wiretest.c +++ b/lustre/utils/wiretest.c @@ -477,6 +477,8 @@ void lustre_assert_wire_constants(void) (unsigned)LMAI_STRIPED); LASSERTF(LMAI_ORPHAN == 0x00000010UL, "found 0x%.8xUL\n", (unsigned)LMAI_ORPHAN); + LASSERTF(LMAI_ENCRYPT == 0x00000020UL, "found 0x%.8xUL\n", + (unsigned)LMAI_ENCRYPT); /* Checks for struct lustre_ost_attrs */ LASSERTF((int)sizeof(struct lustre_ost_attrs) == 64, "found %lld\n", @@ -2601,6 +2603,8 @@ void lustre_assert_wire_constants(void) (unsigned)LUSTRE_INLINE_DATA_FL); LASSERTF(LUSTRE_SET_SYNC_FL == 0x00040000UL, "found 0x%.8xUL\n", (unsigned)LUSTRE_SET_SYNC_FL); + LASSERTF(LUSTRE_ENCRYPT_FL == 0x00800000UL, "found 0x%.8xUL\n", + (unsigned)LUSTRE_ENCRYPT_FL); LASSERTF(MDS_INODELOCK_LOOKUP == 0x00000001UL, "found 0x%.8xUL\n", (unsigned)MDS_INODELOCK_LOOKUP); LASSERTF(MDS_INODELOCK_UPDATE == 0x00000002UL, "found 0x%.8xUL\n",