mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-30 07:34:12 +08:00
e46e01eebb
commit bda0be7ad9
("security: make inode_follow_link RCU-walk aware")
switched selinux_inode_follow_link() to use avc_has_perm_flags() and
pass down the MAY_NOT_BLOCK flag if called during RCU walk. However,
the only test of MAY_NOT_BLOCK occurs during slow_avc_audit()
and only if passing an inode as audit data (LSM_AUDIT_DATA_INODE). Since
selinux_inode_follow_link() passes a dentry directly, passing MAY_NOT_BLOCK
here serves no purpose. Switch selinux_inode_follow_link() to use
avc_has_perm() and drop avc_has_perm_flags() since there are no other
users.
Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: Paul Moore <paul@paul-moore.com>
192 lines
5.0 KiB
C
192 lines
5.0 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/*
|
|
* Access vector cache interface for object managers.
|
|
*
|
|
* Author : Stephen Smalley, <sds@tycho.nsa.gov>
|
|
*/
|
|
#ifndef _SELINUX_AVC_H_
|
|
#define _SELINUX_AVC_H_
|
|
|
|
#include <linux/stddef.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/kdev_t.h>
|
|
#include <linux/spinlock.h>
|
|
#include <linux/init.h>
|
|
#include <linux/audit.h>
|
|
#include <linux/lsm_audit.h>
|
|
#include <linux/in6.h>
|
|
#include "flask.h"
|
|
#include "av_permissions.h"
|
|
#include "security.h"
|
|
|
|
/*
|
|
* An entry in the AVC.
|
|
*/
|
|
struct avc_entry;
|
|
|
|
struct task_struct;
|
|
struct inode;
|
|
struct sock;
|
|
struct sk_buff;
|
|
|
|
/*
|
|
* AVC statistics
|
|
*/
|
|
struct avc_cache_stats {
|
|
unsigned int lookups;
|
|
unsigned int misses;
|
|
unsigned int allocations;
|
|
unsigned int reclaims;
|
|
unsigned int frees;
|
|
};
|
|
|
|
/*
|
|
* We only need this data after we have decided to send an audit message.
|
|
*/
|
|
struct selinux_audit_data {
|
|
u32 ssid;
|
|
u32 tsid;
|
|
u16 tclass;
|
|
u32 requested;
|
|
u32 audited;
|
|
u32 denied;
|
|
int result;
|
|
struct selinux_state *state;
|
|
};
|
|
|
|
/*
|
|
* AVC operations
|
|
*/
|
|
|
|
void __init avc_init(void);
|
|
|
|
static inline u32 avc_audit_required(u32 requested,
|
|
struct av_decision *avd,
|
|
int result,
|
|
u32 auditdeny,
|
|
u32 *deniedp)
|
|
{
|
|
u32 denied, audited;
|
|
denied = requested & ~avd->allowed;
|
|
if (unlikely(denied)) {
|
|
audited = denied & avd->auditdeny;
|
|
/*
|
|
* auditdeny is TRICKY! Setting a bit in
|
|
* this field means that ANY denials should NOT be audited if
|
|
* the policy contains an explicit dontaudit rule for that
|
|
* permission. Take notice that this is unrelated to the
|
|
* actual permissions that were denied. As an example lets
|
|
* assume:
|
|
*
|
|
* denied == READ
|
|
* avd.auditdeny & ACCESS == 0 (not set means explicit rule)
|
|
* auditdeny & ACCESS == 1
|
|
*
|
|
* We will NOT audit the denial even though the denied
|
|
* permission was READ and the auditdeny checks were for
|
|
* ACCESS
|
|
*/
|
|
if (auditdeny && !(auditdeny & avd->auditdeny))
|
|
audited = 0;
|
|
} else if (result)
|
|
audited = denied = requested;
|
|
else
|
|
audited = requested & avd->auditallow;
|
|
*deniedp = denied;
|
|
return audited;
|
|
}
|
|
|
|
int slow_avc_audit(struct selinux_state *state,
|
|
u32 ssid, u32 tsid, u16 tclass,
|
|
u32 requested, u32 audited, u32 denied, int result,
|
|
struct common_audit_data *a,
|
|
unsigned flags);
|
|
|
|
/**
|
|
* avc_audit - Audit the granting or denial of permissions.
|
|
* @ssid: source security identifier
|
|
* @tsid: target security identifier
|
|
* @tclass: target security class
|
|
* @requested: requested permissions
|
|
* @avd: access vector decisions
|
|
* @result: result from avc_has_perm_noaudit
|
|
* @a: auxiliary audit data
|
|
* @flags: VFS walk flags
|
|
*
|
|
* Audit the granting or denial of permissions in accordance
|
|
* with the policy. This function is typically called by
|
|
* avc_has_perm() after a permission check, but can also be
|
|
* called directly by callers who use avc_has_perm_noaudit()
|
|
* in order to separate the permission check from the auditing.
|
|
* For example, this separation is useful when the permission check must
|
|
* be performed under a lock, to allow the lock to be released
|
|
* before calling the auditing code.
|
|
*/
|
|
static inline int avc_audit(struct selinux_state *state,
|
|
u32 ssid, u32 tsid,
|
|
u16 tclass, u32 requested,
|
|
struct av_decision *avd,
|
|
int result,
|
|
struct common_audit_data *a,
|
|
int flags)
|
|
{
|
|
u32 audited, denied;
|
|
audited = avc_audit_required(requested, avd, result, 0, &denied);
|
|
if (likely(!audited))
|
|
return 0;
|
|
return slow_avc_audit(state, ssid, tsid, tclass,
|
|
requested, audited, denied, result,
|
|
a, flags);
|
|
}
|
|
|
|
#define AVC_STRICT 1 /* Ignore permissive mode. */
|
|
#define AVC_EXTENDED_PERMS 2 /* update extended permissions */
|
|
#define AVC_NONBLOCKING 4 /* non blocking */
|
|
int avc_has_perm_noaudit(struct selinux_state *state,
|
|
u32 ssid, u32 tsid,
|
|
u16 tclass, u32 requested,
|
|
unsigned flags,
|
|
struct av_decision *avd);
|
|
|
|
int avc_has_perm(struct selinux_state *state,
|
|
u32 ssid, u32 tsid,
|
|
u16 tclass, u32 requested,
|
|
struct common_audit_data *auditdata);
|
|
|
|
int avc_has_extended_perms(struct selinux_state *state,
|
|
u32 ssid, u32 tsid, u16 tclass, u32 requested,
|
|
u8 driver, u8 perm, struct common_audit_data *ad);
|
|
|
|
|
|
u32 avc_policy_seqno(struct selinux_state *state);
|
|
|
|
#define AVC_CALLBACK_GRANT 1
|
|
#define AVC_CALLBACK_TRY_REVOKE 2
|
|
#define AVC_CALLBACK_REVOKE 4
|
|
#define AVC_CALLBACK_RESET 8
|
|
#define AVC_CALLBACK_AUDITALLOW_ENABLE 16
|
|
#define AVC_CALLBACK_AUDITALLOW_DISABLE 32
|
|
#define AVC_CALLBACK_AUDITDENY_ENABLE 64
|
|
#define AVC_CALLBACK_AUDITDENY_DISABLE 128
|
|
#define AVC_CALLBACK_ADD_XPERMS 256
|
|
|
|
int avc_add_callback(int (*callback)(u32 event), u32 events);
|
|
|
|
/* Exported to selinuxfs */
|
|
struct selinux_avc;
|
|
int avc_get_hash_stats(struct selinux_avc *avc, char *page);
|
|
unsigned int avc_get_cache_threshold(struct selinux_avc *avc);
|
|
void avc_set_cache_threshold(struct selinux_avc *avc,
|
|
unsigned int cache_threshold);
|
|
|
|
/* Attempt to free avc node cache */
|
|
void avc_disable(void);
|
|
|
|
#ifdef CONFIG_SECURITY_SELINUX_AVC_STATS
|
|
DECLARE_PER_CPU(struct avc_cache_stats, avc_cache_stats);
|
|
#endif
|
|
|
|
#endif /* _SELINUX_AVC_H_ */
|
|
|