LSM/SELinux: inode_{get,set,notify}secctx hooks to access LSM security context information.
This patch introduces three new hooks. The inode_getsecctx hook is used to get all relevant information from an LSM about an inode. The inode_setsecctx is used to set both the in-core and on-disk state for the inode based on a context derived from inode_getsecctx.The final hook inode_notifysecctx will notify the LSM of a change for the in-core state of the inode in question. These hooks are for use in the labeled NFS code and addresses concerns of how to set security on an inode in a multi-xattr LSM. For historical reasons Stephen Smalley's explanation of the reason for these hooks is pasted below. Quote Stephen Smalley inode_setsecctx: Change the security context of an inode. Updates the in core security context managed by the security module and invokes the fs code as needed (via __vfs_setxattr_noperm) to update any backing xattrs that represent the context. Example usage: NFS server invokes this hook to change the security context in its incore inode and on the backing file system to a value provided by the client on a SETATTR operation. inode_notifysecctx: Notify the security module of what the security context of an inode should be. Initializes the incore security context managed by the security module for this inode. Example usage: NFS client invokes this hook to initialize the security context in its incore inode to the value provided by the server for the file when the server returned the file's attributes to the client. Signed-off-by: David P. Quigley <dpquigl@tycho.nsa.gov> Acked-by: Serge Hallyn <serue@us.ibm.com> Signed-off-by: James Morris <jmorris@namei.org>
This commit is contained in:
parent
b1ab7e4b2a
commit
1ee65e37e9
5 changed files with 143 additions and 0 deletions
|
@ -1382,6 +1382,41 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
|
||||||
* audit_rule_init.
|
* audit_rule_init.
|
||||||
* @rule contains the allocated rule
|
* @rule contains the allocated rule
|
||||||
*
|
*
|
||||||
|
* @inode_notifysecctx:
|
||||||
|
* Notify the security module of what the security context of an inode
|
||||||
|
* should be. Initializes the incore security context managed by the
|
||||||
|
* security module for this inode. Example usage: NFS client invokes
|
||||||
|
* this hook to initialize the security context in its incore inode to the
|
||||||
|
* value provided by the server for the file when the server returned the
|
||||||
|
* file's attributes to the client.
|
||||||
|
*
|
||||||
|
* Must be called with inode->i_mutex locked.
|
||||||
|
*
|
||||||
|
* @inode we wish to set the security context of.
|
||||||
|
* @ctx contains the string which we wish to set in the inode.
|
||||||
|
* @ctxlen contains the length of @ctx.
|
||||||
|
*
|
||||||
|
* @inode_setsecctx:
|
||||||
|
* Change the security context of an inode. Updates the
|
||||||
|
* incore security context managed by the security module and invokes the
|
||||||
|
* fs code as needed (via __vfs_setxattr_noperm) to update any backing
|
||||||
|
* xattrs that represent the context. Example usage: NFS server invokes
|
||||||
|
* this hook to change the security context in its incore inode and on the
|
||||||
|
* backing filesystem to a value provided by the client on a SETATTR
|
||||||
|
* operation.
|
||||||
|
*
|
||||||
|
* Must be called with inode->i_mutex locked.
|
||||||
|
*
|
||||||
|
* @dentry contains the inode we wish to set the security context of.
|
||||||
|
* @ctx contains the string which we wish to set in the inode.
|
||||||
|
* @ctxlen contains the length of @ctx.
|
||||||
|
*
|
||||||
|
* @inode_getsecctx:
|
||||||
|
* Returns a string containing all relavent security context information
|
||||||
|
*
|
||||||
|
* @inode we wish to set the security context of.
|
||||||
|
* @ctx is a pointer in which to place the allocated security context.
|
||||||
|
* @ctxlen points to the place to put the length of @ctx.
|
||||||
* This is the main security structure.
|
* This is the main security structure.
|
||||||
*/
|
*/
|
||||||
struct security_operations {
|
struct security_operations {
|
||||||
|
@ -1590,6 +1625,10 @@ struct security_operations {
|
||||||
int (*secctx_to_secid) (const char *secdata, u32 seclen, u32 *secid);
|
int (*secctx_to_secid) (const char *secdata, u32 seclen, u32 *secid);
|
||||||
void (*release_secctx) (char *secdata, u32 seclen);
|
void (*release_secctx) (char *secdata, u32 seclen);
|
||||||
|
|
||||||
|
int (*inode_notifysecctx)(struct inode *inode, void *ctx, u32 ctxlen);
|
||||||
|
int (*inode_setsecctx)(struct dentry *dentry, void *ctx, u32 ctxlen);
|
||||||
|
int (*inode_getsecctx)(struct inode *inode, void **ctx, u32 *ctxlen);
|
||||||
|
|
||||||
#ifdef CONFIG_SECURITY_NETWORK
|
#ifdef CONFIG_SECURITY_NETWORK
|
||||||
int (*unix_stream_connect) (struct socket *sock,
|
int (*unix_stream_connect) (struct socket *sock,
|
||||||
struct socket *other, struct sock *newsk);
|
struct socket *other, struct sock *newsk);
|
||||||
|
@ -1839,6 +1878,9 @@ int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen);
|
||||||
int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
|
int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid);
|
||||||
void security_release_secctx(char *secdata, u32 seclen);
|
void security_release_secctx(char *secdata, u32 seclen);
|
||||||
|
|
||||||
|
int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen);
|
||||||
|
int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen);
|
||||||
|
int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen);
|
||||||
#else /* CONFIG_SECURITY */
|
#else /* CONFIG_SECURITY */
|
||||||
struct security_mnt_opts {
|
struct security_mnt_opts {
|
||||||
};
|
};
|
||||||
|
@ -2595,6 +2637,19 @@ static inline int security_secctx_to_secid(const char *secdata,
|
||||||
static inline void security_release_secctx(char *secdata, u32 seclen)
|
static inline void security_release_secctx(char *secdata, u32 seclen)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
|
||||||
|
{
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
static inline int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
|
||||||
|
{
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
static inline int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
|
||||||
|
{
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
#endif /* CONFIG_SECURITY */
|
#endif /* CONFIG_SECURITY */
|
||||||
|
|
||||||
#ifdef CONFIG_SECURITY_NETWORK
|
#ifdef CONFIG_SECURITY_NETWORK
|
||||||
|
|
|
@ -822,6 +822,20 @@ static void cap_release_secctx(char *secdata, u32 seclen)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int cap_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cap_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cap_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
#ifdef CONFIG_KEYS
|
#ifdef CONFIG_KEYS
|
||||||
static int cap_key_alloc(struct key *key, const struct cred *cred,
|
static int cap_key_alloc(struct key *key, const struct cred *cred,
|
||||||
unsigned long flags)
|
unsigned long flags)
|
||||||
|
@ -1032,6 +1046,9 @@ void security_fixup_ops(struct security_operations *ops)
|
||||||
set_to_cap_if_null(ops, secid_to_secctx);
|
set_to_cap_if_null(ops, secid_to_secctx);
|
||||||
set_to_cap_if_null(ops, secctx_to_secid);
|
set_to_cap_if_null(ops, secctx_to_secid);
|
||||||
set_to_cap_if_null(ops, release_secctx);
|
set_to_cap_if_null(ops, release_secctx);
|
||||||
|
set_to_cap_if_null(ops, inode_notifysecctx);
|
||||||
|
set_to_cap_if_null(ops, inode_setsecctx);
|
||||||
|
set_to_cap_if_null(ops, inode_getsecctx);
|
||||||
#ifdef CONFIG_SECURITY_NETWORK
|
#ifdef CONFIG_SECURITY_NETWORK
|
||||||
set_to_cap_if_null(ops, unix_stream_connect);
|
set_to_cap_if_null(ops, unix_stream_connect);
|
||||||
set_to_cap_if_null(ops, unix_may_send);
|
set_to_cap_if_null(ops, unix_may_send);
|
||||||
|
|
|
@ -974,6 +974,24 @@ void security_release_secctx(char *secdata, u32 seclen)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(security_release_secctx);
|
EXPORT_SYMBOL(security_release_secctx);
|
||||||
|
|
||||||
|
int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
|
||||||
|
{
|
||||||
|
return security_ops->inode_notifysecctx(inode, ctx, ctxlen);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(security_inode_notifysecctx);
|
||||||
|
|
||||||
|
int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
|
||||||
|
{
|
||||||
|
return security_ops->inode_setsecctx(dentry, ctx, ctxlen);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(security_inode_setsecctx);
|
||||||
|
|
||||||
|
int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
|
||||||
|
{
|
||||||
|
return security_ops->inode_getsecctx(inode, ctx, ctxlen);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(security_inode_getsecctx);
|
||||||
|
|
||||||
#ifdef CONFIG_SECURITY_NETWORK
|
#ifdef CONFIG_SECURITY_NETWORK
|
||||||
|
|
||||||
int security_unix_stream_connect(struct socket *sock, struct socket *other,
|
int security_unix_stream_connect(struct socket *sock, struct socket *other,
|
||||||
|
|
|
@ -5351,6 +5351,32 @@ static void selinux_release_secctx(char *secdata, u32 seclen)
|
||||||
kfree(secdata);
|
kfree(secdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* called with inode->i_mutex locked
|
||||||
|
*/
|
||||||
|
static int selinux_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
|
||||||
|
{
|
||||||
|
return selinux_inode_setsecurity(inode, XATTR_SELINUX_SUFFIX, ctx, ctxlen, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* called with inode->i_mutex locked
|
||||||
|
*/
|
||||||
|
static int selinux_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
|
||||||
|
{
|
||||||
|
return __vfs_setxattr_noperm(dentry, XATTR_NAME_SELINUX, ctx, ctxlen, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int selinux_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
|
||||||
|
{
|
||||||
|
int len = 0;
|
||||||
|
len = selinux_inode_getsecurity(inode, XATTR_SELINUX_SUFFIX,
|
||||||
|
ctx, true);
|
||||||
|
if (len < 0)
|
||||||
|
return len;
|
||||||
|
*ctxlen = len;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
#ifdef CONFIG_KEYS
|
#ifdef CONFIG_KEYS
|
||||||
|
|
||||||
static int selinux_key_alloc(struct key *k, const struct cred *cred,
|
static int selinux_key_alloc(struct key *k, const struct cred *cred,
|
||||||
|
@ -5550,6 +5576,9 @@ static struct security_operations selinux_ops = {
|
||||||
.secid_to_secctx = selinux_secid_to_secctx,
|
.secid_to_secctx = selinux_secid_to_secctx,
|
||||||
.secctx_to_secid = selinux_secctx_to_secid,
|
.secctx_to_secid = selinux_secctx_to_secid,
|
||||||
.release_secctx = selinux_release_secctx,
|
.release_secctx = selinux_release_secctx,
|
||||||
|
.inode_notifysecctx = selinux_inode_notifysecctx,
|
||||||
|
.inode_setsecctx = selinux_inode_setsecctx,
|
||||||
|
.inode_getsecctx = selinux_inode_getsecctx,
|
||||||
|
|
||||||
.unix_stream_connect = selinux_socket_unix_stream_connect,
|
.unix_stream_connect = selinux_socket_unix_stream_connect,
|
||||||
.unix_may_send = selinux_socket_unix_may_send,
|
.unix_may_send = selinux_socket_unix_may_send,
|
||||||
|
|
|
@ -3057,6 +3057,27 @@ static void smack_release_secctx(char *secdata, u32 seclen)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int smack_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen)
|
||||||
|
{
|
||||||
|
return smack_inode_setsecurity(inode, XATTR_SMACK_SUFFIX, ctx, ctxlen, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int smack_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen)
|
||||||
|
{
|
||||||
|
return __vfs_setxattr_noperm(dentry, XATTR_NAME_SMACK, ctx, ctxlen, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int smack_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen)
|
||||||
|
{
|
||||||
|
int len = 0;
|
||||||
|
len = smack_inode_getsecurity(inode, XATTR_SMACK_SUFFIX, ctx, true);
|
||||||
|
|
||||||
|
if (len < 0)
|
||||||
|
return len;
|
||||||
|
*ctxlen = len;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
struct security_operations smack_ops = {
|
struct security_operations smack_ops = {
|
||||||
.name = "smack",
|
.name = "smack",
|
||||||
|
|
||||||
|
@ -3185,6 +3206,9 @@ struct security_operations smack_ops = {
|
||||||
.secid_to_secctx = smack_secid_to_secctx,
|
.secid_to_secctx = smack_secid_to_secctx,
|
||||||
.secctx_to_secid = smack_secctx_to_secid,
|
.secctx_to_secid = smack_secctx_to_secid,
|
||||||
.release_secctx = smack_release_secctx,
|
.release_secctx = smack_release_secctx,
|
||||||
|
.inode_notifysecctx = smack_inode_notifysecctx,
|
||||||
|
.inode_setsecctx = smack_inode_setsecctx,
|
||||||
|
.inode_getsecctx = smack_inode_getsecctx,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue