On client side, security context must be set on the inode of
every new dir or file that is being created.
With LL_SBI_FILE_SECCTX, security context is obtained from the
dentry thanks to a call to ll_dentry_init_security(). And it is
saved to security.xxx xattr directly on MDS side when processing
the create request. So it is only necessary to call
security_inode_notifysecctx() to set the sec ctx on the client's
inode.
Without LL_SBI_FILE_SECCTX, security context can only be obtained
from the inode, ie after the file has been created on MDS side.
So use ll_inode_init_security() that will set the sec ctx on the
client's inode, and at the same time save it on disk to
security.xxx xattr, generating an additional request to the MDS.
Signed-off-by: Sebastien Buisson <sbuisson@ddn.com>
Change-Id: I08b7828db6a4106cca0e78e57bed2967b86a922c
Reviewed-on: https://review.whamcloud.com/24426
Reviewed-by: Faccini Bruno <bruno.faccini@intel.com>
Tested-by: Jenkins
Reviewed-by: Jean-Baptiste Riaux <riaux.jb@intel.com>
Tested-by: Maloo <hpdd-maloo@intel.com>
Reviewed-by: Oleg Drokin <oleg.drokin@intel.com>
- if (!(sbi->ll_flags & LL_SBI_FILE_SECCTX)) {
+ if (sbi->ll_flags & LL_SBI_FILE_SECCTX) {
+ inode_lock(inode);
+ err = security_inode_notifysecctx(inode,
+ op_data->op_file_secctx,
+ op_data->op_file_secctx_size);
+ inode_unlock(inode);
+ } else {
err = ll_inode_init_security(&dentry, inode, parent);
err = ll_inode_init_security(&dentry, inode, parent);
- if (err)
- GOTO(out_inode, err);
+ if (err)
+ GOTO(out_inode, err);
out_inode:
if (inode != NULL)
out_inode:
if (inode != NULL)
#include "llite_internal.h"
static int ll_create_it(struct inode *dir, struct dentry *dentry,
#include "llite_internal.h"
static int ll_create_it(struct inode *dir, struct dentry *dentry,
- struct lookup_intent *it);
+ struct lookup_intent *it,
+ void *secctx, __u32 secctxlen);
/* called from iget5_locked->find_inode() under inode_lock spinlock */
static int ll_test_inode(struct inode *inode, void *opaque)
/* called from iget5_locked->find_inode() under inode_lock spinlock */
static int ll_test_inode(struct inode *inode, void *opaque)
}
static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry,
}
static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry,
- struct lookup_intent *it)
+ struct lookup_intent *it,
+ void **secctx, __u32 *secctxlen)
{
struct lookup_intent lookup_it = { .it_op = IT_LOOKUP };
struct dentry *save = dentry, *retval;
{
struct lookup_intent lookup_it = { .it_op = IT_LOOKUP };
struct dentry *save = dentry, *retval;
&op_data->op_file_secctx_size);
if (rc < 0)
GOTO(out, retval = ERR_PTR(rc));
&op_data->op_file_secctx_size);
if (rc < 0)
GOTO(out, retval = ERR_PTR(rc));
+ if (secctx != NULL)
+ *secctx = op_data->op_file_secctx;
+ if (secctxlen != NULL)
+ *secctxlen = op_data->op_file_secctx_size;
}
rc = md_intent_lock(ll_i2mdexp(parent), op_data, it, &req,
}
rc = md_intent_lock(ll_i2mdexp(parent), op_data, it, &req,
GOTO(out, retval = (dentry == save) ? NULL : dentry);
out:
GOTO(out, retval = (dentry == save) ? NULL : dentry);
out:
- if (op_data != NULL && !IS_ERR(op_data))
+ if (op_data != NULL && !IS_ERR(op_data)) {
+ if (secctx != NULL && secctxlen != NULL) {
+ /* caller needs sec ctx info, so reset it in op_data to
+ * prevent it from being freed */
+ op_data->op_file_secctx = NULL;
+ op_data->op_file_secctx_size = 0;
+ }
ll_finish_md_op_data(op_data);
ll_finish_md_op_data(op_data);
ptlrpc_req_finished(req);
return retval;
ptlrpc_req_finished(req);
return retval;
itp = NULL;
else
itp = ⁢
itp = NULL;
else
itp = ⁢
- de = ll_lookup_it(parent, dentry, itp);
+ de = ll_lookup_it(parent, dentry, itp, NULL, NULL);
if (itp != NULL)
ll_intent_release(itp);
if (itp != NULL)
ll_intent_release(itp);
struct lookup_intent *it;
struct dentry *de;
long long lookup_flags = LOOKUP_OPEN;
struct lookup_intent *it;
struct dentry *de;
long long lookup_flags = LOOKUP_OPEN;
+ void *secctx = NULL;
+ __u32 secctxlen = 0;
it->it_flags &= ~MDS_OPEN_FL_INTERNAL;
/* Dentry added to dcache tree in ll_lookup_it */
it->it_flags &= ~MDS_OPEN_FL_INTERNAL;
/* Dentry added to dcache tree in ll_lookup_it */
- de = ll_lookup_it(dir, dentry, it);
+ de = ll_lookup_it(dir, dentry, it, &secctx, &secctxlen);
if (IS_ERR(de))
rc = PTR_ERR(de);
else if (de != NULL)
if (IS_ERR(de))
rc = PTR_ERR(de);
else if (de != NULL)
if (!rc) {
if (it_disposition(it, DISP_OPEN_CREATE)) {
/* Dentry instantiated in ll_create_it. */
if (!rc) {
if (it_disposition(it, DISP_OPEN_CREATE)) {
/* Dentry instantiated in ll_create_it. */
- rc = ll_create_it(dir, dentry, it);
+ rc = ll_create_it(dir, dentry, it, secctx, secctxlen);
+ security_release_secctx(secctx, secctxlen);
if (rc) {
/* We dget in ll_splice_alias. */
if (de != NULL)
if (rc) {
/* We dget in ll_splice_alias. */
if (de != NULL)
static struct dentry *ll_lookup_nd(struct inode *parent, struct dentry *dentry,
struct nameidata *nd)
{
static struct dentry *ll_lookup_nd(struct inode *parent, struct dentry *dentry,
struct nameidata *nd)
{
- struct dentry *de;
- ENTRY;
+ struct dentry *de;
+ ENTRY;
- if (nd && !(nd->flags & (LOOKUP_CONTINUE|LOOKUP_PARENT))) {
- struct lookup_intent *it;
+ if (nd && !(nd->flags & (LOOKUP_CONTINUE|LOOKUP_PARENT))) {
+ struct lookup_intent *it;
- if (ll_d2d(dentry) && ll_d2d(dentry)->lld_it) {
- it = ll_d2d(dentry)->lld_it;
- ll_d2d(dentry)->lld_it = NULL;
- } else {
+ if (ll_d2d(dentry) && ll_d2d(dentry)->lld_it) {
+ it = ll_d2d(dentry)->lld_it;
+ ll_d2d(dentry)->lld_it = NULL;
+ } else {
/*
* Optimize away (CREATE && !OPEN). Let .create handle
* the race. But only if we have write permissions
/*
* Optimize away (CREATE && !OPEN). Let .create handle
* the race. But only if we have write permissions
MAY_WRITE | MAY_EXEC) == 0))
RETURN(NULL);
MAY_WRITE | MAY_EXEC) == 0))
RETURN(NULL);
- it = ll_convert_intent(&nd->intent.open, nd->flags);
- if (IS_ERR(it))
- RETURN((struct dentry *)it);
- }
-
- de = ll_lookup_it(parent, dentry, it);
- if (de)
- dentry = de;
- if ((nd->flags & LOOKUP_OPEN) && !IS_ERR(dentry)) { /* Open */
- if (dentry->d_inode &&
- it_disposition(it, DISP_OPEN_OPEN)) { /* nocreate */
- if (S_ISFIFO(dentry->d_inode->i_mode)) {
+ it = ll_convert_intent(&nd->intent.open, nd->flags);
+ if (IS_ERR(it))
+ RETURN((struct dentry *)it);
+ }
+
+ de = ll_lookup_it(parent, dentry, it, NULL, NULL);
+ if (de)
+ dentry = de;
+ if ((nd->flags & LOOKUP_OPEN) && !IS_ERR(dentry)) { /* Open */
+ if (dentry->d_inode &&
+ it_disposition(it, DISP_OPEN_OPEN)) { /* nocreate */
+ if (S_ISFIFO(dentry->d_inode->i_mode)) {
/* We cannot call open here as it might
* deadlock. This case is unreachable in
* practice because of
* OBD_CONNECT_NODEVOH. */
/* We cannot call open here as it might
* deadlock. This case is unreachable in
* practice because of
* OBD_CONNECT_NODEVOH. */
struct file *filp;
nd->intent.open.file->private_data = it;
struct file *filp;
nd->intent.open.file->private_data = it;
dput(de);
de = (struct dentry *)filp;
}
dput(de);
de = (struct dentry *)filp;
}
- }
- } else if (it_disposition(it, DISP_OPEN_CREATE)) {
- // XXX This can only reliably work on assumption
- // that there are NO hashed negative dentries.
- ll_d2d(dentry)->lld_it = it;
- it = NULL; /* Will be freed in ll_create_nd */
- /* We absolutely depend on ll_create_nd to be
- * called to not leak this intent and possible
- * data attached to it */
- }
- }
-
- if (it) {
- ll_intent_release(it);
- OBD_FREE(it, sizeof(*it));
- }
- } else {
- de = ll_lookup_it(parent, dentry, NULL);
+ }
+ } else if (it_disposition(it, DISP_OPEN_CREATE)) {
+ /* XXX This can only reliably work on assumption
+ * that there are NO hashed negative dentries.*/
+ ll_d2d(dentry)->lld_it = it;
+ it = NULL; /* Will be freed in ll_create_nd */
+ /* We absolutely depend on ll_create_nd to be
+ * called to not leak this intent and possible
+ * data attached to it */
+ }
+ }
+
+ if (it) {
+ ll_intent_release(it);
+ OBD_FREE(it, sizeof(*it));
+ }
+ } else {
+ de = ll_lookup_it(parent, dentry, NULL, NULL, NULL);
* with d_instantiate().
*/
static int ll_create_it(struct inode *dir, struct dentry *dentry,
* with d_instantiate().
*/
static int ll_create_it(struct inode *dir, struct dentry *dentry,
- struct lookup_intent *it)
+ struct lookup_intent *it,
+ void *secctx, __u32 secctxlen)
{
struct inode *inode;
int rc = 0;
{
struct inode *inode;
int rc = 0;
if (IS_ERR(inode))
RETURN(PTR_ERR(inode));
if (IS_ERR(inode))
RETURN(PTR_ERR(inode));
+ if ((ll_i2sbi(inode)->ll_flags & LL_SBI_FILE_SECCTX) &&
+ secctx != NULL) {
+ inode_lock(inode);
+ /* must be done before d_instantiate, because it calls
+ * security_d_instantiate, which means a getxattr if security
+ * context is not set yet */
+ rc = security_inode_notifysecctx(inode, secctx, secctxlen);
+ inode_unlock(inode);
+ if (rc)
+ RETURN(rc);
+ }
+
d_instantiate(dentry, inode);
if (!(ll_i2sbi(inode)->ll_flags & LL_SBI_FILE_SECCTX)) {
d_instantiate(dentry, inode);
if (!(ll_i2sbi(inode)->ll_flags & LL_SBI_FILE_SECCTX)) {
from_kuid(&init_user_ns, current_fsuid()),
from_kgid(&init_user_ns, current_fsgid()),
cfs_curproc_cap_pack(), rdev, &request);
from_kuid(&init_user_ns, current_fsuid()),
from_kgid(&init_user_ns, current_fsgid()),
cfs_curproc_cap_pack(), rdev, &request);
- ll_finish_md_op_data(op_data);
- op_data = NULL;
if (err < 0 && err != -EREMOTE)
GOTO(err_exit, err);
if (err < 0 && err != -EREMOTE)
GOTO(err_exit, err);
ptlrpc_req_finished(request);
request = NULL;
ptlrpc_req_finished(request);
request = NULL;
+ ll_finish_md_op_data(op_data);
if (err)
GOTO(err_exit, err);
if (err)
GOTO(err_exit, err);
+ if (sbi->ll_flags & LL_SBI_FILE_SECCTX) {
+ inode_lock(inode);
+ /* must be done before d_instantiate, because it calls
+ * security_d_instantiate, which means a getxattr if security
+ * context is not set yet */
+ err = security_inode_notifysecctx(inode,
+ op_data->op_file_secctx,
+ op_data->op_file_secctx_size);
+ inode_unlock(inode);
+ if (err)
+ GOTO(err_exit, err);
+ }
+
d_instantiate(dchild, inode);
if (!(sbi->ll_flags & LL_SBI_FILE_SECCTX)) {
d_instantiate(dchild, inode);
if (!(sbi->ll_flags & LL_SBI_FILE_SECCTX)) {
- rc = ll_create_it(dir, dentry, it);
+ rc = ll_create_it(dir, dentry, it, NULL, 0);
if (nd && (nd->flags & LOOKUP_OPEN) && dentry->d_inode) { /* Open */
struct file *filp;
if (nd && (nd->flags & LOOKUP_OPEN) && dentry->d_inode) { /* Open */
struct file *filp;