linux/security/selinux/avc.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 * Implementation of the kernel access vector cache (AVC).
 *
 * Authors:  Stephen Smalley, <[email protected]>
 *	     James Morris <[email protected]>
 *
 * Update:   KaiGai, Kohei <[email protected]>
 *	Replaced the avc_lock spinlock by RCU.
 *
 * Copyright (C) 2003 Red Hat, Inc., James Morris <[email protected]>
 */
#include <linux/types.h>
#include <linux/stddef.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/dcache.h>
#include <linux/init.h>
#include <linux/skbuff.h>
#include <linux/percpu.h>
#include <linux/list.h>
#include <net/sock.h>
#include <linux/un.h>
#include <net/af_unix.h>
#include <linux/ip.h>
#include <linux/audit.h>
#include <linux/ipv6.h>
#include <net/ipv6.h>
#include "avc.h"
#include "avc_ss.h"
#include "classmap.h"

#define CREATE_TRACE_POINTS
#include <trace/events/avc.h>

#define AVC_CACHE_SLOTS
#define AVC_DEF_CACHE_THRESHOLD
#define AVC_CACHE_RECLAIM

#ifdef CONFIG_SECURITY_SELINUX_AVC_STATS
#define avc_cache_stats_incr(field)
#else
#define avc_cache_stats_incr
#endif

struct avc_entry {};

struct avc_node {};

struct avc_xperms_decision_node {};

struct avc_xperms_node {};

struct avc_cache {};

struct avc_callback_node {};

#ifdef CONFIG_SECURITY_SELINUX_AVC_STATS
DEFINE_PER_CPU(struct avc_cache_stats, avc_cache_stats) =;
#endif

struct selinux_avc {};

static struct selinux_avc selinux_avc;

void selinux_avc_init(void)
{}

unsigned int avc_get_cache_threshold(void)
{}

void avc_set_cache_threshold(unsigned int cache_threshold)
{}

static struct avc_callback_node *avc_callbacks __ro_after_init;
static struct kmem_cache *avc_node_cachep __ro_after_init;
static struct kmem_cache *avc_xperms_data_cachep __ro_after_init;
static struct kmem_cache *avc_xperms_decision_cachep __ro_after_init;
static struct kmem_cache *avc_xperms_cachep __ro_after_init;

static inline u32 avc_hash(u32 ssid, u32 tsid, u16 tclass)
{}

/**
 * avc_init - Initialize the AVC.
 *
 * Initialize the access vector cache.
 */
void __init avc_init(void)
{}

int avc_get_hash_stats(char *page)
{}

/*
 * using a linked list for extended_perms_decision lookup because the list is
 * always small. i.e. less than 5, typically 1
 */
static struct extended_perms_decision *avc_xperms_decision_lookup(u8 driver,
					struct avc_xperms_node *xp_node)
{}

static inline unsigned int
avc_xperms_has_perm(struct extended_perms_decision *xpd,
					u8 perm, u8 which)
{}

static void avc_xperms_allow_perm(struct avc_xperms_node *xp_node,
				u8 driver, u8 perm)
{}

static void avc_xperms_decision_free(struct avc_xperms_decision_node *xpd_node)
{}

static void avc_xperms_free(struct avc_xperms_node *xp_node)
{}

static void avc_copy_xperms_decision(struct extended_perms_decision *dest,
					struct extended_perms_decision *src)
{}

/*
 * similar to avc_copy_xperms_decision, but only copy decision
 * information relevant to this perm
 */
static inline void avc_quick_copy_xperms_decision(u8 perm,
			struct extended_perms_decision *dest,
			struct extended_perms_decision *src)
{}

static struct avc_xperms_decision_node
		*avc_xperms_decision_alloc(u8 which)
{}

static int avc_add_xperms_decision(struct avc_node *node,
			struct extended_perms_decision *src)
{}

static struct avc_xperms_node *avc_xperms_alloc(void)
{}

static int avc_xperms_populate(struct avc_node *node,
				struct avc_xperms_node *src)
{}

static inline u32 avc_xperms_audit_required(u32 requested,
					struct av_decision *avd,
					struct extended_perms_decision *xpd,
					u8 perm,
					int result,
					u32 *deniedp)
{}

static inline int avc_xperms_audit(u32 ssid, u32 tsid, u16 tclass,
				   u32 requested, struct av_decision *avd,
				   struct extended_perms_decision *xpd,
				   u8 perm, int result,
				   struct common_audit_data *ad)
{}

static void avc_node_free(struct rcu_head *rhead)
{}

static void avc_node_delete(struct avc_node *node)
{}

static void avc_node_kill(struct avc_node *node)
{}

static void avc_node_replace(struct avc_node *new, struct avc_node *old)
{}

static inline int avc_reclaim_node(void)
{}

static struct avc_node *avc_alloc_node(void)
{}

static void avc_node_populate(struct avc_node *node, u32 ssid, u32 tsid, u16 tclass, struct av_decision *avd)
{}

static inline struct avc_node *avc_search_node(u32 ssid, u32 tsid, u16 tclass)
{}

/**
 * avc_lookup - Look up an AVC entry.
 * @ssid: source security identifier
 * @tsid: target security identifier
 * @tclass: target security class
 *
 * Look up an AVC entry that is valid for the
 * (@ssid, @tsid), interpreting the permissions
 * based on @tclass.  If a valid AVC entry exists,
 * then this function returns the avc_node.
 * Otherwise, this function returns NULL.
 */
static struct avc_node *avc_lookup(u32 ssid, u32 tsid, u16 tclass)
{}

static int avc_latest_notif_update(u32 seqno, int is_insert)
{}

/**
 * avc_insert - Insert an AVC entry.
 * @ssid: source security identifier
 * @tsid: target security identifier
 * @tclass: target security class
 * @avd: resulting av decision
 * @xp_node: resulting extended permissions
 *
 * Insert an AVC entry for the SID pair
 * (@ssid, @tsid) and class @tclass.
 * The access vectors and the sequence number are
 * normally provided by the security server in
 * response to a security_compute_av() call.  If the
 * sequence number @avd->seqno is not less than the latest
 * revocation notification, then the function copies
 * the access vectors into a cache entry.
 */
static void avc_insert(u32 ssid, u32 tsid, u16 tclass,
		       struct av_decision *avd, struct avc_xperms_node *xp_node)
{}

/**
 * avc_audit_pre_callback - SELinux specific information
 * will be called by generic audit code
 * @ab: the audit buffer
 * @a: audit_data
 */
static void avc_audit_pre_callback(struct audit_buffer *ab, void *a)
{}

/**
 * avc_audit_post_callback - SELinux specific information
 * will be called by generic audit code
 * @ab: the audit buffer
 * @a: audit_data
 */
static void avc_audit_post_callback(struct audit_buffer *ab, void *a)
{}

/*
 * This is the slow part of avc audit with big stack footprint.
 * Note that it is non-blocking and can be called from under
 * rcu_read_lock().
 */
noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass,
			    u32 requested, u32 audited, u32 denied, int result,
			    struct common_audit_data *a)
{}

/**
 * avc_add_callback - Register a callback for security events.
 * @callback: callback function
 * @events: security events
 *
 * Register a callback function for events in the set @events.
 * Returns %0 on success or -%ENOMEM if insufficient memory
 * exists to add the callback.
 */
int __init avc_add_callback(int (*callback)(u32 event), u32 events)
{}

/**
 * avc_update_node - Update an AVC entry
 * @event : Updating event
 * @perms : Permission mask bits
 * @driver: xperm driver information
 * @xperm: xperm permissions
 * @ssid: AVC entry source sid
 * @tsid: AVC entry target sid
 * @tclass : AVC entry target object class
 * @seqno : sequence number when decision was made
 * @xpd: extended_perms_decision to be added to the node
 * @flags: the AVC_* flags, e.g. AVC_EXTENDED_PERMS, or 0.
 *
 * if a valid AVC entry doesn't exist,this function returns -ENOENT.
 * if kmalloc() called internal returns NULL, this function returns -ENOMEM.
 * otherwise, this function updates the AVC entry. The original AVC-entry object
 * will release later by RCU.
 */
