Commit 1086eeac authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'lsm-pr-20230829' of git://git.kernel.org/pub/scm/linux/kernel/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
parents 1dbae189 8e4672d6
......@@ -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 *);
......
......@@ -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,
......@@ -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;
}
......
......@@ -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,
......@@ -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,
......
......@@ -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__);
......@@ -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).
......
......@@ -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,
......@@ -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);
......@@ -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;
}
......@@ -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)
......
......@@ -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();
......
......@@ -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;
......
......@@ -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;
......
......@@ -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,
......@@ -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);
......
......@@ -385,10 +385,11 @@ 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)) {
......@@ -396,7 +397,13 @@ int evm_init_hmac(struct inode *inode, const struct xattr *lsm_xattr,
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;
......
......@@ -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>
......@@ -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);
}
......@@ -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;
......
......@@ -31,8 +31,6 @@
#include <linux/msg.h>
#include <net/flow.h>
#define MAX_LSM_EVM_XATTR 2
/* How many LSMs were built into the kernel? */
#define LSM_COUNT (__end_lsm_info - __start_lsm_info)
......@@ -212,6 +210,8 @@ static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed)
lsm_set_blob_size(&needed->lbs_msg_msg, &blob_sizes.lbs_msg_msg);
lsm_set_blob_size(&needed->lbs_superblock, &blob_sizes.lbs_superblock);
lsm_set_blob_size(&needed->lbs_task, &blob_sizes.lbs_task);
lsm_set_blob_size(&needed->lbs_xattr_count,
&blob_sizes.lbs_xattr_count);
}
/* Prepare LSM for initialization. */
......@@ -378,6 +378,7 @@ static void __init ordered_lsm_init(void)
init_debug("msg_msg blob size = %d\n", blob_sizes.lbs_msg_msg);
init_debug("superblock blob size = %d\n", blob_sizes.lbs_superblock);
init_debug("task blob size = %d\n", blob_sizes.lbs_task);
init_debug("xattr slots = %d\n", blob_sizes.lbs_xattr_count);
/*
* Create any kmem_caches needed for blobs
......@@ -840,7 +841,7 @@ int security_binder_transfer_binder(const struct cred *from,
* Return: Returns 0 if permission is granted.
*/
int security_binder_transfer_file(const struct cred *from,
const struct cred *to, struct file *file)
const struct cred *to, const struct file *file)
{
return call_int_hook(binder_transfer_file, 0, from, to, file);
}
......@@ -893,7 +894,7 @@ int security_ptrace_traceme(struct task_struct *parent)
*
* Return: Returns 0 if the capability sets were successfully obtained.
*/
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)
......@@ -1605,46 +1606,70 @@ EXPORT_SYMBOL(security_dentry_create_files_as);
* created inode and set up the incore security field for the new inode. This
* hook is called by the fs code as part of the inode creation transaction and
* provides for atomic labeling of the inode, unlike the post_create/mkdir/...
* hooks called by the VFS. The hook function is expected to allocate the name
* and value via kmalloc, with the caller being responsible for calling kfree
* after using them. If the security module does not use security attributes
* or does not wish to put a security attribute on this particular inode, then
* it should return -EOPNOTSUPP to skip this processing.
* hooks called by the VFS.
*
* The hook function is expected to populate the xattrs array, by calling
* lsm_get_xattr_slot() to retrieve the slots reserved by the security module
* with the lbs_xattr_count field of the lsm_blob_sizes structure. For each
* slot, the hook function should set ->name to the attribute name suffix
* (e.g. selinux), to allocate ->value (will be freed by the caller) and set it
* to the attribute value, to set ->value_len to the length of the value. If
* the security module does not use security attributes or does not wish to put
* a security attribute on this particular inode, then it should return
* -EOPNOTSUPP to skip this processing.
*
* Return: Returns 0 on success, -EOPNOTSUPP if no security attribute is
* needed, or -ENOMEM on memory allocation failure.
* Return: Returns 0 if the LSM successfully initialized all of the inode
* security attributes that are required, negative values otherwise.
*/
int security_inode_init_security(struct inode *inode, struct inode *dir,
const struct qstr *qstr,
const initxattrs initxattrs, void *fs_data)
{
struct xattr new_xattrs[MAX_LSM_EVM_XATTR + 1];
struct xattr *lsm_xattr, *evm_xattr, *xattr;
int ret;
struct security_hook_list *hp;
struct xattr *new_xattrs = NULL;
int ret = -EOPNOTSUPP, xattr_count = 0;
if (unlikely(IS_PRIVATE(inode)))
return 0;
if (!initxattrs)
return call_int_hook(inode_init_security, -EOPNOTSUPP, inode,
dir, qstr, NULL, NULL, NULL);
memset(new_xattrs, 0, sizeof(new_xattrs));
lsm_xattr = new_xattrs;
ret = call_int_hook(inode_init_security, -EOPNOTSUPP, inode, dir, qstr,
&lsm_xattr->name,
&lsm_xattr->value,
&lsm_xattr->value_len);
if (ret)
if (!blob_sizes.lbs_xattr_count)
return 0;
if (initxattrs) {
/* Allocate +1 for EVM and +1 as terminator. */
new_xattrs = kcalloc(blob_sizes.lbs_xattr_count + 2,
sizeof(*new_xattrs), GFP_NOFS);
if (!new_xattrs)
return -ENOMEM;
}
hlist_for_each_entry(hp, &security_hook_heads.inode_init_security,
list) {
ret = hp->hook.inode_init_security(inode, dir, qstr, new_xattrs,
&xattr_count);
if (ret && ret != -EOPNOTSUPP)
goto out;
/*
* As documented in lsm_hooks.h, -EOPNOTSUPP in this context
* means that the LSM is not willing to provide an xattr, not
* that it wants to signal an error. Thus, continue to invoke
* the remaining LSMs.
*/
}
/* If initxattrs() is NULL, xattr_count is zero, skip the call. */
if (!xattr_count)
goto out;
evm_xattr = lsm_xattr + 1;
ret = evm_inode_init_security(inode, lsm_xattr, evm_xattr);
ret = evm_inode_init_security(inode, dir, qstr, new_xattrs,
&xattr_count);
if (ret)
goto out;
ret = initxattrs(inode, new_xattrs, fs_data);
out:
for (xattr = new_xattrs; xattr->value != NULL; xattr++)
kfree(xattr->value);
for (; xattr_count > 0; xattr_count--)
kfree(new_xattrs[xattr_count - 1].value);
kfree(new_xattrs);
return (ret == -EOPNOTSUPP) ? 0 : ret;
}
EXPORT_SYMBOL(security_inode_init_security);
......@@ -2731,7 +2756,7 @@ int security_file_lock(struct file *file, unsigned int cmd)
/**
* security_file_fcntl() - Check if fcntl() op is allowed
* @file: file
* @cmd: fnctl command
* @cmd: fcntl command
* @arg: command argument
*
* Check permission before allowing the file operation specified by @cmd from
......@@ -4410,6 +4435,13 @@ void security_sk_clone(const struct sock *sk, struct sock *newsk)
}
EXPORT_SYMBOL(security_sk_clone);
/**
* security_sk_classify_flow() - Set a flow's secid based on socket
* @sk: original socket
* @flic: target flow
*
* Set the target flow's secid to socket's secid.
*/
void security_sk_classify_flow(const struct sock *sk, struct flowi_common *flic)
{
call_void_hook(sk_getsecid, sk, &flic->flowic_secid);
......
......@@ -104,6 +104,8 @@
#include "audit.h"
#include "avc_ss.h"
#define SELINUX_INODE_INIT_XATTRS 1
struct selinux_state selinux_state;
/* SECMARK reference count */
......@@ -1714,7 +1716,7 @@ static inline int file_path_has_perm(const struct cred *cred,
}
#ifdef CONFIG_BPF_SYSCALL
static int bpf_fd_pass(struct file *file, u32 sid);
static int bpf_fd_pass(const struct file *file, u32 sid);
#endif
/* Check whether a task can use an open file descriptor to
......@@ -1975,7 +1977,7 @@ static inline u32 file_mask_to_av(int mode, int mask)
}
/* Convert a Linux file to an access vector. */
static inline u32 file_to_av(struct file *file)
static inline u32 file_to_av(const struct file *file)
{
u32 av = 0;
......@@ -2050,7 +2052,7 @@ static int selinux_binder_transfer_binder(const struct cred *from,
static int selinux_binder_transfer_file(const struct cred *from,
const struct cred *to,
struct file *file)
const struct file *file)
{
u32 sid = cred_sid(to);
struct file_security_struct *fsec = selinux_file(file);
......@@ -2105,7 +2107,7 @@ static int selinux_ptrace_traceme(struct task_struct *parent)
SECCLASS_PROCESS, PROCESS__PTRACE, NULL);
}
static int selinux_capget(struct task_struct *target, kernel_cap_t *effective,
static int selinux_capget(const struct task_struct *target, kernel_cap_t *effective,
kernel_cap_t *inheritable, kernel_cap_t *permitted)
{
return avc_has_perm(current_sid(), task_sid_obj(target),
......@@ -2893,11 +2895,11 @@ static int selinux_dentry_create_files_as(struct dentry *dentry, int mode,
static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
const struct qstr *qstr,
const char **name,
void **value, size_t *len)
struct xattr *xattrs, int *xattr_count)
{
const struct task_security_struct *tsec = selinux_cred(current_cred());
struct superblock_security_struct *sbsec;
struct xattr *xattr = lsm_get_xattr_slot(xattrs, xattr_count);
u32 newsid, clen;
int rc;
char *context;
......@@ -2924,16 +2926,14 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
!(sbsec->flags & SBLABEL_MNT))
return -EOPNOTSUPP;
if (name)
*name = XATTR_SELINUX_SUFFIX;
if (value && len) {
if (xattr) {
rc = security_sid_to_context_force(newsid,
&context, &clen);
if (rc)
return rc;
*value = context;
*len = clen;
xattr->value = context;
xattr->value_len = clen;
xattr->name = XATTR_SELINUX_SUFFIX;
}
return 0;
......@@ -6732,7 +6732,7 @@ static u32 bpf_map_fmode_to_av(fmode_t fmode)
* access the bpf object and that's why we have to add this additional check in
* selinux_file_receive and selinux_binder_transfer_files.
*/
static int bpf_fd_pass(struct file *file, u32 sid)
static int bpf_fd_pass(const struct file *file, u32 sid)
{
struct bpf_security_struct *bpfsec;
struct bpf_prog *prog;
......@@ -6829,6 +6829,7 @@ struct lsm_blob_sizes selinux_blob_sizes __ro_after_init = {
.lbs_ipc = sizeof(struct ipc_security_struct),
.lbs_msg_msg = sizeof(struct msg_security_struct),
.lbs_superblock = sizeof(struct superblock_security_struct),
.lbs_xattr_count = SELINUX_INODE_INIT_XATTRS,
};
#ifdef CONFIG_PERF_EVENTS
......
......@@ -128,7 +128,7 @@ struct task_smack {
#define SMK_INODE_INSTANT 0x01 /* inode is instantiated */
#define SMK_INODE_TRANSMUTE 0x02 /* directory is transmuting */
#define SMK_INODE_CHANGED 0x04 /* smack was transmuted */
#define SMK_INODE_CHANGED 0x04 /* smack was transmuted (unused) */
#define SMK_INODE_IMPURE 0x08 /* involved in an impure transaction */
/*
......
......@@ -52,6 +52,15 @@
#define SMK_RECEIVING 1
#define SMK_SENDING 2
/*
* Smack uses multiple xattrs.
* SMACK64 - for access control,
* SMACK64TRANSMUTE - label initialization,
* Not saved on files - SMACK64IPIN and SMACK64IPOUT,
* Must be set explicitly - SMACK64EXEC and SMACK64MMAP
*/
#define SMACK_INODE_INIT_XATTRS 2
#ifdef SMACK_IPV6_PORT_LABELING
static DEFINE_MUTEX(smack_ipv6_lock);
static LIST_HEAD(smk_ipv6_port_list);
......@@ -973,27 +982,23 @@ static int smack_inode_alloc_security(struct inode *inode)
* @inode: the newly created inode
* @dir: containing directory object
* @qstr: unused
* @name: where to put the attribute name
* @value: where to put the attribute value
* @len: where to put the length of the attribute
* @xattrs: where to put the attributes
* @xattr_count: current number of LSM-provided xattrs (updated)
*
* Returns 0 if it all works out, -ENOMEM if there's no memory
*/
static int smack_inode_init_security(struct inode *inode, struct inode *dir,
const struct qstr *qstr, const char **name,
void **value, size_t *len)
const struct qstr *qstr,
struct xattr *xattrs, int *xattr_count)
{
struct task_smack *tsp = smack_cred(current_cred());
struct inode_smack *issp = smack_inode(inode);
struct smack_known *skp = smk_of_task(tsp);
struct smack_known *isp = smk_of_inode(inode);
struct smack_known *dsp = smk_of_inode(dir);
struct xattr *xattr = lsm_get_xattr_slot(xattrs, xattr_count);
int may;
if (name)
*name = XATTR_SMACK_SUFFIX;
if (value && len) {
if (xattr) {
/*
* If equal, transmuting already occurred in
* smack_dentry_create_files_as(). No need to check again.
......@@ -1014,6 +1019,8 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
if ((tsp->smk_task == tsp->smk_transmuted) ||
(may > 0 && ((may & MAY_TRANSMUTE) != 0) &&
smk_inode_transmutable(dir))) {
struct xattr *xattr_transmute;
/*
* The caller of smack_dentry_create_files_as()
* should have overridden the current cred, so the
......@@ -1022,14 +1029,26 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir,
*/
if (tsp->smk_task != tsp->smk_transmuted)
isp = dsp;
issp->smk_flags |= SMK_INODE_CHANGED;
xattr_transmute = lsm_get_xattr_slot(xattrs,
xattr_count);
if (xattr_transmute) {
xattr_transmute->value = kmemdup(TRANS_TRUE,
TRANS_TRUE_SIZE,
GFP_NOFS);
if (!xattr_transmute->value)
return -ENOMEM;
xattr_transmute->value_len = TRANS_TRUE_SIZE;
xattr_transmute->name = XATTR_SMACK_TRANSMUTE;
}
}
*value = kstrdup(isp->smk_known, GFP_NOFS);
if (*value == NULL)
xattr->value = kstrdup(isp->smk_known, GFP_NOFS);
if (!xattr->value)
return -ENOMEM;
*len = strlen(isp->smk_known);
xattr->value_len = strlen(isp->smk_known);
xattr->name = XATTR_SMACK_SUFFIX;
}
return 0;
......@@ -3568,20 +3587,12 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
* If there is a transmute attribute on the
* directory mark the inode.
*/
if (isp->smk_flags & SMK_INODE_CHANGED) {
isp->smk_flags &= ~SMK_INODE_CHANGED;
rc = __vfs_setxattr(&nop_mnt_idmap, dp, inode,
XATTR_NAME_SMACKTRANSMUTE,
TRANS_TRUE, TRANS_TRUE_SIZE,
0);
} else {
rc = __vfs_getxattr(dp, inode,
XATTR_NAME_SMACKTRANSMUTE, trattr,
TRANS_TRUE_SIZE);
if (rc >= 0 && strncmp(trattr, TRANS_TRUE,
TRANS_TRUE_SIZE) != 0)
rc = -EINVAL;
}
rc = __vfs_getxattr(dp, inode,
XATTR_NAME_SMACKTRANSMUTE, trattr,
TRANS_TRUE_SIZE);
if (rc >= 0 && strncmp(trattr, TRANS_TRUE,
TRANS_TRUE_SIZE) != 0)
rc = -EINVAL;
if (rc >= 0)
transflag = SMK_INODE_TRANSMUTE;
}
......@@ -4919,6 +4930,7 @@ struct lsm_blob_sizes smack_blob_sizes __ro_after_init = {
.lbs_ipc = sizeof(struct smack_known *),
.lbs_msg_msg = sizeof(struct smack_known *),
.lbs_superblock = sizeof(struct superblock_smack),
.lbs_xattr_count = SMACK_INODE_INIT_XATTRS,
};
static struct security_hook_list smack_hooks[] __ro_after_init = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment