Skip to content

Commit

Permalink
Merge tag 'lsm-pr-20230829' of git://git.kernel.org/pub/scm/linux/ker…
Browse files Browse the repository at this point in the history
…nel/git/pcmoore/lsm

Pull LSM updates from Paul Moore:

 - Add proper multi-LSM support for xattrs in the
   security_inode_init_security() hook

   Historically the LSM layer has only allowed a single LSM to add an
   xattr to an inode, with IMA/EVM measuring that and adding its own as
   well. As we work towards promoting IMA/EVM to a "proper LSM" instead
   of the special case that it is now, we need to better support the
   case of multiple LSMs each adding xattrs to an inode and after
   several attempts we now appear to have something that is working
   well. It is worth noting that in the process of making this change we
   uncovered a problem with Smack's SMACK64TRANSMUTE xattr which is also
   fixed in this pull request.

 - Additional LSM hook constification

   Two patches to constify parameters to security_capget() and
   security_binder_transfer_file(). While I generally don't make a
   special note of who submitted these patches, these were the work of
   an Outreachy intern, Khadija Kamran, and that makes me happy;
   hopefully it does the same for all of you reading this.

 - LSM hook comment header fixes

   One patch to add a missing hook comment header, one to fix a minor
   typo.

 - Remove an old, unused credential function declaration

   It wasn't clear to me who should pick this up, but it was trivial,
   obviously correct, and arguably the LSM layer has a vested interest
   in credentials so I merged it. Sadly I'm now noticing that despite my
   subject line cleanup I didn't cleanup the "unsued" misspelling, sigh

* tag 'lsm-pr-20230829' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/lsm:
  lsm: constify the 'file' parameter in security_binder_transfer_file()
  lsm: constify the 'target' parameter in security_capget()
  lsm: add comment block for security_sk_classify_flow LSM hook
  security: Fix ret values doc for security_inode_init_security()
  cred: remove unsued extern declaration change_create_files_as()
  evm: Support multiple LSMs providing an xattr
  evm: Align evm_inode_init_security() definition with LSM infrastructure
  smack: Set the SMACK64TRANSMUTE xattr in smack_inode_init_security()
  security: Allow all LSMs to provide xattrs for inode_init_security hook
  lsm: fix typo in security_file_lock() comment header
  • Loading branch information
Linus Torvalds committed Aug 30, 2023
2 parents 1dbae18 + 8e4672d commit 1086eea
Show file tree
Hide file tree
Showing 15 changed files with 202 additions and 101 deletions.
1 change: 0 additions & 1 deletion include/linux/cred.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,6 @@ extern void abort_creds(struct cred *);
extern const struct cred *override_creds(const struct cred *);
extern void revert_creds(const struct cred *);
extern struct cred *prepare_kernel_cred(struct task_struct *);
extern int change_create_files_as(struct cred *, struct inode *);
extern int set_security_override(struct cred *, u32);
extern int set_security_override_from_ctx(struct cred *, const char *);
extern int set_create_files_as(struct cred *, struct inode *);
Expand Down
14 changes: 8 additions & 6 deletions include/linux/evm.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,10 @@ static inline void evm_inode_post_set_acl(struct dentry *dentry,
{
return evm_inode_post_setxattr(dentry, acl_name, NULL, 0);
}
extern int evm_inode_init_security(struct inode *inode,
const struct xattr *xattr_array,
struct xattr *evm);

int evm_inode_init_security(struct inode *inode, struct inode *dir,
const struct qstr *qstr, struct xattr *xattrs,
int *xattr_count);
extern bool evm_revalidate_status(const char *xattr_name);
extern int evm_protected_xattr_if_enabled(const char *req_xattr_name);
extern int evm_read_protected_xattrs(struct dentry *dentry, u8 *buffer,
Expand Down Expand Up @@ -157,9 +158,10 @@ static inline void evm_inode_post_set_acl(struct dentry *dentry,
return;
}

static inline int evm_inode_init_security(struct inode *inode,
const struct xattr *xattr_array,
struct xattr *evm)
static inline int evm_inode_init_security(struct inode *inode, struct inode *dir,
const struct qstr *qstr,
struct xattr *xattrs,
int *xattr_count)
{
return 0;
}
Expand Down
10 changes: 5 additions & 5 deletions include/linux/lsm_hook_defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,11 @@ LSM_HOOK(int, 0, binder_transaction, const struct cred *from,
LSM_HOOK(int, 0, binder_transfer_binder, const struct cred *from,
const struct cred *to)
LSM_HOOK(int, 0, binder_transfer_file, const struct cred *from,
const struct cred *to, struct file *file)
const struct cred *to, const struct file *file)
LSM_HOOK(int, 0, ptrace_access_check, struct task_struct *child,
unsigned int mode)
LSM_HOOK(int, 0, ptrace_traceme, struct task_struct *parent)
LSM_HOOK(int, 0, capget, struct task_struct *target, kernel_cap_t *effective,
LSM_HOOK(int, 0, capget, const struct task_struct *target, kernel_cap_t *effective,
kernel_cap_t *inheritable, kernel_cap_t *permitted)
LSM_HOOK(int, 0, capset, struct cred *new, const struct cred *old,
const kernel_cap_t *effective, const kernel_cap_t *inheritable,
Expand Down Expand Up @@ -112,9 +112,9 @@ LSM_HOOK(int, 0, path_notify, const struct path *path, u64 mask,
unsigned int obj_type)
LSM_HOOK(int, 0, inode_alloc_security, struct inode *inode)
LSM_HOOK(void, LSM_RET_VOID, inode_free_security, struct inode *inode)
LSM_HOOK(int, 0, inode_init_security, struct inode *inode,
struct inode *dir, const struct qstr *qstr, const char **name,
void **value, size_t *len)
LSM_HOOK(int, -EOPNOTSUPP, inode_init_security, struct inode *inode,
struct inode *dir, const struct qstr *qstr, struct xattr *xattrs,
int *xattr_count)
LSM_HOOK(int, 0, inode_init_security_anon, struct inode *inode,
const struct qstr *name, const struct inode *context_inode)
LSM_HOOK(int, 0, inode_create, struct inode *dir, struct dentry *dentry,
Expand Down
20 changes: 20 additions & 0 deletions include/linux/lsm_hooks.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include <linux/security.h>
#include <linux/init.h>
#include <linux/rculist.h>
#include <linux/xattr.h>

union security_list_options {
#define LSM_HOOK(RET, DEFAULT, NAME, ...) RET (*NAME)(__VA_ARGS__);
Expand Down Expand Up @@ -63,8 +64,27 @@ struct lsm_blob_sizes {
int lbs_ipc;
int lbs_msg_msg;
int lbs_task;
int lbs_xattr_count; /* number of xattr slots in new_xattrs array */
};

/**
* lsm_get_xattr_slot - Return the next available slot and increment the index
* @xattrs: array storing LSM-provided xattrs
* @xattr_count: number of already stored xattrs (updated)
*
* Retrieve the first available slot in the @xattrs array to fill with an xattr,
* and increment @xattr_count.
*
* Return: The slot to fill in @xattrs if non-NULL, NULL otherwise.
*/
static inline struct xattr *lsm_get_xattr_slot(struct xattr *xattrs,
int *xattr_count)
{
if (unlikely(!xattrs))
return NULL;
return &xattrs[(*xattr_count)++];
}

/*
* LSM_RET_VOID is used as the default value in LSM_HOOK definitions for void
* LSM hooks (in include/linux/lsm_hook_defs.h).
Expand Down
11 changes: 6 additions & 5 deletions include/linux/security.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,8 @@ extern int cap_capable(const struct cred *cred, struct user_namespace *ns,
extern int cap_settime(const struct timespec64 *ts, const struct timezone *tz);
extern int cap_ptrace_access_check(struct task_struct *child, unsigned int mode);
extern int cap_ptrace_traceme(struct task_struct *parent);
extern int cap_capget(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted);
extern int cap_capget(const struct task_struct *target, kernel_cap_t *effective,
kernel_cap_t *inheritable, kernel_cap_t *permitted);
extern int cap_capset(struct cred *new, const struct cred *old,
const kernel_cap_t *effective,
const kernel_cap_t *inheritable,
Expand Down Expand Up @@ -268,10 +269,10 @@ int security_binder_transaction(const struct cred *from,
int security_binder_transfer_binder(const struct cred *from,
const struct cred *to);
int security_binder_transfer_file(const struct cred *from,
const struct cred *to, struct file *file);
const struct cred *to, const struct file *file);
int security_ptrace_access_check(struct task_struct *child, unsigned int mode);
int security_ptrace_traceme(struct task_struct *parent);
int security_capget(struct task_struct *target,
int security_capget(const struct task_struct *target,
kernel_cap_t *effective,
kernel_cap_t *inheritable,
kernel_cap_t *permitted);
Expand Down Expand Up @@ -538,7 +539,7 @@ static inline int security_binder_transfer_binder(const struct cred *from,

static inline int security_binder_transfer_file(const struct cred *from,
const struct cred *to,
struct file *file)
const struct file *file)
{
return 0;
}
Expand All @@ -554,7 +555,7 @@ static inline int security_ptrace_traceme(struct task_struct *parent)
return cap_ptrace_traceme(parent);
}

static inline int security_capget(struct task_struct *target,
static inline int security_capget(const struct task_struct *target,
kernel_cap_t *effective,
kernel_cap_t *inheritable,
kernel_cap_t *permitted)
Expand Down
2 changes: 1 addition & 1 deletion kernel/capability.c
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ static inline int cap_get_target_pid(pid_t pid, kernel_cap_t *pEp,
int ret;

if (pid && (pid != task_pid_vnr(current))) {
struct task_struct *target;
const struct task_struct *target;

rcu_read_lock();

Expand Down
2 changes: 1 addition & 1 deletion security/apparmor/lsm.c
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ static int apparmor_ptrace_traceme(struct task_struct *parent)
}

/* Derived from security/commoncap.c:cap_capget */
static int apparmor_capget(struct task_struct *target, kernel_cap_t *effective,
static int apparmor_capget(const struct task_struct *target, kernel_cap_t *effective,
kernel_cap_t *inheritable, kernel_cap_t *permitted)
{
struct aa_label *label;
Expand Down
2 changes: 1 addition & 1 deletion security/commoncap.c
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ int cap_ptrace_traceme(struct task_struct *parent)
* This function retrieves the capabilities of the nominated task and returns
* them to the caller.
*/
int cap_capget(struct task_struct *target, kernel_cap_t *effective,
int cap_capget(const struct task_struct *target, kernel_cap_t *effective,
kernel_cap_t *inheritable, kernel_cap_t *permitted)
{
const struct cred *cred;
Expand Down
4 changes: 3 additions & 1 deletion security/integrity/evm/evm.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ struct evm_digest {
char digest[IMA_MAX_DIGEST_SIZE];
} __packed;

int evm_protected_xattr(const char *req_xattr_name);

int evm_init_key(void);
int evm_update_evmxattr(struct dentry *dentry,
const char *req_xattr_name,
Expand All @@ -58,7 +60,7 @@ int evm_calc_hash(struct dentry *dentry, const char *req_xattr_name,
const char *req_xattr_value,
size_t req_xattr_value_len, char type,
struct evm_digest *data);
int evm_init_hmac(struct inode *inode, const struct xattr *xattr,
int evm_init_hmac(struct inode *inode, const struct xattr *xattrs,
char *hmac_val);
int evm_init_secfs(void);

Expand Down
11 changes: 9 additions & 2 deletions security/integrity/evm/evm_crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -385,18 +385,25 @@ int evm_update_evmxattr(struct dentry *dentry, const char *xattr_name,
return rc;
}

int evm_init_hmac(struct inode *inode, const struct xattr *lsm_xattr,
int evm_init_hmac(struct inode *inode, const struct xattr *xattrs,
char *hmac_val)
{
struct shash_desc *desc;
const struct xattr *xattr;

desc = init_desc(EVM_XATTR_HMAC, HASH_ALGO_SHA1);
if (IS_ERR(desc)) {
pr_info("init_desc failed\n");
return PTR_ERR(desc);
}

crypto_shash_update(desc, lsm_xattr->value, lsm_xattr->value_len);
for (xattr = xattrs; xattr->name; xattr++) {
if (!evm_protected_xattr(xattr->name))
continue;

crypto_shash_update(desc, xattr->value, xattr->value_len);
}

hmac_add_misc(desc, inode, EVM_XATTR_HMAC, hmac_val);
kfree(desc);
return 0;
Expand Down
39 changes: 32 additions & 7 deletions security/integrity/evm/evm_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <linux/evm.h>
#include <linux/magic.h>
#include <linux/posix_acl_xattr.h>
#include <linux/lsm_hooks.h>

#include <crypto/hash.h>
#include <crypto/hash_info.h>
Expand Down Expand Up @@ -305,7 +306,7 @@ static int evm_protected_xattr_common(const char *req_xattr_name,
return found;
}

static int evm_protected_xattr(const char *req_xattr_name)
int evm_protected_xattr(const char *req_xattr_name)
{
return evm_protected_xattr_common(req_xattr_name, false);
}
Expand Down Expand Up @@ -866,23 +867,47 @@ void evm_inode_post_setattr(struct dentry *dentry, int ia_valid)
/*
* evm_inode_init_security - initializes security.evm HMAC value
*/
int evm_inode_init_security(struct inode *inode,
const struct xattr *lsm_xattr,
struct xattr *evm_xattr)
int evm_inode_init_security(struct inode *inode, struct inode *dir,
const struct qstr *qstr, struct xattr *xattrs,
int *xattr_count)
{
struct evm_xattr *xattr_data;
struct xattr *xattr, *evm_xattr;
bool evm_protected_xattrs = false;
int rc;

if (!(evm_initialized & EVM_INIT_HMAC) ||
!evm_protected_xattr(lsm_xattr->name))
if (!(evm_initialized & EVM_INIT_HMAC) || !xattrs)
return 0;

/*
* security_inode_init_security() makes sure that the xattrs array is
* contiguous, there is enough space for security.evm, and that there is
* a terminator at the end of the array.
*/
for (xattr = xattrs; xattr->name; xattr++) {
if (evm_protected_xattr(xattr->name))
evm_protected_xattrs = true;
}

/* EVM xattr not needed. */
if (!evm_protected_xattrs)
return 0;

evm_xattr = lsm_get_xattr_slot(xattrs, xattr_count);
/*
* Array terminator (xattr name = NULL) must be the first non-filled
* xattr slot.
*/
WARN_ONCE(evm_xattr != xattr,
"%s: xattrs terminator is not the first non-filled slot\n",
__func__);

xattr_data = kzalloc(sizeof(*xattr_data), GFP_NOFS);
if (!xattr_data)
return -ENOMEM;

xattr_data->data.type = EVM_XATTR_HMAC;
rc = evm_init_hmac(inode, lsm_xattr, xattr_data->digest);
rc = evm_init_hmac(inode, xattrs, xattr_data->digest);
if (rc < 0)
goto out;

Expand Down
Loading

0 comments on commit 1086eea

Please sign in to comment.