linux/security/apparmor/lsm.c

// SPDX-License-Identifier: GPL-2.0-only
/*
 * AppArmor security module
 *
 * This file contains AppArmor LSM hooks.
 *
 * Copyright (C) 1998-2008 Novell/SUSE
 * Copyright 2009-2010 Canonical Ltd.
 */

#include <linux/lsm_hooks.h>
#include <linux/moduleparam.h>
#include <linux/mm.h>
#include <linux/mman.h>
#include <linux/mount.h>
#include <linux/namei.h>
#include <linux/ptrace.h>
#include <linux/ctype.h>
#include <linux/sysctl.h>
#include <linux/audit.h>
#include <linux/user_namespace.h>
#include <linux/netfilter_ipv4.h>
#include <linux/netfilter_ipv6.h>
#include <linux/zstd.h>
#include <net/sock.h>
#include <uapi/linux/mount.h>
#include <uapi/linux/lsm.h>

#include "include/apparmor.h"
#include "include/apparmorfs.h"
#include "include/audit.h"
#include "include/capability.h"
#include "include/cred.h"
#include "include/file.h"
#include "include/ipc.h"
#include "include/net.h"
#include "include/path.h"
#include "include/label.h"
#include "include/policy.h"
#include "include/policy_ns.h"
#include "include/procattr.h"
#include "include/mount.h"
#include "include/secid.h"

/* Flag indicating whether initialization completed */
int apparmor_initialized;

aa_buffer;

struct aa_local_cache {};

#define RESERVE_COUNT
static int reserve_count =;
static int buffer_count;

static LIST_HEAD(aa_global_buffers);
static DEFINE_SPINLOCK(aa_buffers_lock);
static DEFINE_PER_CPU(struct aa_local_cache, aa_local_buffers);

/*
 * LSM hook functions
 */

/*
 * put the associated labels
 */
static void apparmor_cred_free(struct cred *cred)
{}

/*
 * allocate the apparmor part of blank credentials
 */
static int apparmor_cred_alloc_blank(struct cred *cred, gfp_t gfp)
{}

/*
 * prepare new cred label for modification by prepare_cred block
 */
static int apparmor_cred_prepare(struct cred *new, const struct cred *old,
				 gfp_t gfp)
{}

/*
 * transfer the apparmor data to a blank set of creds
 */
static void apparmor_cred_transfer(struct cred *new, const struct cred *old)
{}

static void apparmor_task_free(struct task_struct *task)
{}

static int apparmor_task_alloc(struct task_struct *task,
			       unsigned long clone_flags)
{}

static int apparmor_ptrace_access_check(struct task_struct *child,
					unsigned int mode)
{}

static int apparmor_ptrace_traceme(struct task_struct *parent)
{}

/* Derived from security/commoncap.c:cap_capget */
static int apparmor_capget(const struct task_struct *target, kernel_cap_t *effective,
			   kernel_cap_t *inheritable, kernel_cap_t *permitted)
{}

static int apparmor_capable(const struct cred *cred, struct user_namespace *ns,
			    int cap, unsigned int opts)
{}

/**
 * common_perm - basic common permission check wrapper fn for paths
 * @op: operation being checked
 * @path: path to check permission of  (NOT NULL)
 * @mask: requested permissions mask
 * @cond: conditional info for the permission request  (NOT NULL)
 *
 * Returns: %0 else error code if error or permission denied
 */
static int common_perm(const char *op, const struct path *path, u32 mask,
		       struct path_cond *cond)
{}

/**
 * common_perm_cond - common permission wrapper around inode cond
 * @op: operation being checked
 * @path: location to check (NOT NULL)
 * @mask: requested permissions mask
 *
 * Returns: %0 else error code if error or permission denied
 */
static int common_perm_cond(const char *op, const struct path *path, u32 mask)
{}

/**
 * common_perm_dir_dentry - common permission wrapper when path is dir, dentry
 * @op: operation being checked
 * @dir: directory of the dentry  (NOT NULL)
 * @dentry: dentry to check  (NOT NULL)
 * @mask: requested permissions mask
 * @cond: conditional info for the permission request  (NOT NULL)
 *
 * Returns: %0 else error code if error or permission denied
 */
static int common_perm_dir_dentry(const char *op, const struct path *dir,
				  struct dentry *dentry, u32 mask,
				  struct path_cond *cond)
{}

/**
 * common_perm_rm - common permission wrapper for operations doing rm
 * @op: operation being checked
 * @dir: directory that the dentry is in  (NOT NULL)
 * @dentry: dentry being rm'd  (NOT NULL)
 * @mask: requested permission mask
 *
 * Returns: %0 else error code if error or permission denied
 */
static int common_perm_rm(const char *op, const struct path *dir,
			  struct dentry *dentry, u32 mask)
{}

/**
 * common_perm_create - common permission wrapper for operations doing create
 * @op: operation being checked
 * @dir: directory that dentry will be created in  (NOT NULL)
 * @dentry: dentry to create   (NOT NULL)
 * @mask: request permission mask
 * @mode: created file mode
 *
 * Returns: %0 else error code if error or permission denied
 */
static int common_perm_create(const char *op, const struct path *dir,
			      struct dentry *dentry, u32 mask, umode_t mode)
{}

static int apparmor_path_unlink(const struct path *dir, struct dentry *dentry)
{}

static int apparmor_path_mkdir(const struct path *dir, struct dentry *dentry,
			       umode_t mode)
{}

static int apparmor_path_rmdir(const struct path *dir, struct dentry *dentry)
{}

static int apparmor_path_mknod(const struct path *dir, struct dentry *dentry,
			       umode_t mode, unsigned int dev)
{}

static int apparmor_path_truncate(const struct path *path)
{}

static int apparmor_file_truncate(struct file *file)
{}

static int apparmor_path_symlink(const struct path *dir, struct dentry *dentry,
				 const char *old_name)
{}

static int apparmor_path_link(struct dentry *old_dentry, const struct path *new_dir,
			      struct dentry *new_dentry)
{}

static int apparmor_path_rename(const struct path *old_dir, struct dentry *old_dentry,
				const struct path *new_dir, struct dentry *new_dentry,
				const unsigned int flags)
{}

static int apparmor_path_chmod(const struct path *path, umode_t mode)
{}

static int apparmor_path_chown(const struct path *path, kuid_t uid, kgid_t gid)
{}

static int apparmor_inode_getattr(const struct path *path)
{}

static int apparmor_file_open(struct file *file)
{}

static int apparmor_file_alloc_security(struct file *file)
{}

static void apparmor_file_free_security(struct file *file)
{}

static int common_file_perm(const char *op, struct file *file, u32 mask,
			    bool in_atomic)
{}

static int apparmor_file_receive(struct file *file)
{}

static int apparmor_file_permission(struct file *file, int mask)
{}

static int apparmor_file_lock(struct file *file, unsigned int cmd)
{}

static int common_mmap(const char *op, struct file *file, unsigned long prot,
		       unsigned long flags, bool in_atomic)
{}

static int apparmor_mmap_file(struct file *file, unsigned long reqprot,
			      unsigned long prot, unsigned long flags)
{}

static int apparmor_file_mprotect(struct vm_area_struct *vma,
				  unsigned long reqprot, unsigned long prot)
{}

#ifdef CONFIG_IO_URING
static const char *audit_uring_mask(u32 mask)
{}

static void audit_uring_cb(struct audit_buffer *ab, void *va)
{}

static int profile_uring(struct aa_profile *profile, u32 request,
			 struct aa_label *new, int cap,
			 struct apparmor_audit_data *ad)
{}

/**
 * apparmor_uring_override_creds - check the requested cred override
 * @new: the target creds
 *
 * Check to see if the current task is allowed to override it's credentials
 * to service an io_uring operation.
 */
static int apparmor_uring_override_creds(const struct cred *new)
{}

/**
 * apparmor_uring_sqpoll - check if a io_uring polling thread can be created
 *
 * Check to see if the current task is allowed to create a new io_uring
 * kernel polling thread.
 */
static int apparmor_uring_sqpoll(void)
{}
#endif /* CONFIG_IO_URING */

static int apparmor_sb_mount(const char *dev_name, const struct path *path,
			     const char *type, unsigned long flags, void *data)
{}

static int apparmor_move_mount(const struct path *from_path,
			       const struct path *to_path)
{}

static int apparmor_sb_umount(struct vfsmount *mnt, int flags)
{}

static int apparmor_sb_pivotroot(const struct path *old_path,
				 const struct path *new_path)
{}

static int apparmor_getselfattr(unsigned int attr, struct lsm_ctx __user *lx,
				u32 *size, u32 flags)
{}

static int apparmor_getprocattr(struct task_struct *task, const char *name,
				char **value)
{}

static int do_setattr(u64 attr, void *value, size_t size)
{}

static int apparmor_setselfattr(unsigned int attr, struct lsm_ctx *ctx,
				u32 size, u32 flags)
{}

static int apparmor_setprocattr(const char *name, void *value,
				size_t size)
{}

/**
 * apparmor_bprm_committing_creds - do task cleanup on committing new creds
 * @bprm: binprm for the exec  (NOT NULL)
 */
static void apparmor_bprm_committing_creds(const struct linux_binprm *bprm)
{}

/**
 * apparmor_bprm_committed_creds() - do cleanup after new creds committed
 * @bprm: binprm for the exec  (NOT NULL)
 */
static void apparmor_bprm_committed_creds(const struct linux_binprm *bprm)
{}

static void apparmor_current_getsecid_subj(u32 *secid)
{}

static void apparmor_task_getsecid_obj(struct task_struct *p, u32 *secid)
{}

static int apparmor_task_setrlimit(struct task_struct *task,
		unsigned int resource, struct rlimit *new_rlim)
{}

static int apparmor_task_kill(struct task_struct *target, struct kernel_siginfo *info,
			      int sig, const struct cred *cred)
{}

static int apparmor_userns_create(const struct cred *cred)
{}

static void apparmor_sk_free_security(struct sock *sk)
{}

/**
 * apparmor_sk_clone_security - clone the sk_security field
 * @sk: sock to have security cloned
 * @newsk: sock getting clone
 */
static void apparmor_sk_clone_security(const struct sock *sk,
				       struct sock *newsk)
{}

static int apparmor_socket_create(int family, int type, int protocol, int kern)
{}

/**
 * apparmor_socket_post_create - setup the per-socket security struct
 * @sock: socket that is being setup
 * @family: family of socket being created
 * @type: type of the socket
 * @protocol: protocol of the socket
 * @kern: socket is a special kernel socket
 *
 * Note:
 * -   kernel sockets labeled kernel_t used to use unconfined
 * -   socket may not have sk here if created with sock_create_lite or
 *     sock_alloc. These should be accept cases which will be handled in
 *     sock_graft.
 */
static int apparmor_socket_post_create(struct socket *sock, int family,
				       int type, int protocol, int kern)
{}

static int apparmor_socket_bind(struct socket *sock,
				struct sockaddr *address, int addrlen)
{}

static int apparmor_socket_connect(struct socket *sock,
				   struct sockaddr *address, int addrlen)
{}

static int apparmor_socket_listen(struct socket *sock, int backlog)
{}

/*
 * Note: while @newsock is created and has some information, the accept
 *       has not been done.
 */
static int apparmor_socket_accept(struct socket *sock, struct socket *newsock)
{}

static int aa_sock_msg_perm(const char *op, u32 request, struct socket *sock,
			    struct msghdr *msg, int size)
{}

static int apparmor_socket_sendmsg(struct socket *sock,
				   struct msghdr *msg, int size)
{}

static int apparmor_socket_recvmsg(struct socket *sock,
				   struct msghdr *msg, int size, int flags)
{}

/* revaliation, get/set attr, shutdown */
static int aa_sock_perm(const char *op, u32 request, struct socket *sock)
{}

static int apparmor_socket_getsockname(struct socket *sock)
{}

static int apparmor_socket_getpeername(struct socket *sock)
{}

/* revaliation, get/set attr, opt */
static int aa_sock_opt_perm(const char *op, u32 request, struct socket *sock,
			    int level, int optname)
{}

static int apparmor_socket_getsockopt(struct socket *sock, int level,
				      int optname)
{}

static int apparmor_socket_setsockopt(struct socket *sock, int level,
				      int optname)
{}

static int apparmor_socket_shutdown(struct socket *sock, int how)
{}

#ifdef CONFIG_NETWORK_SECMARK
/**
 * apparmor_socket_sock_rcv_skb - check perms before associating skb to sk
 * @sk: sk to associate @skb with
 * @skb: skb to check for perms
 *
 * Note: can not sleep may be called with locks held
 *
 * dont want protocol specific in __skb_recv_datagram()
 * to deny an incoming connection  socket_sock_rcv_skb()
 */
static int apparmor_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
{}
#endif


static struct aa_label *sk_peer_label(struct sock *sk)
{}

/**
 * apparmor_socket_getpeersec_stream - get security context of peer
 * @sock: socket that we are trying to get the peer context of
 * @optval: output - buffer to copy peer name to
 * @optlen: output - size of copied name in @optval
 * @len: size of @optval buffer
 * Returns: 0 on success, -errno of failure
 *
 * Note: for tcp only valid if using ipsec or cipso on lan
 */
static int apparmor_socket_getpeersec_stream(struct socket *sock,
					     sockptr_t optval, sockptr_t optlen,
					     unsigned int len)
{}

