#define _LUSTRE_CRYPTO_H_
struct ll_sb_info;
+int ll_set_encflags(struct inode *inode, void *encctx, __u32 encctxlen,
+ bool preload);
+void llcrypt_free_ctx(void *encctx, __u32 size);
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);
return !!(exp_connect_flags2(exp) & OBD_CONNECT2_SELINUX_POLICY);
}
+static inline int exp_connect_encrypt(struct obd_export *exp)
+{
+ return !!(exp_connect_flags2(exp) & OBD_CONNECT2_ENCRYPT);
+}
+
enum {
/* archive_ids in array format */
KKUC_CT_DATA_ARRAY_MAGIC = 0x092013cea,
};
/* Maximal number of fields (buffers) in a request message. */
-#define REQ_MAX_FIELD_NR 11
+#define REQ_MAX_FIELD_NR 12
struct req_capsule {
struct ptlrpc_request *rc_req;
extern struct req_msg_field RMF_FILE_SECCTX_NAME;
extern struct req_msg_field RMF_FILE_SECCTX;
extern struct req_msg_field RMF_FID_ARRAY;
+extern struct req_msg_field RMF_FILE_ENCCTX;
/*
* connection handle received in MDS_CONNECT request.
void *sp_cr_file_secctx; /* xattr value */
size_t sp_cr_file_secctx_size; /* xattr value size */
+ /* File encryption context for creates. */
+ void *sp_cr_file_encctx; /* enc ctx value */
+ size_t sp_cr_file_encctx_size; /* enc ctx size */
+
/* Archive ID used for auto PCC attach when create newly files. */
__u32 sp_archive_id;
void *op_file_secctx;
__u32 op_file_secctx_size;
+ /* File encryption context, for creates/metadata ops */
+ void *op_file_encctx;
+ __u32 op_file_encctx_size;
+
__u32 op_projid;
/* Used by readdir */
#define OBD_MD_FLOSTLAYOUT (0x0080000000000000ULL) /* contain ost_layout */
#define OBD_MD_FLPROJID (0x0100000000000000ULL) /* project ID */
#define OBD_MD_SECCTX (0x0200000000000000ULL) /* embed security xattr */
-
#define OBD_MD_FLLAZYSIZE (0x0400000000000000ULL) /* Lazy size */
#define OBD_MD_FLLAZYBLOCKS (0x0800000000000000ULL) /* Lazy blocks */
-
#define OBD_MD_FLBTIME (0x1000000000000000ULL) /* birth time */
+#define OBD_MD_ENCCTX (0x2000000000000000ULL) /* embed encryption ctx */
#define OBD_MD_FLALLQUOTA (OBD_MD_FLUSRQUOTA | \
OBD_MD_FLGRPQUOTA | \
return rc;
}
+int ll_set_encflags(struct inode *inode, void *encctx, __u32 encctxlen,
+ bool preload)
+{
+ unsigned int ext_flags;
+ int rc = 0;
+
+ /* used as encryption unit size */
+ if (S_ISREG(inode->i_mode))
+ inode->i_blkbits = LUSTRE_ENCRYPTION_BLOCKBITS;
+ ext_flags = ll_inode_to_ext_flags(inode->i_flags) | LUSTRE_ENCRYPT_FL;
+ ll_update_inode_flags(inode, ext_flags);
+
+ if (encctx && encctxlen)
+ rc = ll_xattr_cache_insert(inode,
+ LL_XATTR_NAME_ENCRYPTION_CONTEXT,
+ encctx, encctxlen);
+ if (rc)
+ return rc;
+
+ return preload ? llcrypt_get_encryption_info(inode) : 0;
+}
+
+/* ll_set_context has 2 distinct behaviors, depending on the value of inode
+ * parameter:
+ * - inode is NULL:
+ * passed fs_data is a struct md_op_data *. We need to store enc ctx in
+ * op_data, so that it will be sent along to the server with the request that
+ * the caller is preparing, thus saving a setxattr request.
+ * - inode is not NULL:
+ * normal case in which passed fs_data is a struct dentry *, letting proceed
+ * with setxattr operation.
+ * This use case should only be used when explicitly setting a new encryption
+ * policy on an existing, empty directory.
+ */
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;
+ if (inode == NULL) {
+ struct md_op_data *op_data = (struct md_op_data *)fs_data;
- ext_flags = ll_inode_to_ext_flags(inode->i_flags) | LUSTRE_ENCRYPT_FL;
- dentry = (struct dentry *)fs_data;
+ if (!op_data)
+ return -EINVAL;
+
+ OBD_ALLOC(op_data->op_file_encctx, len);
+ if (op_data->op_file_encctx == NULL)
+ return -ENOMEM;
+ op_data->op_file_encctx_size = len;
+ memcpy(op_data->op_file_encctx, ctx, len);
+ return 0;
+ }
/* 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;
-
+ dentry = (struct dentry *)fs_data;
rc = ll_vfs_setxattr(dentry, inode, LL_XATTR_NAME_ENCRYPTION_CONTEXT,
ctx, len, XATTR_CREATE);
if (rc)
return rc;
- /* used as encryption unit size */
- if (S_ISREG(inode->i_mode))
- inode->i_blkbits = LUSTRE_ENCRYPTION_BLOCKBITS;
- ll_update_inode_flags(inode, ext_flags);
- return 0;
+ return ll_set_encflags(inode, (void *)ctx, len, false);
+}
+
+inline void llcrypt_free_ctx(void *encctx, __u32 size)
+{
+ if (encctx)
+ OBD_FREE(encctx, size);
}
inline bool ll_sbi_has_test_dummy_encryption(struct ll_sb_info *sbi)
.max_namelen = NAME_MAX,
};
#else /* !HAVE_LUSTRE_CRYPTO */
+int ll_set_encflags(struct inode *inode, void *encctx, __u32 encctxlen,
+ bool preload)
+{
+ return 0;
+}
+
+inline void llcrypt_free_ctx(void *encctx, __u32 size)
+{
+}
+
inline bool ll_sbi_has_test_dummy_encryption(struct ll_sb_info *sbi)
{
return false;
if (IS_ERR(op_data))
RETURN(PTR_ERR(op_data));
- if (IS_ENCRYPTED(parent) ||
- unlikely(llcrypt_dummy_context_enabled(parent))) {
+ if (ll_sbi_has_encrypt(sbi) &&
+ (IS_ENCRYPTED(parent) ||
+ unlikely(llcrypt_dummy_context_enabled(parent)))) {
err = llcrypt_get_encryption_info(parent);
if (err)
GOTO(out_op_data, err);
GOTO(out_op_data, err);
}
+ if (encrypt) {
+ err = llcrypt_inherit_context(parent, NULL, op_data, false);
+ if (err)
+ GOTO(out_op_data, err);
+ }
+
op_data->op_cli_flags |= CLI_SET_MEA;
err = md_create(sbi->ll_md_exp, op_data, lump, len, mode,
from_kuid(&init_user_ns, current_fsuid()),
GOTO(out_inode, err);
if (encrypt) {
- err = llcrypt_inherit_context(parent, inode, NULL, false);
+ err = ll_set_encflags(inode, op_data->op_file_encctx,
+ op_data->op_file_encctx_size, false);
if (err)
GOTO(out_inode, err);
}
size_t size,
__u64 valid);
+int ll_xattr_cache_insert(struct inode *inode,
+ const char *name,
+ char *buffer,
+ size_t size);
+
static inline bool obd_connect_has_secctx(struct obd_connect_data *data)
{
#ifdef CONFIG_SECURITY
ll_unlock_md_op_lsm(op_data);
security_release_secctx(op_data->op_file_secctx,
op_data->op_file_secctx_size);
- OBD_FREE_PTR(op_data);
+ llcrypt_free_ctx(op_data->op_file_encctx, op_data->op_file_encctx_size);
+ OBD_FREE_PTR(op_data);
}
int ll_show_options(struct seq_file *seq, struct dentry *dentry)
static int ll_create_it(struct inode *dir, struct dentry *dentry,
struct lookup_intent *it,
- void *secctx, __u32 secctxlen, bool encrypt);
+ void *secctx, __u32 secctxlen, bool encrypt,
+ void *encctx, __u32 encctxlen);
/* called from iget5_locked->find_inode() under inode_lock spinlock */
static int ll_test_inode(struct inode *inode, void *opaque)
struct lookup_intent *it,
struct inode *parent, struct dentry **de,
void *secctx, __u32 secctxlen,
+ void *encctx, __u32 encctxlen,
ktime_t kstart, bool encrypt)
{
struct inode *inode = NULL;
rc = security_inode_notifysecctx(inode, secctx,
secctxlen);
if (rc)
- CWARN("cannot set security context for "
- DFID": rc = %d\n",
- PFID(ll_inode2fid(inode)), rc);
+ CWARN("%s: cannot set security context for "DFID": rc = %d\n",
+ ll_i2sbi(inode)->ll_fsname,
+ PFID(ll_inode2fid(inode)),
+ rc);
+ }
+
+ /* If encryption context was returned by MDT, put it in
+ * inode now to save an extra getxattr and avoid deadlock.
+ */
+ if (body->mbo_valid & OBD_MD_ENCCTX) {
+ encctx = req_capsule_server_get(pill, &RMF_FILE_ENCCTX);
+ encctxlen = req_capsule_get_size(pill,
+ &RMF_FILE_ENCCTX,
+ RCL_SERVER);
+
+ if (encctxlen) {
+ CDEBUG(D_SEC,
+ "server returned encryption ctx for "DFID"\n",
+ PFID(ll_inode2fid(inode)));
+ rc = ll_xattr_cache_insert(inode,
+ LL_XATTR_NAME_ENCRYPTION_CONTEXT,
+ encctx, encctxlen);
+ if (rc)
+ CWARN("%s: cannot set enc ctx for "DFID": rc = %d\n",
+ ll_i2sbi(inode)->ll_fsname,
+ PFID(ll_inode2fid(inode)), rc);
+ }
}
}
struct lookup_intent *it,
void **secctx, __u32 *secctxlen,
struct pcc_create_attach *pca,
- bool encrypt)
+ bool encrypt,
+ void **encctx, __u32 *encctxlen)
{
ktime_t kstart = ktime_get();
struct lookup_intent lookup_it = { .it_op = IT_LOOKUP };
if (secctxlen != NULL)
*secctxlen = 0;
}
+ if (it->it_op & IT_CREAT && encrypt) {
+ rc = llcrypt_inherit_context(parent, NULL, op_data, false);
+ if (rc)
+ GOTO(out, retval = ERR_PTR(rc));
+ if (encctx != NULL)
+ *encctx = op_data->op_file_encctx;
+ if (encctxlen != NULL)
+ *encctxlen = op_data->op_file_encctx_size;
+ } else {
+ if (encctx != NULL)
+ *encctx = NULL;
+ if (encctxlen != NULL)
+ *encctxlen = 0;
+ }
/* ask for security context upon intent */
if (it->it_op & (IT_LOOKUP | IT_GETATTR | IT_OPEN)) {
rc = ll_lookup_it_finish(req, it, parent, &dentry,
secctx != NULL ? *secctx : NULL,
secctxlen != NULL ? *secctxlen : 0,
+ encctx != NULL ? *encctx : NULL,
+ encctxlen != NULL ? *encctxlen : 0,
kstart, encrypt);
if (rc != 0) {
ll_intent_release(it);
op_data->op_file_secctx = NULL;
op_data->op_file_secctx_size = 0;
}
+ if (encctx != NULL && encctxlen != NULL &&
+ it->it_op & IT_CREAT && encrypt) {
+ /* caller needs enc ctx info, so reset it in op_data to
+ * prevent it from being freed
+ */
+ op_data->op_file_encctx = NULL;
+ op_data->op_file_encctx_size = 0;
+ }
ll_finish_md_op_data(op_data);
}
itp = NULL;
else
itp = ⁢
- de = ll_lookup_it(parent, dentry, itp, NULL, NULL, NULL, false);
+ de = ll_lookup_it(parent, dentry, itp, NULL, NULL, NULL, false,
+ NULL, NULL);
if (itp != NULL)
ll_intent_release(itp);
long long lookup_flags = LOOKUP_OPEN;
void *secctx = NULL;
__u32 secctxlen = 0;
+ void *encctx = NULL;
+ __u32 encctxlen = 0;
struct ll_sb_info *sbi = NULL;
struct pcc_create_attach pca = { NULL, NULL };
bool encrypt = false;
it->it_flags = (open_flags & ~O_ACCMODE) | OPEN_FMODE(open_flags);
it->it_flags &= ~MDS_OPEN_FL_INTERNAL;
- if (IS_ENCRYPTED(dir)) {
+ if (ll_sbi_has_encrypt(ll_i2sbi(dir)) && IS_ENCRYPTED(dir)) {
/* we know that we are going to create a regular file because
* we set S_IFREG bit on it->it_create_mode above
*/
}
/* Dentry added to dcache tree in ll_lookup_it */
- de = ll_lookup_it(dir, dentry, it, &secctx, &secctxlen, &pca, encrypt);
+ de = ll_lookup_it(dir, dentry, it, &secctx, &secctxlen, &pca, encrypt,
+ &encctx, &encctxlen);
if (IS_ERR(de))
rc = PTR_ERR(de);
else if (de != NULL)
if (it_disposition(it, DISP_OPEN_CREATE)) {
/* Dentry instantiated in ll_create_it. */
rc = ll_create_it(dir, dentry, it, secctx, secctxlen,
- encrypt);
+ encrypt, encctx, encctxlen);
security_release_secctx(secctx, secctxlen);
+ llcrypt_free_ctx(encctx, encctxlen);
if (rc) {
/* We dget in ll_splice_alias. */
if (de != NULL)
* already created PCC copy.
*/
pcc_create_attach_cleanup(dir->i_sb, &pca);
+
+ if (open_flags & O_CREAT && encrypt &&
+ dentry->d_inode) {
+ rc = ll_set_encflags(dentry->d_inode, encctx,
+ encctxlen, true);
+ llcrypt_free_ctx(encctx, encctxlen);
+ if (rc)
+ GOTO(out_release, rc);
+ }
}
if (dentry->d_inode && it_disposition(it, DISP_OPEN_OPEN)) {
*/
static int ll_create_it(struct inode *dir, struct dentry *dentry,
struct lookup_intent *it,
- void *secctx, __u32 secctxlen, bool encrypt)
+ void *secctx, __u32 secctxlen, bool encrypt,
+ void *encctx, __u32 encctxlen)
{
struct inode *inode;
__u64 bits = 0;
d_instantiate(dentry, inode);
if (encrypt) {
- rc = llcrypt_inherit_context(dir, inode, dentry, true);
+ rc = ll_set_encflags(inode, encctx, encctxlen, true);
if (rc)
RETURN(rc);
}
struct inode *inode = NULL;
struct ll_sb_info *sbi = ll_i2sbi(dir);
int tgt_len = 0;
- int encrypt = 0;
+ bool encrypt = false;
int err;
ENTRY;
GOTO(err_exit, err);
}
- if ((IS_ENCRYPTED(dir) &&
+ if (ll_sbi_has_encrypt(sbi) &&
+ ((IS_ENCRYPTED(dir) &&
(S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) ||
- (unlikely(llcrypt_dummy_context_enabled(dir)) && S_ISDIR(mode))) {
+ (unlikely(llcrypt_dummy_context_enabled(dir)) && S_ISDIR(mode)))) {
err = llcrypt_get_encryption_info(dir);
if (err)
GOTO(err_exit, err);
if (!llcrypt_has_encryption_key(dir))
GOTO(err_exit, err = -ENOKEY);
- encrypt = 1;
+ encrypt = true;
+ }
+
+ if (encrypt) {
+ err = llcrypt_inherit_context(dir, NULL, op_data, false);
+ if (err)
+ GOTO(err_exit, err);
}
err = md_create(sbi->ll_md_exp, op_data, tgt, tgt_len, mode,
d_instantiate(dchild, inode);
if (encrypt) {
- err = llcrypt_inherit_context(dir, inode, NULL, true);
+ err = ll_set_encflags(inode, op_data->op_file_encctx,
+ op_data->op_file_encctx_size, true);
if (err)
GOTO(err_exit, err);
}
RETURN(rc);
}
+/**
+ * Insert an xattr value into the cache.
+ *
+ * Add @name xattr with @buffer value and @size length for @inode.
+ * Init cache for @inode if necessary.
+ *
+ * \retval 0 success
+ * \retval < 0 from ll_xattr_cache_add(), except -EPROTO is ignored for
+ * LL_XATTR_NAME_ENCRYPTION_CONTEXT xattr
+ */
+int ll_xattr_cache_insert(struct inode *inode,
+ const char *name,
+ char *buffer,
+ size_t size)
+{
+ struct ll_inode_info *lli = ll_i2info(inode);
+ int rc;
+
+ ENTRY;
+
+ down_read(&lli->lli_xattrs_list_rwsem);
+ if (!ll_xattr_cache_valid(lli))
+ ll_xattr_cache_init(lli);
+ rc = ll_xattr_cache_add(&lli->lli_xattrs, name, buffer,
+ size);
+ up_read(&lli->lli_xattrs_list_rwsem);
+
+ if (rc == -EPROTO &&
+ strcmp(name, LL_XATTR_NAME_ENCRYPTION_CONTEXT) == 0)
+ /* it means enc ctx was already in cache,
+ * ignore error as it cannot be modified
+ */
+ rc = 0;
+ RETURN(rc);
+}
void mdc_file_secctx_pack(struct ptlrpc_request *req,
const char *secctx_name,
const void *secctx, size_t secctx_size);
+void mdc_file_encctx_pack(struct ptlrpc_request *req,
+ const void *encctx, size_t encctx_size);
void mdc_file_sepol_pack(struct ptlrpc_request *req);
void mdc_unlink_pack(struct ptlrpc_request *req, struct md_op_data *op_data);
memcpy(buf, secctx, buf_size);
}
+void mdc_file_encctx_pack(struct ptlrpc_request *req,
+ const void *encctx, size_t encctx_size)
+{
+ void *buf;
+ size_t buf_size;
+
+ if (encctx == NULL)
+ return;
+
+ buf = req_capsule_client_get(&req->rq_pill, &RMF_FILE_ENCCTX);
+ buf_size = req_capsule_get_size(&req->rq_pill, &RMF_FILE_ENCCTX,
+ RCL_CLIENT);
+
+ LASSERT(buf_size == encctx_size);
+ memcpy(buf, encctx, buf_size);
+}
+
void mdc_file_sepol_pack(struct ptlrpc_request *req)
{
void *buf;
op_data->op_file_secctx,
op_data->op_file_secctx_size);
+ mdc_file_encctx_pack(req, op_data->op_file_encctx,
+ op_data->op_file_encctx_size);
+
/* pack SELinux policy info if any */
mdc_file_sepol_pack(req);
}
op_data->op_file_secctx,
op_data->op_file_secctx_size);
+ mdc_file_encctx_pack(req, op_data->op_file_encctx,
+ op_data->op_file_encctx_size);
+
/* pack SELinux policy info if any */
mdc_file_sepol_pack(req);
}
req_capsule_set_size(&req->rq_pill, &RMF_FILE_SECCTX, RCL_CLIENT,
op_data->op_file_secctx_size);
+ req_capsule_set_size(&req->rq_pill, &RMF_FILE_ENCCTX, RCL_CLIENT,
+ op_data->op_file_encctx_size);
+
/* get SELinux policy info if any */
rc = sptlrpc_get_sepol(req);
if (rc < 0) {
RCL_SERVER, 0);
}
+ if (exp_connect_encrypt(exp) && !(it->it_op & IT_CREAT) &&
+ it->it_op & IT_OPEN)
+ req_capsule_set_size(&req->rq_pill, &RMF_FILE_ENCCTX,
+ RCL_SERVER,
+ obd->u.cli.cl_max_mds_easize);
+ else
+ req_capsule_set_size(&req->rq_pill, &RMF_FILE_ENCCTX,
+ RCL_SERVER, 0);
+
/**
* Inline buffer for possible data from Data-on-MDT files.
*/
/* pack the intent */
lit = req_capsule_client_get(&req->rq_pill, &RMF_LDLM_INTENT);
lit->opc = IT_GETXATTR;
+ /* Message below is checked in sanity-selinux test_20d
+ * and sanity-sec test_49
+ */
CDEBUG(D_INFO, "%s: get xattrs for "DFID"\n",
exp->exp_obd->obd_name, PFID(&op_data->op_fid1));
RCL_SERVER, 0);
}
+ if (exp_connect_encrypt(exp) && it->it_op & (IT_LOOKUP | IT_GETATTR))
+ req_capsule_set_size(&req->rq_pill, &RMF_FILE_ENCCTX,
+ RCL_SERVER, easize);
+ else
+ req_capsule_set_size(&req->rq_pill, &RMF_FILE_ENCCTX,
+ RCL_SERVER, 0);
+
ptlrpc_request_set_replen(req);
RETURN(req);
}
req_capsule_set_size(&req->rq_pill, &RMF_FILE_SECCTX, RCL_CLIENT,
op_data->op_file_secctx_size);
+ req_capsule_set_size(&req->rq_pill, &RMF_FILE_ENCCTX, RCL_CLIENT,
+ op_data->op_file_encctx_size);
+
/* get SELinux policy info if any */
rc = sptlrpc_get_sepol(req);
if (rc < 0) {
LASSERT(obd_md_valid == OBD_MD_FLXATTR ||
obd_md_valid == OBD_MD_FLXATTRLS);
- /* The below message is checked in sanity-selinux.sh test_20d */
+ /* Message below is checked in sanity-selinux test_20d
+ * and sanity-sec test_49
+ */
CDEBUG(D_INFO, "%s: get xattr '%s' for "DFID"\n",
exp->exp_obd->obd_name, name, PFID(fid));
rc = mdc_xattr_common(exp, &RQF_MDS_GETXATTR, fid, MDS_GETXATTR,
if (rc < 0)
GOTO(out, rc);
}
+
+ if (spec->sp_cr_file_encctx != NULL) {
+ buf = mdd_buf_get_const(env, spec->sp_cr_file_encctx,
+ spec->sp_cr_file_encctx_size);
+ rc = mdo_declare_xattr_set(env, c, buf,
+ LL_XATTR_NAME_ENCRYPTION_CONTEXT, 0,
+ handle);
+ if (rc < 0)
+ GOTO(out, rc);
+ }
out:
return rc;
}
GOTO(err_initlized, rc);
}
+ if (spec->sp_cr_file_encctx != NULL) {
+ buf = mdd_buf_get_const(env, spec->sp_cr_file_encctx,
+ spec->sp_cr_file_encctx_size);
+ rc = mdo_xattr_set(env, son, buf,
+ LL_XATTR_NAME_ENCRYPTION_CONTEXT, 0,
+ handle);
+ if (rc < 0)
+ GOTO(err_initlized, rc);
+ }
+
err_initlized:
if (unlikely(rc != 0)) {
int rc2;
const char *name,
int fl, struct thandle *handle)
{
- struct dt_object *next = mdd_object_child(obj);
- return dt_declare_xattr_set(env, next, buf, name, fl, handle);
+ struct dt_object *next = mdd_object_child(obj);
+ int rc;
+
+ rc = dt_declare_xattr_set(env, next, buf, name, fl, handle);
+ if (rc >= 0 && strcmp(name, LL_XATTR_NAME_ENCRYPTION_CONTEXT) == 0) {
+ struct lu_attr la = { 0 };
+
+ la.la_valid = LA_FLAGS;
+ la.la_flags = LUSTRE_ENCRYPT_FL;
+ rc = dt_declare_attr_set(env, next, &la, handle);
+ }
+ return rc;
}
static inline int mdo_xattr_set(const struct lu_env *env,struct mdd_object *obj,
int fl, struct thandle *handle)
{
struct dt_object *next = mdd_object_child(obj);
+ int rc;
if (!mdd_object_exists(obj))
return -ENOENT;
- return dt_xattr_set(env, next, buf, name, fl, handle);
+ rc = dt_xattr_set(env, next, buf, name, fl, handle);
+ if (rc >= 0 && strcmp(name, LL_XATTR_NAME_ENCRYPTION_CONTEXT) == 0) {
+ struct lu_attr la = { 0 };
+
+ la.la_valid = LA_FLAGS;
+ la.la_flags = LUSTRE_ENCRYPT_FL;
+ rc = dt_attr_set(env, next, &la, handle);
+ }
+ return rc;
}
static inline int mdo_declare_xattr_del(const struct lu_env *env,
}
rc = mdt_pack_secctx_in_reply(info, child);
+ if (unlikely(rc)) {
+ mdt_object_unlock(info, child, lhc, 1);
+ RETURN(rc);
+ }
+
+ rc = mdt_pack_encctx_in_reply(info, child);
if (unlikely(rc))
mdt_object_unlock(info, child, lhc, 1);
RETURN(rc);
GOTO(out_child, rc);
}
+ rc = mdt_pack_encctx_in_reply(info, child);
+ if (unlikely(rc)) {
+ mdt_object_unlock(info, child, lhc, 1);
+ GOTO(out_child, rc);
+ }
+
lock = ldlm_handle2lock(&lhc->mlh_reg_lh);
if (lock) {
/* Debugging code. */
req_capsule_has_field(pill, &RMF_FILE_SECCTX_NAME,
RCL_CLIENT)) {
if (req_capsule_get_size(pill, &RMF_FILE_SECCTX_NAME,
- RCL_CLIENT) != 0) {
+ RCL_CLIENT) != 0)
/* pre-set size in server part with max size */
req_capsule_set_size(pill, &RMF_FILE_SECCTX,
RCL_SERVER,
- info->mti_mdt->mdt_max_ea_size);
- } else {
+ OBD_MAX_DEFAULT_EA_SIZE);
+ else
req_capsule_set_size(pill, &RMF_FILE_SECCTX,
RCL_SERVER, 0);
- }
}
+}
+
+static void mdt_preset_encctx_size(struct mdt_thread_info *info)
+{
+ struct req_capsule *pill = info->mti_pill;
+ if (req_capsule_has_field(pill, &RMF_FILE_ENCCTX,
+ RCL_SERVER))
+ /* pre-set size in server part with max size */
+ req_capsule_set_size(pill, &RMF_FILE_ENCCTX,
+ RCL_SERVER,
+ info->mti_mdt->mdt_max_mdsize);
}
static int mdt_reint_internal(struct mdt_thread_info *info,
LUSTRE_POSIX_ACL_MAX_SIZE_OLD);
mdt_preset_secctx_size(info);
+ mdt_preset_encctx_size(info);
rc = req_capsule_server_pack(pill);
if (rc != 0) {
LUSTRE_POSIX_ACL_MAX_SIZE_OLD);
mdt_preset_secctx_size(info);
+ mdt_preset_encctx_size(info);
rc = req_capsule_server_pack(pill);
if (rc)
struct mdt_body *repbody);
int mdt_pack_secctx_in_reply(struct mdt_thread_info *info,
struct mdt_object *child);
+int mdt_pack_encctx_in_reply(struct mdt_thread_info *info,
+ struct mdt_object *child);
static inline struct mdt_device *mdt_dev(struct lu_device *d)
{
!(body->mbo_valid & OBD_MD_SECCTX))
req_capsule_shrink(pill, &RMF_FILE_SECCTX, 0, RCL_SERVER);
+ /* Shrink optional ENCCTX buffer if it is not used */
+ if (req_capsule_has_field(pill, &RMF_FILE_ENCCTX, RCL_SERVER) &&
+ req_capsule_get_size(pill, &RMF_FILE_ENCCTX, RCL_SERVER) != 0 &&
+ !(body->mbo_valid & OBD_MD_ENCCTX))
+ req_capsule_shrink(pill, &RMF_FILE_ENCCTX, 0, RCL_SERVER);
+
/*
* Some more field should be shrinked if needed.
* This should be done by those who added fields to reply message.
return 0;
}
+static int mdt_file_encctx_unpack(struct req_capsule *pill,
+ void **encctx, size_t *encctx_size)
+{
+ *encctx = NULL;
+ *encctx_size = 0;
+
+ if (!exp_connect_encrypt(pill->rc_req->rq_export))
+ return 0;
+
+ if (!req_capsule_has_field(pill, &RMF_FILE_ENCCTX, RCL_CLIENT) ||
+ !req_capsule_field_present(pill, &RMF_FILE_ENCCTX, RCL_CLIENT))
+ return -EPROTO;
+
+ *encctx_size = req_capsule_get_size(pill, &RMF_FILE_ENCCTX, RCL_CLIENT);
+ if (*encctx_size == 0)
+ return 0;
+
+ *encctx = req_capsule_client_get(pill, &RMF_FILE_ENCCTX);
+
+ return 0;
+}
+
static int mdt_setattr_unpack_rec(struct mdt_thread_info *info)
{
struct lu_ucred *uc = mdt_ucred(info);
if (rc < 0)
RETURN(rc);
+ rc = mdt_file_encctx_unpack(pill, &sp->sp_cr_file_encctx,
+ &sp->sp_cr_file_encctx_size);
+ if (rc < 0)
+ RETURN(rc);
+
rc = req_check_sepol(pill);
if (rc)
RETURN(rc);
if (rc < 0)
RETURN(rc);
+ rc = mdt_file_encctx_unpack(pill, &sp->sp_cr_file_encctx,
+ &sp->sp_cr_file_encctx_size);
+ if (rc < 0)
+ RETURN(rc);
+
rc = req_check_sepol(pill);
if (rc)
RETURN(rc);
RETURN(0);
}
+
+int mdt_pack_encctx_in_reply(struct mdt_thread_info *info,
+ struct mdt_object *child)
+{
+ struct lu_buf *buffer;
+ struct mdt_body *repbody;
+ struct req_capsule *pill = info->mti_pill;
+ struct obd_export *exp = mdt_info_req(info)->rq_export;
+ int rc = 0;
+
+ if (!exp_connect_encrypt(exp))
+ return rc;
+
+ if (req_capsule_has_field(pill, &RMF_FILE_ENCCTX, RCL_SERVER) &&
+ req_capsule_get_size(pill, &RMF_FILE_ENCCTX, RCL_SERVER) != 0) {
+ struct lu_attr la = { 0 };
+ struct dt_object *dt = mdt_obj2dt(child);
+
+ if (dt && dt->do_ops && dt->do_ops->do_attr_get)
+ dt_attr_get(info->mti_env, mdt_obj2dt(child), &la);
+
+ if (la.la_valid & LA_FLAGS && la.la_flags & LUSTRE_ENCRYPT_FL) {
+ buffer = &info->mti_buf;
+
+ /* fill reply buffer with encryption context now */
+ buffer->lb_len =
+ req_capsule_get_size(pill, &RMF_FILE_ENCCTX,
+ RCL_SERVER);
+ buffer->lb_buf =
+ req_capsule_server_get(pill, &RMF_FILE_ENCCTX);
+ rc = mo_xattr_get(info->mti_env,
+ mdt_object_child(child),
+ buffer,
+ LL_XATTR_NAME_ENCRYPTION_CONTEXT);
+ if (rc >= 0) {
+ CDEBUG(D_SEC,
+ "found encryption ctx of size %d for "DFID"\n",
+ rc, PFID(mdt_object_fid(child)));
+
+ repbody = req_capsule_server_get(pill,
+ &RMF_MDT_BODY);
+ repbody->mbo_valid |= OBD_MD_ENCCTX;
+ if (rc < buffer->lb_len)
+ req_capsule_shrink(pill,
+ &RMF_FILE_ENCCTX, rc,
+ RCL_SERVER);
+ rc = 0;
+ } else {
+ CDEBUG(D_SEC,
+ "encryption ctx not found for "DFID": rc = %d\n",
+ PFID(mdt_object_fid(child)), rc);
+ req_capsule_shrink(pill, &RMF_FILE_ENCCTX, 0,
+ RCL_SERVER);
+ /* handling -ENOENT is important because it may
+ * change object state in DNE env dropping
+ * LOHA_EXISTS flag, it is important to return
+ * that to the caller.
+ * Check LU-13115 for details.
+ */
+ if (rc != -ENOENT)
+ rc = 0;
+ }
+ } else {
+ req_capsule_shrink(pill, &RMF_FILE_ENCCTX, 0,
+ RCL_SERVER);
+ }
+ }
+ return rc;
+}
if (unlikely(rc))
GOTO(out, rc);
+ rc = mdt_pack_encctx_in_reply(info, o);
+ if (unlikely(rc))
+ GOTO(out, rc);
+
rc = mdt_finish_open(info, NULL, o, open_flags, 0, rep);
} else {
/*
if (unlikely(rc))
GOTO(out_child, result = rc);
+ rc = mdt_pack_encctx_in_reply(info, child);
+ if (unlikely(rc))
+ GOTO(out_child, result = rc);
+
rc = mdt_check_resent_lock(info, child, lhc);
if (rc < 0) {
GOTO(out_child, result = rc);
&RMF_DLM_REQ,
&RMF_FILE_SECCTX_NAME,
&RMF_FILE_SECCTX,
- &RMF_SELINUX_POL
+ &RMF_SELINUX_POL,
+ &RMF_FILE_ENCCTX,
};
static const struct req_msg_field *mds_reint_create_sym_client[] = {
&RMF_DLM_REQ,
&RMF_FILE_SECCTX_NAME,
&RMF_FILE_SECCTX,
- &RMF_SELINUX_POL
+ &RMF_SELINUX_POL,
+ &RMF_FILE_ENCCTX,
};
static const struct req_msg_field *mds_reint_open_client[] = {
&RMF_EADATA,
&RMF_FILE_SECCTX_NAME,
&RMF_FILE_SECCTX,
- &RMF_SELINUX_POL
+ &RMF_SELINUX_POL,
+ &RMF_FILE_ENCCTX,
};
static const struct req_msg_field *mds_reint_open_server[] = {
&RMF_CAPA1,
&RMF_CAPA2,
&RMF_NIOBUF_INLINE,
- &RMF_FILE_SECCTX
+ &RMF_FILE_SECCTX,
+ &RMF_FILE_ENCCTX,
};
static const struct req_msg_field *ldlm_intent_getattr_client[] = {
&RMF_ACL,
&RMF_CAPA1,
&RMF_FILE_SECCTX,
- &RMF_DEFAULT_MDT_MD
+ &RMF_DEFAULT_MDT_MD,
+ &RMF_FILE_ENCCTX,
};
static const struct req_msg_field *ldlm_intent_create_client[] = {
&RMF_EADATA,
&RMF_FILE_SECCTX_NAME,
&RMF_FILE_SECCTX,
- &RMF_SELINUX_POL
+ &RMF_SELINUX_POL,
+ &RMF_FILE_ENCCTX,
};
static const struct req_msg_field *ldlm_intent_open_client[] = {
&RMF_EADATA,
&RMF_FILE_SECCTX_NAME,
&RMF_FILE_SECCTX,
- &RMF_SELINUX_POL
+ &RMF_SELINUX_POL,
+ &RMF_FILE_ENCCTX,
};
static const struct req_msg_field *ldlm_intent_getxattr_client[] = {
DEFINE_MSGF("file_secctx", RMF_F_NO_SIZE_CHECK, -1, NULL, NULL);
EXPORT_SYMBOL(RMF_FILE_SECCTX);
+struct req_msg_field RMF_FILE_ENCCTX =
+ DEFINE_MSGF("file_encctx", RMF_F_NO_SIZE_CHECK, -1, NULL, NULL);
+EXPORT_SYMBOL(RMF_FILE_ENCCTX);
+
struct req_msg_field RMF_LLOGD_BODY =
DEFINE_MSGF("llogd_body", 0,
sizeof(struct llogd_body), lustre_swab_llogd_body, NULL);
OBD_MD_FLLAZYSIZE);
LASSERTF(OBD_MD_FLLAZYBLOCKS == (0x0800000000000000ULL), "found 0x%.16llxULL\n",
OBD_MD_FLLAZYBLOCKS);
+ LASSERTF(OBD_MD_ENCCTX == (0x2000000000000000ULL), "found 0x%.16llxULL\n",
+ OBD_MD_ENCCTX);
BUILD_BUG_ON(OBD_FL_INLINEDATA != 0x00000001);
BUILD_BUG_ON(OBD_FL_OBDMDEXISTS != 0x00000002);
BUILD_BUG_ON(OBD_FL_DELORPHAN != 0x00000004);
}
run_test 48b "encrypted file: concurrent truncate"
+trace_cmd() {
+ local cmd="$@"
+ local xattr_name="security.c"
+
+ sync ; sync ; echo 3 > /proc/sys/vm/drop_caches
+ $LCTL set_param debug=+info
+ $LCTL clear
+
+ echo $cmd
+ eval $cmd
+
+ $LCTL dk | grep -E "get xattr '${xattr_name}'|get xattrs"
+ [ $? -ne 0 ] || error "get xattr event was triggered"
+}
+
+test_49() {
+ $LCTL get_param mdc.*.import | grep -q client_encryption ||
+ skip "client encryption not supported"
+
+ mount.lustre --help |& grep -q "test_dummy_encryption:" ||
+ skip "need dummy encryption support"
+
+ stack_trap cleanup_for_enc_tests EXIT
+ setup_for_enc_tests
+
+ local dirname=$DIR/$tdir/subdir
+
+ mkdir $dirname
+
+ trace_cmd stat $dirname
+ trace_cmd touch $dirname/f1
+ trace_cmd stat $dirname/f1
+ trace_cmd cat $dirname/f1
+ dd if=/dev/zero of=$dirname/f1 bs=1M count=10 conv=fsync
+ trace_cmd $TRUNCATE $dirname/f1 10240
+ trace_cmd $LFS setstripe -E -1 -S 4M $dirname/f2
+ trace_cmd $LFS migrate -E -1 -S 256K $dirname/f2
+ trace_cmd $LFS setdirstripe -i 1 $dirname/d2
+ trace_cmd $LFS migrate -m 0 $dirname/d2
+
+ $LFS setdirstripe -i 1 -c 1 $dirname/d3
+ dirname=$dirname/d3/subdir
+ mkdir $dirname
+
+ trace_cmd stat $dirname
+ trace_cmd touch $dirname/f1
+ trace_cmd stat $dirname/f1
+ trace_cmd cat $dirname/f1
+ dd if=/dev/zero of=$dirname/f1 bs=1M count=10 conv=fsync
+ trace_cmd $TRUNCATE $dirname/f1 10240
+ trace_cmd $LFS setstripe -E -1 -S 4M $dirname/f2
+ trace_cmd $LFS migrate -E -1 -S 256K $dirname/f2
+}
+run_test 49 "Avoid getxattr for encryption context"
+
log "cleanup: ======================================================"
sec_unsetup() {
CHECK_DEFINE_64X(OBD_MD_SECCTX);
CHECK_DEFINE_64X(OBD_MD_FLLAZYSIZE);
CHECK_DEFINE_64X(OBD_MD_FLLAZYBLOCKS);
+ CHECK_DEFINE_64X(OBD_MD_ENCCTX);
CHECK_CVALUE_X(OBD_FL_INLINEDATA);
CHECK_CVALUE_X(OBD_FL_OBDMDEXISTS);
OBD_MD_FLLAZYSIZE);
LASSERTF(OBD_MD_FLLAZYBLOCKS == (0x0800000000000000ULL), "found 0x%.16llxULL\n",
OBD_MD_FLLAZYBLOCKS);
+ LASSERTF(OBD_MD_ENCCTX == (0x2000000000000000ULL), "found 0x%.16llxULL\n",
+ OBD_MD_ENCCTX);
BUILD_BUG_ON(OBD_FL_INLINEDATA != 0x00000001);
BUILD_BUG_ON(OBD_FL_OBDMDEXISTS != 0x00000002);
BUILD_BUG_ON(OBD_FL_DELORPHAN != 0x00000004);