static int avc_update_node(u32 event, u32 perms, u8 driver, u8 xperm, u32 ssid,
			   u32 tsid, u16 tclass, u32 seqno,
			   struct extended_perms_decision *xpd,
			   u32 flags)
{}

/**
 * avc_flush - Flush the cache
 */
static void avc_flush(void)
{}

/**
 * avc_ss_reset - Flush the cache and revalidate migrated permissions.
 * @seqno: policy sequence number
 */
int avc_ss_reset(u32 seqno)
{}

/**
 * avc_compute_av - Add an entry to the AVC based on the security policy
 * @ssid: subject
 * @tsid: object/target
 * @tclass: object class
 * @avd: access vector decision
 * @xp_node: AVC extended permissions node
 *
 * Slow-path helper function for avc_has_perm_noaudit, when the avc_node lookup
 * fails.  Don't inline this, since it's the slow-path and just results in a
 * bigger stack frame.
 */
static noinline void avc_compute_av(u32 ssid, u32 tsid, u16 tclass,
				    struct av_decision *avd,
				    struct avc_xperms_node *xp_node)
{}

static noinline int avc_denied(u32 ssid, u32 tsid,
			       u16 tclass, u32 requested,
			       u8 driver, u8 xperm, unsigned int flags,
			       struct av_decision *avd)
{}

/*
 * The avc extended permissions logic adds an additional 256 bits of
 * permissions to an avc node when extended permissions for that node are
 * specified in the avtab. If the additional 256 permissions is not adequate,
 * as-is the case with ioctls, then multiple may be chained together and the
 * driver field is used to specify which set contains the permission.
 */
int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested,
			   u8 driver, u8 xperm, struct common_audit_data *ad)
{}

/**
 * avc_perm_nonode - Add an entry to the AVC
 * @ssid: subject
 * @tsid: object/target
 * @tclass: object class
 * @requested: requested permissions
 * @flags: AVC flags
 * @avd: access vector decision
 *
 * This is the "we have no node" part of avc_has_perm_noaudit(), which is
 * unlikely and needs extra stack space for the new node that we generate, so
 * don't inline it.
 */
static noinline int avc_perm_nonode(u32 ssid, u32 tsid, u16 tclass,
				    u32 requested, unsigned int flags,
				    struct av_decision *avd)
{}

/**
 * avc_has_perm_noaudit - Check permissions but perform no auditing.
 * @ssid: source security identifier
 * @tsid: target security identifier
 * @tclass: target security class
 * @requested: requested permissions, interpreted based on @tclass
 * @flags:  AVC_STRICT or 0
 * @avd: access vector decisions
 *
 * Check the AVC to determine whether the @requested permissions are granted
 * for the SID pair (@ssid, @tsid), interpreting the permissions
 * based on @tclass, and call the security server on a cache miss to obtain
 * a new decision and add it to the cache.  Return a copy of the decisions
 * in @avd.  Return %0 if all @requested permissions are granted,
 * -%EACCES if any permissions are denied, or another -errno upon
 * other errors.  This function is typically called by avc_has_perm(),
 * but may also be called directly to separate permission checking from
 * auditing, e.g. in cases where a lock must be held for the check but
 * should be released for the auditing.
 */
inline int avc_has_perm_noaudit(u32 ssid, u32 tsid,
				u16 tclass, u32 requested,
				unsigned int flags,
				struct av_decision *avd)
{}

/**
 * avc_has_perm - Check permissions and perform any appropriate auditing.
 * @ssid: source security identifier
 * @tsid: target security identifier
 * @tclass: target security class
 * @requested: requested permissions, interpreted based on @tclass
 * @auditdata: auxiliary audit data
 *
 * Check the AVC to determine whether the @requested permissions are granted
 * for the SID pair (@ssid, @tsid), interpreting the permissions
 * based on @tclass, and call the security server on a cache miss to obtain
 * a new decision and add it to the cache.  Audit the granting or denial of
 * permissions in accordance with the policy.  Return %0 if all @requested
 * permissions are granted, -%EACCES if any permissions are denied, or
 * another -errno upon other errors.
 */
int avc_has_perm(u32 ssid, u32 tsid, u16 tclass,
		 u32 requested, struct common_audit_data *auditdata)
{}

u32 avc_policy_seqno(void)
{}