/**
 * apparmor_socket_getpeersec_dgram - get security label of packet
 * @sock: the peer socket
 * @skb: packet data
 * @secid: pointer to where to put the secid of the packet
 *
 * Sets the netlabel socket state on sk from parent
 */
static int apparmor_socket_getpeersec_dgram(struct socket *sock,
					    struct sk_buff *skb, u32 *secid)

{}

/**
 * apparmor_sock_graft - Initialize newly created socket
 * @sk: child sock
 * @parent: parent socket
 *
 * Note: could set off of SOCK_CTX(parent) but need to track inode and we can
 *       just set sk security information off of current creating process label
 *       Labeling of sk for accept case - probably should be sock based
 *       instead of task, because of the case where an implicitly labeled
 *       socket is shared by different tasks.
 */
static void apparmor_sock_graft(struct sock *sk, struct socket *parent)
{}

#ifdef CONFIG_NETWORK_SECMARK
static int apparmor_inet_conn_request(const struct sock *sk, struct sk_buff *skb,
				      struct request_sock *req)
{}
#endif

/*
 * The cred blob is a pointer to, not an instance of, an aa_label.
 */
struct lsm_blob_sizes apparmor_blob_sizes __ro_after_init =;

static const struct lsm_id apparmor_lsmid =;

static struct security_hook_list apparmor_hooks[] __ro_after_init =;

/*
 * AppArmor sysfs module parameters
 */

static int param_set_aabool(const char *val, const struct kernel_param *kp);
static int param_get_aabool(char *buffer, const struct kernel_param *kp);
#define param_check_aabool
static const struct kernel_param_ops param_ops_aabool =;

static int param_set_aauint(const char *val, const struct kernel_param *kp);
static int param_get_aauint(char *buffer, const struct kernel_param *kp);
#define param_check_aauint
static const struct kernel_param_ops param_ops_aauint =;

static int param_set_aacompressionlevel(const char *val,
					const struct kernel_param *kp);
static int param_get_aacompressionlevel(char *buffer,
					const struct kernel_param *kp);
#define param_check_aacompressionlevel
static const struct kernel_param_ops param_ops_aacompressionlevel =;

static int param_set_aalockpolicy(const char *val, const struct kernel_param *kp);
static int param_get_aalockpolicy(char *buffer, const struct kernel_param *kp);
#define param_check_aalockpolicy
static const struct kernel_param_ops param_ops_aalockpolicy =;

static int param_set_audit(const char *val, const struct kernel_param *kp);
static int param_get_audit(char *buffer, const struct kernel_param *kp);

static int param_set_mode(const char *val, const struct kernel_param *kp);
static int param_get_mode(char *buffer, const struct kernel_param *kp);

/* Flag values, also controllable via /sys/module/apparmor/parameters
 * We define special types as we want to do additional mediation.
 */

/* AppArmor global enforcement switch - complain, enforce, kill */
enum profile_mode aa_g_profile_mode =;
module_param_call();

/* whether policy verification hashing is enabled */
bool aa_g_hash_policy = IS_ENABLED();
#ifdef CONFIG_SECURITY_APPARMOR_HASH
module_param_named(hash_policy, aa_g_hash_policy, aabool, S_IRUSR | S_IWUSR);
#endif

/* whether policy exactly as loaded is retained for debug and checkpointing */
bool aa_g_export_binary = IS_ENABLED();
#ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY
module_param_named(export_binary, aa_g_export_binary, aabool, 0600);
#endif

/* policy loaddata compression level */
int aa_g_rawdata_compression_level =;
module_param_named(rawdata_compression_level, aa_g_rawdata_compression_level,
		   aacompressionlevel, 0400);

/* Debug mode */
bool aa_g_debug = IS_ENABLED();
module_param_named(debug, aa_g_debug, aabool, S_IRUSR | S_IWUSR);

/* Audit mode */
enum audit_mode aa_g_audit;
module_param_call();

/* Determines if audit header is included in audited messages.  This
 * provides more context if the audit daemon is not running
 */
bool aa_g_audit_header =;
module_param_named(audit_header, aa_g_audit_header, aabool,
		   S_IRUSR | S_IWUSR);

/* lock out loading/removal of policy
 * TODO: add in at boot loading of policy, which is the only way to
 *       load policy, if lock_policy is set
 */
bool aa_g_lock_policy;
module_param_named(lock_policy, aa_g_lock_policy, aalockpolicy,
		   S_IRUSR | S_IWUSR);

