18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * AppArmor security module
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * This file contains AppArmor LSM hooks.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Copyright (C) 1998-2008 Novell/SUSE
88c2ecf20Sopenharmony_ci * Copyright 2009-2010 Canonical Ltd.
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/lsm_hooks.h>
128c2ecf20Sopenharmony_ci#include <linux/moduleparam.h>
138c2ecf20Sopenharmony_ci#include <linux/mm.h>
148c2ecf20Sopenharmony_ci#include <linux/mman.h>
158c2ecf20Sopenharmony_ci#include <linux/mount.h>
168c2ecf20Sopenharmony_ci#include <linux/namei.h>
178c2ecf20Sopenharmony_ci#include <linux/ptrace.h>
188c2ecf20Sopenharmony_ci#include <linux/ctype.h>
198c2ecf20Sopenharmony_ci#include <linux/sysctl.h>
208c2ecf20Sopenharmony_ci#include <linux/audit.h>
218c2ecf20Sopenharmony_ci#include <linux/user_namespace.h>
228c2ecf20Sopenharmony_ci#include <linux/netfilter_ipv4.h>
238c2ecf20Sopenharmony_ci#include <linux/netfilter_ipv6.h>
248c2ecf20Sopenharmony_ci#include <linux/zlib.h>
258c2ecf20Sopenharmony_ci#include <net/sock.h>
268c2ecf20Sopenharmony_ci#include <uapi/linux/mount.h>
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci#include "include/apparmor.h"
298c2ecf20Sopenharmony_ci#include "include/apparmorfs.h"
308c2ecf20Sopenharmony_ci#include "include/audit.h"
318c2ecf20Sopenharmony_ci#include "include/capability.h"
328c2ecf20Sopenharmony_ci#include "include/cred.h"
338c2ecf20Sopenharmony_ci#include "include/file.h"
348c2ecf20Sopenharmony_ci#include "include/ipc.h"
358c2ecf20Sopenharmony_ci#include "include/net.h"
368c2ecf20Sopenharmony_ci#include "include/path.h"
378c2ecf20Sopenharmony_ci#include "include/label.h"
388c2ecf20Sopenharmony_ci#include "include/policy.h"
398c2ecf20Sopenharmony_ci#include "include/policy_ns.h"
408c2ecf20Sopenharmony_ci#include "include/procattr.h"
418c2ecf20Sopenharmony_ci#include "include/mount.h"
428c2ecf20Sopenharmony_ci#include "include/secid.h"
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci/* Flag indicating whether initialization completed */
458c2ecf20Sopenharmony_ciint apparmor_initialized;
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ciunion aa_buffer {
488c2ecf20Sopenharmony_ci	struct list_head list;
498c2ecf20Sopenharmony_ci	char buffer[1];
508c2ecf20Sopenharmony_ci};
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci#define RESERVE_COUNT 2
538c2ecf20Sopenharmony_cistatic int reserve_count = RESERVE_COUNT;
548c2ecf20Sopenharmony_cistatic int buffer_count;
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cistatic LIST_HEAD(aa_global_buffers);
578c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(aa_buffers_lock);
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci/*
608c2ecf20Sopenharmony_ci * LSM hook functions
618c2ecf20Sopenharmony_ci */
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci/*
648c2ecf20Sopenharmony_ci * put the associated labels
658c2ecf20Sopenharmony_ci */
668c2ecf20Sopenharmony_cistatic void apparmor_cred_free(struct cred *cred)
678c2ecf20Sopenharmony_ci{
688c2ecf20Sopenharmony_ci	aa_put_label(cred_label(cred));
698c2ecf20Sopenharmony_ci	set_cred_label(cred, NULL);
708c2ecf20Sopenharmony_ci}
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci/*
738c2ecf20Sopenharmony_ci * allocate the apparmor part of blank credentials
748c2ecf20Sopenharmony_ci */
758c2ecf20Sopenharmony_cistatic int apparmor_cred_alloc_blank(struct cred *cred, gfp_t gfp)
768c2ecf20Sopenharmony_ci{
778c2ecf20Sopenharmony_ci	set_cred_label(cred, NULL);
788c2ecf20Sopenharmony_ci	return 0;
798c2ecf20Sopenharmony_ci}
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci/*
828c2ecf20Sopenharmony_ci * prepare new cred label for modification by prepare_cred block
838c2ecf20Sopenharmony_ci */
848c2ecf20Sopenharmony_cistatic int apparmor_cred_prepare(struct cred *new, const struct cred *old,
858c2ecf20Sopenharmony_ci				 gfp_t gfp)
868c2ecf20Sopenharmony_ci{
878c2ecf20Sopenharmony_ci	set_cred_label(new, aa_get_newest_label(cred_label(old)));
888c2ecf20Sopenharmony_ci	return 0;
898c2ecf20Sopenharmony_ci}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci/*
928c2ecf20Sopenharmony_ci * transfer the apparmor data to a blank set of creds
938c2ecf20Sopenharmony_ci */
948c2ecf20Sopenharmony_cistatic void apparmor_cred_transfer(struct cred *new, const struct cred *old)
958c2ecf20Sopenharmony_ci{
968c2ecf20Sopenharmony_ci	set_cred_label(new, aa_get_newest_label(cred_label(old)));
978c2ecf20Sopenharmony_ci}
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_cistatic void apparmor_task_free(struct task_struct *task)
1008c2ecf20Sopenharmony_ci{
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	aa_free_task_ctx(task_ctx(task));
1038c2ecf20Sopenharmony_ci}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_cistatic int apparmor_task_alloc(struct task_struct *task,
1068c2ecf20Sopenharmony_ci			       unsigned long clone_flags)
1078c2ecf20Sopenharmony_ci{
1088c2ecf20Sopenharmony_ci	struct aa_task_ctx *new = task_ctx(task);
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	aa_dup_task_ctx(new, task_ctx(current));
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	return 0;
1138c2ecf20Sopenharmony_ci}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_cistatic int apparmor_ptrace_access_check(struct task_struct *child,
1168c2ecf20Sopenharmony_ci					unsigned int mode)
1178c2ecf20Sopenharmony_ci{
1188c2ecf20Sopenharmony_ci	struct aa_label *tracer, *tracee;
1198c2ecf20Sopenharmony_ci	int error;
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	tracer = __begin_current_label_crit_section();
1228c2ecf20Sopenharmony_ci	tracee = aa_get_task_label(child);
1238c2ecf20Sopenharmony_ci	error = aa_may_ptrace(tracer, tracee,
1248c2ecf20Sopenharmony_ci			(mode & PTRACE_MODE_READ) ? AA_PTRACE_READ
1258c2ecf20Sopenharmony_ci						  : AA_PTRACE_TRACE);
1268c2ecf20Sopenharmony_ci	aa_put_label(tracee);
1278c2ecf20Sopenharmony_ci	__end_current_label_crit_section(tracer);
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	return error;
1308c2ecf20Sopenharmony_ci}
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_cistatic int apparmor_ptrace_traceme(struct task_struct *parent)
1338c2ecf20Sopenharmony_ci{
1348c2ecf20Sopenharmony_ci	struct aa_label *tracer, *tracee;
1358c2ecf20Sopenharmony_ci	int error;
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	tracee = __begin_current_label_crit_section();
1388c2ecf20Sopenharmony_ci	tracer = aa_get_task_label(parent);
1398c2ecf20Sopenharmony_ci	error = aa_may_ptrace(tracer, tracee, AA_PTRACE_TRACE);
1408c2ecf20Sopenharmony_ci	aa_put_label(tracer);
1418c2ecf20Sopenharmony_ci	__end_current_label_crit_section(tracee);
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	return error;
1448c2ecf20Sopenharmony_ci}
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci/* Derived from security/commoncap.c:cap_capget */
1478c2ecf20Sopenharmony_cistatic int apparmor_capget(struct task_struct *target, kernel_cap_t *effective,
1488c2ecf20Sopenharmony_ci			   kernel_cap_t *inheritable, kernel_cap_t *permitted)
1498c2ecf20Sopenharmony_ci{
1508c2ecf20Sopenharmony_ci	struct aa_label *label;
1518c2ecf20Sopenharmony_ci	const struct cred *cred;
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	rcu_read_lock();
1548c2ecf20Sopenharmony_ci	cred = __task_cred(target);
1558c2ecf20Sopenharmony_ci	label = aa_get_newest_cred_label(cred);
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	/*
1588c2ecf20Sopenharmony_ci	 * cap_capget is stacked ahead of this and will
1598c2ecf20Sopenharmony_ci	 * initialize effective and permitted.
1608c2ecf20Sopenharmony_ci	 */
1618c2ecf20Sopenharmony_ci	if (!unconfined(label)) {
1628c2ecf20Sopenharmony_ci		struct aa_profile *profile;
1638c2ecf20Sopenharmony_ci		struct label_it i;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci		label_for_each_confined(i, label, profile) {
1668c2ecf20Sopenharmony_ci			if (COMPLAIN_MODE(profile))
1678c2ecf20Sopenharmony_ci				continue;
1688c2ecf20Sopenharmony_ci			*effective = cap_intersect(*effective,
1698c2ecf20Sopenharmony_ci						   profile->caps.allow);
1708c2ecf20Sopenharmony_ci			*permitted = cap_intersect(*permitted,
1718c2ecf20Sopenharmony_ci						   profile->caps.allow);
1728c2ecf20Sopenharmony_ci		}
1738c2ecf20Sopenharmony_ci	}
1748c2ecf20Sopenharmony_ci	rcu_read_unlock();
1758c2ecf20Sopenharmony_ci	aa_put_label(label);
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	return 0;
1788c2ecf20Sopenharmony_ci}
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_cistatic int apparmor_capable(const struct cred *cred, struct user_namespace *ns,
1818c2ecf20Sopenharmony_ci			    int cap, unsigned int opts)
1828c2ecf20Sopenharmony_ci{
1838c2ecf20Sopenharmony_ci	struct aa_label *label;
1848c2ecf20Sopenharmony_ci	int error = 0;
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	label = aa_get_newest_cred_label(cred);
1878c2ecf20Sopenharmony_ci	if (!unconfined(label))
1888c2ecf20Sopenharmony_ci		error = aa_capable(label, cap, opts);
1898c2ecf20Sopenharmony_ci	aa_put_label(label);
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	return error;
1928c2ecf20Sopenharmony_ci}
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci/**
1958c2ecf20Sopenharmony_ci * common_perm - basic common permission check wrapper fn for paths
1968c2ecf20Sopenharmony_ci * @op: operation being checked
1978c2ecf20Sopenharmony_ci * @path: path to check permission of  (NOT NULL)
1988c2ecf20Sopenharmony_ci * @mask: requested permissions mask
1998c2ecf20Sopenharmony_ci * @cond: conditional info for the permission request  (NOT NULL)
2008c2ecf20Sopenharmony_ci *
2018c2ecf20Sopenharmony_ci * Returns: %0 else error code if error or permission denied
2028c2ecf20Sopenharmony_ci */
2038c2ecf20Sopenharmony_cistatic int common_perm(const char *op, const struct path *path, u32 mask,
2048c2ecf20Sopenharmony_ci		       struct path_cond *cond)
2058c2ecf20Sopenharmony_ci{
2068c2ecf20Sopenharmony_ci	struct aa_label *label;
2078c2ecf20Sopenharmony_ci	int error = 0;
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	label = __begin_current_label_crit_section();
2108c2ecf20Sopenharmony_ci	if (!unconfined(label))
2118c2ecf20Sopenharmony_ci		error = aa_path_perm(op, label, path, 0, mask, cond);
2128c2ecf20Sopenharmony_ci	__end_current_label_crit_section(label);
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	return error;
2158c2ecf20Sopenharmony_ci}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci/**
2188c2ecf20Sopenharmony_ci * common_perm_cond - common permission wrapper around inode cond
2198c2ecf20Sopenharmony_ci * @op: operation being checked
2208c2ecf20Sopenharmony_ci * @path: location to check (NOT NULL)
2218c2ecf20Sopenharmony_ci * @mask: requested permissions mask
2228c2ecf20Sopenharmony_ci *
2238c2ecf20Sopenharmony_ci * Returns: %0 else error code if error or permission denied
2248c2ecf20Sopenharmony_ci */
2258c2ecf20Sopenharmony_cistatic int common_perm_cond(const char *op, const struct path *path, u32 mask)
2268c2ecf20Sopenharmony_ci{
2278c2ecf20Sopenharmony_ci	struct path_cond cond = { d_backing_inode(path->dentry)->i_uid,
2288c2ecf20Sopenharmony_ci				  d_backing_inode(path->dentry)->i_mode
2298c2ecf20Sopenharmony_ci	};
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	if (!path_mediated_fs(path->dentry))
2328c2ecf20Sopenharmony_ci		return 0;
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	return common_perm(op, path, mask, &cond);
2358c2ecf20Sopenharmony_ci}
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci/**
2388c2ecf20Sopenharmony_ci * common_perm_dir_dentry - common permission wrapper when path is dir, dentry
2398c2ecf20Sopenharmony_ci * @op: operation being checked
2408c2ecf20Sopenharmony_ci * @dir: directory of the dentry  (NOT NULL)
2418c2ecf20Sopenharmony_ci * @dentry: dentry to check  (NOT NULL)
2428c2ecf20Sopenharmony_ci * @mask: requested permissions mask
2438c2ecf20Sopenharmony_ci * @cond: conditional info for the permission request  (NOT NULL)
2448c2ecf20Sopenharmony_ci *
2458c2ecf20Sopenharmony_ci * Returns: %0 else error code if error or permission denied
2468c2ecf20Sopenharmony_ci */
2478c2ecf20Sopenharmony_cistatic int common_perm_dir_dentry(const char *op, const struct path *dir,
2488c2ecf20Sopenharmony_ci				  struct dentry *dentry, u32 mask,
2498c2ecf20Sopenharmony_ci				  struct path_cond *cond)
2508c2ecf20Sopenharmony_ci{
2518c2ecf20Sopenharmony_ci	struct path path = { .mnt = dir->mnt, .dentry = dentry };
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	return common_perm(op, &path, mask, cond);
2548c2ecf20Sopenharmony_ci}
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci/**
2578c2ecf20Sopenharmony_ci * common_perm_rm - common permission wrapper for operations doing rm
2588c2ecf20Sopenharmony_ci * @op: operation being checked
2598c2ecf20Sopenharmony_ci * @dir: directory that the dentry is in  (NOT NULL)
2608c2ecf20Sopenharmony_ci * @dentry: dentry being rm'd  (NOT NULL)
2618c2ecf20Sopenharmony_ci * @mask: requested permission mask
2628c2ecf20Sopenharmony_ci *
2638c2ecf20Sopenharmony_ci * Returns: %0 else error code if error or permission denied
2648c2ecf20Sopenharmony_ci */
2658c2ecf20Sopenharmony_cistatic int common_perm_rm(const char *op, const struct path *dir,
2668c2ecf20Sopenharmony_ci			  struct dentry *dentry, u32 mask)
2678c2ecf20Sopenharmony_ci{
2688c2ecf20Sopenharmony_ci	struct inode *inode = d_backing_inode(dentry);
2698c2ecf20Sopenharmony_ci	struct path_cond cond = { };
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	if (!inode || !path_mediated_fs(dentry))
2728c2ecf20Sopenharmony_ci		return 0;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	cond.uid = inode->i_uid;
2758c2ecf20Sopenharmony_ci	cond.mode = inode->i_mode;
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_ci	return common_perm_dir_dentry(op, dir, dentry, mask, &cond);
2788c2ecf20Sopenharmony_ci}
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci/**
2818c2ecf20Sopenharmony_ci * common_perm_create - common permission wrapper for operations doing create
2828c2ecf20Sopenharmony_ci * @op: operation being checked
2838c2ecf20Sopenharmony_ci * @dir: directory that dentry will be created in  (NOT NULL)
2848c2ecf20Sopenharmony_ci * @dentry: dentry to create   (NOT NULL)
2858c2ecf20Sopenharmony_ci * @mask: request permission mask
2868c2ecf20Sopenharmony_ci * @mode: created file mode
2878c2ecf20Sopenharmony_ci *
2888c2ecf20Sopenharmony_ci * Returns: %0 else error code if error or permission denied
2898c2ecf20Sopenharmony_ci */
2908c2ecf20Sopenharmony_cistatic int common_perm_create(const char *op, const struct path *dir,
2918c2ecf20Sopenharmony_ci			      struct dentry *dentry, u32 mask, umode_t mode)
2928c2ecf20Sopenharmony_ci{
2938c2ecf20Sopenharmony_ci	struct path_cond cond = { current_fsuid(), mode };
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	if (!path_mediated_fs(dir->dentry))
2968c2ecf20Sopenharmony_ci		return 0;
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	return common_perm_dir_dentry(op, dir, dentry, mask, &cond);
2998c2ecf20Sopenharmony_ci}
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_cistatic int apparmor_path_unlink(const struct path *dir, struct dentry *dentry)
3028c2ecf20Sopenharmony_ci{
3038c2ecf20Sopenharmony_ci	return common_perm_rm(OP_UNLINK, dir, dentry, AA_MAY_DELETE);
3048c2ecf20Sopenharmony_ci}
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_cistatic int apparmor_path_mkdir(const struct path *dir, struct dentry *dentry,
3078c2ecf20Sopenharmony_ci			       umode_t mode)
3088c2ecf20Sopenharmony_ci{
3098c2ecf20Sopenharmony_ci	return common_perm_create(OP_MKDIR, dir, dentry, AA_MAY_CREATE,
3108c2ecf20Sopenharmony_ci				  S_IFDIR);
3118c2ecf20Sopenharmony_ci}
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_cistatic int apparmor_path_rmdir(const struct path *dir, struct dentry *dentry)
3148c2ecf20Sopenharmony_ci{
3158c2ecf20Sopenharmony_ci	return common_perm_rm(OP_RMDIR, dir, dentry, AA_MAY_DELETE);
3168c2ecf20Sopenharmony_ci}
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_cistatic int apparmor_path_mknod(const struct path *dir, struct dentry *dentry,
3198c2ecf20Sopenharmony_ci			       umode_t mode, unsigned int dev)
3208c2ecf20Sopenharmony_ci{
3218c2ecf20Sopenharmony_ci	return common_perm_create(OP_MKNOD, dir, dentry, AA_MAY_CREATE, mode);
3228c2ecf20Sopenharmony_ci}
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_cistatic int apparmor_path_truncate(const struct path *path)
3258c2ecf20Sopenharmony_ci{
3268c2ecf20Sopenharmony_ci	return common_perm_cond(OP_TRUNC, path, MAY_WRITE | AA_MAY_SETATTR);
3278c2ecf20Sopenharmony_ci}
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_cistatic int apparmor_path_symlink(const struct path *dir, struct dentry *dentry,
3308c2ecf20Sopenharmony_ci				 const char *old_name)
3318c2ecf20Sopenharmony_ci{
3328c2ecf20Sopenharmony_ci	return common_perm_create(OP_SYMLINK, dir, dentry, AA_MAY_CREATE,
3338c2ecf20Sopenharmony_ci				  S_IFLNK);
3348c2ecf20Sopenharmony_ci}
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_cistatic int apparmor_path_link(struct dentry *old_dentry, const struct path *new_dir,
3378c2ecf20Sopenharmony_ci			      struct dentry *new_dentry)
3388c2ecf20Sopenharmony_ci{
3398c2ecf20Sopenharmony_ci	struct aa_label *label;
3408c2ecf20Sopenharmony_ci	int error = 0;
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	if (!path_mediated_fs(old_dentry))
3438c2ecf20Sopenharmony_ci		return 0;
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	label = begin_current_label_crit_section();
3468c2ecf20Sopenharmony_ci	if (!unconfined(label))
3478c2ecf20Sopenharmony_ci		error = aa_path_link(label, old_dentry, new_dir, new_dentry);
3488c2ecf20Sopenharmony_ci	end_current_label_crit_section(label);
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	return error;
3518c2ecf20Sopenharmony_ci}
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_cistatic int apparmor_path_rename(const struct path *old_dir, struct dentry *old_dentry,
3548c2ecf20Sopenharmony_ci				const struct path *new_dir, struct dentry *new_dentry)
3558c2ecf20Sopenharmony_ci{
3568c2ecf20Sopenharmony_ci	struct aa_label *label;
3578c2ecf20Sopenharmony_ci	int error = 0;
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	if (!path_mediated_fs(old_dentry))
3608c2ecf20Sopenharmony_ci		return 0;
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	label = begin_current_label_crit_section();
3638c2ecf20Sopenharmony_ci	if (!unconfined(label)) {
3648c2ecf20Sopenharmony_ci		struct path old_path = { .mnt = old_dir->mnt,
3658c2ecf20Sopenharmony_ci					 .dentry = old_dentry };
3668c2ecf20Sopenharmony_ci		struct path new_path = { .mnt = new_dir->mnt,
3678c2ecf20Sopenharmony_ci					 .dentry = new_dentry };
3688c2ecf20Sopenharmony_ci		struct path_cond cond = { d_backing_inode(old_dentry)->i_uid,
3698c2ecf20Sopenharmony_ci					  d_backing_inode(old_dentry)->i_mode
3708c2ecf20Sopenharmony_ci		};
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci		error = aa_path_perm(OP_RENAME_SRC, label, &old_path, 0,
3738c2ecf20Sopenharmony_ci				     MAY_READ | AA_MAY_GETATTR | MAY_WRITE |
3748c2ecf20Sopenharmony_ci				     AA_MAY_SETATTR | AA_MAY_DELETE,
3758c2ecf20Sopenharmony_ci				     &cond);
3768c2ecf20Sopenharmony_ci		if (!error)
3778c2ecf20Sopenharmony_ci			error = aa_path_perm(OP_RENAME_DEST, label, &new_path,
3788c2ecf20Sopenharmony_ci					     0, MAY_WRITE | AA_MAY_SETATTR |
3798c2ecf20Sopenharmony_ci					     AA_MAY_CREATE, &cond);
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	}
3828c2ecf20Sopenharmony_ci	end_current_label_crit_section(label);
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	return error;
3858c2ecf20Sopenharmony_ci}
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_cistatic int apparmor_path_chmod(const struct path *path, umode_t mode)
3888c2ecf20Sopenharmony_ci{
3898c2ecf20Sopenharmony_ci	return common_perm_cond(OP_CHMOD, path, AA_MAY_CHMOD);
3908c2ecf20Sopenharmony_ci}
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_cistatic int apparmor_path_chown(const struct path *path, kuid_t uid, kgid_t gid)
3938c2ecf20Sopenharmony_ci{
3948c2ecf20Sopenharmony_ci	return common_perm_cond(OP_CHOWN, path, AA_MAY_CHOWN);
3958c2ecf20Sopenharmony_ci}
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_cistatic int apparmor_inode_getattr(const struct path *path)
3988c2ecf20Sopenharmony_ci{
3998c2ecf20Sopenharmony_ci	return common_perm_cond(OP_GETATTR, path, AA_MAY_GETATTR);
4008c2ecf20Sopenharmony_ci}
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_cistatic int apparmor_file_open(struct file *file)
4038c2ecf20Sopenharmony_ci{
4048c2ecf20Sopenharmony_ci	struct aa_file_ctx *fctx = file_ctx(file);
4058c2ecf20Sopenharmony_ci	struct aa_label *label;
4068c2ecf20Sopenharmony_ci	int error = 0;
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	if (!path_mediated_fs(file->f_path.dentry))
4098c2ecf20Sopenharmony_ci		return 0;
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	/* If in exec, permission is handled by bprm hooks.
4128c2ecf20Sopenharmony_ci	 * Cache permissions granted by the previous exec check, with
4138c2ecf20Sopenharmony_ci	 * implicit read and executable mmap which are required to
4148c2ecf20Sopenharmony_ci	 * actually execute the image.
4158c2ecf20Sopenharmony_ci	 */
4168c2ecf20Sopenharmony_ci	if (current->in_execve) {
4178c2ecf20Sopenharmony_ci		fctx->allow = MAY_EXEC | MAY_READ | AA_EXEC_MMAP;
4188c2ecf20Sopenharmony_ci		return 0;
4198c2ecf20Sopenharmony_ci	}
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	label = aa_get_newest_cred_label(file->f_cred);
4228c2ecf20Sopenharmony_ci	if (!unconfined(label)) {
4238c2ecf20Sopenharmony_ci		struct inode *inode = file_inode(file);
4248c2ecf20Sopenharmony_ci		struct path_cond cond = { inode->i_uid, inode->i_mode };
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_ci		error = aa_path_perm(OP_OPEN, label, &file->f_path, 0,
4278c2ecf20Sopenharmony_ci				     aa_map_file_to_perms(file), &cond);
4288c2ecf20Sopenharmony_ci		/* todo cache full allowed permissions set and state */
4298c2ecf20Sopenharmony_ci		fctx->allow = aa_map_file_to_perms(file);
4308c2ecf20Sopenharmony_ci	}
4318c2ecf20Sopenharmony_ci	aa_put_label(label);
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	return error;
4348c2ecf20Sopenharmony_ci}
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_cistatic int apparmor_file_alloc_security(struct file *file)
4378c2ecf20Sopenharmony_ci{
4388c2ecf20Sopenharmony_ci	struct aa_file_ctx *ctx = file_ctx(file);
4398c2ecf20Sopenharmony_ci	struct aa_label *label = begin_current_label_crit_section();
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_ci	spin_lock_init(&ctx->lock);
4428c2ecf20Sopenharmony_ci	rcu_assign_pointer(ctx->label, aa_get_label(label));
4438c2ecf20Sopenharmony_ci	end_current_label_crit_section(label);
4448c2ecf20Sopenharmony_ci	return 0;
4458c2ecf20Sopenharmony_ci}
4468c2ecf20Sopenharmony_ci
4478c2ecf20Sopenharmony_cistatic void apparmor_file_free_security(struct file *file)
4488c2ecf20Sopenharmony_ci{
4498c2ecf20Sopenharmony_ci	struct aa_file_ctx *ctx = file_ctx(file);
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	if (ctx)
4528c2ecf20Sopenharmony_ci		aa_put_label(rcu_access_pointer(ctx->label));
4538c2ecf20Sopenharmony_ci}
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_cistatic int common_file_perm(const char *op, struct file *file, u32 mask,
4568c2ecf20Sopenharmony_ci			    bool in_atomic)
4578c2ecf20Sopenharmony_ci{
4588c2ecf20Sopenharmony_ci	struct aa_label *label;
4598c2ecf20Sopenharmony_ci	int error = 0;
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	/* don't reaudit files closed during inheritance */
4628c2ecf20Sopenharmony_ci	if (file->f_path.dentry == aa_null.dentry)
4638c2ecf20Sopenharmony_ci		return -EACCES;
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	label = __begin_current_label_crit_section();
4668c2ecf20Sopenharmony_ci	error = aa_file_perm(op, label, file, mask, in_atomic);
4678c2ecf20Sopenharmony_ci	__end_current_label_crit_section(label);
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_ci	return error;
4708c2ecf20Sopenharmony_ci}
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_cistatic int apparmor_file_receive(struct file *file)
4738c2ecf20Sopenharmony_ci{
4748c2ecf20Sopenharmony_ci	return common_file_perm(OP_FRECEIVE, file, aa_map_file_to_perms(file),
4758c2ecf20Sopenharmony_ci				false);
4768c2ecf20Sopenharmony_ci}
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_cistatic int apparmor_file_permission(struct file *file, int mask)
4798c2ecf20Sopenharmony_ci{
4808c2ecf20Sopenharmony_ci	return common_file_perm(OP_FPERM, file, mask, false);
4818c2ecf20Sopenharmony_ci}
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_cistatic int apparmor_file_lock(struct file *file, unsigned int cmd)
4848c2ecf20Sopenharmony_ci{
4858c2ecf20Sopenharmony_ci	u32 mask = AA_MAY_LOCK;
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci	if (cmd == F_WRLCK)
4888c2ecf20Sopenharmony_ci		mask |= MAY_WRITE;
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	return common_file_perm(OP_FLOCK, file, mask, false);
4918c2ecf20Sopenharmony_ci}
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_cistatic int common_mmap(const char *op, struct file *file, unsigned long prot,
4948c2ecf20Sopenharmony_ci		       unsigned long flags, bool in_atomic)
4958c2ecf20Sopenharmony_ci{
4968c2ecf20Sopenharmony_ci	int mask = 0;
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci	if (!file || !file_ctx(file))
4998c2ecf20Sopenharmony_ci		return 0;
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	if (prot & PROT_READ)
5028c2ecf20Sopenharmony_ci		mask |= MAY_READ;
5038c2ecf20Sopenharmony_ci	/*
5048c2ecf20Sopenharmony_ci	 * Private mappings don't require write perms since they don't
5058c2ecf20Sopenharmony_ci	 * write back to the files
5068c2ecf20Sopenharmony_ci	 */
5078c2ecf20Sopenharmony_ci	if ((prot & PROT_WRITE) && !(flags & MAP_PRIVATE))
5088c2ecf20Sopenharmony_ci		mask |= MAY_WRITE;
5098c2ecf20Sopenharmony_ci	if (prot & PROT_EXEC)
5108c2ecf20Sopenharmony_ci		mask |= AA_EXEC_MMAP;
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci	return common_file_perm(op, file, mask, in_atomic);
5138c2ecf20Sopenharmony_ci}
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_cistatic int apparmor_mmap_file(struct file *file, unsigned long reqprot,
5168c2ecf20Sopenharmony_ci			      unsigned long prot, unsigned long flags)
5178c2ecf20Sopenharmony_ci{
5188c2ecf20Sopenharmony_ci	return common_mmap(OP_FMMAP, file, prot, flags, GFP_ATOMIC);
5198c2ecf20Sopenharmony_ci}
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_cistatic int apparmor_file_mprotect(struct vm_area_struct *vma,
5228c2ecf20Sopenharmony_ci				  unsigned long reqprot, unsigned long prot)
5238c2ecf20Sopenharmony_ci{
5248c2ecf20Sopenharmony_ci	return common_mmap(OP_FMPROT, vma->vm_file, prot,
5258c2ecf20Sopenharmony_ci			   !(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0,
5268c2ecf20Sopenharmony_ci			   false);
5278c2ecf20Sopenharmony_ci}
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_cistatic int apparmor_sb_mount(const char *dev_name, const struct path *path,
5308c2ecf20Sopenharmony_ci			     const char *type, unsigned long flags, void *data)
5318c2ecf20Sopenharmony_ci{
5328c2ecf20Sopenharmony_ci	struct aa_label *label;
5338c2ecf20Sopenharmony_ci	int error = 0;
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci	/* Discard magic */
5368c2ecf20Sopenharmony_ci	if ((flags & MS_MGC_MSK) == MS_MGC_VAL)
5378c2ecf20Sopenharmony_ci		flags &= ~MS_MGC_MSK;
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci	flags &= ~AA_MS_IGNORE_MASK;
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	label = __begin_current_label_crit_section();
5428c2ecf20Sopenharmony_ci	if (!unconfined(label)) {
5438c2ecf20Sopenharmony_ci		if (flags & MS_REMOUNT)
5448c2ecf20Sopenharmony_ci			error = aa_remount(label, path, flags, data);
5458c2ecf20Sopenharmony_ci		else if (flags & MS_BIND)
5468c2ecf20Sopenharmony_ci			error = aa_bind_mount(label, path, dev_name, flags);
5478c2ecf20Sopenharmony_ci		else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE |
5488c2ecf20Sopenharmony_ci				  MS_UNBINDABLE))
5498c2ecf20Sopenharmony_ci			error = aa_mount_change_type(label, path, flags);
5508c2ecf20Sopenharmony_ci		else if (flags & MS_MOVE)
5518c2ecf20Sopenharmony_ci			error = aa_move_mount(label, path, dev_name);
5528c2ecf20Sopenharmony_ci		else
5538c2ecf20Sopenharmony_ci			error = aa_new_mount(label, dev_name, path, type,
5548c2ecf20Sopenharmony_ci					     flags, data);
5558c2ecf20Sopenharmony_ci	}
5568c2ecf20Sopenharmony_ci	__end_current_label_crit_section(label);
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci	return error;
5598c2ecf20Sopenharmony_ci}
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_cistatic int apparmor_sb_umount(struct vfsmount *mnt, int flags)
5628c2ecf20Sopenharmony_ci{
5638c2ecf20Sopenharmony_ci	struct aa_label *label;
5648c2ecf20Sopenharmony_ci	int error = 0;
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci	label = __begin_current_label_crit_section();
5678c2ecf20Sopenharmony_ci	if (!unconfined(label))
5688c2ecf20Sopenharmony_ci		error = aa_umount(label, mnt, flags);
5698c2ecf20Sopenharmony_ci	__end_current_label_crit_section(label);
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci	return error;
5728c2ecf20Sopenharmony_ci}
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_cistatic int apparmor_sb_pivotroot(const struct path *old_path,
5758c2ecf20Sopenharmony_ci				 const struct path *new_path)
5768c2ecf20Sopenharmony_ci{
5778c2ecf20Sopenharmony_ci	struct aa_label *label;
5788c2ecf20Sopenharmony_ci	int error = 0;
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci	label = aa_get_current_label();
5818c2ecf20Sopenharmony_ci	if (!unconfined(label))
5828c2ecf20Sopenharmony_ci		error = aa_pivotroot(label, old_path, new_path);
5838c2ecf20Sopenharmony_ci	aa_put_label(label);
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci	return error;
5868c2ecf20Sopenharmony_ci}
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_cistatic int apparmor_getprocattr(struct task_struct *task, char *name,
5898c2ecf20Sopenharmony_ci				char **value)
5908c2ecf20Sopenharmony_ci{
5918c2ecf20Sopenharmony_ci	int error = -ENOENT;
5928c2ecf20Sopenharmony_ci	/* released below */
5938c2ecf20Sopenharmony_ci	const struct cred *cred = get_task_cred(task);
5948c2ecf20Sopenharmony_ci	struct aa_task_ctx *ctx = task_ctx(current);
5958c2ecf20Sopenharmony_ci	struct aa_label *label = NULL;
5968c2ecf20Sopenharmony_ci
5978c2ecf20Sopenharmony_ci	if (strcmp(name, "current") == 0)
5988c2ecf20Sopenharmony_ci		label = aa_get_newest_label(cred_label(cred));
5998c2ecf20Sopenharmony_ci	else if (strcmp(name, "prev") == 0  && ctx->previous)
6008c2ecf20Sopenharmony_ci		label = aa_get_newest_label(ctx->previous);
6018c2ecf20Sopenharmony_ci	else if (strcmp(name, "exec") == 0 && ctx->onexec)
6028c2ecf20Sopenharmony_ci		label = aa_get_newest_label(ctx->onexec);
6038c2ecf20Sopenharmony_ci	else
6048c2ecf20Sopenharmony_ci		error = -EINVAL;
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	if (label)
6078c2ecf20Sopenharmony_ci		error = aa_getprocattr(label, value);
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	aa_put_label(label);
6108c2ecf20Sopenharmony_ci	put_cred(cred);
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci	return error;
6138c2ecf20Sopenharmony_ci}
6148c2ecf20Sopenharmony_ci
6158c2ecf20Sopenharmony_cistatic int apparmor_setprocattr(const char *name, void *value,
6168c2ecf20Sopenharmony_ci				size_t size)
6178c2ecf20Sopenharmony_ci{
6188c2ecf20Sopenharmony_ci	char *command, *largs = NULL, *args = value;
6198c2ecf20Sopenharmony_ci	size_t arg_size;
6208c2ecf20Sopenharmony_ci	int error;
6218c2ecf20Sopenharmony_ci	DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, OP_SETPROCATTR);
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci	if (size == 0)
6248c2ecf20Sopenharmony_ci		return -EINVAL;
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci	/* AppArmor requires that the buffer must be null terminated atm */
6278c2ecf20Sopenharmony_ci	if (args[size - 1] != '\0') {
6288c2ecf20Sopenharmony_ci		/* null terminate */
6298c2ecf20Sopenharmony_ci		largs = args = kmalloc(size + 1, GFP_KERNEL);
6308c2ecf20Sopenharmony_ci		if (!args)
6318c2ecf20Sopenharmony_ci			return -ENOMEM;
6328c2ecf20Sopenharmony_ci		memcpy(args, value, size);
6338c2ecf20Sopenharmony_ci		args[size] = '\0';
6348c2ecf20Sopenharmony_ci	}
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci	error = -EINVAL;
6378c2ecf20Sopenharmony_ci	args = strim(args);
6388c2ecf20Sopenharmony_ci	command = strsep(&args, " ");
6398c2ecf20Sopenharmony_ci	if (!args)
6408c2ecf20Sopenharmony_ci		goto out;
6418c2ecf20Sopenharmony_ci	args = skip_spaces(args);
6428c2ecf20Sopenharmony_ci	if (!*args)
6438c2ecf20Sopenharmony_ci		goto out;
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci	arg_size = size - (args - (largs ? largs : (char *) value));
6468c2ecf20Sopenharmony_ci	if (strcmp(name, "current") == 0) {
6478c2ecf20Sopenharmony_ci		if (strcmp(command, "changehat") == 0) {
6488c2ecf20Sopenharmony_ci			error = aa_setprocattr_changehat(args, arg_size,
6498c2ecf20Sopenharmony_ci							 AA_CHANGE_NOFLAGS);
6508c2ecf20Sopenharmony_ci		} else if (strcmp(command, "permhat") == 0) {
6518c2ecf20Sopenharmony_ci			error = aa_setprocattr_changehat(args, arg_size,
6528c2ecf20Sopenharmony_ci							 AA_CHANGE_TEST);
6538c2ecf20Sopenharmony_ci		} else if (strcmp(command, "changeprofile") == 0) {
6548c2ecf20Sopenharmony_ci			error = aa_change_profile(args, AA_CHANGE_NOFLAGS);
6558c2ecf20Sopenharmony_ci		} else if (strcmp(command, "permprofile") == 0) {
6568c2ecf20Sopenharmony_ci			error = aa_change_profile(args, AA_CHANGE_TEST);
6578c2ecf20Sopenharmony_ci		} else if (strcmp(command, "stack") == 0) {
6588c2ecf20Sopenharmony_ci			error = aa_change_profile(args, AA_CHANGE_STACK);
6598c2ecf20Sopenharmony_ci		} else
6608c2ecf20Sopenharmony_ci			goto fail;
6618c2ecf20Sopenharmony_ci	} else if (strcmp(name, "exec") == 0) {
6628c2ecf20Sopenharmony_ci		if (strcmp(command, "exec") == 0)
6638c2ecf20Sopenharmony_ci			error = aa_change_profile(args, AA_CHANGE_ONEXEC);
6648c2ecf20Sopenharmony_ci		else if (strcmp(command, "stack") == 0)
6658c2ecf20Sopenharmony_ci			error = aa_change_profile(args, (AA_CHANGE_ONEXEC |
6668c2ecf20Sopenharmony_ci							 AA_CHANGE_STACK));
6678c2ecf20Sopenharmony_ci		else
6688c2ecf20Sopenharmony_ci			goto fail;
6698c2ecf20Sopenharmony_ci	} else
6708c2ecf20Sopenharmony_ci		/* only support the "current" and "exec" process attributes */
6718c2ecf20Sopenharmony_ci		goto fail;
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ci	if (!error)
6748c2ecf20Sopenharmony_ci		error = size;
6758c2ecf20Sopenharmony_ciout:
6768c2ecf20Sopenharmony_ci	kfree(largs);
6778c2ecf20Sopenharmony_ci	return error;
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_cifail:
6808c2ecf20Sopenharmony_ci	aad(&sa)->label = begin_current_label_crit_section();
6818c2ecf20Sopenharmony_ci	aad(&sa)->info = name;
6828c2ecf20Sopenharmony_ci	aad(&sa)->error = error = -EINVAL;
6838c2ecf20Sopenharmony_ci	aa_audit_msg(AUDIT_APPARMOR_DENIED, &sa, NULL);
6848c2ecf20Sopenharmony_ci	end_current_label_crit_section(aad(&sa)->label);
6858c2ecf20Sopenharmony_ci	goto out;
6868c2ecf20Sopenharmony_ci}
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci/**
6898c2ecf20Sopenharmony_ci * apparmor_bprm_committing_creds - do task cleanup on committing new creds
6908c2ecf20Sopenharmony_ci * @bprm: binprm for the exec  (NOT NULL)
6918c2ecf20Sopenharmony_ci */
6928c2ecf20Sopenharmony_cistatic void apparmor_bprm_committing_creds(struct linux_binprm *bprm)
6938c2ecf20Sopenharmony_ci{
6948c2ecf20Sopenharmony_ci	struct aa_label *label = aa_current_raw_label();
6958c2ecf20Sopenharmony_ci	struct aa_label *new_label = cred_label(bprm->cred);
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_ci	/* bail out if unconfined or not changing profile */
6988c2ecf20Sopenharmony_ci	if ((new_label->proxy == label->proxy) ||
6998c2ecf20Sopenharmony_ci	    (unconfined(new_label)))
7008c2ecf20Sopenharmony_ci		return;
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci	aa_inherit_files(bprm->cred, current->files);
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci	current->pdeath_signal = 0;
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci	/* reset soft limits and set hard limits for the new label */
7078c2ecf20Sopenharmony_ci	__aa_transition_rlimits(label, new_label);
7088c2ecf20Sopenharmony_ci}
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci/**
7118c2ecf20Sopenharmony_ci * apparmor_bprm_committed_cred - do cleanup after new creds committed
7128c2ecf20Sopenharmony_ci * @bprm: binprm for the exec  (NOT NULL)
7138c2ecf20Sopenharmony_ci */
7148c2ecf20Sopenharmony_cistatic void apparmor_bprm_committed_creds(struct linux_binprm *bprm)
7158c2ecf20Sopenharmony_ci{
7168c2ecf20Sopenharmony_ci	/* clear out temporary/transitional state from the context */
7178c2ecf20Sopenharmony_ci	aa_clear_task_ctx_trans(task_ctx(current));
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_ci	return;
7208c2ecf20Sopenharmony_ci}
7218c2ecf20Sopenharmony_ci
7228c2ecf20Sopenharmony_cistatic void apparmor_task_getsecid(struct task_struct *p, u32 *secid)
7238c2ecf20Sopenharmony_ci{
7248c2ecf20Sopenharmony_ci	struct aa_label *label = aa_get_task_label(p);
7258c2ecf20Sopenharmony_ci	*secid = label->secid;
7268c2ecf20Sopenharmony_ci	aa_put_label(label);
7278c2ecf20Sopenharmony_ci}
7288c2ecf20Sopenharmony_ci
7298c2ecf20Sopenharmony_cistatic int apparmor_task_setrlimit(struct task_struct *task,
7308c2ecf20Sopenharmony_ci		unsigned int resource, struct rlimit *new_rlim)
7318c2ecf20Sopenharmony_ci{
7328c2ecf20Sopenharmony_ci	struct aa_label *label = __begin_current_label_crit_section();
7338c2ecf20Sopenharmony_ci	int error = 0;
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci	if (!unconfined(label))
7368c2ecf20Sopenharmony_ci		error = aa_task_setrlimit(label, task, resource, new_rlim);
7378c2ecf20Sopenharmony_ci	__end_current_label_crit_section(label);
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci	return error;
7408c2ecf20Sopenharmony_ci}
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_cistatic int apparmor_task_kill(struct task_struct *target, struct kernel_siginfo *info,
7438c2ecf20Sopenharmony_ci			      int sig, const struct cred *cred)
7448c2ecf20Sopenharmony_ci{
7458c2ecf20Sopenharmony_ci	struct aa_label *cl, *tl;
7468c2ecf20Sopenharmony_ci	int error;
7478c2ecf20Sopenharmony_ci
7488c2ecf20Sopenharmony_ci	if (cred) {
7498c2ecf20Sopenharmony_ci		/*
7508c2ecf20Sopenharmony_ci		 * Dealing with USB IO specific behavior
7518c2ecf20Sopenharmony_ci		 */
7528c2ecf20Sopenharmony_ci		cl = aa_get_newest_cred_label(cred);
7538c2ecf20Sopenharmony_ci		tl = aa_get_task_label(target);
7548c2ecf20Sopenharmony_ci		error = aa_may_signal(cl, tl, sig);
7558c2ecf20Sopenharmony_ci		aa_put_label(cl);
7568c2ecf20Sopenharmony_ci		aa_put_label(tl);
7578c2ecf20Sopenharmony_ci		return error;
7588c2ecf20Sopenharmony_ci	}
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci	cl = __begin_current_label_crit_section();
7618c2ecf20Sopenharmony_ci	tl = aa_get_task_label(target);
7628c2ecf20Sopenharmony_ci	error = aa_may_signal(cl, tl, sig);
7638c2ecf20Sopenharmony_ci	aa_put_label(tl);
7648c2ecf20Sopenharmony_ci	__end_current_label_crit_section(cl);
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci	return error;
7678c2ecf20Sopenharmony_ci}
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_ci/**
7708c2ecf20Sopenharmony_ci * apparmor_sk_alloc_security - allocate and attach the sk_security field
7718c2ecf20Sopenharmony_ci */
7728c2ecf20Sopenharmony_cistatic int apparmor_sk_alloc_security(struct sock *sk, int family, gfp_t flags)
7738c2ecf20Sopenharmony_ci{
7748c2ecf20Sopenharmony_ci	struct aa_sk_ctx *ctx;
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_ci	ctx = kzalloc(sizeof(*ctx), flags);
7778c2ecf20Sopenharmony_ci	if (!ctx)
7788c2ecf20Sopenharmony_ci		return -ENOMEM;
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci	SK_CTX(sk) = ctx;
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci	return 0;
7838c2ecf20Sopenharmony_ci}
7848c2ecf20Sopenharmony_ci
7858c2ecf20Sopenharmony_ci/**
7868c2ecf20Sopenharmony_ci * apparmor_sk_free_security - free the sk_security field
7878c2ecf20Sopenharmony_ci */
7888c2ecf20Sopenharmony_cistatic void apparmor_sk_free_security(struct sock *sk)
7898c2ecf20Sopenharmony_ci{
7908c2ecf20Sopenharmony_ci	struct aa_sk_ctx *ctx = SK_CTX(sk);
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_ci	SK_CTX(sk) = NULL;
7938c2ecf20Sopenharmony_ci	aa_put_label(ctx->label);
7948c2ecf20Sopenharmony_ci	aa_put_label(ctx->peer);
7958c2ecf20Sopenharmony_ci	kfree(ctx);
7968c2ecf20Sopenharmony_ci}
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_ci/**
7998c2ecf20Sopenharmony_ci * apparmor_clone_security - clone the sk_security field
8008c2ecf20Sopenharmony_ci */
8018c2ecf20Sopenharmony_cistatic void apparmor_sk_clone_security(const struct sock *sk,
8028c2ecf20Sopenharmony_ci				       struct sock *newsk)
8038c2ecf20Sopenharmony_ci{
8048c2ecf20Sopenharmony_ci	struct aa_sk_ctx *ctx = SK_CTX(sk);
8058c2ecf20Sopenharmony_ci	struct aa_sk_ctx *new = SK_CTX(newsk);
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_ci	if (new->label)
8088c2ecf20Sopenharmony_ci		aa_put_label(new->label);
8098c2ecf20Sopenharmony_ci	new->label = aa_get_label(ctx->label);
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ci	if (new->peer)
8128c2ecf20Sopenharmony_ci		aa_put_label(new->peer);
8138c2ecf20Sopenharmony_ci	new->peer = aa_get_label(ctx->peer);
8148c2ecf20Sopenharmony_ci}
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_ci/**
8178c2ecf20Sopenharmony_ci * apparmor_socket_create - check perms before creating a new socket
8188c2ecf20Sopenharmony_ci */
8198c2ecf20Sopenharmony_cistatic int apparmor_socket_create(int family, int type, int protocol, int kern)
8208c2ecf20Sopenharmony_ci{
8218c2ecf20Sopenharmony_ci	struct aa_label *label;
8228c2ecf20Sopenharmony_ci	int error = 0;
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_ci	AA_BUG(in_interrupt());
8258c2ecf20Sopenharmony_ci
8268c2ecf20Sopenharmony_ci	label = begin_current_label_crit_section();
8278c2ecf20Sopenharmony_ci	if (!(kern || unconfined(label)))
8288c2ecf20Sopenharmony_ci		error = af_select(family,
8298c2ecf20Sopenharmony_ci				  create_perm(label, family, type, protocol),
8308c2ecf20Sopenharmony_ci				  aa_af_perm(label, OP_CREATE, AA_MAY_CREATE,
8318c2ecf20Sopenharmony_ci					     family, type, protocol));
8328c2ecf20Sopenharmony_ci	end_current_label_crit_section(label);
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ci	return error;
8358c2ecf20Sopenharmony_ci}
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci/**
8388c2ecf20Sopenharmony_ci * apparmor_socket_post_create - setup the per-socket security struct
8398c2ecf20Sopenharmony_ci *
8408c2ecf20Sopenharmony_ci * Note:
8418c2ecf20Sopenharmony_ci * -   kernel sockets currently labeled unconfined but we may want to
8428c2ecf20Sopenharmony_ci *     move to a special kernel label
8438c2ecf20Sopenharmony_ci * -   socket may not have sk here if created with sock_create_lite or
8448c2ecf20Sopenharmony_ci *     sock_alloc. These should be accept cases which will be handled in
8458c2ecf20Sopenharmony_ci *     sock_graft.
8468c2ecf20Sopenharmony_ci */
8478c2ecf20Sopenharmony_cistatic int apparmor_socket_post_create(struct socket *sock, int family,
8488c2ecf20Sopenharmony_ci				       int type, int protocol, int kern)
8498c2ecf20Sopenharmony_ci{
8508c2ecf20Sopenharmony_ci	struct aa_label *label;
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_ci	if (kern) {
8538c2ecf20Sopenharmony_ci		struct aa_ns *ns = aa_get_current_ns();
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_ci		label = aa_get_label(ns_unconfined(ns));
8568c2ecf20Sopenharmony_ci		aa_put_ns(ns);
8578c2ecf20Sopenharmony_ci	} else
8588c2ecf20Sopenharmony_ci		label = aa_get_current_label();
8598c2ecf20Sopenharmony_ci
8608c2ecf20Sopenharmony_ci	if (sock->sk) {
8618c2ecf20Sopenharmony_ci		struct aa_sk_ctx *ctx = SK_CTX(sock->sk);
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ci		aa_put_label(ctx->label);
8648c2ecf20Sopenharmony_ci		ctx->label = aa_get_label(label);
8658c2ecf20Sopenharmony_ci	}
8668c2ecf20Sopenharmony_ci	aa_put_label(label);
8678c2ecf20Sopenharmony_ci
8688c2ecf20Sopenharmony_ci	return 0;
8698c2ecf20Sopenharmony_ci}
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_ci/**
8728c2ecf20Sopenharmony_ci * apparmor_socket_bind - check perms before bind addr to socket
8738c2ecf20Sopenharmony_ci */
8748c2ecf20Sopenharmony_cistatic int apparmor_socket_bind(struct socket *sock,
8758c2ecf20Sopenharmony_ci				struct sockaddr *address, int addrlen)
8768c2ecf20Sopenharmony_ci{
8778c2ecf20Sopenharmony_ci	AA_BUG(!sock);
8788c2ecf20Sopenharmony_ci	AA_BUG(!sock->sk);
8798c2ecf20Sopenharmony_ci	AA_BUG(!address);
8808c2ecf20Sopenharmony_ci	AA_BUG(in_interrupt());
8818c2ecf20Sopenharmony_ci
8828c2ecf20Sopenharmony_ci	return af_select(sock->sk->sk_family,
8838c2ecf20Sopenharmony_ci			 bind_perm(sock, address, addrlen),
8848c2ecf20Sopenharmony_ci			 aa_sk_perm(OP_BIND, AA_MAY_BIND, sock->sk));
8858c2ecf20Sopenharmony_ci}
8868c2ecf20Sopenharmony_ci
8878c2ecf20Sopenharmony_ci/**
8888c2ecf20Sopenharmony_ci * apparmor_socket_connect - check perms before connecting @sock to @address
8898c2ecf20Sopenharmony_ci */
8908c2ecf20Sopenharmony_cistatic int apparmor_socket_connect(struct socket *sock,
8918c2ecf20Sopenharmony_ci				   struct sockaddr *address, int addrlen)
8928c2ecf20Sopenharmony_ci{
8938c2ecf20Sopenharmony_ci	AA_BUG(!sock);
8948c2ecf20Sopenharmony_ci	AA_BUG(!sock->sk);
8958c2ecf20Sopenharmony_ci	AA_BUG(!address);
8968c2ecf20Sopenharmony_ci	AA_BUG(in_interrupt());
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci	return af_select(sock->sk->sk_family,
8998c2ecf20Sopenharmony_ci			 connect_perm(sock, address, addrlen),
9008c2ecf20Sopenharmony_ci			 aa_sk_perm(OP_CONNECT, AA_MAY_CONNECT, sock->sk));
9018c2ecf20Sopenharmony_ci}
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_ci/**
9048c2ecf20Sopenharmony_ci * apparmor_socket_list - check perms before allowing listen
9058c2ecf20Sopenharmony_ci */
9068c2ecf20Sopenharmony_cistatic int apparmor_socket_listen(struct socket *sock, int backlog)
9078c2ecf20Sopenharmony_ci{
9088c2ecf20Sopenharmony_ci	AA_BUG(!sock);
9098c2ecf20Sopenharmony_ci	AA_BUG(!sock->sk);
9108c2ecf20Sopenharmony_ci	AA_BUG(in_interrupt());
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci	return af_select(sock->sk->sk_family,
9138c2ecf20Sopenharmony_ci			 listen_perm(sock, backlog),
9148c2ecf20Sopenharmony_ci			 aa_sk_perm(OP_LISTEN, AA_MAY_LISTEN, sock->sk));
9158c2ecf20Sopenharmony_ci}
9168c2ecf20Sopenharmony_ci
9178c2ecf20Sopenharmony_ci/**
9188c2ecf20Sopenharmony_ci * apparmor_socket_accept - check perms before accepting a new connection.
9198c2ecf20Sopenharmony_ci *
9208c2ecf20Sopenharmony_ci * Note: while @newsock is created and has some information, the accept
9218c2ecf20Sopenharmony_ci *       has not been done.
9228c2ecf20Sopenharmony_ci */
9238c2ecf20Sopenharmony_cistatic int apparmor_socket_accept(struct socket *sock, struct socket *newsock)
9248c2ecf20Sopenharmony_ci{
9258c2ecf20Sopenharmony_ci	AA_BUG(!sock);
9268c2ecf20Sopenharmony_ci	AA_BUG(!sock->sk);
9278c2ecf20Sopenharmony_ci	AA_BUG(!newsock);
9288c2ecf20Sopenharmony_ci	AA_BUG(in_interrupt());
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ci	return af_select(sock->sk->sk_family,
9318c2ecf20Sopenharmony_ci			 accept_perm(sock, newsock),
9328c2ecf20Sopenharmony_ci			 aa_sk_perm(OP_ACCEPT, AA_MAY_ACCEPT, sock->sk));
9338c2ecf20Sopenharmony_ci}
9348c2ecf20Sopenharmony_ci
9358c2ecf20Sopenharmony_cistatic int aa_sock_msg_perm(const char *op, u32 request, struct socket *sock,
9368c2ecf20Sopenharmony_ci			    struct msghdr *msg, int size)
9378c2ecf20Sopenharmony_ci{
9388c2ecf20Sopenharmony_ci	AA_BUG(!sock);
9398c2ecf20Sopenharmony_ci	AA_BUG(!sock->sk);
9408c2ecf20Sopenharmony_ci	AA_BUG(!msg);
9418c2ecf20Sopenharmony_ci	AA_BUG(in_interrupt());
9428c2ecf20Sopenharmony_ci
9438c2ecf20Sopenharmony_ci	return af_select(sock->sk->sk_family,
9448c2ecf20Sopenharmony_ci			 msg_perm(op, request, sock, msg, size),
9458c2ecf20Sopenharmony_ci			 aa_sk_perm(op, request, sock->sk));
9468c2ecf20Sopenharmony_ci}
9478c2ecf20Sopenharmony_ci
9488c2ecf20Sopenharmony_ci/**
9498c2ecf20Sopenharmony_ci * apparmor_socket_sendmsg - check perms before sending msg to another socket
9508c2ecf20Sopenharmony_ci */
9518c2ecf20Sopenharmony_cistatic int apparmor_socket_sendmsg(struct socket *sock,
9528c2ecf20Sopenharmony_ci				   struct msghdr *msg, int size)
9538c2ecf20Sopenharmony_ci{
9548c2ecf20Sopenharmony_ci	return aa_sock_msg_perm(OP_SENDMSG, AA_MAY_SEND, sock, msg, size);
9558c2ecf20Sopenharmony_ci}
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_ci/**
9588c2ecf20Sopenharmony_ci * apparmor_socket_recvmsg - check perms before receiving a message
9598c2ecf20Sopenharmony_ci */
9608c2ecf20Sopenharmony_cistatic int apparmor_socket_recvmsg(struct socket *sock,
9618c2ecf20Sopenharmony_ci				   struct msghdr *msg, int size, int flags)
9628c2ecf20Sopenharmony_ci{
9638c2ecf20Sopenharmony_ci	return aa_sock_msg_perm(OP_RECVMSG, AA_MAY_RECEIVE, sock, msg, size);
9648c2ecf20Sopenharmony_ci}
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_ci/* revaliation, get/set attr, shutdown */
9678c2ecf20Sopenharmony_cistatic int aa_sock_perm(const char *op, u32 request, struct socket *sock)
9688c2ecf20Sopenharmony_ci{
9698c2ecf20Sopenharmony_ci	AA_BUG(!sock);
9708c2ecf20Sopenharmony_ci	AA_BUG(!sock->sk);
9718c2ecf20Sopenharmony_ci	AA_BUG(in_interrupt());
9728c2ecf20Sopenharmony_ci
9738c2ecf20Sopenharmony_ci	return af_select(sock->sk->sk_family,
9748c2ecf20Sopenharmony_ci			 sock_perm(op, request, sock),
9758c2ecf20Sopenharmony_ci			 aa_sk_perm(op, request, sock->sk));
9768c2ecf20Sopenharmony_ci}
9778c2ecf20Sopenharmony_ci
9788c2ecf20Sopenharmony_ci/**
9798c2ecf20Sopenharmony_ci * apparmor_socket_getsockname - check perms before getting the local address
9808c2ecf20Sopenharmony_ci */
9818c2ecf20Sopenharmony_cistatic int apparmor_socket_getsockname(struct socket *sock)
9828c2ecf20Sopenharmony_ci{
9838c2ecf20Sopenharmony_ci	return aa_sock_perm(OP_GETSOCKNAME, AA_MAY_GETATTR, sock);
9848c2ecf20Sopenharmony_ci}
9858c2ecf20Sopenharmony_ci
9868c2ecf20Sopenharmony_ci/**
9878c2ecf20Sopenharmony_ci * apparmor_socket_getpeername - check perms before getting remote address
9888c2ecf20Sopenharmony_ci */
9898c2ecf20Sopenharmony_cistatic int apparmor_socket_getpeername(struct socket *sock)
9908c2ecf20Sopenharmony_ci{
9918c2ecf20Sopenharmony_ci	return aa_sock_perm(OP_GETPEERNAME, AA_MAY_GETATTR, sock);
9928c2ecf20Sopenharmony_ci}
9938c2ecf20Sopenharmony_ci
9948c2ecf20Sopenharmony_ci/* revaliation, get/set attr, opt */
9958c2ecf20Sopenharmony_cistatic int aa_sock_opt_perm(const char *op, u32 request, struct socket *sock,
9968c2ecf20Sopenharmony_ci			    int level, int optname)
9978c2ecf20Sopenharmony_ci{
9988c2ecf20Sopenharmony_ci	AA_BUG(!sock);
9998c2ecf20Sopenharmony_ci	AA_BUG(!sock->sk);
10008c2ecf20Sopenharmony_ci	AA_BUG(in_interrupt());
10018c2ecf20Sopenharmony_ci
10028c2ecf20Sopenharmony_ci	return af_select(sock->sk->sk_family,
10038c2ecf20Sopenharmony_ci			 opt_perm(op, request, sock, level, optname),
10048c2ecf20Sopenharmony_ci			 aa_sk_perm(op, request, sock->sk));
10058c2ecf20Sopenharmony_ci}
10068c2ecf20Sopenharmony_ci
10078c2ecf20Sopenharmony_ci/**
10088c2ecf20Sopenharmony_ci * apparmor_getsockopt - check perms before getting socket options
10098c2ecf20Sopenharmony_ci */
10108c2ecf20Sopenharmony_cistatic int apparmor_socket_getsockopt(struct socket *sock, int level,
10118c2ecf20Sopenharmony_ci				      int optname)
10128c2ecf20Sopenharmony_ci{
10138c2ecf20Sopenharmony_ci	return aa_sock_opt_perm(OP_GETSOCKOPT, AA_MAY_GETOPT, sock,
10148c2ecf20Sopenharmony_ci				level, optname);
10158c2ecf20Sopenharmony_ci}
10168c2ecf20Sopenharmony_ci
10178c2ecf20Sopenharmony_ci/**
10188c2ecf20Sopenharmony_ci * apparmor_setsockopt - check perms before setting socket options
10198c2ecf20Sopenharmony_ci */
10208c2ecf20Sopenharmony_cistatic int apparmor_socket_setsockopt(struct socket *sock, int level,
10218c2ecf20Sopenharmony_ci				      int optname)
10228c2ecf20Sopenharmony_ci{
10238c2ecf20Sopenharmony_ci	return aa_sock_opt_perm(OP_SETSOCKOPT, AA_MAY_SETOPT, sock,
10248c2ecf20Sopenharmony_ci				level, optname);
10258c2ecf20Sopenharmony_ci}
10268c2ecf20Sopenharmony_ci
10278c2ecf20Sopenharmony_ci/**
10288c2ecf20Sopenharmony_ci * apparmor_socket_shutdown - check perms before shutting down @sock conn
10298c2ecf20Sopenharmony_ci */
10308c2ecf20Sopenharmony_cistatic int apparmor_socket_shutdown(struct socket *sock, int how)
10318c2ecf20Sopenharmony_ci{
10328c2ecf20Sopenharmony_ci	return aa_sock_perm(OP_SHUTDOWN, AA_MAY_SHUTDOWN, sock);
10338c2ecf20Sopenharmony_ci}
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_ci#ifdef CONFIG_NETWORK_SECMARK
10368c2ecf20Sopenharmony_ci/**
10378c2ecf20Sopenharmony_ci * apparmor_socket_sock_recv_skb - check perms before associating skb to sk
10388c2ecf20Sopenharmony_ci *
10398c2ecf20Sopenharmony_ci * Note: can not sleep may be called with locks held
10408c2ecf20Sopenharmony_ci *
10418c2ecf20Sopenharmony_ci * dont want protocol specific in __skb_recv_datagram()
10428c2ecf20Sopenharmony_ci * to deny an incoming connection  socket_sock_rcv_skb()
10438c2ecf20Sopenharmony_ci */
10448c2ecf20Sopenharmony_cistatic int apparmor_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb)
10458c2ecf20Sopenharmony_ci{
10468c2ecf20Sopenharmony_ci	struct aa_sk_ctx *ctx = SK_CTX(sk);
10478c2ecf20Sopenharmony_ci
10488c2ecf20Sopenharmony_ci	if (!skb->secmark)
10498c2ecf20Sopenharmony_ci		return 0;
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_ci	/*
10528c2ecf20Sopenharmony_ci	 * If reach here before socket_post_create hook is called, in which
10538c2ecf20Sopenharmony_ci	 * case label is null, drop the packet.
10548c2ecf20Sopenharmony_ci	 */
10558c2ecf20Sopenharmony_ci	if (!ctx->label)
10568c2ecf20Sopenharmony_ci		return -EACCES;
10578c2ecf20Sopenharmony_ci
10588c2ecf20Sopenharmony_ci	return apparmor_secmark_check(ctx->label, OP_RECVMSG, AA_MAY_RECEIVE,
10598c2ecf20Sopenharmony_ci				      skb->secmark, sk);
10608c2ecf20Sopenharmony_ci}
10618c2ecf20Sopenharmony_ci#endif
10628c2ecf20Sopenharmony_ci
10638c2ecf20Sopenharmony_ci
10648c2ecf20Sopenharmony_cistatic struct aa_label *sk_peer_label(struct sock *sk)
10658c2ecf20Sopenharmony_ci{
10668c2ecf20Sopenharmony_ci	struct aa_sk_ctx *ctx = SK_CTX(sk);
10678c2ecf20Sopenharmony_ci
10688c2ecf20Sopenharmony_ci	if (ctx->peer)
10698c2ecf20Sopenharmony_ci		return ctx->peer;
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_ci	return ERR_PTR(-ENOPROTOOPT);
10728c2ecf20Sopenharmony_ci}
10738c2ecf20Sopenharmony_ci
10748c2ecf20Sopenharmony_ci/**
10758c2ecf20Sopenharmony_ci * apparmor_socket_getpeersec_stream - get security context of peer
10768c2ecf20Sopenharmony_ci *
10778c2ecf20Sopenharmony_ci * Note: for tcp only valid if using ipsec or cipso on lan
10788c2ecf20Sopenharmony_ci */
10798c2ecf20Sopenharmony_cistatic int apparmor_socket_getpeersec_stream(struct socket *sock,
10808c2ecf20Sopenharmony_ci					     char __user *optval,
10818c2ecf20Sopenharmony_ci					     int __user *optlen,
10828c2ecf20Sopenharmony_ci					     unsigned int len)
10838c2ecf20Sopenharmony_ci{
10848c2ecf20Sopenharmony_ci	char *name;
10858c2ecf20Sopenharmony_ci	int slen, error = 0;
10868c2ecf20Sopenharmony_ci	struct aa_label *label;
10878c2ecf20Sopenharmony_ci	struct aa_label *peer;
10888c2ecf20Sopenharmony_ci
10898c2ecf20Sopenharmony_ci	label = begin_current_label_crit_section();
10908c2ecf20Sopenharmony_ci	peer = sk_peer_label(sock->sk);
10918c2ecf20Sopenharmony_ci	if (IS_ERR(peer)) {
10928c2ecf20Sopenharmony_ci		error = PTR_ERR(peer);
10938c2ecf20Sopenharmony_ci		goto done;
10948c2ecf20Sopenharmony_ci	}
10958c2ecf20Sopenharmony_ci	slen = aa_label_asxprint(&name, labels_ns(label), peer,
10968c2ecf20Sopenharmony_ci				 FLAG_SHOW_MODE | FLAG_VIEW_SUBNS |
10978c2ecf20Sopenharmony_ci				 FLAG_HIDDEN_UNCONFINED, GFP_KERNEL);
10988c2ecf20Sopenharmony_ci	/* don't include terminating \0 in slen, it breaks some apps */
10998c2ecf20Sopenharmony_ci	if (slen < 0) {
11008c2ecf20Sopenharmony_ci		error = -ENOMEM;
11018c2ecf20Sopenharmony_ci	} else {
11028c2ecf20Sopenharmony_ci		if (slen > len) {
11038c2ecf20Sopenharmony_ci			error = -ERANGE;
11048c2ecf20Sopenharmony_ci		} else if (copy_to_user(optval, name, slen)) {
11058c2ecf20Sopenharmony_ci			error = -EFAULT;
11068c2ecf20Sopenharmony_ci			goto out;
11078c2ecf20Sopenharmony_ci		}
11088c2ecf20Sopenharmony_ci		if (put_user(slen, optlen))
11098c2ecf20Sopenharmony_ci			error = -EFAULT;
11108c2ecf20Sopenharmony_ciout:
11118c2ecf20Sopenharmony_ci		kfree(name);
11128c2ecf20Sopenharmony_ci
11138c2ecf20Sopenharmony_ci	}
11148c2ecf20Sopenharmony_ci
11158c2ecf20Sopenharmony_cidone:
11168c2ecf20Sopenharmony_ci	end_current_label_crit_section(label);
11178c2ecf20Sopenharmony_ci
11188c2ecf20Sopenharmony_ci	return error;
11198c2ecf20Sopenharmony_ci}
11208c2ecf20Sopenharmony_ci
11218c2ecf20Sopenharmony_ci/**
11228c2ecf20Sopenharmony_ci * apparmor_socket_getpeersec_dgram - get security label of packet
11238c2ecf20Sopenharmony_ci * @sock: the peer socket
11248c2ecf20Sopenharmony_ci * @skb: packet data
11258c2ecf20Sopenharmony_ci * @secid: pointer to where to put the secid of the packet
11268c2ecf20Sopenharmony_ci *
11278c2ecf20Sopenharmony_ci * Sets the netlabel socket state on sk from parent
11288c2ecf20Sopenharmony_ci */
11298c2ecf20Sopenharmony_cistatic int apparmor_socket_getpeersec_dgram(struct socket *sock,
11308c2ecf20Sopenharmony_ci					    struct sk_buff *skb, u32 *secid)
11318c2ecf20Sopenharmony_ci
11328c2ecf20Sopenharmony_ci{
11338c2ecf20Sopenharmony_ci	/* TODO: requires secid support */
11348c2ecf20Sopenharmony_ci	return -ENOPROTOOPT;
11358c2ecf20Sopenharmony_ci}
11368c2ecf20Sopenharmony_ci
11378c2ecf20Sopenharmony_ci/**
11388c2ecf20Sopenharmony_ci * apparmor_sock_graft - Initialize newly created socket
11398c2ecf20Sopenharmony_ci * @sk: child sock
11408c2ecf20Sopenharmony_ci * @parent: parent socket
11418c2ecf20Sopenharmony_ci *
11428c2ecf20Sopenharmony_ci * Note: could set off of SOCK_CTX(parent) but need to track inode and we can
11438c2ecf20Sopenharmony_ci *       just set sk security information off of current creating process label
11448c2ecf20Sopenharmony_ci *       Labeling of sk for accept case - probably should be sock based
11458c2ecf20Sopenharmony_ci *       instead of task, because of the case where an implicitly labeled
11468c2ecf20Sopenharmony_ci *       socket is shared by different tasks.
11478c2ecf20Sopenharmony_ci */
11488c2ecf20Sopenharmony_cistatic void apparmor_sock_graft(struct sock *sk, struct socket *parent)
11498c2ecf20Sopenharmony_ci{
11508c2ecf20Sopenharmony_ci	struct aa_sk_ctx *ctx = SK_CTX(sk);
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_ci	if (!ctx->label)
11538c2ecf20Sopenharmony_ci		ctx->label = aa_get_current_label();
11548c2ecf20Sopenharmony_ci}
11558c2ecf20Sopenharmony_ci
11568c2ecf20Sopenharmony_ci#ifdef CONFIG_NETWORK_SECMARK
11578c2ecf20Sopenharmony_cistatic int apparmor_inet_conn_request(struct sock *sk, struct sk_buff *skb,
11588c2ecf20Sopenharmony_ci				      struct request_sock *req)
11598c2ecf20Sopenharmony_ci{
11608c2ecf20Sopenharmony_ci	struct aa_sk_ctx *ctx = SK_CTX(sk);
11618c2ecf20Sopenharmony_ci
11628c2ecf20Sopenharmony_ci	if (!skb->secmark)
11638c2ecf20Sopenharmony_ci		return 0;
11648c2ecf20Sopenharmony_ci
11658c2ecf20Sopenharmony_ci	return apparmor_secmark_check(ctx->label, OP_CONNECT, AA_MAY_CONNECT,
11668c2ecf20Sopenharmony_ci				      skb->secmark, sk);
11678c2ecf20Sopenharmony_ci}
11688c2ecf20Sopenharmony_ci#endif
11698c2ecf20Sopenharmony_ci
11708c2ecf20Sopenharmony_ci/*
11718c2ecf20Sopenharmony_ci * The cred blob is a pointer to, not an instance of, an aa_label.
11728c2ecf20Sopenharmony_ci */
11738c2ecf20Sopenharmony_cistruct lsm_blob_sizes apparmor_blob_sizes __lsm_ro_after_init = {
11748c2ecf20Sopenharmony_ci	.lbs_cred = sizeof(struct aa_label *),
11758c2ecf20Sopenharmony_ci	.lbs_file = sizeof(struct aa_file_ctx),
11768c2ecf20Sopenharmony_ci	.lbs_task = sizeof(struct aa_task_ctx),
11778c2ecf20Sopenharmony_ci};
11788c2ecf20Sopenharmony_ci
11798c2ecf20Sopenharmony_cistatic struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = {
11808c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check),
11818c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme),
11828c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(capget, apparmor_capget),
11838c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(capable, apparmor_capable),
11848c2ecf20Sopenharmony_ci
11858c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(sb_mount, apparmor_sb_mount),
11868c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(sb_umount, apparmor_sb_umount),
11878c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(sb_pivotroot, apparmor_sb_pivotroot),
11888c2ecf20Sopenharmony_ci
11898c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(path_link, apparmor_path_link),
11908c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(path_unlink, apparmor_path_unlink),
11918c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(path_symlink, apparmor_path_symlink),
11928c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(path_mkdir, apparmor_path_mkdir),
11938c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(path_rmdir, apparmor_path_rmdir),
11948c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(path_mknod, apparmor_path_mknod),
11958c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(path_rename, apparmor_path_rename),
11968c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(path_chmod, apparmor_path_chmod),
11978c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(path_chown, apparmor_path_chown),
11988c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(path_truncate, apparmor_path_truncate),
11998c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(inode_getattr, apparmor_inode_getattr),
12008c2ecf20Sopenharmony_ci
12018c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(file_open, apparmor_file_open),
12028c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(file_receive, apparmor_file_receive),
12038c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(file_permission, apparmor_file_permission),
12048c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(file_alloc_security, apparmor_file_alloc_security),
12058c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(file_free_security, apparmor_file_free_security),
12068c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(mmap_file, apparmor_mmap_file),
12078c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(file_mprotect, apparmor_file_mprotect),
12088c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(file_lock, apparmor_file_lock),
12098c2ecf20Sopenharmony_ci
12108c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(getprocattr, apparmor_getprocattr),
12118c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(setprocattr, apparmor_setprocattr),
12128c2ecf20Sopenharmony_ci
12138c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(sk_alloc_security, apparmor_sk_alloc_security),
12148c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(sk_free_security, apparmor_sk_free_security),
12158c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(sk_clone_security, apparmor_sk_clone_security),
12168c2ecf20Sopenharmony_ci
12178c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(socket_create, apparmor_socket_create),
12188c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(socket_post_create, apparmor_socket_post_create),
12198c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(socket_bind, apparmor_socket_bind),
12208c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(socket_connect, apparmor_socket_connect),
12218c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(socket_listen, apparmor_socket_listen),
12228c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(socket_accept, apparmor_socket_accept),
12238c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(socket_sendmsg, apparmor_socket_sendmsg),
12248c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(socket_recvmsg, apparmor_socket_recvmsg),
12258c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(socket_getsockname, apparmor_socket_getsockname),
12268c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(socket_getpeername, apparmor_socket_getpeername),
12278c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(socket_getsockopt, apparmor_socket_getsockopt),
12288c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(socket_setsockopt, apparmor_socket_setsockopt),
12298c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(socket_shutdown, apparmor_socket_shutdown),
12308c2ecf20Sopenharmony_ci#ifdef CONFIG_NETWORK_SECMARK
12318c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(socket_sock_rcv_skb, apparmor_socket_sock_rcv_skb),
12328c2ecf20Sopenharmony_ci#endif
12338c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(socket_getpeersec_stream,
12348c2ecf20Sopenharmony_ci		      apparmor_socket_getpeersec_stream),
12358c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(socket_getpeersec_dgram,
12368c2ecf20Sopenharmony_ci		      apparmor_socket_getpeersec_dgram),
12378c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(sock_graft, apparmor_sock_graft),
12388c2ecf20Sopenharmony_ci#ifdef CONFIG_NETWORK_SECMARK
12398c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(inet_conn_request, apparmor_inet_conn_request),
12408c2ecf20Sopenharmony_ci#endif
12418c2ecf20Sopenharmony_ci
12428c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(cred_alloc_blank, apparmor_cred_alloc_blank),
12438c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(cred_free, apparmor_cred_free),
12448c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(cred_prepare, apparmor_cred_prepare),
12458c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(cred_transfer, apparmor_cred_transfer),
12468c2ecf20Sopenharmony_ci
12478c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(bprm_creds_for_exec, apparmor_bprm_creds_for_exec),
12488c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(bprm_committing_creds, apparmor_bprm_committing_creds),
12498c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(bprm_committed_creds, apparmor_bprm_committed_creds),
12508c2ecf20Sopenharmony_ci
12518c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(task_free, apparmor_task_free),
12528c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(task_alloc, apparmor_task_alloc),
12538c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(task_getsecid, apparmor_task_getsecid),
12548c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(task_setrlimit, apparmor_task_setrlimit),
12558c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(task_kill, apparmor_task_kill),
12568c2ecf20Sopenharmony_ci
12578c2ecf20Sopenharmony_ci#ifdef CONFIG_AUDIT
12588c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(audit_rule_init, aa_audit_rule_init),
12598c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(audit_rule_known, aa_audit_rule_known),
12608c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(audit_rule_match, aa_audit_rule_match),
12618c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(audit_rule_free, aa_audit_rule_free),
12628c2ecf20Sopenharmony_ci#endif
12638c2ecf20Sopenharmony_ci
12648c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(secid_to_secctx, apparmor_secid_to_secctx),
12658c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(secctx_to_secid, apparmor_secctx_to_secid),
12668c2ecf20Sopenharmony_ci	LSM_HOOK_INIT(release_secctx, apparmor_release_secctx),
12678c2ecf20Sopenharmony_ci};
12688c2ecf20Sopenharmony_ci
12698c2ecf20Sopenharmony_ci/*
12708c2ecf20Sopenharmony_ci * AppArmor sysfs module parameters
12718c2ecf20Sopenharmony_ci */
12728c2ecf20Sopenharmony_ci
12738c2ecf20Sopenharmony_cistatic int param_set_aabool(const char *val, const struct kernel_param *kp);
12748c2ecf20Sopenharmony_cistatic int param_get_aabool(char *buffer, const struct kernel_param *kp);
12758c2ecf20Sopenharmony_ci#define param_check_aabool param_check_bool
12768c2ecf20Sopenharmony_cistatic const struct kernel_param_ops param_ops_aabool = {
12778c2ecf20Sopenharmony_ci	.flags = KERNEL_PARAM_OPS_FL_NOARG,
12788c2ecf20Sopenharmony_ci	.set = param_set_aabool,
12798c2ecf20Sopenharmony_ci	.get = param_get_aabool
12808c2ecf20Sopenharmony_ci};
12818c2ecf20Sopenharmony_ci
12828c2ecf20Sopenharmony_cistatic int param_set_aauint(const char *val, const struct kernel_param *kp);
12838c2ecf20Sopenharmony_cistatic int param_get_aauint(char *buffer, const struct kernel_param *kp);
12848c2ecf20Sopenharmony_ci#define param_check_aauint param_check_uint
12858c2ecf20Sopenharmony_cistatic const struct kernel_param_ops param_ops_aauint = {
12868c2ecf20Sopenharmony_ci	.set = param_set_aauint,
12878c2ecf20Sopenharmony_ci	.get = param_get_aauint
12888c2ecf20Sopenharmony_ci};
12898c2ecf20Sopenharmony_ci
12908c2ecf20Sopenharmony_cistatic int param_set_aacompressionlevel(const char *val,
12918c2ecf20Sopenharmony_ci					const struct kernel_param *kp);
12928c2ecf20Sopenharmony_cistatic int param_get_aacompressionlevel(char *buffer,
12938c2ecf20Sopenharmony_ci					const struct kernel_param *kp);
12948c2ecf20Sopenharmony_ci#define param_check_aacompressionlevel param_check_int
12958c2ecf20Sopenharmony_cistatic const struct kernel_param_ops param_ops_aacompressionlevel = {
12968c2ecf20Sopenharmony_ci	.set = param_set_aacompressionlevel,
12978c2ecf20Sopenharmony_ci	.get = param_get_aacompressionlevel
12988c2ecf20Sopenharmony_ci};
12998c2ecf20Sopenharmony_ci
13008c2ecf20Sopenharmony_cistatic int param_set_aalockpolicy(const char *val, const struct kernel_param *kp);
13018c2ecf20Sopenharmony_cistatic int param_get_aalockpolicy(char *buffer, const struct kernel_param *kp);
13028c2ecf20Sopenharmony_ci#define param_check_aalockpolicy param_check_bool
13038c2ecf20Sopenharmony_cistatic const struct kernel_param_ops param_ops_aalockpolicy = {
13048c2ecf20Sopenharmony_ci	.flags = KERNEL_PARAM_OPS_FL_NOARG,
13058c2ecf20Sopenharmony_ci	.set = param_set_aalockpolicy,
13068c2ecf20Sopenharmony_ci	.get = param_get_aalockpolicy
13078c2ecf20Sopenharmony_ci};
13088c2ecf20Sopenharmony_ci
13098c2ecf20Sopenharmony_cistatic int param_set_audit(const char *val, const struct kernel_param *kp);
13108c2ecf20Sopenharmony_cistatic int param_get_audit(char *buffer, const struct kernel_param *kp);
13118c2ecf20Sopenharmony_ci
13128c2ecf20Sopenharmony_cistatic int param_set_mode(const char *val, const struct kernel_param *kp);
13138c2ecf20Sopenharmony_cistatic int param_get_mode(char *buffer, const struct kernel_param *kp);
13148c2ecf20Sopenharmony_ci
13158c2ecf20Sopenharmony_ci/* Flag values, also controllable via /sys/module/apparmor/parameters
13168c2ecf20Sopenharmony_ci * We define special types as we want to do additional mediation.
13178c2ecf20Sopenharmony_ci */
13188c2ecf20Sopenharmony_ci
13198c2ecf20Sopenharmony_ci/* AppArmor global enforcement switch - complain, enforce, kill */
13208c2ecf20Sopenharmony_cienum profile_mode aa_g_profile_mode = APPARMOR_ENFORCE;
13218c2ecf20Sopenharmony_cimodule_param_call(mode, param_set_mode, param_get_mode,
13228c2ecf20Sopenharmony_ci		  &aa_g_profile_mode, S_IRUSR | S_IWUSR);
13238c2ecf20Sopenharmony_ci
13248c2ecf20Sopenharmony_ci/* whether policy verification hashing is enabled */
13258c2ecf20Sopenharmony_cibool aa_g_hash_policy = IS_ENABLED(CONFIG_SECURITY_APPARMOR_HASH_DEFAULT);
13268c2ecf20Sopenharmony_ci#ifdef CONFIG_SECURITY_APPARMOR_HASH
13278c2ecf20Sopenharmony_cimodule_param_named(hash_policy, aa_g_hash_policy, aabool, S_IRUSR | S_IWUSR);
13288c2ecf20Sopenharmony_ci#endif
13298c2ecf20Sopenharmony_ci
13308c2ecf20Sopenharmony_ci/* policy loaddata compression level */
13318c2ecf20Sopenharmony_ciint aa_g_rawdata_compression_level = Z_DEFAULT_COMPRESSION;
13328c2ecf20Sopenharmony_cimodule_param_named(rawdata_compression_level, aa_g_rawdata_compression_level,
13338c2ecf20Sopenharmony_ci		   aacompressionlevel, 0400);
13348c2ecf20Sopenharmony_ci
13358c2ecf20Sopenharmony_ci/* Debug mode */
13368c2ecf20Sopenharmony_cibool aa_g_debug = IS_ENABLED(CONFIG_SECURITY_APPARMOR_DEBUG_MESSAGES);
13378c2ecf20Sopenharmony_cimodule_param_named(debug, aa_g_debug, aabool, S_IRUSR | S_IWUSR);
13388c2ecf20Sopenharmony_ci
13398c2ecf20Sopenharmony_ci/* Audit mode */
13408c2ecf20Sopenharmony_cienum audit_mode aa_g_audit;
13418c2ecf20Sopenharmony_cimodule_param_call(audit, param_set_audit, param_get_audit,
13428c2ecf20Sopenharmony_ci		  &aa_g_audit, S_IRUSR | S_IWUSR);
13438c2ecf20Sopenharmony_ci
13448c2ecf20Sopenharmony_ci/* Determines if audit header is included in audited messages.  This
13458c2ecf20Sopenharmony_ci * provides more context if the audit daemon is not running
13468c2ecf20Sopenharmony_ci */
13478c2ecf20Sopenharmony_cibool aa_g_audit_header = true;
13488c2ecf20Sopenharmony_cimodule_param_named(audit_header, aa_g_audit_header, aabool,
13498c2ecf20Sopenharmony_ci		   S_IRUSR | S_IWUSR);
13508c2ecf20Sopenharmony_ci
13518c2ecf20Sopenharmony_ci/* lock out loading/removal of policy
13528c2ecf20Sopenharmony_ci * TODO: add in at boot loading of policy, which is the only way to
13538c2ecf20Sopenharmony_ci *       load policy, if lock_policy is set
13548c2ecf20Sopenharmony_ci */
13558c2ecf20Sopenharmony_cibool aa_g_lock_policy;
13568c2ecf20Sopenharmony_cimodule_param_named(lock_policy, aa_g_lock_policy, aalockpolicy,
13578c2ecf20Sopenharmony_ci		   S_IRUSR | S_IWUSR);
13588c2ecf20Sopenharmony_ci
13598c2ecf20Sopenharmony_ci/* Syscall logging mode */
13608c2ecf20Sopenharmony_cibool aa_g_logsyscall;
13618c2ecf20Sopenharmony_cimodule_param_named(logsyscall, aa_g_logsyscall, aabool, S_IRUSR | S_IWUSR);
13628c2ecf20Sopenharmony_ci
13638c2ecf20Sopenharmony_ci/* Maximum pathname length before accesses will start getting rejected */
13648c2ecf20Sopenharmony_ciunsigned int aa_g_path_max = 2 * PATH_MAX;
13658c2ecf20Sopenharmony_cimodule_param_named(path_max, aa_g_path_max, aauint, S_IRUSR);
13668c2ecf20Sopenharmony_ci
13678c2ecf20Sopenharmony_ci/* Determines how paranoid loading of policy is and how much verification
13688c2ecf20Sopenharmony_ci * on the loaded policy is done.
13698c2ecf20Sopenharmony_ci * DEPRECATED: read only as strict checking of load is always done now
13708c2ecf20Sopenharmony_ci * that none root users (user namespaces) can load policy.
13718c2ecf20Sopenharmony_ci */
13728c2ecf20Sopenharmony_cibool aa_g_paranoid_load = true;
13738c2ecf20Sopenharmony_cimodule_param_named(paranoid_load, aa_g_paranoid_load, aabool, S_IRUGO);
13748c2ecf20Sopenharmony_ci
13758c2ecf20Sopenharmony_cistatic int param_get_aaintbool(char *buffer, const struct kernel_param *kp);
13768c2ecf20Sopenharmony_cistatic int param_set_aaintbool(const char *val, const struct kernel_param *kp);
13778c2ecf20Sopenharmony_ci#define param_check_aaintbool param_check_int
13788c2ecf20Sopenharmony_cistatic const struct kernel_param_ops param_ops_aaintbool = {
13798c2ecf20Sopenharmony_ci	.set = param_set_aaintbool,
13808c2ecf20Sopenharmony_ci	.get = param_get_aaintbool
13818c2ecf20Sopenharmony_ci};
13828c2ecf20Sopenharmony_ci/* Boot time disable flag */
13838c2ecf20Sopenharmony_cistatic int apparmor_enabled __lsm_ro_after_init = 1;
13848c2ecf20Sopenharmony_cimodule_param_named(enabled, apparmor_enabled, aaintbool, 0444);
13858c2ecf20Sopenharmony_ci
13868c2ecf20Sopenharmony_cistatic int __init apparmor_enabled_setup(char *str)
13878c2ecf20Sopenharmony_ci{
13888c2ecf20Sopenharmony_ci	unsigned long enabled;
13898c2ecf20Sopenharmony_ci	int error = kstrtoul(str, 0, &enabled);
13908c2ecf20Sopenharmony_ci	if (!error)
13918c2ecf20Sopenharmony_ci		apparmor_enabled = enabled ? 1 : 0;
13928c2ecf20Sopenharmony_ci	return 1;
13938c2ecf20Sopenharmony_ci}
13948c2ecf20Sopenharmony_ci
13958c2ecf20Sopenharmony_ci__setup("apparmor=", apparmor_enabled_setup);
13968c2ecf20Sopenharmony_ci
13978c2ecf20Sopenharmony_ci/* set global flag turning off the ability to load policy */
13988c2ecf20Sopenharmony_cistatic int param_set_aalockpolicy(const char *val, const struct kernel_param *kp)
13998c2ecf20Sopenharmony_ci{
14008c2ecf20Sopenharmony_ci	if (!apparmor_enabled)
14018c2ecf20Sopenharmony_ci		return -EINVAL;
14028c2ecf20Sopenharmony_ci	if (apparmor_initialized && !policy_admin_capable(NULL))
14038c2ecf20Sopenharmony_ci		return -EPERM;
14048c2ecf20Sopenharmony_ci	return param_set_bool(val, kp);
14058c2ecf20Sopenharmony_ci}
14068c2ecf20Sopenharmony_ci
14078c2ecf20Sopenharmony_cistatic int param_get_aalockpolicy(char *buffer, const struct kernel_param *kp)
14088c2ecf20Sopenharmony_ci{
14098c2ecf20Sopenharmony_ci	if (!apparmor_enabled)
14108c2ecf20Sopenharmony_ci		return -EINVAL;
14118c2ecf20Sopenharmony_ci	if (apparmor_initialized && !policy_view_capable(NULL))
14128c2ecf20Sopenharmony_ci		return -EPERM;
14138c2ecf20Sopenharmony_ci	return param_get_bool(buffer, kp);
14148c2ecf20Sopenharmony_ci}
14158c2ecf20Sopenharmony_ci
14168c2ecf20Sopenharmony_cistatic int param_set_aabool(const char *val, const struct kernel_param *kp)
14178c2ecf20Sopenharmony_ci{
14188c2ecf20Sopenharmony_ci	if (!apparmor_enabled)
14198c2ecf20Sopenharmony_ci		return -EINVAL;
14208c2ecf20Sopenharmony_ci	if (apparmor_initialized && !policy_admin_capable(NULL))
14218c2ecf20Sopenharmony_ci		return -EPERM;
14228c2ecf20Sopenharmony_ci	return param_set_bool(val, kp);
14238c2ecf20Sopenharmony_ci}
14248c2ecf20Sopenharmony_ci
14258c2ecf20Sopenharmony_cistatic int param_get_aabool(char *buffer, const struct kernel_param *kp)
14268c2ecf20Sopenharmony_ci{
14278c2ecf20Sopenharmony_ci	if (!apparmor_enabled)
14288c2ecf20Sopenharmony_ci		return -EINVAL;
14298c2ecf20Sopenharmony_ci	if (apparmor_initialized && !policy_view_capable(NULL))
14308c2ecf20Sopenharmony_ci		return -EPERM;
14318c2ecf20Sopenharmony_ci	return param_get_bool(buffer, kp);
14328c2ecf20Sopenharmony_ci}
14338c2ecf20Sopenharmony_ci
14348c2ecf20Sopenharmony_cistatic int param_set_aauint(const char *val, const struct kernel_param *kp)
14358c2ecf20Sopenharmony_ci{
14368c2ecf20Sopenharmony_ci	int error;
14378c2ecf20Sopenharmony_ci
14388c2ecf20Sopenharmony_ci	if (!apparmor_enabled)
14398c2ecf20Sopenharmony_ci		return -EINVAL;
14408c2ecf20Sopenharmony_ci	/* file is ro but enforce 2nd line check */
14418c2ecf20Sopenharmony_ci	if (apparmor_initialized)
14428c2ecf20Sopenharmony_ci		return -EPERM;
14438c2ecf20Sopenharmony_ci
14448c2ecf20Sopenharmony_ci	error = param_set_uint(val, kp);
14458c2ecf20Sopenharmony_ci	aa_g_path_max = max_t(uint32_t, aa_g_path_max, sizeof(union aa_buffer));
14468c2ecf20Sopenharmony_ci	pr_info("AppArmor: buffer size set to %d bytes\n", aa_g_path_max);
14478c2ecf20Sopenharmony_ci
14488c2ecf20Sopenharmony_ci	return error;
14498c2ecf20Sopenharmony_ci}
14508c2ecf20Sopenharmony_ci
14518c2ecf20Sopenharmony_cistatic int param_get_aauint(char *buffer, const struct kernel_param *kp)
14528c2ecf20Sopenharmony_ci{
14538c2ecf20Sopenharmony_ci	if (!apparmor_enabled)
14548c2ecf20Sopenharmony_ci		return -EINVAL;
14558c2ecf20Sopenharmony_ci	if (apparmor_initialized && !policy_view_capable(NULL))
14568c2ecf20Sopenharmony_ci		return -EPERM;
14578c2ecf20Sopenharmony_ci	return param_get_uint(buffer, kp);
14588c2ecf20Sopenharmony_ci}
14598c2ecf20Sopenharmony_ci
14608c2ecf20Sopenharmony_ci/* Can only be set before AppArmor is initialized (i.e. on boot cmdline). */
14618c2ecf20Sopenharmony_cistatic int param_set_aaintbool(const char *val, const struct kernel_param *kp)
14628c2ecf20Sopenharmony_ci{
14638c2ecf20Sopenharmony_ci	struct kernel_param kp_local;
14648c2ecf20Sopenharmony_ci	bool value;
14658c2ecf20Sopenharmony_ci	int error;
14668c2ecf20Sopenharmony_ci
14678c2ecf20Sopenharmony_ci	if (apparmor_initialized)
14688c2ecf20Sopenharmony_ci		return -EPERM;
14698c2ecf20Sopenharmony_ci
14708c2ecf20Sopenharmony_ci	/* Create local copy, with arg pointing to bool type. */
14718c2ecf20Sopenharmony_ci	value = !!*((int *)kp->arg);
14728c2ecf20Sopenharmony_ci	memcpy(&kp_local, kp, sizeof(kp_local));
14738c2ecf20Sopenharmony_ci	kp_local.arg = &value;
14748c2ecf20Sopenharmony_ci
14758c2ecf20Sopenharmony_ci	error = param_set_bool(val, &kp_local);
14768c2ecf20Sopenharmony_ci	if (!error)
14778c2ecf20Sopenharmony_ci		*((int *)kp->arg) = *((bool *)kp_local.arg);
14788c2ecf20Sopenharmony_ci	return error;
14798c2ecf20Sopenharmony_ci}
14808c2ecf20Sopenharmony_ci
14818c2ecf20Sopenharmony_ci/*
14828c2ecf20Sopenharmony_ci * To avoid changing /sys/module/apparmor/parameters/enabled from Y/N to
14838c2ecf20Sopenharmony_ci * 1/0, this converts the "int that is actually bool" back to bool for
14848c2ecf20Sopenharmony_ci * display in the /sys filesystem, while keeping it "int" for the LSM
14858c2ecf20Sopenharmony_ci * infrastructure.
14868c2ecf20Sopenharmony_ci */
14878c2ecf20Sopenharmony_cistatic int param_get_aaintbool(char *buffer, const struct kernel_param *kp)
14888c2ecf20Sopenharmony_ci{
14898c2ecf20Sopenharmony_ci	struct kernel_param kp_local;
14908c2ecf20Sopenharmony_ci	bool value;
14918c2ecf20Sopenharmony_ci
14928c2ecf20Sopenharmony_ci	/* Create local copy, with arg pointing to bool type. */
14938c2ecf20Sopenharmony_ci	value = !!*((int *)kp->arg);
14948c2ecf20Sopenharmony_ci	memcpy(&kp_local, kp, sizeof(kp_local));
14958c2ecf20Sopenharmony_ci	kp_local.arg = &value;
14968c2ecf20Sopenharmony_ci
14978c2ecf20Sopenharmony_ci	return param_get_bool(buffer, &kp_local);
14988c2ecf20Sopenharmony_ci}
14998c2ecf20Sopenharmony_ci
15008c2ecf20Sopenharmony_cistatic int param_set_aacompressionlevel(const char *val,
15018c2ecf20Sopenharmony_ci					const struct kernel_param *kp)
15028c2ecf20Sopenharmony_ci{
15038c2ecf20Sopenharmony_ci	int error;
15048c2ecf20Sopenharmony_ci
15058c2ecf20Sopenharmony_ci	if (!apparmor_enabled)
15068c2ecf20Sopenharmony_ci		return -EINVAL;
15078c2ecf20Sopenharmony_ci	if (apparmor_initialized)
15088c2ecf20Sopenharmony_ci		return -EPERM;
15098c2ecf20Sopenharmony_ci
15108c2ecf20Sopenharmony_ci	error = param_set_int(val, kp);
15118c2ecf20Sopenharmony_ci
15128c2ecf20Sopenharmony_ci	aa_g_rawdata_compression_level = clamp(aa_g_rawdata_compression_level,
15138c2ecf20Sopenharmony_ci					       Z_NO_COMPRESSION,
15148c2ecf20Sopenharmony_ci					       Z_BEST_COMPRESSION);
15158c2ecf20Sopenharmony_ci	pr_info("AppArmor: policy rawdata compression level set to %u\n",
15168c2ecf20Sopenharmony_ci		aa_g_rawdata_compression_level);
15178c2ecf20Sopenharmony_ci
15188c2ecf20Sopenharmony_ci	return error;
15198c2ecf20Sopenharmony_ci}
15208c2ecf20Sopenharmony_ci
15218c2ecf20Sopenharmony_cistatic int param_get_aacompressionlevel(char *buffer,
15228c2ecf20Sopenharmony_ci					const struct kernel_param *kp)
15238c2ecf20Sopenharmony_ci{
15248c2ecf20Sopenharmony_ci	if (!apparmor_enabled)
15258c2ecf20Sopenharmony_ci		return -EINVAL;
15268c2ecf20Sopenharmony_ci	if (apparmor_initialized && !policy_view_capable(NULL))
15278c2ecf20Sopenharmony_ci		return -EPERM;
15288c2ecf20Sopenharmony_ci	return param_get_int(buffer, kp);
15298c2ecf20Sopenharmony_ci}
15308c2ecf20Sopenharmony_ci
15318c2ecf20Sopenharmony_cistatic int param_get_audit(char *buffer, const struct kernel_param *kp)
15328c2ecf20Sopenharmony_ci{
15338c2ecf20Sopenharmony_ci	if (!apparmor_enabled)
15348c2ecf20Sopenharmony_ci		return -EINVAL;
15358c2ecf20Sopenharmony_ci	if (apparmor_initialized && !policy_view_capable(NULL))
15368c2ecf20Sopenharmony_ci		return -EPERM;
15378c2ecf20Sopenharmony_ci	return sprintf(buffer, "%s", audit_mode_names[aa_g_audit]);
15388c2ecf20Sopenharmony_ci}
15398c2ecf20Sopenharmony_ci
15408c2ecf20Sopenharmony_cistatic int param_set_audit(const char *val, const struct kernel_param *kp)
15418c2ecf20Sopenharmony_ci{
15428c2ecf20Sopenharmony_ci	int i;
15438c2ecf20Sopenharmony_ci
15448c2ecf20Sopenharmony_ci	if (!apparmor_enabled)
15458c2ecf20Sopenharmony_ci		return -EINVAL;
15468c2ecf20Sopenharmony_ci	if (!val)
15478c2ecf20Sopenharmony_ci		return -EINVAL;
15488c2ecf20Sopenharmony_ci	if (apparmor_initialized && !policy_admin_capable(NULL))
15498c2ecf20Sopenharmony_ci		return -EPERM;
15508c2ecf20Sopenharmony_ci
15518c2ecf20Sopenharmony_ci	i = match_string(audit_mode_names, AUDIT_MAX_INDEX, val);
15528c2ecf20Sopenharmony_ci	if (i < 0)
15538c2ecf20Sopenharmony_ci		return -EINVAL;
15548c2ecf20Sopenharmony_ci
15558c2ecf20Sopenharmony_ci	aa_g_audit = i;
15568c2ecf20Sopenharmony_ci	return 0;
15578c2ecf20Sopenharmony_ci}
15588c2ecf20Sopenharmony_ci
15598c2ecf20Sopenharmony_cistatic int param_get_mode(char *buffer, const struct kernel_param *kp)
15608c2ecf20Sopenharmony_ci{
15618c2ecf20Sopenharmony_ci	if (!apparmor_enabled)
15628c2ecf20Sopenharmony_ci		return -EINVAL;
15638c2ecf20Sopenharmony_ci	if (apparmor_initialized && !policy_view_capable(NULL))
15648c2ecf20Sopenharmony_ci		return -EPERM;
15658c2ecf20Sopenharmony_ci
15668c2ecf20Sopenharmony_ci	return sprintf(buffer, "%s", aa_profile_mode_names[aa_g_profile_mode]);
15678c2ecf20Sopenharmony_ci}
15688c2ecf20Sopenharmony_ci
15698c2ecf20Sopenharmony_cistatic int param_set_mode(const char *val, const struct kernel_param *kp)
15708c2ecf20Sopenharmony_ci{
15718c2ecf20Sopenharmony_ci	int i;
15728c2ecf20Sopenharmony_ci
15738c2ecf20Sopenharmony_ci	if (!apparmor_enabled)
15748c2ecf20Sopenharmony_ci		return -EINVAL;
15758c2ecf20Sopenharmony_ci	if (!val)
15768c2ecf20Sopenharmony_ci		return -EINVAL;
15778c2ecf20Sopenharmony_ci	if (apparmor_initialized && !policy_admin_capable(NULL))
15788c2ecf20Sopenharmony_ci		return -EPERM;
15798c2ecf20Sopenharmony_ci
15808c2ecf20Sopenharmony_ci	i = match_string(aa_profile_mode_names, APPARMOR_MODE_NAMES_MAX_INDEX,
15818c2ecf20Sopenharmony_ci			 val);
15828c2ecf20Sopenharmony_ci	if (i < 0)
15838c2ecf20Sopenharmony_ci		return -EINVAL;
15848c2ecf20Sopenharmony_ci
15858c2ecf20Sopenharmony_ci	aa_g_profile_mode = i;
15868c2ecf20Sopenharmony_ci	return 0;
15878c2ecf20Sopenharmony_ci}
15888c2ecf20Sopenharmony_ci
15898c2ecf20Sopenharmony_cichar *aa_get_buffer(bool in_atomic)
15908c2ecf20Sopenharmony_ci{
15918c2ecf20Sopenharmony_ci	union aa_buffer *aa_buf;
15928c2ecf20Sopenharmony_ci	bool try_again = true;
15938c2ecf20Sopenharmony_ci	gfp_t flags = (GFP_KERNEL | __GFP_RETRY_MAYFAIL | __GFP_NOWARN);
15948c2ecf20Sopenharmony_ci
15958c2ecf20Sopenharmony_ciretry:
15968c2ecf20Sopenharmony_ci	spin_lock(&aa_buffers_lock);
15978c2ecf20Sopenharmony_ci	if (buffer_count > reserve_count ||
15988c2ecf20Sopenharmony_ci	    (in_atomic && !list_empty(&aa_global_buffers))) {
15998c2ecf20Sopenharmony_ci		aa_buf = list_first_entry(&aa_global_buffers, union aa_buffer,
16008c2ecf20Sopenharmony_ci					  list);
16018c2ecf20Sopenharmony_ci		list_del(&aa_buf->list);
16028c2ecf20Sopenharmony_ci		buffer_count--;
16038c2ecf20Sopenharmony_ci		spin_unlock(&aa_buffers_lock);
16048c2ecf20Sopenharmony_ci		return &aa_buf->buffer[0];
16058c2ecf20Sopenharmony_ci	}
16068c2ecf20Sopenharmony_ci	if (in_atomic) {
16078c2ecf20Sopenharmony_ci		/*
16088c2ecf20Sopenharmony_ci		 * out of reserve buffers and in atomic context so increase
16098c2ecf20Sopenharmony_ci		 * how many buffers to keep in reserve
16108c2ecf20Sopenharmony_ci		 */
16118c2ecf20Sopenharmony_ci		reserve_count++;
16128c2ecf20Sopenharmony_ci		flags = GFP_ATOMIC;
16138c2ecf20Sopenharmony_ci	}
16148c2ecf20Sopenharmony_ci	spin_unlock(&aa_buffers_lock);
16158c2ecf20Sopenharmony_ci
16168c2ecf20Sopenharmony_ci	if (!in_atomic)
16178c2ecf20Sopenharmony_ci		might_sleep();
16188c2ecf20Sopenharmony_ci	aa_buf = kmalloc(aa_g_path_max, flags);
16198c2ecf20Sopenharmony_ci	if (!aa_buf) {
16208c2ecf20Sopenharmony_ci		if (try_again) {
16218c2ecf20Sopenharmony_ci			try_again = false;
16228c2ecf20Sopenharmony_ci			goto retry;
16238c2ecf20Sopenharmony_ci		}
16248c2ecf20Sopenharmony_ci		pr_warn_once("AppArmor: Failed to allocate a memory buffer.\n");
16258c2ecf20Sopenharmony_ci		return NULL;
16268c2ecf20Sopenharmony_ci	}
16278c2ecf20Sopenharmony_ci	return &aa_buf->buffer[0];
16288c2ecf20Sopenharmony_ci}
16298c2ecf20Sopenharmony_ci
16308c2ecf20Sopenharmony_civoid aa_put_buffer(char *buf)
16318c2ecf20Sopenharmony_ci{
16328c2ecf20Sopenharmony_ci	union aa_buffer *aa_buf;
16338c2ecf20Sopenharmony_ci
16348c2ecf20Sopenharmony_ci	if (!buf)
16358c2ecf20Sopenharmony_ci		return;
16368c2ecf20Sopenharmony_ci	aa_buf = container_of(buf, union aa_buffer, buffer[0]);
16378c2ecf20Sopenharmony_ci
16388c2ecf20Sopenharmony_ci	spin_lock(&aa_buffers_lock);
16398c2ecf20Sopenharmony_ci	list_add(&aa_buf->list, &aa_global_buffers);
16408c2ecf20Sopenharmony_ci	buffer_count++;
16418c2ecf20Sopenharmony_ci	spin_unlock(&aa_buffers_lock);
16428c2ecf20Sopenharmony_ci}
16438c2ecf20Sopenharmony_ci
16448c2ecf20Sopenharmony_ci/*
16458c2ecf20Sopenharmony_ci * AppArmor init functions
16468c2ecf20Sopenharmony_ci */
16478c2ecf20Sopenharmony_ci
16488c2ecf20Sopenharmony_ci/**
16498c2ecf20Sopenharmony_ci * set_init_ctx - set a task context and profile on the first task.
16508c2ecf20Sopenharmony_ci *
16518c2ecf20Sopenharmony_ci * TODO: allow setting an alternate profile than unconfined
16528c2ecf20Sopenharmony_ci */
16538c2ecf20Sopenharmony_cistatic int __init set_init_ctx(void)
16548c2ecf20Sopenharmony_ci{
16558c2ecf20Sopenharmony_ci	struct cred *cred = (__force struct cred *)current->real_cred;
16568c2ecf20Sopenharmony_ci
16578c2ecf20Sopenharmony_ci	set_cred_label(cred, aa_get_label(ns_unconfined(root_ns)));
16588c2ecf20Sopenharmony_ci
16598c2ecf20Sopenharmony_ci	return 0;
16608c2ecf20Sopenharmony_ci}
16618c2ecf20Sopenharmony_ci
16628c2ecf20Sopenharmony_cistatic void destroy_buffers(void)
16638c2ecf20Sopenharmony_ci{
16648c2ecf20Sopenharmony_ci	union aa_buffer *aa_buf;
16658c2ecf20Sopenharmony_ci
16668c2ecf20Sopenharmony_ci	spin_lock(&aa_buffers_lock);
16678c2ecf20Sopenharmony_ci	while (!list_empty(&aa_global_buffers)) {
16688c2ecf20Sopenharmony_ci		aa_buf = list_first_entry(&aa_global_buffers, union aa_buffer,
16698c2ecf20Sopenharmony_ci					 list);
16708c2ecf20Sopenharmony_ci		list_del(&aa_buf->list);
16718c2ecf20Sopenharmony_ci		spin_unlock(&aa_buffers_lock);
16728c2ecf20Sopenharmony_ci		kfree(aa_buf);
16738c2ecf20Sopenharmony_ci		spin_lock(&aa_buffers_lock);
16748c2ecf20Sopenharmony_ci	}
16758c2ecf20Sopenharmony_ci	spin_unlock(&aa_buffers_lock);
16768c2ecf20Sopenharmony_ci}
16778c2ecf20Sopenharmony_ci
16788c2ecf20Sopenharmony_cistatic int __init alloc_buffers(void)
16798c2ecf20Sopenharmony_ci{
16808c2ecf20Sopenharmony_ci	union aa_buffer *aa_buf;
16818c2ecf20Sopenharmony_ci	int i, num;
16828c2ecf20Sopenharmony_ci
16838c2ecf20Sopenharmony_ci	/*
16848c2ecf20Sopenharmony_ci	 * A function may require two buffers at once. Usually the buffers are
16858c2ecf20Sopenharmony_ci	 * used for a short period of time and are shared. On UP kernel buffers
16868c2ecf20Sopenharmony_ci	 * two should be enough, with more CPUs it is possible that more
16878c2ecf20Sopenharmony_ci	 * buffers will be used simultaneously. The preallocated pool may grow.
16888c2ecf20Sopenharmony_ci	 * This preallocation has also the side-effect that AppArmor will be
16898c2ecf20Sopenharmony_ci	 * disabled early at boot if aa_g_path_max is extremly high.
16908c2ecf20Sopenharmony_ci	 */
16918c2ecf20Sopenharmony_ci	if (num_online_cpus() > 1)
16928c2ecf20Sopenharmony_ci		num = 4 + RESERVE_COUNT;
16938c2ecf20Sopenharmony_ci	else
16948c2ecf20Sopenharmony_ci		num = 2 + RESERVE_COUNT;
16958c2ecf20Sopenharmony_ci
16968c2ecf20Sopenharmony_ci	for (i = 0; i < num; i++) {
16978c2ecf20Sopenharmony_ci
16988c2ecf20Sopenharmony_ci		aa_buf = kmalloc(aa_g_path_max, GFP_KERNEL |
16998c2ecf20Sopenharmony_ci				 __GFP_RETRY_MAYFAIL | __GFP_NOWARN);
17008c2ecf20Sopenharmony_ci		if (!aa_buf) {
17018c2ecf20Sopenharmony_ci			destroy_buffers();
17028c2ecf20Sopenharmony_ci			return -ENOMEM;
17038c2ecf20Sopenharmony_ci		}
17048c2ecf20Sopenharmony_ci		aa_put_buffer(&aa_buf->buffer[0]);
17058c2ecf20Sopenharmony_ci	}
17068c2ecf20Sopenharmony_ci	return 0;
17078c2ecf20Sopenharmony_ci}
17088c2ecf20Sopenharmony_ci
17098c2ecf20Sopenharmony_ci#ifdef CONFIG_SYSCTL
17108c2ecf20Sopenharmony_cistatic int apparmor_dointvec(struct ctl_table *table, int write,
17118c2ecf20Sopenharmony_ci			     void *buffer, size_t *lenp, loff_t *ppos)
17128c2ecf20Sopenharmony_ci{
17138c2ecf20Sopenharmony_ci	if (!policy_admin_capable(NULL))
17148c2ecf20Sopenharmony_ci		return -EPERM;
17158c2ecf20Sopenharmony_ci	if (!apparmor_enabled)
17168c2ecf20Sopenharmony_ci		return -EINVAL;
17178c2ecf20Sopenharmony_ci
17188c2ecf20Sopenharmony_ci	return proc_dointvec(table, write, buffer, lenp, ppos);
17198c2ecf20Sopenharmony_ci}
17208c2ecf20Sopenharmony_ci
17218c2ecf20Sopenharmony_cistatic struct ctl_path apparmor_sysctl_path[] = {
17228c2ecf20Sopenharmony_ci	{ .procname = "kernel", },
17238c2ecf20Sopenharmony_ci	{ }
17248c2ecf20Sopenharmony_ci};
17258c2ecf20Sopenharmony_ci
17268c2ecf20Sopenharmony_cistatic struct ctl_table apparmor_sysctl_table[] = {
17278c2ecf20Sopenharmony_ci	{
17288c2ecf20Sopenharmony_ci		.procname       = "unprivileged_userns_apparmor_policy",
17298c2ecf20Sopenharmony_ci		.data           = &unprivileged_userns_apparmor_policy,
17308c2ecf20Sopenharmony_ci		.maxlen         = sizeof(int),
17318c2ecf20Sopenharmony_ci		.mode           = 0600,
17328c2ecf20Sopenharmony_ci		.proc_handler   = apparmor_dointvec,
17338c2ecf20Sopenharmony_ci	},
17348c2ecf20Sopenharmony_ci	{ }
17358c2ecf20Sopenharmony_ci};
17368c2ecf20Sopenharmony_ci
17378c2ecf20Sopenharmony_cistatic int __init apparmor_init_sysctl(void)
17388c2ecf20Sopenharmony_ci{
17398c2ecf20Sopenharmony_ci	return register_sysctl_paths(apparmor_sysctl_path,
17408c2ecf20Sopenharmony_ci				     apparmor_sysctl_table) ? 0 : -ENOMEM;
17418c2ecf20Sopenharmony_ci}
17428c2ecf20Sopenharmony_ci#else
17438c2ecf20Sopenharmony_cistatic inline int apparmor_init_sysctl(void)
17448c2ecf20Sopenharmony_ci{
17458c2ecf20Sopenharmony_ci	return 0;
17468c2ecf20Sopenharmony_ci}
17478c2ecf20Sopenharmony_ci#endif /* CONFIG_SYSCTL */
17488c2ecf20Sopenharmony_ci
17498c2ecf20Sopenharmony_ci#if defined(CONFIG_NETFILTER) && defined(CONFIG_NETWORK_SECMARK)
17508c2ecf20Sopenharmony_cistatic unsigned int apparmor_ip_postroute(void *priv,
17518c2ecf20Sopenharmony_ci					  struct sk_buff *skb,
17528c2ecf20Sopenharmony_ci					  const struct nf_hook_state *state)
17538c2ecf20Sopenharmony_ci{
17548c2ecf20Sopenharmony_ci	struct aa_sk_ctx *ctx;
17558c2ecf20Sopenharmony_ci	struct sock *sk;
17568c2ecf20Sopenharmony_ci
17578c2ecf20Sopenharmony_ci	if (!skb->secmark)
17588c2ecf20Sopenharmony_ci		return NF_ACCEPT;
17598c2ecf20Sopenharmony_ci
17608c2ecf20Sopenharmony_ci	sk = skb_to_full_sk(skb);
17618c2ecf20Sopenharmony_ci	if (sk == NULL)
17628c2ecf20Sopenharmony_ci		return NF_ACCEPT;
17638c2ecf20Sopenharmony_ci
17648c2ecf20Sopenharmony_ci	ctx = SK_CTX(sk);
17658c2ecf20Sopenharmony_ci	if (!apparmor_secmark_check(ctx->label, OP_SENDMSG, AA_MAY_SEND,
17668c2ecf20Sopenharmony_ci				    skb->secmark, sk))
17678c2ecf20Sopenharmony_ci		return NF_ACCEPT;
17688c2ecf20Sopenharmony_ci
17698c2ecf20Sopenharmony_ci	return NF_DROP_ERR(-ECONNREFUSED);
17708c2ecf20Sopenharmony_ci
17718c2ecf20Sopenharmony_ci}
17728c2ecf20Sopenharmony_ci
17738c2ecf20Sopenharmony_cistatic unsigned int apparmor_ipv4_postroute(void *priv,
17748c2ecf20Sopenharmony_ci					    struct sk_buff *skb,
17758c2ecf20Sopenharmony_ci					    const struct nf_hook_state *state)
17768c2ecf20Sopenharmony_ci{
17778c2ecf20Sopenharmony_ci	return apparmor_ip_postroute(priv, skb, state);
17788c2ecf20Sopenharmony_ci}
17798c2ecf20Sopenharmony_ci
17808c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
17818c2ecf20Sopenharmony_cistatic unsigned int apparmor_ipv6_postroute(void *priv,
17828c2ecf20Sopenharmony_ci					    struct sk_buff *skb,
17838c2ecf20Sopenharmony_ci					    const struct nf_hook_state *state)
17848c2ecf20Sopenharmony_ci{
17858c2ecf20Sopenharmony_ci	return apparmor_ip_postroute(priv, skb, state);
17868c2ecf20Sopenharmony_ci}
17878c2ecf20Sopenharmony_ci#endif
17888c2ecf20Sopenharmony_ci
17898c2ecf20Sopenharmony_cistatic const struct nf_hook_ops apparmor_nf_ops[] = {
17908c2ecf20Sopenharmony_ci	{
17918c2ecf20Sopenharmony_ci		.hook =         apparmor_ipv4_postroute,
17928c2ecf20Sopenharmony_ci		.pf =           NFPROTO_IPV4,
17938c2ecf20Sopenharmony_ci		.hooknum =      NF_INET_POST_ROUTING,
17948c2ecf20Sopenharmony_ci		.priority =     NF_IP_PRI_SELINUX_FIRST,
17958c2ecf20Sopenharmony_ci	},
17968c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6)
17978c2ecf20Sopenharmony_ci	{
17988c2ecf20Sopenharmony_ci		.hook =         apparmor_ipv6_postroute,
17998c2ecf20Sopenharmony_ci		.pf =           NFPROTO_IPV6,
18008c2ecf20Sopenharmony_ci		.hooknum =      NF_INET_POST_ROUTING,
18018c2ecf20Sopenharmony_ci		.priority =     NF_IP6_PRI_SELINUX_FIRST,
18028c2ecf20Sopenharmony_ci	},
18038c2ecf20Sopenharmony_ci#endif
18048c2ecf20Sopenharmony_ci};
18058c2ecf20Sopenharmony_ci
18068c2ecf20Sopenharmony_cistatic int __net_init apparmor_nf_register(struct net *net)
18078c2ecf20Sopenharmony_ci{
18088c2ecf20Sopenharmony_ci	int ret;
18098c2ecf20Sopenharmony_ci
18108c2ecf20Sopenharmony_ci	ret = nf_register_net_hooks(net, apparmor_nf_ops,
18118c2ecf20Sopenharmony_ci				    ARRAY_SIZE(apparmor_nf_ops));
18128c2ecf20Sopenharmony_ci	return ret;
18138c2ecf20Sopenharmony_ci}
18148c2ecf20Sopenharmony_ci
18158c2ecf20Sopenharmony_cistatic void __net_exit apparmor_nf_unregister(struct net *net)
18168c2ecf20Sopenharmony_ci{
18178c2ecf20Sopenharmony_ci	nf_unregister_net_hooks(net, apparmor_nf_ops,
18188c2ecf20Sopenharmony_ci				ARRAY_SIZE(apparmor_nf_ops));
18198c2ecf20Sopenharmony_ci}
18208c2ecf20Sopenharmony_ci
18218c2ecf20Sopenharmony_cistatic struct pernet_operations apparmor_net_ops = {
18228c2ecf20Sopenharmony_ci	.init = apparmor_nf_register,
18238c2ecf20Sopenharmony_ci	.exit = apparmor_nf_unregister,
18248c2ecf20Sopenharmony_ci};
18258c2ecf20Sopenharmony_ci
18268c2ecf20Sopenharmony_cistatic int __init apparmor_nf_ip_init(void)
18278c2ecf20Sopenharmony_ci{
18288c2ecf20Sopenharmony_ci	int err;
18298c2ecf20Sopenharmony_ci
18308c2ecf20Sopenharmony_ci	if (!apparmor_enabled)
18318c2ecf20Sopenharmony_ci		return 0;
18328c2ecf20Sopenharmony_ci
18338c2ecf20Sopenharmony_ci	err = register_pernet_subsys(&apparmor_net_ops);
18348c2ecf20Sopenharmony_ci	if (err)
18358c2ecf20Sopenharmony_ci		panic("Apparmor: register_pernet_subsys: error %d\n", err);
18368c2ecf20Sopenharmony_ci
18378c2ecf20Sopenharmony_ci	return 0;
18388c2ecf20Sopenharmony_ci}
18398c2ecf20Sopenharmony_ci__initcall(apparmor_nf_ip_init);
18408c2ecf20Sopenharmony_ci#endif
18418c2ecf20Sopenharmony_ci
18428c2ecf20Sopenharmony_cistatic int __init apparmor_init(void)
18438c2ecf20Sopenharmony_ci{
18448c2ecf20Sopenharmony_ci	int error;
18458c2ecf20Sopenharmony_ci
18468c2ecf20Sopenharmony_ci	aa_secids_init();
18478c2ecf20Sopenharmony_ci
18488c2ecf20Sopenharmony_ci	error = aa_setup_dfa_engine();
18498c2ecf20Sopenharmony_ci	if (error) {
18508c2ecf20Sopenharmony_ci		AA_ERROR("Unable to setup dfa engine\n");
18518c2ecf20Sopenharmony_ci		goto alloc_out;
18528c2ecf20Sopenharmony_ci	}
18538c2ecf20Sopenharmony_ci
18548c2ecf20Sopenharmony_ci	error = aa_alloc_root_ns();
18558c2ecf20Sopenharmony_ci	if (error) {
18568c2ecf20Sopenharmony_ci		AA_ERROR("Unable to allocate default profile namespace\n");
18578c2ecf20Sopenharmony_ci		goto alloc_out;
18588c2ecf20Sopenharmony_ci	}
18598c2ecf20Sopenharmony_ci
18608c2ecf20Sopenharmony_ci	error = apparmor_init_sysctl();
18618c2ecf20Sopenharmony_ci	if (error) {
18628c2ecf20Sopenharmony_ci		AA_ERROR("Unable to register sysctls\n");
18638c2ecf20Sopenharmony_ci		goto alloc_out;
18648c2ecf20Sopenharmony_ci
18658c2ecf20Sopenharmony_ci	}
18668c2ecf20Sopenharmony_ci
18678c2ecf20Sopenharmony_ci	error = alloc_buffers();
18688c2ecf20Sopenharmony_ci	if (error) {
18698c2ecf20Sopenharmony_ci		AA_ERROR("Unable to allocate work buffers\n");
18708c2ecf20Sopenharmony_ci		goto alloc_out;
18718c2ecf20Sopenharmony_ci	}
18728c2ecf20Sopenharmony_ci
18738c2ecf20Sopenharmony_ci	error = set_init_ctx();
18748c2ecf20Sopenharmony_ci	if (error) {
18758c2ecf20Sopenharmony_ci		AA_ERROR("Failed to set context on init task\n");
18768c2ecf20Sopenharmony_ci		aa_free_root_ns();
18778c2ecf20Sopenharmony_ci		goto buffers_out;
18788c2ecf20Sopenharmony_ci	}
18798c2ecf20Sopenharmony_ci	security_add_hooks(apparmor_hooks, ARRAY_SIZE(apparmor_hooks),
18808c2ecf20Sopenharmony_ci				"apparmor");
18818c2ecf20Sopenharmony_ci
18828c2ecf20Sopenharmony_ci	/* Report that AppArmor successfully initialized */
18838c2ecf20Sopenharmony_ci	apparmor_initialized = 1;
18848c2ecf20Sopenharmony_ci	if (aa_g_profile_mode == APPARMOR_COMPLAIN)
18858c2ecf20Sopenharmony_ci		aa_info_message("AppArmor initialized: complain mode enabled");
18868c2ecf20Sopenharmony_ci	else if (aa_g_profile_mode == APPARMOR_KILL)
18878c2ecf20Sopenharmony_ci		aa_info_message("AppArmor initialized: kill mode enabled");
18888c2ecf20Sopenharmony_ci	else
18898c2ecf20Sopenharmony_ci		aa_info_message("AppArmor initialized");
18908c2ecf20Sopenharmony_ci
18918c2ecf20Sopenharmony_ci	return error;
18928c2ecf20Sopenharmony_ci
18938c2ecf20Sopenharmony_cibuffers_out:
18948c2ecf20Sopenharmony_ci	destroy_buffers();
18958c2ecf20Sopenharmony_cialloc_out:
18968c2ecf20Sopenharmony_ci	aa_destroy_aafs();
18978c2ecf20Sopenharmony_ci	aa_teardown_dfa_engine();
18988c2ecf20Sopenharmony_ci
18998c2ecf20Sopenharmony_ci	apparmor_enabled = false;
19008c2ecf20Sopenharmony_ci	return error;
19018c2ecf20Sopenharmony_ci}
19028c2ecf20Sopenharmony_ci
19038c2ecf20Sopenharmony_ciDEFINE_LSM(apparmor) = {
19048c2ecf20Sopenharmony_ci	.name = "apparmor",
19058c2ecf20Sopenharmony_ci	.flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE,
19068c2ecf20Sopenharmony_ci	.enabled = &apparmor_enabled,
19078c2ecf20Sopenharmony_ci	.blobs = &apparmor_blob_sizes,
19088c2ecf20Sopenharmony_ci	.init = apparmor_init,
19098c2ecf20Sopenharmony_ci};
1910