/** description of flavors for client & server */
struct sptlrpc_flavor rq_flvr;
- /**
- * SELinux policy info at the time of the request
- * sepol string format is:
- * <mode>:<policy name>:<policy version>:<policy hash>
- */
- char rq_sepol[LUSTRE_NODEMAP_SEPOL_LENGTH + 1];
-
/* client/server security flags */
unsigned int
rq_ctx_init:1, /* context initiation */
#define PTLRPC_SEC_FL_BULK 0x0008 /* intensive bulk i/o expected */
#define PTLRPC_SEC_FL_PAG 0x0010 /* PAG mode */
+struct sptlrpc_sepol {
+ struct rcu_head ssp_rcu;
+ struct kref ssp_ref;
+ /** mtime of SELinux policy file */
+ ktime_t ssp_mtime;
+ /**
+ * SELinux policy info
+ * sepol string format is:
+ * <mode>:<policy name>:<policy version>:<policy hash>
+ */
+ __u32 ssp_sepol_size;
+ char ssp_sepol[0];
+};
+
/**
* The ptlrpc_sec represents the client side ptlrpc security facilities,
* each obd_import (both regular and reverse import) must associate with
/** owning import */
struct obd_import *ps_import;
spinlock_t ps_lock;
- /** mtime of SELinux policy file */
- ktime_t ps_sepol_mtime;
/** next check time of SELinux policy file */
ktime_t ps_sepol_checknext;
- /**
- * SELinux policy info
- * sepol string format is:
- * <mode>:<policy name>:<policy version>:<policy hash>
- */
- char ps_sepol[LUSTRE_NODEMAP_SEPOL_LENGTH
- + 1];
+ /** SELinux policy file information */
+ struct sptlrpc_sepol *ps_sepol;
/*
* garbage collection
int sptlrpc_cli_unwrap_early_reply(struct ptlrpc_request *req,
struct ptlrpc_request **req_ret);
void sptlrpc_cli_finish_early_reply(struct ptlrpc_request *early_req);
-
void sptlrpc_request_out_callback(struct ptlrpc_request *req);
-int sptlrpc_get_sepol(struct ptlrpc_request *req);
+
+static inline size_t sptlrpc_sepol_size(struct sptlrpc_sepol *sepol)
+{
+ return sepol ? sepol->ssp_sepol_size : 0;
+}
+
+void sptlrpc_sepol_put(struct sptlrpc_sepol *pol);
+struct sptlrpc_sepol *sptlrpc_sepol_get_cached(struct ptlrpc_sec *imp_sec);
+struct sptlrpc_sepol *sptlrpc_sepol_get(struct ptlrpc_request *req);
/*
* exported higher interface of import & request
void *ea, size_t ealen);
void mdc_create_pack(struct req_capsule *pill, struct md_op_data *op_data,
const void *data, size_t datalen, umode_t mode,
- uid_t uid, gid_t gid, kernel_cap_t capability, u64 rdev);
+ uid_t uid, gid_t gid, kernel_cap_t cap_effective, u64 rdev,
+ struct sptlrpc_sepol *sepol);
void mdc_open_pack(struct req_capsule *pill, struct md_op_data *op_data,
- umode_t mode, __u64 rdev, __u64 flags,
- const void *data, size_t datalen);
+ umode_t mode, __u64 rdev, __u64 flags, const void *lmm,
+ size_t lmmlen, struct sptlrpc_sepol *sepol);
void mdc_file_secctx_pack(struct req_capsule *pill,
const char *secctx_name,
const void *secctx, size_t secctx_size);
void mdc_file_encctx_pack(struct req_capsule *pill,
const void *encctx, size_t encctx_size);
-void mdc_file_sepol_pack(struct req_capsule *pill);
+void mdc_file_sepol_pack(struct req_capsule *pill, struct sptlrpc_sepol *p);
-void mdc_unlink_pack(struct req_capsule *pill, struct md_op_data *op_data);
-void mdc_link_pack(struct req_capsule *pill, struct md_op_data *op_data);
+void mdc_unlink_pack(struct req_capsule *pill, struct md_op_data *op_data,
+ struct sptlrpc_sepol *sepol);
+void mdc_link_pack(struct req_capsule *pill, struct md_op_data *op_data,
+ struct sptlrpc_sepol *sepol);
void mdc_rename_pack(struct req_capsule *pill, struct md_op_data *op_data,
const char *old, size_t oldlen,
- const char *new, size_t newlen);
+ const char *new, size_t newlen,
+ struct sptlrpc_sepol *sepol);
void mdc_migrate_pack(struct req_capsule *pill, struct md_op_data *op_data,
const char *name, size_t namelen);
void mdc_close_pack(struct req_capsule *pill, struct md_op_data *op_data);
memcpy(buf, encctx, buf_size);
}
-void mdc_file_sepol_pack(struct req_capsule *pill)
+void mdc_file_sepol_pack(struct req_capsule *pill, struct sptlrpc_sepol *p)
{
void *buf;
size_t buf_size;
- struct ptlrpc_request *req = pill->rc_req;
- if (strlen(req->rq_sepol) == 0)
+ if (!p || !p->ssp_sepol_size)
return;
buf = req_capsule_client_get(pill, &RMF_SELINUX_POL);
buf_size = req_capsule_get_size(pill, &RMF_SELINUX_POL,
RCL_CLIENT);
- LASSERT(buf_size == strlen(req->rq_sepol) + 1);
- snprintf(buf, strlen(req->rq_sepol) + 1, "%s", req->rq_sepol);
+ LASSERT(buf_size == p->ssp_sepol_size);
+ strlcpy(buf, p->ssp_sepol, p->ssp_sepol_size);
}
void mdc_readdir_pack(struct req_capsule *pill, __u64 pgoff, size_t size,
/* packing of MDS records */
void mdc_create_pack(struct req_capsule *pill, struct md_op_data *op_data,
const void *data, size_t datalen, umode_t mode,
- uid_t uid, gid_t gid, kernel_cap_t cap_effective, u64 rdev)
+ uid_t uid, gid_t gid, kernel_cap_t cap_effective, u64 rdev,
+ struct sptlrpc_sepol *sepol)
{
struct mdt_rec_create *rec;
char *tmp;
op_data->op_file_encctx_size);
/* pack SELinux policy info if any */
- mdc_file_sepol_pack(pill);
+ mdc_file_sepol_pack(pill, sepol);
}
static inline __u64 mds_pack_open_flags(__u64 flags)
/* packing of MDS records */
void mdc_open_pack(struct req_capsule *pill, struct md_op_data *op_data,
umode_t mode, __u64 rdev, __u64 flags, const void *lmm,
- size_t lmmlen)
+ size_t lmmlen, struct sptlrpc_sepol *sepol)
{
struct mdt_rec_create *rec;
char *tmp;
op_data->op_file_encctx_size);
/* pack SELinux policy info if any */
- mdc_file_sepol_pack(pill);
+ mdc_file_sepol_pack(pill, sepol);
}
if (lmm) {
}
}
-void mdc_unlink_pack(struct req_capsule *pill, struct md_op_data *op_data)
+void mdc_unlink_pack(struct req_capsule *pill, struct md_op_data *op_data,
+ struct sptlrpc_sepol *sepol)
{
struct mdt_rec_unlink *rec;
mdc_pack_name(pill, &RMF_NAME, op_data->op_name, op_data->op_namelen);
/* pack SELinux policy info if any */
- mdc_file_sepol_pack(pill);
+ mdc_file_sepol_pack(pill, sepol);
}
-void mdc_link_pack(struct req_capsule *pill, struct md_op_data *op_data)
+void mdc_link_pack(struct req_capsule *pill, struct md_op_data *op_data,
+ struct sptlrpc_sepol *sepol)
{
struct mdt_rec_link *rec;
mdc_pack_name(pill, &RMF_NAME, op_data->op_name, op_data->op_namelen);
/* pack SELinux policy info if any */
- mdc_file_sepol_pack(pill);
+ mdc_file_sepol_pack(pill, sepol);
}
static void mdc_close_intent_pack(struct req_capsule *pill,
void mdc_rename_pack(struct req_capsule *pill, struct md_op_data *op_data,
const char *old, size_t oldlen,
- const char *new, size_t newlen)
+ const char *new, size_t newlen,
+ struct sptlrpc_sepol *sepol)
{
struct mdt_rec_rename *rec;
mdc_pack_name(pill, &RMF_SYMTGT, new, newlen);
/* pack SELinux policy info if any */
- mdc_file_sepol_pack(pill);
+ mdc_file_sepol_pack(pill, sepol);
}
void mdc_migrate_pack(struct req_capsule *pill, struct md_op_data *op_data,
int count = 0;
enum ldlm_mode mode;
int repsize, repsize_estimate;
+ struct sptlrpc_sepol *sepol;
int rc;
ENTRY;
op_data->op_file_encctx_size);
/* get SELinux policy info if any */
- rc = sptlrpc_get_sepol(req);
- if (rc < 0) {
- ptlrpc_request_free(req);
- RETURN(ERR_PTR(rc));
- }
+ sepol = sptlrpc_sepol_get(req);
+ if (IS_ERR(sepol))
+ GOTO(err_free_rq, rc = PTR_ERR(sepol));
+
req_capsule_set_size(&req->rq_pill, &RMF_SELINUX_POL, RCL_CLIENT,
- strlen(req->rq_sepol) ?
- strlen(req->rq_sepol) + 1 : 0);
+ sptlrpc_sepol_size(sepol));
rc = ldlm_prep_enqueue_req(exp, req, &cancels, count);
- if (rc < 0) {
- ptlrpc_request_free(req);
- RETURN(ERR_PTR(rc));
- }
+ if (rc < 0)
+ GOTO(err_put_sepol, rc);
spin_lock(&req->rq_lock);
req->rq_replay = req->rq_import->imp_replayable;
/* pack the intended request */
mdc_open_pack(&req->rq_pill, op_data, it->it_create_mode, 0,
- it->it_flags, lmm, lmmsize);
+ it->it_flags, lmm, lmmsize, sepol);
+
+ sptlrpc_sepol_put(sepol);
req_capsule_set_size(&req->rq_pill, &RMF_MDT_MD, RCL_SERVER,
mdt_md_capsule_size);
*/
req->rq_reqmsg->lm_repsize = repsize;
RETURN(req);
+
+err_put_sepol:
+ sptlrpc_sepol_put(sepol);
+err_free_rq:
+ ptlrpc_request_free(req);
+ return ERR_PTR(rc);
}
#define GA_DEFAULT_EA_NAME_LEN 20
{
struct ptlrpc_request *req;
struct ldlm_intent *lit;
+ struct sptlrpc_sepol *sepol;
int rc, count = 0;
LIST_HEAD(cancels);
u32 ea_vals_buf_size = GA_DEFAULT_EA_VAL_LEN * GA_DEFAULT_EA_NUM;
RETURN(ERR_PTR(-ENOMEM));
/* get SELinux policy info if any */
- rc = sptlrpc_get_sepol(req);
- if (rc < 0) {
- ptlrpc_request_free(req);
- RETURN(ERR_PTR(rc));
- }
+ sepol = sptlrpc_sepol_get(req);
+ if (IS_ERR(sepol))
+ GOTO(err_free_rq, rc = PTR_ERR(sepol));
+
req_capsule_set_size(&req->rq_pill, &RMF_SELINUX_POL, RCL_CLIENT,
- strlen(req->rq_sepol) ?
- strlen(req->rq_sepol) + 1 : 0);
+ sptlrpc_sepol_size(sepol));
rc = ldlm_prep_enqueue_req(exp, req, &cancels, count);
- if (rc) {
- ptlrpc_request_free(req);
- RETURN(ERR_PTR(rc));
- }
+ if (rc)
+ GOTO(err_put_sepol, rc);
/* pack the intent */
lit = req_capsule_client_get(&req->rq_pill, &RMF_LDLM_INTENT);
ea_vals_buf_size, -1, 0);
/* get SELinux policy info if any */
- mdc_file_sepol_pack(&req->rq_pill);
+ mdc_file_sepol_pack(&req->rq_pill, sepol);
+ sptlrpc_sepol_put(sepol);
req_capsule_set_size(&req->rq_pill, &RMF_EADATA, RCL_SERVER,
GA_DEFAULT_EA_NAME_LEN * GA_DEFAULT_EA_NUM);
ptlrpc_request_set_replen(req);
RETURN(req);
+
+err_put_sepol:
+ sptlrpc_sepol_put(sepol);
+err_free_rq:
+ ptlrpc_request_free(req);
+ RETURN(ERR_PTR(rc));
}
static struct ptlrpc_request *
struct ptlrpc_request **request)
{
struct ptlrpc_request *req;
+ struct sptlrpc_sepol *sepol;
int level, rc;
int count, resends = 0;
struct obd_import *import = exp->exp_obd->u.cli.cl_import;
op_data->op_file_encctx_size);
/* get SELinux policy info if any */
- rc = sptlrpc_get_sepol(req);
- if (rc < 0) {
- ptlrpc_request_free(req);
- RETURN(rc);
- }
+ sepol = sptlrpc_sepol_get(req);
+ if (IS_ERR(sepol))
+ GOTO(err_free_rq, rc = PTR_ERR(sepol));
+
req_capsule_set_size(&req->rq_pill, &RMF_SELINUX_POL, RCL_CLIENT,
- strlen(req->rq_sepol) ?
- strlen(req->rq_sepol) + 1 : 0);
+ sptlrpc_sepol_size(sepol));
rc = mdc_prep_elc_req(exp, req, MDS_REINT, &cancels, count);
- if (rc) {
- ptlrpc_request_free(req);
- RETURN(rc);
- }
+ if (rc)
+ GOTO(err_put_sepol, rc);
/*
* mdc_create_pack() fills msg->bufs[1] with name and msg->bufs[2] with
* tgt, for symlinks or lov MD data.
*/
mdc_create_pack(&req->rq_pill, op_data, data, datalen, mode, uid,
- gid, cap_effective, rdev);
+ gid, cap_effective, rdev, sepol);
+
+ sptlrpc_sepol_put(sepol);
req_capsule_set_size(&req->rq_pill, &RMF_MDT_MD, RCL_SERVER,
exp->exp_obd->u.cli.cl_default_mds_easize);
}
*request = req;
+
+ RETURN(rc);
+
+err_put_sepol:
+ sptlrpc_sepol_put(sepol);
+err_free_rq:
+ ptlrpc_request_free(req);
+
RETURN(rc);
}
int mdc_unlink(struct obd_export *exp, struct md_op_data *op_data,
- struct ptlrpc_request **request)
+ struct ptlrpc_request **request)
{
LIST_HEAD(cancels);
- struct obd_device *obd = class_exp2obd(exp);
- struct ptlrpc_request *req = *request;
- int count = 0, rc;
- ENTRY;
+ struct obd_device *obd = class_exp2obd(exp);
+ struct ptlrpc_request *req = *request;
+ struct sptlrpc_sepol *sepol;
+ int count = 0, rc;
+ ENTRY;
- LASSERT(req == NULL);
+ LASSERT(req == NULL);
if ((op_data->op_flags & MF_MDC_CANCEL_FID1) &&
(fid_is_sane(&op_data->op_fid1)))
CLI_DIRTY_DATA ?
MDS_INODELOCK_ELC :
MDS_INODELOCK_FULL);
- req = ptlrpc_request_alloc(class_exp2cliimp(exp),
- &RQF_MDS_REINT_UNLINK);
- if (req == NULL) {
- ldlm_lock_list_put(&cancels, l_bl_ast, count);
- RETURN(-ENOMEM);
- }
+ req = ptlrpc_request_alloc(class_exp2cliimp(exp),
+ &RQF_MDS_REINT_UNLINK);
+ if (req == NULL) {
+ ldlm_lock_list_put(&cancels, l_bl_ast, count);
+ RETURN(-ENOMEM);
+ }
- req_capsule_set_size(&req->rq_pill, &RMF_NAME, RCL_CLIENT,
- op_data->op_namelen + 1);
+ req_capsule_set_size(&req->rq_pill, &RMF_NAME, RCL_CLIENT,
+ op_data->op_namelen + 1);
/* get SELinux policy info if any */
- rc = sptlrpc_get_sepol(req);
- if (rc < 0) {
- ptlrpc_request_free(req);
- RETURN(rc);
- }
+ sepol = sptlrpc_sepol_get(req);
+ if (IS_ERR(sepol))
+ GOTO(err_free_rq, rc = PTR_ERR(sepol));
+
req_capsule_set_size(&req->rq_pill, &RMF_SELINUX_POL, RCL_CLIENT,
- strlen(req->rq_sepol) ?
- strlen(req->rq_sepol) + 1 : 0);
+ sptlrpc_sepol_size(sepol));
rc = mdc_prep_elc_req(exp, req, MDS_REINT, &cancels, count);
- if (rc) {
- ptlrpc_request_free(req);
- RETURN(rc);
- }
+ if (rc)
+ GOTO(err_put_sepol, rc);
- mdc_unlink_pack(&req->rq_pill, op_data);
+ mdc_unlink_pack(&req->rq_pill, op_data, sepol);
+ sptlrpc_sepol_put(sepol);
req_capsule_set_size(&req->rq_pill, &RMF_MDT_MD, RCL_SERVER,
obd->u.cli.cl_default_mds_easize);
ptlrpc_request_set_replen(req);
- *request = req;
+ *request = req;
rc = mdc_reint(req, LUSTRE_IMP_FULL);
- if (rc == -ERESTARTSYS)
- rc = 0;
- RETURN(rc);
+ if (rc == -ERESTARTSYS)
+ rc = 0;
+
+ RETURN(rc);
+
+err_put_sepol:
+ sptlrpc_sepol_put(sepol);
+err_free_rq:
+ ptlrpc_request_free(req);
+
+ RETURN(rc);
}
int mdc_link(struct obd_export *exp, struct md_op_data *op_data,
- struct ptlrpc_request **request)
+ struct ptlrpc_request **request)
{
LIST_HEAD(cancels);
- struct ptlrpc_request *req;
- int count = 0, rc;
- ENTRY;
+ struct ptlrpc_request *req;
+ struct sptlrpc_sepol *sepol;
+ int count = 0, rc;
+ ENTRY;
- if ((op_data->op_flags & MF_MDC_CANCEL_FID2) &&
- (fid_is_sane(&op_data->op_fid2)))
- count = mdc_resource_get_unused(exp, &op_data->op_fid2,
- &cancels, LCK_EX,
- MDS_INODELOCK_UPDATE);
- if ((op_data->op_flags & MF_MDC_CANCEL_FID1) &&
- (fid_is_sane(&op_data->op_fid1)))
- count += mdc_resource_get_unused(exp, &op_data->op_fid1,
- &cancels, LCK_EX,
- MDS_INODELOCK_UPDATE);
-
- req = ptlrpc_request_alloc(class_exp2cliimp(exp), &RQF_MDS_REINT_LINK);
- if (req == NULL) {
- ldlm_lock_list_put(&cancels, l_bl_ast, count);
- RETURN(-ENOMEM);
- }
+ if ((op_data->op_flags & MF_MDC_CANCEL_FID2) &&
+ (fid_is_sane(&op_data->op_fid2)))
+ count = mdc_resource_get_unused(exp, &op_data->op_fid2,
+ &cancels, LCK_EX,
+ MDS_INODELOCK_UPDATE);
+ if ((op_data->op_flags & MF_MDC_CANCEL_FID1) &&
+ (fid_is_sane(&op_data->op_fid1)))
+ count += mdc_resource_get_unused(exp, &op_data->op_fid1,
+ &cancels, LCK_EX,
+ MDS_INODELOCK_UPDATE);
- req_capsule_set_size(&req->rq_pill, &RMF_NAME, RCL_CLIENT,
- op_data->op_namelen + 1);
+ req = ptlrpc_request_alloc(class_exp2cliimp(exp), &RQF_MDS_REINT_LINK);
+ if (req == NULL) {
+ ldlm_lock_list_put(&cancels, l_bl_ast, count);
+ RETURN(-ENOMEM);
+ }
+
+ req_capsule_set_size(&req->rq_pill, &RMF_NAME, RCL_CLIENT,
+ op_data->op_namelen + 1);
/* get SELinux policy info if any */
- rc = sptlrpc_get_sepol(req);
- if (rc < 0) {
- ptlrpc_request_free(req);
- RETURN(rc);
- }
+ sepol = sptlrpc_sepol_get(req);
+ if (IS_ERR(sepol))
+ GOTO(err_free_rq, rc = PTR_ERR(sepol));
+
req_capsule_set_size(&req->rq_pill, &RMF_SELINUX_POL, RCL_CLIENT,
- strlen(req->rq_sepol) ?
- strlen(req->rq_sepol) + 1 : 0);
+ sptlrpc_sepol_size(sepol));
rc = mdc_prep_elc_req(exp, req, MDS_REINT, &cancels, count);
- if (rc) {
- ptlrpc_request_free(req);
- RETURN(rc);
- }
+ if (rc)
+ GOTO(err_put_sepol, rc);
+
+ mdc_link_pack(&req->rq_pill, op_data, sepol);
+ sptlrpc_sepol_put(sepol);
- mdc_link_pack(&req->rq_pill, op_data);
ptlrpc_request_set_replen(req);
rc = mdc_reint(req, LUSTRE_IMP_FULL);
- *request = req;
- if (rc == -ERESTARTSYS)
- rc = 0;
+ *request = req;
+ if (rc == -ERESTARTSYS)
+ rc = 0;
+
+ RETURN(rc);
+
+err_put_sepol:
+ sptlrpc_sepol_put(sepol);
+err_free_rq:
+ ptlrpc_request_free(req);
- RETURN(rc);
+ RETURN(rc);
}
int mdc_rename(struct obd_export *exp, struct md_op_data *op_data,
LIST_HEAD(cancels);
struct obd_device *obd = exp->exp_obd;
struct ptlrpc_request *req;
+ struct sptlrpc_sepol *sepol;
int count = 0, rc;
ENTRY;
op_data->op_data_size);
/* get SELinux policy info if any */
- rc = sptlrpc_get_sepol(req);
- if (rc < 0) {
- ptlrpc_request_free(req);
- RETURN(rc);
- }
+ sepol = sptlrpc_sepol_get(req);
+ if (IS_ERR(sepol))
+ GOTO(err_free_rq, rc = PTR_ERR(sepol));
+
req_capsule_set_size(&req->rq_pill, &RMF_SELINUX_POL, RCL_CLIENT,
- strlen(req->rq_sepol) ?
- strlen(req->rq_sepol) + 1 : 0);
+ sptlrpc_sepol_size(sepol));
rc = mdc_prep_elc_req(exp, req, MDS_REINT, &cancels, count);
- if (rc) {
- ptlrpc_request_free(req);
- RETURN(rc);
- }
+ if (rc)
+ GOTO(err_put_sepol, rc);
if (exp_connect_cancelset(exp) && req)
ldlm_cli_cancel_list(&cancels, count, req, 0);
mdc_migrate_pack(&req->rq_pill, op_data, old, oldlen);
else
mdc_rename_pack(&req->rq_pill, op_data, old, oldlen,
- new, newlen);
+ new, newlen, sepol);
+
+ sptlrpc_sepol_put(sepol);
req_capsule_set_size(&req->rq_pill, &RMF_MDT_MD, RCL_SERVER,
obd->u.cli.cl_default_mds_easize);
rc = 0;
RETURN(rc);
+
+err_put_sepol:
+ sptlrpc_sepol_put(sepol);
+err_free_rq:
+ ptlrpc_request_free(req);
+
+ RETURN(rc);
}
int mdc_file_resync(struct obd_export *exp, struct md_op_data *op_data)
int input_size, int output_size, int flags,
__u32 suppgid, struct ptlrpc_request **request)
{
- struct ptlrpc_request *req;
- int xattr_namelen = 0;
- char *tmp;
- int rc;
- ENTRY;
+ struct ptlrpc_request *req;
+ struct sptlrpc_sepol *sepol;
+ int xattr_namelen = 0;
+ char *tmp;
+ int rc;
+ ENTRY;
- *request = NULL;
- req = ptlrpc_request_alloc(class_exp2cliimp(exp), fmt);
- if (req == NULL)
- RETURN(-ENOMEM);
+ *request = NULL;
+ req = ptlrpc_request_alloc(class_exp2cliimp(exp), fmt);
+ if (req == NULL)
+ RETURN(-ENOMEM);
if (xattr_name) {
xattr_namelen = strlen(xattr_name) + 1;
input_size);
/* get SELinux policy info if any */
- rc = sptlrpc_get_sepol(req);
- if (rc < 0) {
- ptlrpc_request_free(req);
- RETURN(rc);
- }
+ sepol = sptlrpc_sepol_get(req);
+ if (IS_ERR(sepol))
+ GOTO(err_free_rq, rc = PTR_ERR(sepol));
+
req_capsule_set_size(&req->rq_pill, &RMF_SELINUX_POL, RCL_CLIENT,
- strlen(req->rq_sepol) ?
- strlen(req->rq_sepol) + 1 : 0);
+ sptlrpc_sepol_size(sepol));
/* Flush local XATTR locks to get rid of a possible cancel RPC */
if (opcode == MDS_REINT && fid_is_sane(fid) &&
MDS_INODELOCK_XATTR);
rc = mdc_prep_elc_req(exp, req, MDS_REINT, &cancels, count);
- if (rc) {
- ptlrpc_request_free(req);
- RETURN(rc);
- }
+ if (rc)
+ GOTO(err_put_sepol, rc);
} else {
rc = ptlrpc_request_pack(req, LUSTRE_MDS_VERSION, opcode);
- if (rc) {
- ptlrpc_request_free(req);
- RETURN(rc);
- }
+ if (rc)
+ GOTO(err_put_sepol, rc);
}
if (opcode == MDS_REINT) {
req->rq_request_portal = MDS_READPAGE_PORTAL;
}
- if (xattr_name) {
- tmp = req_capsule_client_get(&req->rq_pill, &RMF_NAME);
- memcpy(tmp, xattr_name, xattr_namelen);
- }
- if (input_size) {
- tmp = req_capsule_client_get(&req->rq_pill, &RMF_EADATA);
- memcpy(tmp, input, input_size);
- }
+ if (xattr_name) {
+ tmp = req_capsule_client_get(&req->rq_pill, &RMF_NAME);
+ memcpy(tmp, xattr_name, xattr_namelen);
+ }
+ if (input_size) {
+ tmp = req_capsule_client_get(&req->rq_pill, &RMF_EADATA);
+ memcpy(tmp, input, input_size);
+ }
- mdc_file_sepol_pack(&req->rq_pill);
+ mdc_file_sepol_pack(&req->rq_pill, sepol);
+ sptlrpc_sepol_put(sepol);
- if (req_capsule_has_field(&req->rq_pill, &RMF_EADATA, RCL_SERVER))
- req_capsule_set_size(&req->rq_pill, &RMF_EADATA,
- RCL_SERVER, output_size);
- ptlrpc_request_set_replen(req);
+ if (req_capsule_has_field(&req->rq_pill, &RMF_EADATA, RCL_SERVER))
+ req_capsule_set_size(&req->rq_pill, &RMF_EADATA,
+ RCL_SERVER, output_size);
+ ptlrpc_request_set_replen(req);
- /* make rpc */
- if (opcode == MDS_REINT)
+ /* make rpc */
+ if (opcode == MDS_REINT)
ptlrpc_get_mod_rpc_slot(req);
- rc = ptlrpc_queue_wait(req);
+ rc = ptlrpc_queue_wait(req);
if (opcode == MDS_REINT)
ptlrpc_put_mod_rpc_slot(req);
- if (rc)
- ptlrpc_req_finished(req);
- else
- *request = req;
- RETURN(rc);
+ if (rc)
+ ptlrpc_req_finished(req);
+ else
+ *request = req;
+ RETURN(rc);
+
+err_put_sepol:
+ sptlrpc_sepol_put(sepol);
+err_free_rq:
+ ptlrpc_request_free(req);
+ RETURN(rc);
+
}
static int mdc_setxattr(struct obd_export *exp, const struct lu_fid *fid,
CDEBUG(D_SEC, "destroy %s@%p\n", sec->ps_policy->sp_name, sec);
+ LASSERT(atomic_read(&sec->ps_nctx) == 0);
LASSERT(hlist_empty(&gsec_kr->gsk_clist));
LASSERT(gsec_kr->gsk_root_ctx == NULL);
sec->ps_import = class_import_get(imp);
spin_lock_init(&sec->ps_lock);
INIT_LIST_HEAD(&sec->ps_gc_list);
- sec->ps_sepol_mtime = ktime_set(0, 0);
- sec->ps_sepol_checknext = ktime_set(0, 0);
- sec->ps_sepol[0] = '\0';
if (!svcctx) {
sec->ps_gc_interval = GSS_GC_INTERVAL;
int set_transno = 0;
__u64 committed_before_reconnect = 0;
struct ptlrpc_request *request;
+ struct sptlrpc_sepol *sepol;
struct obd_connect_data ocd;
char *bufs[] = { NULL,
obd2cli_tgt(imp->imp_obd),
GOTO(out, rc = -ENOMEM);
/* get SELinux policy info if any */
- rc = sptlrpc_get_sepol(request);
- if (rc < 0) {
+ sepol = sptlrpc_sepol_get(request);
+ if (IS_ERR(sepol)) {
ptlrpc_request_free(request);
- GOTO(out, rc);
+ GOTO(out, rc = PTR_ERR(sepol));
}
- bufs[5] = request->rq_sepol;
+ bufs[5] = sepol->ssp_sepol;
req_capsule_set_size(&request->rq_pill, &RMF_SELINUX_POL, RCL_CLIENT,
- strlen(request->rq_sepol) ?
- strlen(request->rq_sepol) + 1 : 0);
+ sptlrpc_sepol_size(sepol));
rc = ptlrpc_request_bufs_pack(request, LUSTRE_OBD_VERSION,
imp->imp_connect_op, bufs, NULL);
+
+ sptlrpc_sepol_put(sepol);
if (rc) {
ptlrpc_request_free(request);
GOTO(out, rc);
static void sec_cop_destroy_sec(struct ptlrpc_sec *sec)
{
struct ptlrpc_sec_policy *policy = sec->ps_policy;
+ struct sptlrpc_sepol *sepol;
LASSERT(atomic_read(&sec->ps_refcount) == 0);
- LASSERT(atomic_read(&sec->ps_nctx) == 0);
LASSERT(policy->sp_cops->destroy_sec);
CDEBUG(D_SEC, "%s@%p: being destroyed\n", sec->ps_policy->sp_name, sec);
+ spin_lock(&sec->ps_lock);
+ sec->ps_sepol_checknext = ktime_set(0, 0);
+ sepol = rcu_dereference_protected(sec->ps_sepol, 1);
+ rcu_assign_pointer(sec->ps_sepol, NULL);
+ spin_unlock(&sec->ps_lock);
+
+ sptlrpc_sepol_put(sepol);
+
policy->sp_cops->destroy_sec(sec);
sptlrpc_policy_put(policy);
}
return policy->sp_sops->install_rctx(imp, ctx);
}
+
/* Get SELinux policy info from userspace */
static int sepol_helper(struct obd_import *imp)
{
[8] = mode_str, /* enforcing mode */
[9] = NULL
};
+ struct sptlrpc_sepol *sepol;
char *envp[] = {
[0] = "HOME=/",
[1] = "PATH=/sbin:/usr/sbin",
int rc = 0;
if (imp == NULL || imp->imp_obd == NULL ||
- imp->imp_obd->obd_type == NULL) {
- rc = -EINVAL;
+ imp->imp_obd->obd_type == NULL)
+ RETURN(-EINVAL);
+
+ argv[2] = (char *)imp->imp_obd->obd_type->typ_name;
+ argv[4] = imp->imp_obd->obd_name;
+
+ rcu_read_lock();
+ sepol = rcu_dereference(imp->imp_sec->ps_sepol);
+ if (!sepol) {
+ /* ps_sepol has not been initialized */
+ argv[5] = NULL;
+ argv[7] = NULL;
} else {
- argv[2] = (char *)imp->imp_obd->obd_type->typ_name;
- argv[4] = imp->imp_obd->obd_name;
- spin_lock(&imp->imp_sec->ps_lock);
- if (ktime_to_ns(imp->imp_sec->ps_sepol_mtime) == 0 &&
- imp->imp_sec->ps_sepol[0] == '\0') {
- /* ps_sepol has not been initialized */
- argv[5] = NULL;
- argv[7] = NULL;
- } else {
- time64_t mtime_ms;
+ time64_t mtime_ms;
- mtime_ms = ktime_to_ms(imp->imp_sec->ps_sepol_mtime);
- snprintf(mtime_str, sizeof(mtime_str), "%lld",
- mtime_ms / MSEC_PER_SEC);
- mode_str[0] = imp->imp_sec->ps_sepol[0];
- }
- spin_unlock(&imp->imp_sec->ps_lock);
- ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
- rc = ret>>8;
+ mtime_ms = ktime_to_ms(sepol->ssp_mtime);
+ snprintf(mtime_str, sizeof(mtime_str), "%lld",
+ mtime_ms / MSEC_PER_SEC);
+ if (sepol->ssp_sepol_size > 1)
+ mode_str[0] = sepol->ssp_sepol[0];
}
+ rcu_read_unlock();
+
+ ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_PROC);
+ rc = ret>>8;
return rc;
}
return 1;
}
-int sptlrpc_get_sepol(struct ptlrpc_request *req)
+static void sptlrpc_sepol_release(struct kref *ref)
+{
+ struct sptlrpc_sepol *p = container_of(ref, struct sptlrpc_sepol,
+ ssp_ref);
+ kfree_rcu(p, ssp_rcu);
+}
+
+void sptlrpc_sepol_put(struct sptlrpc_sepol *pol)
+{
+ if (!pol)
+ return;
+ kref_put(&pol->ssp_ref, sptlrpc_sepol_release);
+}
+EXPORT_SYMBOL(sptlrpc_sepol_put);
+
+struct sptlrpc_sepol *sptlrpc_sepol_get_cached(struct ptlrpc_sec *imp_sec)
+{
+ struct sptlrpc_sepol *p;
+
+retry:
+ rcu_read_lock();
+ p = rcu_dereference(imp_sec->ps_sepol);
+ if (p && !kref_get_unless_zero(&p->ssp_ref)) {
+ rcu_read_unlock();
+ goto retry;
+ }
+ rcu_read_unlock();
+
+ return p;
+}
+EXPORT_SYMBOL(sptlrpc_sepol_get_cached);
+
+struct sptlrpc_sepol *sptlrpc_sepol_get(struct ptlrpc_request *req)
{
struct ptlrpc_sec *imp_sec = req->rq_import->imp_sec;
+ struct sptlrpc_sepol *out;
int rc = 0;
ENTRY;
- (req->rq_sepol)[0] = '\0';
-
#ifndef HAVE_SELINUX
if (unlikely(send_sepol != 0))
CDEBUG(D_SEC,
"Client cannot report SELinux status, it was not built against libselinux.\n");
- RETURN(0);
+ RETURN(NULL);
#endif
if (send_sepol == 0)
- RETURN(0);
+ RETURN(NULL);
if (imp_sec == NULL)
- RETURN(-EINVAL);
+ RETURN(ERR_PTR(-EINVAL));
/* Retrieve SELinux status info */
if (sptlrpc_sepol_needs_check(imp_sec))
rc = sepol_helper(req->rq_import);
- if (likely(rc == 0)) {
- spin_lock(&imp_sec->ps_lock);
- memcpy(req->rq_sepol, imp_sec->ps_sepol,
- sizeof(req->rq_sepol));
- spin_unlock(&imp_sec->ps_lock);
- } else if (rc == -ENODEV) {
+
+ if (unlikely(rc == -ENODEV)) {
CDEBUG(D_SEC,
"Client cannot report SELinux status, SELinux is disabled.\n");
- rc = 0;
+ RETURN(NULL);
}
+ if (unlikely(rc))
+ RETURN(ERR_PTR(rc));
- RETURN(rc);
+ out = sptlrpc_sepol_get_cached(imp_sec);
+ if (!out)
+ RETURN(ERR_PTR(-ENODATA));
+
+ RETURN(out);
}
-EXPORT_SYMBOL(sptlrpc_get_sepol);
+EXPORT_SYMBOL(sptlrpc_sepol_get);
/*
* server side security
LDEBUGFS_SEQ_FOPS_RO(sptlrpc_ctxs_lprocfs);
+static inline
+bool sptlrpc_sepol_update_needed(struct ptlrpc_sec *imp_sec,
+ ktime_t mtime, char *pol, size_t pol_len)
+{
+ struct sptlrpc_sepol *old;
+ bool rc;
+
+ rcu_read_lock();
+ old = rcu_dereference(imp_sec->ps_sepol);
+ if (!old)
+ rc = true;
+ else if (!kref_read(&old->ssp_ref))
+ rc = false;
+ else if (ktime_compare(old->ssp_mtime, mtime) != 0)
+ rc = true;
+ else
+ rc = false;
+ rcu_read_unlock();
+
+ return rc;
+}
+static int sptlrpc_sepol_update(struct obd_import *imp,
+ ktime_t mtime, char *pol, size_t pol_len)
+{
+ struct sptlrpc_sepol *old;
+ struct sptlrpc_sepol *new;
+ struct ptlrpc_sec *imp_sec;
+ int rc = 0;
+
+ imp_sec = sptlrpc_import_sec_ref(imp);
+ if (!imp_sec)
+ RETURN(-ENODEV);
+
+ if (!sptlrpc_sepol_update_needed(imp_sec, mtime, pol, pol_len))
+ GOTO(out, rc);
+
+ new = kmalloc(sizeof(typeof(*new)) + pol_len + 1, GFP_KERNEL);
+ if (!new)
+ GOTO(out, rc = -ENOMEM);
+
+ kref_init(&new->ssp_ref);
+ new->ssp_sepol_size = pol_len + 1;
+ new->ssp_mtime = mtime;
+ strlcpy(new->ssp_sepol, pol, new->ssp_sepol_size);
+
+ spin_lock(&imp_sec->ps_lock);
+ old = rcu_dereference_protected(imp_sec->ps_sepol, 1);
+ rcu_assign_pointer(imp_sec->ps_sepol, new);
+ spin_unlock(&imp_sec->ps_lock);
+ sptlrpc_sepol_put(old);
+out:
+ sptlrpc_sec_put(imp_sec);
+
+ return rc;
+}
+
#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 16, 53, 0)
static ssize_t sepol_seq_write_old(struct obd_device *obd,
const char __user *buffer, size_t count)
struct client_obd *cli = &obd->u.cli;
struct obd_import *imp = cli->cl_import;
struct sepol_downcall_data_old *param;
- size_t maxlen = sizeof(imp->imp_sec->ps_sepol);
+ size_t maxlen = LUSTRE_NODEMAP_SEPOL_LENGTH + 1;
size_t size = sizeof(*param);
size_t maxparam = sizeof(*param) + maxlen;
int len;
GOTO(out, rc);
}
- spin_lock(&imp->imp_sec->ps_lock);
- memcpy(imp->imp_sec->ps_sepol, param->sdd_sepol, len);
- imp->imp_sec->ps_sepol[len + 1] = '\0';
- imp->imp_sec->ps_sepol_mtime = ktime_set(param->sdd_sepol_mtime, 0);
- spin_unlock(&imp->imp_sec->ps_lock);
-
+ rc = sptlrpc_sepol_update(imp, ktime_set(param->sdd_sepol_mtime, 0),
+ param->sdd_sepol, len);
out:
OBD_FREE(param, maxparam);
struct client_obd *cli = &obd->u.cli;
struct obd_import *imp = cli->cl_import;
struct sepol_downcall_data *param;
- size_t maxlen = sizeof(imp->imp_sec->ps_sepol);
+ size_t maxlen = LUSTRE_NODEMAP_SEPOL_LENGTH + 1;
size_t size = sizeof(*param);
size_t maxparam = size + maxlen;
int len;
GOTO(out, rc);
}
- spin_lock(&imp->imp_sec->ps_lock);
- memcpy(imp->imp_sec->ps_sepol, param->sdd_sepol, len);
- imp->imp_sec->ps_sepol[len + 1] = '\0';
- imp->imp_sec->ps_sepol_mtime = ktime_set(param->sdd_sepol_mtime, 0);
- spin_unlock(&imp->imp_sec->ps_lock);
-
+ rc = sptlrpc_sepol_update(imp, ktime_set(param->sdd_sepol_mtime, 0),
+ param->sdd_sepol, len);
out:
OBD_FREE(param, maxparam);
return rc ?: count;
}
-LDEBUGFS_FOPS_WR_ONLY(srpc, sptlrpc_sepol);
+
+static int lprocfs_sptlrpc_sepol_seq_show(struct seq_file *seq, void *v)
+{
+ struct obd_device *obd = seq->private;
+ struct client_obd *cli = &obd->u.cli;
+ struct obd_import *imp = cli->cl_import;
+ struct ptlrpc_sec *imp_sec;
+ struct sptlrpc_sepol *sepol;
+ struct timespec64 ts;
+ int rc = 0;
+
+ imp_sec = sptlrpc_import_sec_ref(imp);
+ if (!imp_sec)
+ RETURN(-ENODEV);
+
+ rcu_read_lock();
+ sepol = rcu_dereference(imp->imp_sec->ps_sepol);
+ if (sepol) {
+ ts = ktime_to_timespec64(sepol->ssp_mtime);
+ seq_printf(seq, "mtime: %lld\n", (long long int) ts.tv_sec);
+ seq_printf(seq, "sepol: %.*s\n",
+ sepol->ssp_sepol_size, sepol->ssp_sepol);
+ } else {
+ seq_puts(seq, "uninitialized\n");
+ }
+ rcu_read_unlock();
+ sptlrpc_sec_put(imp_sec);
+
+ return rc;
+}
+LDEBUGFS_SEQ_FOPS_RW_TYPE(srpc, sptlrpc_sepol);
int sptlrpc_lprocfs_cliobd_attach(struct obd_device *obd)
{
/*
* general layer has take a module reference for us, because we never
- * really destroy the sec, simply release the reference here.
+ * really destroy the sec, take only 1 module reference for all the
+ * imports. This reference will be released by sec_cop_destroy_sec().
+ * The additional ps_refcount will be released in null_kill_sec().
*/
- sptlrpc_policy_put(&null_policy);
+ if (atomic_inc_return(&null_sec.ps_refcount) != 1)
+ sptlrpc_policy_put(&null_policy);
+
return &null_sec;
}
}
static
+void null_kill_sec(struct ptlrpc_sec *sec)
+{
+ /* release the ref taken by null_create_sec() */
+ sptlrpc_sec_put(sec);
+}
+
+static
struct ptlrpc_cli_ctx *null_lookup_ctx(struct ptlrpc_sec *sec,
struct vfs_cred *vcred,
int create, int remove_dead)
static struct ptlrpc_sec_cops null_sec_cops = {
.create_sec = null_create_sec,
.destroy_sec = null_destroy_sec,
+ .kill_sec = null_kill_sec,
.lookup_ctx = null_lookup_ctx,
.flush_ctx_cache = null_flush_ctx_cache,
.alloc_reqbuf = null_alloc_reqbuf,
static HLIST_HEAD(__list);
null_sec.ps_policy = &null_policy;
- atomic_set(&null_sec.ps_refcount, 1); /* always busy */
+ atomic_set(&null_sec.ps_refcount, 0);
null_sec.ps_id = -1;
null_sec.ps_import = NULL;
null_sec.ps_flvr.sf_rpc = SPTLRPC_FLVR_NULL;