/* Syscall logging mode */
bool aa_g_logsyscall;
module_param_named(logsyscall, aa_g_logsyscall, aabool, S_IRUSR | S_IWUSR);

/* Maximum pathname length before accesses will start getting rejected */
unsigned int aa_g_path_max =;
module_param_named(path_max, aa_g_path_max, aauint, S_IRUSR);

/* Determines how paranoid loading of policy is and how much verification
 * on the loaded policy is done.
 * DEPRECATED: read only as strict checking of load is always done now
 * that none root users (user namespaces) can load policy.
 */
bool aa_g_paranoid_load = IS_ENABLED();
module_param_named(paranoid_load, aa_g_paranoid_load, aabool, S_IRUGO);

static int param_get_aaintbool(char *buffer, const struct kernel_param *kp);
static int param_set_aaintbool(const char *val, const struct kernel_param *kp);
#define param_check_aaintbool
static const struct kernel_param_ops param_ops_aaintbool =;
/* Boot time disable flag */
static int apparmor_enabled __ro_after_init =;
module_param_named(enabled, apparmor_enabled, aaintbool, 0444);

static int __init apparmor_enabled_setup(char *str)
{}

__setup();

/* set global flag turning off the ability to load policy */
static int param_set_aalockpolicy(const char *val, const struct kernel_param *kp)
{}

static int param_get_aalockpolicy(char *buffer, const struct kernel_param *kp)
{}

static int param_set_aabool(const char *val, const struct kernel_param *kp)
{}

static int param_get_aabool(char *buffer, const struct kernel_param *kp)
{}

static int param_set_aauint(const char *val, const struct kernel_param *kp)
{}

static int param_get_aauint(char *buffer, const struct kernel_param *kp)
{}

/* Can only be set before AppArmor is initialized (i.e. on boot cmdline). */
static int param_set_aaintbool(const char *val, const struct kernel_param *kp)
{}

/*
 * To avoid changing /sys/module/apparmor/parameters/enabled from Y/N to
 * 1/0, this converts the "int that is actually bool" back to bool for
 * display in the /sys filesystem, while keeping it "int" for the LSM
 * infrastructure.
 */
static int param_get_aaintbool(char *buffer, const struct kernel_param *kp)
{}

static int param_set_aacompressionlevel(const char *val,
					const struct kernel_param *kp)
{}

static int param_get_aacompressionlevel(char *buffer,
					const struct kernel_param *kp)
{}

static int param_get_audit(char *buffer, const struct kernel_param *kp)
{}

static int param_set_audit(const char *val, const struct kernel_param *kp)
{}

static int param_get_mode(char *buffer, const struct kernel_param *kp)
{}

static int param_set_mode(const char *val, const struct kernel_param *kp)
{}

char *aa_get_buffer(bool in_atomic)
{}

void aa_put_buffer(char *buf)
{}

/*
 * AppArmor init functions
 */

/**
 * set_init_ctx - set a task context and profile on the first task.
 *
 * TODO: allow setting an alternate profile than unconfined
 */
static int __init set_init_ctx(void)
{}

static void destroy_buffers(void)
{}

static int __init alloc_buffers(void)
{}

#ifdef CONFIG_SYSCTL
static int apparmor_dointvec(const struct ctl_table *table, int write,
			     void *buffer, size_t *lenp, loff_t *ppos)
{}

static struct ctl_table apparmor_sysctl_table[] =;

static int __init apparmor_init_sysctl(void)
{}
#else
static inline int apparmor_init_sysctl(void)
{
	return 0;
}
#endif /* CONFIG_SYSCTL */

#if defined(CONFIG_NETFILTER) && defined(CONFIG_NETWORK_SECMARK)
static unsigned int apparmor_ip_postroute(void *priv,
					  struct sk_buff *skb,
					  const struct nf_hook_state *state)
{}

static const struct nf_hook_ops apparmor_nf_ops[] =;

static int __net_init apparmor_nf_register(struct net *net)
{}

static void __net_exit apparmor_nf_unregister(struct net *net)
{}

static struct pernet_operations apparmor_net_ops =;

static int __init apparmor_nf_ip_init(void)
{}
__initcall(apparmor_nf_ip_init);
#endif

static char nulldfa_src[] =;
static struct aa_dfa *nulldfa;

static char stacksplitdfa_src[] =;
struct aa_dfa *stacksplitdfa;
struct aa_policydb *nullpdb;

static int __init aa_setup_dfa_engine(void)
{}

static void __init aa_teardown_dfa_engine(void)
{}

static int __init apparmor_init(void)
{}

DEFINE_LSM(apparmor) =;