Skip to content

Commit

Permalink
LSM: Use lsmcontext in security_dentry_init_security
Browse files Browse the repository at this point in the history
Replace the (secctx,seclen) pointer pair with a single
lsmcontext pointer to allow return of the LSM identifier
along with the context and context length. This allows
security_release_secctx() to know how to release the
context. Callers have been modified to use or save the
returned data from the new structure.

Special care is taken in the NFS code, which uses the
same data structure for its own copied labels as it does
for the data which comes from security_dentry_init_security().
In the case of copied labels the data has to be freed, not
released.

Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
  • Loading branch information
cschaufler authored and intel-lab-lkp committed Jun 28, 2022
1 parent c44cd03 commit c930a07
Show file tree
Hide file tree
Showing 12 changed files with 99 additions and 81 deletions.
3 changes: 1 addition & 2 deletions fs/ceph/super.h
Expand Up @@ -1063,8 +1063,7 @@ struct ceph_acl_sec_ctx {
void *acl;
#endif
#ifdef CONFIG_CEPH_FS_SECURITY_LABEL
void *sec_ctx;
u32 sec_ctxlen;
struct lsmcontext lsmctx;
#endif
struct ceph_pagelist *pagelist;
};
Expand Down
19 changes: 6 additions & 13 deletions fs/ceph/xattr.c
Expand Up @@ -1328,8 +1328,7 @@ int ceph_security_init_secctx(struct dentry *dentry, umode_t mode,
int err;

err = security_dentry_init_security(dentry, mode, &dentry->d_name,
&name, &as_ctx->sec_ctx,
&as_ctx->sec_ctxlen);
&name, &as_ctx->lsmctx);
if (err < 0) {
WARN_ON_ONCE(err != -EOPNOTSUPP);
err = 0; /* do nothing */
Expand All @@ -1354,7 +1353,7 @@ int ceph_security_init_secctx(struct dentry *dentry, umode_t mode,
*/
name_len = strlen(name);
err = ceph_pagelist_reserve(pagelist,
4 * 2 + name_len + as_ctx->sec_ctxlen);
4 * 2 + name_len + as_ctx->lsmctx.len);
if (err)
goto out;

Expand All @@ -1374,11 +1373,9 @@ int ceph_security_init_secctx(struct dentry *dentry, umode_t mode,
as_ctx->pagelist = pagelist;
}

ceph_pagelist_encode_32(pagelist, name_len);
ceph_pagelist_append(pagelist, name, name_len);

ceph_pagelist_encode_32(pagelist, as_ctx->sec_ctxlen);
ceph_pagelist_append(pagelist, as_ctx->sec_ctx, as_ctx->sec_ctxlen);
ceph_pagelist_encode_32(pagelist, as_ctx->lsmctx.len);
ceph_pagelist_append(pagelist, as_ctx->lsmctx.context,
as_ctx->lsmctx.len);

err = 0;
out:
Expand All @@ -1391,16 +1388,12 @@ int ceph_security_init_secctx(struct dentry *dentry, umode_t mode,

void ceph_release_acl_sec_ctx(struct ceph_acl_sec_ctx *as_ctx)
{
#ifdef CONFIG_CEPH_FS_SECURITY_LABEL
struct lsmcontext scaff; /* scaffolding */
#endif
#ifdef CONFIG_CEPH_FS_POSIX_ACL
posix_acl_release(as_ctx->acl);
posix_acl_release(as_ctx->default_acl);
#endif
#ifdef CONFIG_CEPH_FS_SECURITY_LABEL
lsmcontext_init(&scaff, as_ctx->sec_ctx, as_ctx->sec_ctxlen, 0);
security_release_secctx(&scaff);
security_release_secctx(&as_ctx->lsmctx);
#endif
if (as_ctx->pagelist)
ceph_pagelist_release(as_ctx->pagelist);
Expand Down
35 changes: 18 additions & 17 deletions fs/fuse/dir.c
Expand Up @@ -464,29 +464,29 @@ static int get_security_context(struct dentry *entry, umode_t mode,
{
struct fuse_secctx *fctx;
struct fuse_secctx_header *header;
void *ctx = NULL, *ptr;
u32 ctxlen, total_len = sizeof(*header);
struct lsmcontext lsmctx = { };
void *ptr;
u32 total_len = sizeof(*header);
int err, nr_ctx = 0;
const char *name;
const char *name = NULL;
size_t namelen;

err = security_dentry_init_security(entry, mode, &entry->d_name,
&name, &ctx, &ctxlen);
if (err) {
if (err != -EOPNOTSUPP)
goto out_err;
/* No LSM is supporting this security hook. Ignore error */
ctxlen = 0;
ctx = NULL;
}
&name, &lsmctx);

/* If no LSM is supporting this security hook ignore error */
if (err && err != -EOPNOTSUPP)
goto out_err;

if (ctxlen) {
if (lsmctx.len) {
nr_ctx = 1;
namelen = strlen(name) + 1;
err = -EIO;
if (WARN_ON(namelen > XATTR_NAME_MAX + 1 || ctxlen > S32_MAX))
if (WARN_ON(namelen > XATTR_NAME_MAX + 1 ||
lsmctx.len > S32_MAX))
goto out_err;
total_len += FUSE_REC_ALIGN(sizeof(*fctx) + namelen + ctxlen);
total_len += FUSE_REC_ALIGN(sizeof(*fctx) + namelen +
lsmctx.len);
}

err = -ENOMEM;
Expand All @@ -499,19 +499,20 @@ static int get_security_context(struct dentry *entry, umode_t mode,
ptr += sizeof(*header);
if (nr_ctx) {
fctx = ptr;
fctx->size = ctxlen;
fctx->size = lsmctx.len;
ptr += sizeof(*fctx);

strcpy(ptr, name);
ptr += namelen;

memcpy(ptr, ctx, ctxlen);
memcpy(ptr, lsmctx.context, lsmctx.len);
}
*security_ctxlen = total_len;
*security_ctx = header;
err = 0;
out_err:
kfree(ctx);
if (nr_ctx)
security_release_secctx(&lsmctx);
return err;
}

Expand Down
2 changes: 1 addition & 1 deletion fs/nfs/dir.c
Expand Up @@ -810,7 +810,7 @@ static int nfs_readdir_entry_decode(struct nfs_readdir_descriptor *desc,
int ret;

if (entry->fattr->label)
entry->fattr->label->len = NFS4_MAXLABELLEN;
entry->fattr->label->lsmctx.len = NFS4_MAXLABELLEN;
ret = xdr_decode(desc, entry, stream);
if (ret || !desc->plus)
return ret;
Expand Down
17 changes: 10 additions & 7 deletions fs/nfs/inode.c
Expand Up @@ -361,14 +361,15 @@ void nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr)
return;

if ((fattr->valid & NFS_ATTR_FATTR_V4_SECURITY_LABEL) && inode->i_security) {
error = security_inode_notifysecctx(inode, fattr->label->label,
fattr->label->len);
error = security_inode_notifysecctx(inode,
fattr->label->lsmctx.context,
fattr->label->lsmctx.len);
if (error)
printk(KERN_ERR "%s() %s %d "
"security_inode_notifysecctx() %d\n",
__func__,
(char *)fattr->label->label,
fattr->label->len, error);
(char *)fattr->label->lsmctx.context,
fattr->label->lsmctx.len, error);
nfs_clear_label_invalid(inode);
}
}
Expand All @@ -384,12 +385,14 @@ struct nfs4_label *nfs4_label_alloc(struct nfs_server *server, gfp_t flags)
if (label == NULL)
return ERR_PTR(-ENOMEM);

label->label = kzalloc(NFS4_MAXLABELLEN, flags);
if (label->label == NULL) {
label->lsmctx.context = kzalloc(NFS4_MAXLABELLEN, flags);
if (label->lsmctx.context == NULL) {
kfree(label);
return ERR_PTR(-ENOMEM);
}
label->len = NFS4_MAXLABELLEN;
label->lsmctx.len = NFS4_MAXLABELLEN;
/* Use an invalid LSM slot as this should never be "released". */
label->lsmctx.slot = -1;

return label;
}
Expand Down
8 changes: 5 additions & 3 deletions fs/nfs/internal.h
Expand Up @@ -342,13 +342,15 @@ nfs4_label_copy(struct nfs4_label *dst, struct nfs4_label *src)
if (!dst || !src)
return NULL;

if (src->len > NFS4_MAXLABELLEN)
if (src->lsmctx.len > NFS4_MAXLABELLEN)
return NULL;

dst->lfs = src->lfs;
dst->pi = src->pi;
dst->len = src->len;
memcpy(dst->label, src->label, src->len);
/* Use an invalid LSM slot as lsmctx should never be "released" */
dst->lsmctx.slot = -1;
dst->lsmctx.len = src->lsmctx.len;
memcpy(dst->lsmctx.context, src->lsmctx.context, src->lsmctx.len);

return dst;
}
Expand Down
20 changes: 8 additions & 12 deletions fs/nfs/nfs4proc.c
Expand Up @@ -123,8 +123,7 @@ nfs4_label_init_security(struct inode *dir, struct dentry *dentry,
return NULL;

err = security_dentry_init_security(dentry, sattr->ia_mode,
&dentry->d_name, NULL,
(void **)&label->label, &label->len);
&dentry->d_name, NULL, &label->lsmctx);
if (err == 0)
return label;

Expand All @@ -133,12 +132,8 @@ nfs4_label_init_security(struct inode *dir, struct dentry *dentry,
static inline void
nfs4_label_release_security(struct nfs4_label *label)
{
struct lsmcontext scaff; /* scaffolding */

if (label) {
lsmcontext_init(&scaff, label->label, label->len, 0);
security_release_secctx(&scaff);
}
if (label)
security_release_secctx(&label->lsmctx);
}
static inline u32 *nfs4_bitmask(struct nfs_server *server, struct nfs4_label *label)
{
Expand Down Expand Up @@ -3800,7 +3795,7 @@ nfs4_atomic_open(struct inode *dir, struct nfs_open_context *ctx,
int open_flags, struct iattr *attr, int *opened)
{
struct nfs4_state *state;
struct nfs4_label l = {0, 0, 0, NULL}, *label = NULL;
struct nfs4_label l = { }, *label = NULL;

label = nfs4_label_init_security(dir, ctx->dentry, attr, &l);

Expand Down Expand Up @@ -6108,7 +6103,7 @@ static int _nfs4_get_security_label(struct inode *inode, void *buf,
size_t buflen)
{
struct nfs_server *server = NFS_SERVER(inode);
struct nfs4_label label = {0, 0, buflen, buf};
struct nfs4_label label = {0, 0, {buf, buflen, -1} };

u32 bitmask[3] = { 0, 0, FATTR4_WORD2_SECURITY_LABEL };
struct nfs_fattr fattr = {
Expand Down Expand Up @@ -6136,7 +6131,7 @@ static int _nfs4_get_security_label(struct inode *inode, void *buf,
return ret;
if (!(fattr.valid & NFS_ATTR_FATTR_V4_SECURITY_LABEL))
return -ENOENT;
return label.len;
return label.lsmctx.len;
}

static int nfs4_get_security_label(struct inode *inode, void *buf,
Expand Down Expand Up @@ -6213,7 +6208,8 @@ static int nfs4_do_set_security_label(struct inode *inode,
static int
nfs4_set_security_label(struct inode *inode, const void *buf, size_t buflen)
{
struct nfs4_label ilabel = {0, 0, buflen, (char *)buf };
struct nfs4_label ilabel = {0, 0,
{(char *)buf, buflen, -1}};
struct nfs_fattr *fattr;
int status;

Expand Down
22 changes: 12 additions & 10 deletions fs/nfs/nfs4xdr.c
Expand Up @@ -1154,7 +1154,7 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap,
}

if (label && (attrmask[2] & FATTR4_WORD2_SECURITY_LABEL)) {
len += 4 + 4 + 4 + (XDR_QUADLEN(label->len) << 2);
len += 4 + 4 + 4 + (XDR_QUADLEN(label->lsmctx.len) << 2);
bmval[2] |= FATTR4_WORD2_SECURITY_LABEL;
}

Expand Down Expand Up @@ -1186,8 +1186,9 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap,
if (label && (bmval[2] & FATTR4_WORD2_SECURITY_LABEL)) {
*p++ = cpu_to_be32(label->lfs);
*p++ = cpu_to_be32(label->pi);
*p++ = cpu_to_be32(label->len);
p = xdr_encode_opaque_fixed(p, label->label, label->len);
*p++ = cpu_to_be32(label->lsmctx.len);
p = xdr_encode_opaque_fixed(p, label->lsmctx.context,
label->lsmctx.len);
}
if (bmval[2] & FATTR4_WORD2_MODE_UMASK) {
*p++ = cpu_to_be32(iap->ia_mode & S_IALLUGO);
Expand Down Expand Up @@ -4236,12 +4237,12 @@ static int decode_attr_security_label(struct xdr_stream *xdr, uint32_t *bitmap,
return -EIO;
if (len < NFS4_MAXLABELLEN) {
if (label) {
if (label->len) {
if (label->len < len)
if (label->lsmctx.len) {
if (label->lsmctx.len < len)
return -ERANGE;
memcpy(label->label, p, len);
memcpy(label->lsmctx.context, p, len);
}
label->len = len;
label->lsmctx.len = len;
label->pi = pi;
label->lfs = lfs;
status = NFS_ATTR_FATTR_V4_SECURITY_LABEL;
Expand All @@ -4250,10 +4251,11 @@ static int decode_attr_security_label(struct xdr_stream *xdr, uint32_t *bitmap,
} else
printk(KERN_WARNING "%s: label too long (%u)!\n",
__func__, len);
if (label && label->label)
if (label && label->lsmctx.context)
dprintk("%s: label=%.*s, len=%d, PI=%d, LFS=%d\n",
__func__, label->len, (char *)label->label,
label->len, label->pi, label->lfs);
__func__, label->lsmctx.len,
(char *)label->lsmctx.context,
label->lsmctx.len, label->pi, label->lfs);
}
return status;
}
Expand Down
8 changes: 4 additions & 4 deletions include/linux/nfs4.h
Expand Up @@ -15,6 +15,7 @@

#include <linux/list.h>
#include <linux/uidgid.h>
#include <linux/security.h>
#include <uapi/linux/nfs4.h>
#include <linux/sunrpc/msg_prot.h>

Expand Down Expand Up @@ -44,10 +45,9 @@ struct nfs4_acl {
#define NFS4_MAXLABELLEN 2048

struct nfs4_label {
uint32_t lfs;
uint32_t pi;
u32 len;
char *label;
uint32_t lfs;
uint32_t pi;
struct lsmcontext lsmctx;
};

typedef struct { char data[NFS4_VERIFIER_SIZE]; } nfs4_verifier;
Expand Down
2 changes: 1 addition & 1 deletion include/linux/nfs_fs.h
Expand Up @@ -428,7 +428,7 @@ static inline void nfs4_label_free(struct nfs4_label *label)
{
#ifdef CONFIG_NFS_V4_SECURITY_LABEL
if (label) {
kfree(label->label);
kfree(label->lsmctx.context);
kfree(label);
}
#endif
Expand Down
18 changes: 14 additions & 4 deletions include/linux/security.h
Expand Up @@ -229,8 +229,19 @@ static inline bool lsmblob_equal(const struct lsmblob *bloba,
}

/* Map lsm names to blob slot numbers */
#if LSMBLOB_ENTRIES > 0
extern int lsm_name_to_slot(char *name);
extern const char *lsm_slot_to_name(int slot);
#else
static inline int lsm_name_to_slot(char *name)
{
return LSMBLOB_INVALID;
}
static inline const char *lsm_slot_to_name(int slot)
{
return NULL;
}
#endif

/**
* lsmblob_value - find the first non-zero value in an lsmblob structure.
Expand Down Expand Up @@ -470,8 +481,8 @@ int security_sb_clone_mnt_opts(const struct super_block *oldsb,
int security_move_mount(const struct path *from_path, const struct path *to_path);
int security_dentry_init_security(struct dentry *dentry, int mode,
const struct qstr *name,
const char **xattr_name, void **ctx,
u32 *ctxlen);
const char **xattr_name,
struct lsmcontext *lsmcxt);
int security_dentry_create_files_as(struct dentry *dentry, int mode,
struct qstr *name,
const struct cred *old,
Expand Down Expand Up @@ -888,8 +899,7 @@ static inline int security_dentry_init_security(struct dentry *dentry,
int mode,
const struct qstr *name,
const char **xattr_name,
void **ctx,
u32 *ctxlen)
struct lsmcontext *lsmcxt)
{
return -EOPNOTSUPP;
}
Expand Down

0 comments on commit c930a07

Please sign in to comment.