162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * AppArmor security module 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * This file contains AppArmor LSM hooks. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (C) 1998-2008 Novell/SUSE 862306a36Sopenharmony_ci * Copyright 2009-2010 Canonical Ltd. 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/lsm_hooks.h> 1262306a36Sopenharmony_ci#include <linux/moduleparam.h> 1362306a36Sopenharmony_ci#include <linux/mm.h> 1462306a36Sopenharmony_ci#include <linux/mman.h> 1562306a36Sopenharmony_ci#include <linux/mount.h> 1662306a36Sopenharmony_ci#include <linux/namei.h> 1762306a36Sopenharmony_ci#include <linux/ptrace.h> 1862306a36Sopenharmony_ci#include <linux/ctype.h> 1962306a36Sopenharmony_ci#include <linux/sysctl.h> 2062306a36Sopenharmony_ci#include <linux/audit.h> 2162306a36Sopenharmony_ci#include <linux/user_namespace.h> 2262306a36Sopenharmony_ci#include <linux/netfilter_ipv4.h> 2362306a36Sopenharmony_ci#include <linux/netfilter_ipv6.h> 2462306a36Sopenharmony_ci#include <linux/zstd.h> 2562306a36Sopenharmony_ci#include <net/sock.h> 2662306a36Sopenharmony_ci#include <uapi/linux/mount.h> 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#include "include/apparmor.h" 2962306a36Sopenharmony_ci#include "include/apparmorfs.h" 3062306a36Sopenharmony_ci#include "include/audit.h" 3162306a36Sopenharmony_ci#include "include/capability.h" 3262306a36Sopenharmony_ci#include "include/cred.h" 3362306a36Sopenharmony_ci#include "include/file.h" 3462306a36Sopenharmony_ci#include "include/ipc.h" 3562306a36Sopenharmony_ci#include "include/net.h" 3662306a36Sopenharmony_ci#include "include/path.h" 3762306a36Sopenharmony_ci#include "include/label.h" 3862306a36Sopenharmony_ci#include "include/policy.h" 3962306a36Sopenharmony_ci#include "include/policy_ns.h" 4062306a36Sopenharmony_ci#include "include/procattr.h" 4162306a36Sopenharmony_ci#include "include/mount.h" 4262306a36Sopenharmony_ci#include "include/secid.h" 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci/* Flag indicating whether initialization completed */ 4562306a36Sopenharmony_ciint apparmor_initialized; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ciunion aa_buffer { 4862306a36Sopenharmony_ci struct list_head list; 4962306a36Sopenharmony_ci DECLARE_FLEX_ARRAY(char, buffer); 5062306a36Sopenharmony_ci}; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci#define RESERVE_COUNT 2 5362306a36Sopenharmony_cistatic int reserve_count = RESERVE_COUNT; 5462306a36Sopenharmony_cistatic int buffer_count; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic LIST_HEAD(aa_global_buffers); 5762306a36Sopenharmony_cistatic DEFINE_SPINLOCK(aa_buffers_lock); 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci/* 6062306a36Sopenharmony_ci * LSM hook functions 6162306a36Sopenharmony_ci */ 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci/* 6462306a36Sopenharmony_ci * put the associated labels 6562306a36Sopenharmony_ci */ 6662306a36Sopenharmony_cistatic void apparmor_cred_free(struct cred *cred) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci aa_put_label(cred_label(cred)); 6962306a36Sopenharmony_ci set_cred_label(cred, NULL); 7062306a36Sopenharmony_ci} 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci/* 7362306a36Sopenharmony_ci * allocate the apparmor part of blank credentials 7462306a36Sopenharmony_ci */ 7562306a36Sopenharmony_cistatic int apparmor_cred_alloc_blank(struct cred *cred, gfp_t gfp) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci set_cred_label(cred, NULL); 7862306a36Sopenharmony_ci return 0; 7962306a36Sopenharmony_ci} 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci/* 8262306a36Sopenharmony_ci * prepare new cred label for modification by prepare_cred block 8362306a36Sopenharmony_ci */ 8462306a36Sopenharmony_cistatic int apparmor_cred_prepare(struct cred *new, const struct cred *old, 8562306a36Sopenharmony_ci gfp_t gfp) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci set_cred_label(new, aa_get_newest_label(cred_label(old))); 8862306a36Sopenharmony_ci return 0; 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci/* 9262306a36Sopenharmony_ci * transfer the apparmor data to a blank set of creds 9362306a36Sopenharmony_ci */ 9462306a36Sopenharmony_cistatic void apparmor_cred_transfer(struct cred *new, const struct cred *old) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci set_cred_label(new, aa_get_newest_label(cred_label(old))); 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistatic void apparmor_task_free(struct task_struct *task) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci aa_free_task_ctx(task_ctx(task)); 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistatic int apparmor_task_alloc(struct task_struct *task, 10662306a36Sopenharmony_ci unsigned long clone_flags) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci struct aa_task_ctx *new = task_ctx(task); 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci aa_dup_task_ctx(new, task_ctx(current)); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci return 0; 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_cistatic int apparmor_ptrace_access_check(struct task_struct *child, 11662306a36Sopenharmony_ci unsigned int mode) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci struct aa_label *tracer, *tracee; 11962306a36Sopenharmony_ci const struct cred *cred; 12062306a36Sopenharmony_ci int error; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci cred = get_task_cred(child); 12362306a36Sopenharmony_ci tracee = cred_label(cred); /* ref count on cred */ 12462306a36Sopenharmony_ci tracer = __begin_current_label_crit_section(); 12562306a36Sopenharmony_ci error = aa_may_ptrace(current_cred(), tracer, cred, tracee, 12662306a36Sopenharmony_ci (mode & PTRACE_MODE_READ) ? AA_PTRACE_READ 12762306a36Sopenharmony_ci : AA_PTRACE_TRACE); 12862306a36Sopenharmony_ci __end_current_label_crit_section(tracer); 12962306a36Sopenharmony_ci put_cred(cred); 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci return error; 13262306a36Sopenharmony_ci} 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_cistatic int apparmor_ptrace_traceme(struct task_struct *parent) 13562306a36Sopenharmony_ci{ 13662306a36Sopenharmony_ci struct aa_label *tracer, *tracee; 13762306a36Sopenharmony_ci const struct cred *cred; 13862306a36Sopenharmony_ci int error; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci tracee = __begin_current_label_crit_section(); 14162306a36Sopenharmony_ci cred = get_task_cred(parent); 14262306a36Sopenharmony_ci tracer = cred_label(cred); /* ref count on cred */ 14362306a36Sopenharmony_ci error = aa_may_ptrace(cred, tracer, current_cred(), tracee, 14462306a36Sopenharmony_ci AA_PTRACE_TRACE); 14562306a36Sopenharmony_ci put_cred(cred); 14662306a36Sopenharmony_ci __end_current_label_crit_section(tracee); 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci return error; 14962306a36Sopenharmony_ci} 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci/* Derived from security/commoncap.c:cap_capget */ 15262306a36Sopenharmony_cistatic int apparmor_capget(const struct task_struct *target, kernel_cap_t *effective, 15362306a36Sopenharmony_ci kernel_cap_t *inheritable, kernel_cap_t *permitted) 15462306a36Sopenharmony_ci{ 15562306a36Sopenharmony_ci struct aa_label *label; 15662306a36Sopenharmony_ci const struct cred *cred; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci rcu_read_lock(); 15962306a36Sopenharmony_ci cred = __task_cred(target); 16062306a36Sopenharmony_ci label = aa_get_newest_cred_label(cred); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci /* 16362306a36Sopenharmony_ci * cap_capget is stacked ahead of this and will 16462306a36Sopenharmony_ci * initialize effective and permitted. 16562306a36Sopenharmony_ci */ 16662306a36Sopenharmony_ci if (!unconfined(label)) { 16762306a36Sopenharmony_ci struct aa_profile *profile; 16862306a36Sopenharmony_ci struct label_it i; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci label_for_each_confined(i, label, profile) { 17162306a36Sopenharmony_ci struct aa_ruleset *rules; 17262306a36Sopenharmony_ci if (COMPLAIN_MODE(profile)) 17362306a36Sopenharmony_ci continue; 17462306a36Sopenharmony_ci rules = list_first_entry(&profile->rules, 17562306a36Sopenharmony_ci typeof(*rules), list); 17662306a36Sopenharmony_ci *effective = cap_intersect(*effective, 17762306a36Sopenharmony_ci rules->caps.allow); 17862306a36Sopenharmony_ci *permitted = cap_intersect(*permitted, 17962306a36Sopenharmony_ci rules->caps.allow); 18062306a36Sopenharmony_ci } 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci rcu_read_unlock(); 18362306a36Sopenharmony_ci aa_put_label(label); 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci return 0; 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_cistatic int apparmor_capable(const struct cred *cred, struct user_namespace *ns, 18962306a36Sopenharmony_ci int cap, unsigned int opts) 19062306a36Sopenharmony_ci{ 19162306a36Sopenharmony_ci struct aa_label *label; 19262306a36Sopenharmony_ci int error = 0; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci label = aa_get_newest_cred_label(cred); 19562306a36Sopenharmony_ci if (!unconfined(label)) 19662306a36Sopenharmony_ci error = aa_capable(cred, label, cap, opts); 19762306a36Sopenharmony_ci aa_put_label(label); 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci return error; 20062306a36Sopenharmony_ci} 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci/** 20362306a36Sopenharmony_ci * common_perm - basic common permission check wrapper fn for paths 20462306a36Sopenharmony_ci * @op: operation being checked 20562306a36Sopenharmony_ci * @path: path to check permission of (NOT NULL) 20662306a36Sopenharmony_ci * @mask: requested permissions mask 20762306a36Sopenharmony_ci * @cond: conditional info for the permission request (NOT NULL) 20862306a36Sopenharmony_ci * 20962306a36Sopenharmony_ci * Returns: %0 else error code if error or permission denied 21062306a36Sopenharmony_ci */ 21162306a36Sopenharmony_cistatic int common_perm(const char *op, const struct path *path, u32 mask, 21262306a36Sopenharmony_ci struct path_cond *cond) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci struct aa_label *label; 21562306a36Sopenharmony_ci int error = 0; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci label = __begin_current_label_crit_section(); 21862306a36Sopenharmony_ci if (!unconfined(label)) 21962306a36Sopenharmony_ci error = aa_path_perm(op, current_cred(), label, path, 0, mask, 22062306a36Sopenharmony_ci cond); 22162306a36Sopenharmony_ci __end_current_label_crit_section(label); 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci return error; 22462306a36Sopenharmony_ci} 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci/** 22762306a36Sopenharmony_ci * common_perm_cond - common permission wrapper around inode cond 22862306a36Sopenharmony_ci * @op: operation being checked 22962306a36Sopenharmony_ci * @path: location to check (NOT NULL) 23062306a36Sopenharmony_ci * @mask: requested permissions mask 23162306a36Sopenharmony_ci * 23262306a36Sopenharmony_ci * Returns: %0 else error code if error or permission denied 23362306a36Sopenharmony_ci */ 23462306a36Sopenharmony_cistatic int common_perm_cond(const char *op, const struct path *path, u32 mask) 23562306a36Sopenharmony_ci{ 23662306a36Sopenharmony_ci vfsuid_t vfsuid = i_uid_into_vfsuid(mnt_idmap(path->mnt), 23762306a36Sopenharmony_ci d_backing_inode(path->dentry)); 23862306a36Sopenharmony_ci struct path_cond cond = { 23962306a36Sopenharmony_ci vfsuid_into_kuid(vfsuid), 24062306a36Sopenharmony_ci d_backing_inode(path->dentry)->i_mode 24162306a36Sopenharmony_ci }; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci if (!path_mediated_fs(path->dentry)) 24462306a36Sopenharmony_ci return 0; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci return common_perm(op, path, mask, &cond); 24762306a36Sopenharmony_ci} 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci/** 25062306a36Sopenharmony_ci * common_perm_dir_dentry - common permission wrapper when path is dir, dentry 25162306a36Sopenharmony_ci * @op: operation being checked 25262306a36Sopenharmony_ci * @dir: directory of the dentry (NOT NULL) 25362306a36Sopenharmony_ci * @dentry: dentry to check (NOT NULL) 25462306a36Sopenharmony_ci * @mask: requested permissions mask 25562306a36Sopenharmony_ci * @cond: conditional info for the permission request (NOT NULL) 25662306a36Sopenharmony_ci * 25762306a36Sopenharmony_ci * Returns: %0 else error code if error or permission denied 25862306a36Sopenharmony_ci */ 25962306a36Sopenharmony_cistatic int common_perm_dir_dentry(const char *op, const struct path *dir, 26062306a36Sopenharmony_ci struct dentry *dentry, u32 mask, 26162306a36Sopenharmony_ci struct path_cond *cond) 26262306a36Sopenharmony_ci{ 26362306a36Sopenharmony_ci struct path path = { .mnt = dir->mnt, .dentry = dentry }; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci return common_perm(op, &path, mask, cond); 26662306a36Sopenharmony_ci} 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci/** 26962306a36Sopenharmony_ci * common_perm_rm - common permission wrapper for operations doing rm 27062306a36Sopenharmony_ci * @op: operation being checked 27162306a36Sopenharmony_ci * @dir: directory that the dentry is in (NOT NULL) 27262306a36Sopenharmony_ci * @dentry: dentry being rm'd (NOT NULL) 27362306a36Sopenharmony_ci * @mask: requested permission mask 27462306a36Sopenharmony_ci * 27562306a36Sopenharmony_ci * Returns: %0 else error code if error or permission denied 27662306a36Sopenharmony_ci */ 27762306a36Sopenharmony_cistatic int common_perm_rm(const char *op, const struct path *dir, 27862306a36Sopenharmony_ci struct dentry *dentry, u32 mask) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci struct inode *inode = d_backing_inode(dentry); 28162306a36Sopenharmony_ci struct path_cond cond = { }; 28262306a36Sopenharmony_ci vfsuid_t vfsuid; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci if (!inode || !path_mediated_fs(dentry)) 28562306a36Sopenharmony_ci return 0; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci vfsuid = i_uid_into_vfsuid(mnt_idmap(dir->mnt), inode); 28862306a36Sopenharmony_ci cond.uid = vfsuid_into_kuid(vfsuid); 28962306a36Sopenharmony_ci cond.mode = inode->i_mode; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci return common_perm_dir_dentry(op, dir, dentry, mask, &cond); 29262306a36Sopenharmony_ci} 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci/** 29562306a36Sopenharmony_ci * common_perm_create - common permission wrapper for operations doing create 29662306a36Sopenharmony_ci * @op: operation being checked 29762306a36Sopenharmony_ci * @dir: directory that dentry will be created in (NOT NULL) 29862306a36Sopenharmony_ci * @dentry: dentry to create (NOT NULL) 29962306a36Sopenharmony_ci * @mask: request permission mask 30062306a36Sopenharmony_ci * @mode: created file mode 30162306a36Sopenharmony_ci * 30262306a36Sopenharmony_ci * Returns: %0 else error code if error or permission denied 30362306a36Sopenharmony_ci */ 30462306a36Sopenharmony_cistatic int common_perm_create(const char *op, const struct path *dir, 30562306a36Sopenharmony_ci struct dentry *dentry, u32 mask, umode_t mode) 30662306a36Sopenharmony_ci{ 30762306a36Sopenharmony_ci struct path_cond cond = { current_fsuid(), mode }; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci if (!path_mediated_fs(dir->dentry)) 31062306a36Sopenharmony_ci return 0; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci return common_perm_dir_dentry(op, dir, dentry, mask, &cond); 31362306a36Sopenharmony_ci} 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_cistatic int apparmor_path_unlink(const struct path *dir, struct dentry *dentry) 31662306a36Sopenharmony_ci{ 31762306a36Sopenharmony_ci return common_perm_rm(OP_UNLINK, dir, dentry, AA_MAY_DELETE); 31862306a36Sopenharmony_ci} 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_cistatic int apparmor_path_mkdir(const struct path *dir, struct dentry *dentry, 32162306a36Sopenharmony_ci umode_t mode) 32262306a36Sopenharmony_ci{ 32362306a36Sopenharmony_ci return common_perm_create(OP_MKDIR, dir, dentry, AA_MAY_CREATE, 32462306a36Sopenharmony_ci S_IFDIR); 32562306a36Sopenharmony_ci} 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_cistatic int apparmor_path_rmdir(const struct path *dir, struct dentry *dentry) 32862306a36Sopenharmony_ci{ 32962306a36Sopenharmony_ci return common_perm_rm(OP_RMDIR, dir, dentry, AA_MAY_DELETE); 33062306a36Sopenharmony_ci} 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_cistatic int apparmor_path_mknod(const struct path *dir, struct dentry *dentry, 33362306a36Sopenharmony_ci umode_t mode, unsigned int dev) 33462306a36Sopenharmony_ci{ 33562306a36Sopenharmony_ci return common_perm_create(OP_MKNOD, dir, dentry, AA_MAY_CREATE, mode); 33662306a36Sopenharmony_ci} 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_cistatic int apparmor_path_truncate(const struct path *path) 33962306a36Sopenharmony_ci{ 34062306a36Sopenharmony_ci return common_perm_cond(OP_TRUNC, path, MAY_WRITE | AA_MAY_SETATTR); 34162306a36Sopenharmony_ci} 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_cistatic int apparmor_file_truncate(struct file *file) 34462306a36Sopenharmony_ci{ 34562306a36Sopenharmony_ci return apparmor_path_truncate(&file->f_path); 34662306a36Sopenharmony_ci} 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_cistatic int apparmor_path_symlink(const struct path *dir, struct dentry *dentry, 34962306a36Sopenharmony_ci const char *old_name) 35062306a36Sopenharmony_ci{ 35162306a36Sopenharmony_ci return common_perm_create(OP_SYMLINK, dir, dentry, AA_MAY_CREATE, 35262306a36Sopenharmony_ci S_IFLNK); 35362306a36Sopenharmony_ci} 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_cistatic int apparmor_path_link(struct dentry *old_dentry, const struct path *new_dir, 35662306a36Sopenharmony_ci struct dentry *new_dentry) 35762306a36Sopenharmony_ci{ 35862306a36Sopenharmony_ci struct aa_label *label; 35962306a36Sopenharmony_ci int error = 0; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci if (!path_mediated_fs(old_dentry)) 36262306a36Sopenharmony_ci return 0; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci label = begin_current_label_crit_section(); 36562306a36Sopenharmony_ci if (!unconfined(label)) 36662306a36Sopenharmony_ci error = aa_path_link(current_cred(), label, old_dentry, new_dir, 36762306a36Sopenharmony_ci new_dentry); 36862306a36Sopenharmony_ci end_current_label_crit_section(label); 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci return error; 37162306a36Sopenharmony_ci} 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_cistatic int apparmor_path_rename(const struct path *old_dir, struct dentry *old_dentry, 37462306a36Sopenharmony_ci const struct path *new_dir, struct dentry *new_dentry, 37562306a36Sopenharmony_ci const unsigned int flags) 37662306a36Sopenharmony_ci{ 37762306a36Sopenharmony_ci struct aa_label *label; 37862306a36Sopenharmony_ci int error = 0; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci if (!path_mediated_fs(old_dentry)) 38162306a36Sopenharmony_ci return 0; 38262306a36Sopenharmony_ci if ((flags & RENAME_EXCHANGE) && !path_mediated_fs(new_dentry)) 38362306a36Sopenharmony_ci return 0; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci label = begin_current_label_crit_section(); 38662306a36Sopenharmony_ci if (!unconfined(label)) { 38762306a36Sopenharmony_ci struct mnt_idmap *idmap = mnt_idmap(old_dir->mnt); 38862306a36Sopenharmony_ci vfsuid_t vfsuid; 38962306a36Sopenharmony_ci struct path old_path = { .mnt = old_dir->mnt, 39062306a36Sopenharmony_ci .dentry = old_dentry }; 39162306a36Sopenharmony_ci struct path new_path = { .mnt = new_dir->mnt, 39262306a36Sopenharmony_ci .dentry = new_dentry }; 39362306a36Sopenharmony_ci struct path_cond cond = { 39462306a36Sopenharmony_ci .mode = d_backing_inode(old_dentry)->i_mode 39562306a36Sopenharmony_ci }; 39662306a36Sopenharmony_ci vfsuid = i_uid_into_vfsuid(idmap, d_backing_inode(old_dentry)); 39762306a36Sopenharmony_ci cond.uid = vfsuid_into_kuid(vfsuid); 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci if (flags & RENAME_EXCHANGE) { 40062306a36Sopenharmony_ci struct path_cond cond_exchange = { 40162306a36Sopenharmony_ci .mode = d_backing_inode(new_dentry)->i_mode, 40262306a36Sopenharmony_ci }; 40362306a36Sopenharmony_ci vfsuid = i_uid_into_vfsuid(idmap, d_backing_inode(old_dentry)); 40462306a36Sopenharmony_ci cond_exchange.uid = vfsuid_into_kuid(vfsuid); 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci error = aa_path_perm(OP_RENAME_SRC, current_cred(), 40762306a36Sopenharmony_ci label, &new_path, 0, 40862306a36Sopenharmony_ci MAY_READ | AA_MAY_GETATTR | MAY_WRITE | 40962306a36Sopenharmony_ci AA_MAY_SETATTR | AA_MAY_DELETE, 41062306a36Sopenharmony_ci &cond_exchange); 41162306a36Sopenharmony_ci if (!error) 41262306a36Sopenharmony_ci error = aa_path_perm(OP_RENAME_DEST, current_cred(), 41362306a36Sopenharmony_ci label, &old_path, 41462306a36Sopenharmony_ci 0, MAY_WRITE | AA_MAY_SETATTR | 41562306a36Sopenharmony_ci AA_MAY_CREATE, &cond_exchange); 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci if (!error) 41962306a36Sopenharmony_ci error = aa_path_perm(OP_RENAME_SRC, current_cred(), 42062306a36Sopenharmony_ci label, &old_path, 0, 42162306a36Sopenharmony_ci MAY_READ | AA_MAY_GETATTR | MAY_WRITE | 42262306a36Sopenharmony_ci AA_MAY_SETATTR | AA_MAY_DELETE, 42362306a36Sopenharmony_ci &cond); 42462306a36Sopenharmony_ci if (!error) 42562306a36Sopenharmony_ci error = aa_path_perm(OP_RENAME_DEST, current_cred(), 42662306a36Sopenharmony_ci label, &new_path, 42762306a36Sopenharmony_ci 0, MAY_WRITE | AA_MAY_SETATTR | 42862306a36Sopenharmony_ci AA_MAY_CREATE, &cond); 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci } 43162306a36Sopenharmony_ci end_current_label_crit_section(label); 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci return error; 43462306a36Sopenharmony_ci} 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_cistatic int apparmor_path_chmod(const struct path *path, umode_t mode) 43762306a36Sopenharmony_ci{ 43862306a36Sopenharmony_ci return common_perm_cond(OP_CHMOD, path, AA_MAY_CHMOD); 43962306a36Sopenharmony_ci} 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_cistatic int apparmor_path_chown(const struct path *path, kuid_t uid, kgid_t gid) 44262306a36Sopenharmony_ci{ 44362306a36Sopenharmony_ci return common_perm_cond(OP_CHOWN, path, AA_MAY_CHOWN); 44462306a36Sopenharmony_ci} 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_cistatic int apparmor_inode_getattr(const struct path *path) 44762306a36Sopenharmony_ci{ 44862306a36Sopenharmony_ci return common_perm_cond(OP_GETATTR, path, AA_MAY_GETATTR); 44962306a36Sopenharmony_ci} 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_cistatic int apparmor_file_open(struct file *file) 45262306a36Sopenharmony_ci{ 45362306a36Sopenharmony_ci struct aa_file_ctx *fctx = file_ctx(file); 45462306a36Sopenharmony_ci struct aa_label *label; 45562306a36Sopenharmony_ci int error = 0; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci if (!path_mediated_fs(file->f_path.dentry)) 45862306a36Sopenharmony_ci return 0; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci /* If in exec, permission is handled by bprm hooks. 46162306a36Sopenharmony_ci * Cache permissions granted by the previous exec check, with 46262306a36Sopenharmony_ci * implicit read and executable mmap which are required to 46362306a36Sopenharmony_ci * actually execute the image. 46462306a36Sopenharmony_ci */ 46562306a36Sopenharmony_ci if (current->in_execve) { 46662306a36Sopenharmony_ci fctx->allow = MAY_EXEC | MAY_READ | AA_EXEC_MMAP; 46762306a36Sopenharmony_ci return 0; 46862306a36Sopenharmony_ci } 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci label = aa_get_newest_cred_label(file->f_cred); 47162306a36Sopenharmony_ci if (!unconfined(label)) { 47262306a36Sopenharmony_ci struct mnt_idmap *idmap = file_mnt_idmap(file); 47362306a36Sopenharmony_ci struct inode *inode = file_inode(file); 47462306a36Sopenharmony_ci vfsuid_t vfsuid; 47562306a36Sopenharmony_ci struct path_cond cond = { 47662306a36Sopenharmony_ci .mode = inode->i_mode, 47762306a36Sopenharmony_ci }; 47862306a36Sopenharmony_ci vfsuid = i_uid_into_vfsuid(idmap, inode); 47962306a36Sopenharmony_ci cond.uid = vfsuid_into_kuid(vfsuid); 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci error = aa_path_perm(OP_OPEN, file->f_cred, 48262306a36Sopenharmony_ci label, &file->f_path, 0, 48362306a36Sopenharmony_ci aa_map_file_to_perms(file), &cond); 48462306a36Sopenharmony_ci /* todo cache full allowed permissions set and state */ 48562306a36Sopenharmony_ci fctx->allow = aa_map_file_to_perms(file); 48662306a36Sopenharmony_ci } 48762306a36Sopenharmony_ci aa_put_label(label); 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci return error; 49062306a36Sopenharmony_ci} 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_cistatic int apparmor_file_alloc_security(struct file *file) 49362306a36Sopenharmony_ci{ 49462306a36Sopenharmony_ci struct aa_file_ctx *ctx = file_ctx(file); 49562306a36Sopenharmony_ci struct aa_label *label = begin_current_label_crit_section(); 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci spin_lock_init(&ctx->lock); 49862306a36Sopenharmony_ci rcu_assign_pointer(ctx->label, aa_get_label(label)); 49962306a36Sopenharmony_ci end_current_label_crit_section(label); 50062306a36Sopenharmony_ci return 0; 50162306a36Sopenharmony_ci} 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_cistatic void apparmor_file_free_security(struct file *file) 50462306a36Sopenharmony_ci{ 50562306a36Sopenharmony_ci struct aa_file_ctx *ctx = file_ctx(file); 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci if (ctx) 50862306a36Sopenharmony_ci aa_put_label(rcu_access_pointer(ctx->label)); 50962306a36Sopenharmony_ci} 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_cistatic int common_file_perm(const char *op, struct file *file, u32 mask, 51262306a36Sopenharmony_ci bool in_atomic) 51362306a36Sopenharmony_ci{ 51462306a36Sopenharmony_ci struct aa_label *label; 51562306a36Sopenharmony_ci int error = 0; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci /* don't reaudit files closed during inheritance */ 51862306a36Sopenharmony_ci if (file->f_path.dentry == aa_null.dentry) 51962306a36Sopenharmony_ci return -EACCES; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci label = __begin_current_label_crit_section(); 52262306a36Sopenharmony_ci error = aa_file_perm(op, current_cred(), label, file, mask, in_atomic); 52362306a36Sopenharmony_ci __end_current_label_crit_section(label); 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci return error; 52662306a36Sopenharmony_ci} 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_cistatic int apparmor_file_receive(struct file *file) 52962306a36Sopenharmony_ci{ 53062306a36Sopenharmony_ci return common_file_perm(OP_FRECEIVE, file, aa_map_file_to_perms(file), 53162306a36Sopenharmony_ci false); 53262306a36Sopenharmony_ci} 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_cistatic int apparmor_file_permission(struct file *file, int mask) 53562306a36Sopenharmony_ci{ 53662306a36Sopenharmony_ci return common_file_perm(OP_FPERM, file, mask, false); 53762306a36Sopenharmony_ci} 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_cistatic int apparmor_file_lock(struct file *file, unsigned int cmd) 54062306a36Sopenharmony_ci{ 54162306a36Sopenharmony_ci u32 mask = AA_MAY_LOCK; 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci if (cmd == F_WRLCK) 54462306a36Sopenharmony_ci mask |= MAY_WRITE; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci return common_file_perm(OP_FLOCK, file, mask, false); 54762306a36Sopenharmony_ci} 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_cistatic int common_mmap(const char *op, struct file *file, unsigned long prot, 55062306a36Sopenharmony_ci unsigned long flags, bool in_atomic) 55162306a36Sopenharmony_ci{ 55262306a36Sopenharmony_ci int mask = 0; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci if (!file || !file_ctx(file)) 55562306a36Sopenharmony_ci return 0; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci if (prot & PROT_READ) 55862306a36Sopenharmony_ci mask |= MAY_READ; 55962306a36Sopenharmony_ci /* 56062306a36Sopenharmony_ci * Private mappings don't require write perms since they don't 56162306a36Sopenharmony_ci * write back to the files 56262306a36Sopenharmony_ci */ 56362306a36Sopenharmony_ci if ((prot & PROT_WRITE) && !(flags & MAP_PRIVATE)) 56462306a36Sopenharmony_ci mask |= MAY_WRITE; 56562306a36Sopenharmony_ci if (prot & PROT_EXEC) 56662306a36Sopenharmony_ci mask |= AA_EXEC_MMAP; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci return common_file_perm(op, file, mask, in_atomic); 56962306a36Sopenharmony_ci} 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_cistatic int apparmor_mmap_file(struct file *file, unsigned long reqprot, 57262306a36Sopenharmony_ci unsigned long prot, unsigned long flags) 57362306a36Sopenharmony_ci{ 57462306a36Sopenharmony_ci return common_mmap(OP_FMMAP, file, prot, flags, GFP_ATOMIC); 57562306a36Sopenharmony_ci} 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_cistatic int apparmor_file_mprotect(struct vm_area_struct *vma, 57862306a36Sopenharmony_ci unsigned long reqprot, unsigned long prot) 57962306a36Sopenharmony_ci{ 58062306a36Sopenharmony_ci return common_mmap(OP_FMPROT, vma->vm_file, prot, 58162306a36Sopenharmony_ci !(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0, 58262306a36Sopenharmony_ci false); 58362306a36Sopenharmony_ci} 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_cistatic int apparmor_sb_mount(const char *dev_name, const struct path *path, 58662306a36Sopenharmony_ci const char *type, unsigned long flags, void *data) 58762306a36Sopenharmony_ci{ 58862306a36Sopenharmony_ci struct aa_label *label; 58962306a36Sopenharmony_ci int error = 0; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci /* Discard magic */ 59262306a36Sopenharmony_ci if ((flags & MS_MGC_MSK) == MS_MGC_VAL) 59362306a36Sopenharmony_ci flags &= ~MS_MGC_MSK; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci flags &= ~AA_MS_IGNORE_MASK; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci label = __begin_current_label_crit_section(); 59862306a36Sopenharmony_ci if (!unconfined(label)) { 59962306a36Sopenharmony_ci if (flags & MS_REMOUNT) 60062306a36Sopenharmony_ci error = aa_remount(current_cred(), label, path, flags, 60162306a36Sopenharmony_ci data); 60262306a36Sopenharmony_ci else if (flags & MS_BIND) 60362306a36Sopenharmony_ci error = aa_bind_mount(current_cred(), label, path, 60462306a36Sopenharmony_ci dev_name, flags); 60562306a36Sopenharmony_ci else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | 60662306a36Sopenharmony_ci MS_UNBINDABLE)) 60762306a36Sopenharmony_ci error = aa_mount_change_type(current_cred(), label, 60862306a36Sopenharmony_ci path, flags); 60962306a36Sopenharmony_ci else if (flags & MS_MOVE) 61062306a36Sopenharmony_ci error = aa_move_mount_old(current_cred(), label, path, 61162306a36Sopenharmony_ci dev_name); 61262306a36Sopenharmony_ci else 61362306a36Sopenharmony_ci error = aa_new_mount(current_cred(), label, dev_name, 61462306a36Sopenharmony_ci path, type, flags, data); 61562306a36Sopenharmony_ci } 61662306a36Sopenharmony_ci __end_current_label_crit_section(label); 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci return error; 61962306a36Sopenharmony_ci} 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_cistatic int apparmor_move_mount(const struct path *from_path, 62262306a36Sopenharmony_ci const struct path *to_path) 62362306a36Sopenharmony_ci{ 62462306a36Sopenharmony_ci struct aa_label *label; 62562306a36Sopenharmony_ci int error = 0; 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci label = __begin_current_label_crit_section(); 62862306a36Sopenharmony_ci if (!unconfined(label)) 62962306a36Sopenharmony_ci error = aa_move_mount(current_cred(), label, from_path, 63062306a36Sopenharmony_ci to_path); 63162306a36Sopenharmony_ci __end_current_label_crit_section(label); 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci return error; 63462306a36Sopenharmony_ci} 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_cistatic int apparmor_sb_umount(struct vfsmount *mnt, int flags) 63762306a36Sopenharmony_ci{ 63862306a36Sopenharmony_ci struct aa_label *label; 63962306a36Sopenharmony_ci int error = 0; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci label = __begin_current_label_crit_section(); 64262306a36Sopenharmony_ci if (!unconfined(label)) 64362306a36Sopenharmony_ci error = aa_umount(current_cred(), label, mnt, flags); 64462306a36Sopenharmony_ci __end_current_label_crit_section(label); 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci return error; 64762306a36Sopenharmony_ci} 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_cistatic int apparmor_sb_pivotroot(const struct path *old_path, 65062306a36Sopenharmony_ci const struct path *new_path) 65162306a36Sopenharmony_ci{ 65262306a36Sopenharmony_ci struct aa_label *label; 65362306a36Sopenharmony_ci int error = 0; 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci label = aa_get_current_label(); 65662306a36Sopenharmony_ci if (!unconfined(label)) 65762306a36Sopenharmony_ci error = aa_pivotroot(current_cred(), label, old_path, new_path); 65862306a36Sopenharmony_ci aa_put_label(label); 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci return error; 66162306a36Sopenharmony_ci} 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_cistatic int apparmor_getprocattr(struct task_struct *task, const char *name, 66462306a36Sopenharmony_ci char **value) 66562306a36Sopenharmony_ci{ 66662306a36Sopenharmony_ci int error = -ENOENT; 66762306a36Sopenharmony_ci /* released below */ 66862306a36Sopenharmony_ci const struct cred *cred = get_task_cred(task); 66962306a36Sopenharmony_ci struct aa_task_ctx *ctx = task_ctx(current); 67062306a36Sopenharmony_ci struct aa_label *label = NULL; 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci if (strcmp(name, "current") == 0) 67362306a36Sopenharmony_ci label = aa_get_newest_label(cred_label(cred)); 67462306a36Sopenharmony_ci else if (strcmp(name, "prev") == 0 && ctx->previous) 67562306a36Sopenharmony_ci label = aa_get_newest_label(ctx->previous); 67662306a36Sopenharmony_ci else if (strcmp(name, "exec") == 0 && ctx->onexec) 67762306a36Sopenharmony_ci label = aa_get_newest_label(ctx->onexec); 67862306a36Sopenharmony_ci else 67962306a36Sopenharmony_ci error = -EINVAL; 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci if (label) 68262306a36Sopenharmony_ci error = aa_getprocattr(label, value); 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci aa_put_label(label); 68562306a36Sopenharmony_ci put_cred(cred); 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci return error; 68862306a36Sopenharmony_ci} 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_cistatic int apparmor_setprocattr(const char *name, void *value, 69162306a36Sopenharmony_ci size_t size) 69262306a36Sopenharmony_ci{ 69362306a36Sopenharmony_ci char *command, *largs = NULL, *args = value; 69462306a36Sopenharmony_ci size_t arg_size; 69562306a36Sopenharmony_ci int error; 69662306a36Sopenharmony_ci DEFINE_AUDIT_DATA(ad, LSM_AUDIT_DATA_NONE, AA_CLASS_NONE, 69762306a36Sopenharmony_ci OP_SETPROCATTR); 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci if (size == 0) 70062306a36Sopenharmony_ci return -EINVAL; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci /* AppArmor requires that the buffer must be null terminated atm */ 70362306a36Sopenharmony_ci if (args[size - 1] != '\0') { 70462306a36Sopenharmony_ci /* null terminate */ 70562306a36Sopenharmony_ci largs = args = kmalloc(size + 1, GFP_KERNEL); 70662306a36Sopenharmony_ci if (!args) 70762306a36Sopenharmony_ci return -ENOMEM; 70862306a36Sopenharmony_ci memcpy(args, value, size); 70962306a36Sopenharmony_ci args[size] = '\0'; 71062306a36Sopenharmony_ci } 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci error = -EINVAL; 71362306a36Sopenharmony_ci args = strim(args); 71462306a36Sopenharmony_ci command = strsep(&args, " "); 71562306a36Sopenharmony_ci if (!args) 71662306a36Sopenharmony_ci goto out; 71762306a36Sopenharmony_ci args = skip_spaces(args); 71862306a36Sopenharmony_ci if (!*args) 71962306a36Sopenharmony_ci goto out; 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci arg_size = size - (args - (largs ? largs : (char *) value)); 72262306a36Sopenharmony_ci if (strcmp(name, "current") == 0) { 72362306a36Sopenharmony_ci if (strcmp(command, "changehat") == 0) { 72462306a36Sopenharmony_ci error = aa_setprocattr_changehat(args, arg_size, 72562306a36Sopenharmony_ci AA_CHANGE_NOFLAGS); 72662306a36Sopenharmony_ci } else if (strcmp(command, "permhat") == 0) { 72762306a36Sopenharmony_ci error = aa_setprocattr_changehat(args, arg_size, 72862306a36Sopenharmony_ci AA_CHANGE_TEST); 72962306a36Sopenharmony_ci } else if (strcmp(command, "changeprofile") == 0) { 73062306a36Sopenharmony_ci error = aa_change_profile(args, AA_CHANGE_NOFLAGS); 73162306a36Sopenharmony_ci } else if (strcmp(command, "permprofile") == 0) { 73262306a36Sopenharmony_ci error = aa_change_profile(args, AA_CHANGE_TEST); 73362306a36Sopenharmony_ci } else if (strcmp(command, "stack") == 0) { 73462306a36Sopenharmony_ci error = aa_change_profile(args, AA_CHANGE_STACK); 73562306a36Sopenharmony_ci } else 73662306a36Sopenharmony_ci goto fail; 73762306a36Sopenharmony_ci } else if (strcmp(name, "exec") == 0) { 73862306a36Sopenharmony_ci if (strcmp(command, "exec") == 0) 73962306a36Sopenharmony_ci error = aa_change_profile(args, AA_CHANGE_ONEXEC); 74062306a36Sopenharmony_ci else if (strcmp(command, "stack") == 0) 74162306a36Sopenharmony_ci error = aa_change_profile(args, (AA_CHANGE_ONEXEC | 74262306a36Sopenharmony_ci AA_CHANGE_STACK)); 74362306a36Sopenharmony_ci else 74462306a36Sopenharmony_ci goto fail; 74562306a36Sopenharmony_ci } else 74662306a36Sopenharmony_ci /* only support the "current" and "exec" process attributes */ 74762306a36Sopenharmony_ci goto fail; 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci if (!error) 75062306a36Sopenharmony_ci error = size; 75162306a36Sopenharmony_ciout: 75262306a36Sopenharmony_ci kfree(largs); 75362306a36Sopenharmony_ci return error; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_cifail: 75662306a36Sopenharmony_ci ad.subj_label = begin_current_label_crit_section(); 75762306a36Sopenharmony_ci ad.info = name; 75862306a36Sopenharmony_ci ad.error = error = -EINVAL; 75962306a36Sopenharmony_ci aa_audit_msg(AUDIT_APPARMOR_DENIED, &ad, NULL); 76062306a36Sopenharmony_ci end_current_label_crit_section(ad.subj_label); 76162306a36Sopenharmony_ci goto out; 76262306a36Sopenharmony_ci} 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci/** 76562306a36Sopenharmony_ci * apparmor_bprm_committing_creds - do task cleanup on committing new creds 76662306a36Sopenharmony_ci * @bprm: binprm for the exec (NOT NULL) 76762306a36Sopenharmony_ci */ 76862306a36Sopenharmony_cistatic void apparmor_bprm_committing_creds(struct linux_binprm *bprm) 76962306a36Sopenharmony_ci{ 77062306a36Sopenharmony_ci struct aa_label *label = aa_current_raw_label(); 77162306a36Sopenharmony_ci struct aa_label *new_label = cred_label(bprm->cred); 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci /* bail out if unconfined or not changing profile */ 77462306a36Sopenharmony_ci if ((new_label->proxy == label->proxy) || 77562306a36Sopenharmony_ci (unconfined(new_label))) 77662306a36Sopenharmony_ci return; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci aa_inherit_files(bprm->cred, current->files); 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci current->pdeath_signal = 0; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci /* reset soft limits and set hard limits for the new label */ 78362306a36Sopenharmony_ci __aa_transition_rlimits(label, new_label); 78462306a36Sopenharmony_ci} 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci/** 78762306a36Sopenharmony_ci * apparmor_bprm_committed_creds() - do cleanup after new creds committed 78862306a36Sopenharmony_ci * @bprm: binprm for the exec (NOT NULL) 78962306a36Sopenharmony_ci */ 79062306a36Sopenharmony_cistatic void apparmor_bprm_committed_creds(struct linux_binprm *bprm) 79162306a36Sopenharmony_ci{ 79262306a36Sopenharmony_ci /* clear out temporary/transitional state from the context */ 79362306a36Sopenharmony_ci aa_clear_task_ctx_trans(task_ctx(current)); 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci return; 79662306a36Sopenharmony_ci} 79762306a36Sopenharmony_ci 79862306a36Sopenharmony_cistatic void apparmor_current_getsecid_subj(u32 *secid) 79962306a36Sopenharmony_ci{ 80062306a36Sopenharmony_ci struct aa_label *label = aa_get_current_label(); 80162306a36Sopenharmony_ci *secid = label->secid; 80262306a36Sopenharmony_ci aa_put_label(label); 80362306a36Sopenharmony_ci} 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_cistatic void apparmor_task_getsecid_obj(struct task_struct *p, u32 *secid) 80662306a36Sopenharmony_ci{ 80762306a36Sopenharmony_ci struct aa_label *label = aa_get_task_label(p); 80862306a36Sopenharmony_ci *secid = label->secid; 80962306a36Sopenharmony_ci aa_put_label(label); 81062306a36Sopenharmony_ci} 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_cistatic int apparmor_task_setrlimit(struct task_struct *task, 81362306a36Sopenharmony_ci unsigned int resource, struct rlimit *new_rlim) 81462306a36Sopenharmony_ci{ 81562306a36Sopenharmony_ci struct aa_label *label = __begin_current_label_crit_section(); 81662306a36Sopenharmony_ci int error = 0; 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci if (!unconfined(label)) 81962306a36Sopenharmony_ci error = aa_task_setrlimit(current_cred(), label, task, 82062306a36Sopenharmony_ci resource, new_rlim); 82162306a36Sopenharmony_ci __end_current_label_crit_section(label); 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci return error; 82462306a36Sopenharmony_ci} 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_cistatic int apparmor_task_kill(struct task_struct *target, struct kernel_siginfo *info, 82762306a36Sopenharmony_ci int sig, const struct cred *cred) 82862306a36Sopenharmony_ci{ 82962306a36Sopenharmony_ci const struct cred *tc; 83062306a36Sopenharmony_ci struct aa_label *cl, *tl; 83162306a36Sopenharmony_ci int error; 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci tc = get_task_cred(target); 83462306a36Sopenharmony_ci tl = aa_get_newest_cred_label(tc); 83562306a36Sopenharmony_ci if (cred) { 83662306a36Sopenharmony_ci /* 83762306a36Sopenharmony_ci * Dealing with USB IO specific behavior 83862306a36Sopenharmony_ci */ 83962306a36Sopenharmony_ci cl = aa_get_newest_cred_label(cred); 84062306a36Sopenharmony_ci error = aa_may_signal(cred, cl, tc, tl, sig); 84162306a36Sopenharmony_ci aa_put_label(cl); 84262306a36Sopenharmony_ci } else { 84362306a36Sopenharmony_ci cl = __begin_current_label_crit_section(); 84462306a36Sopenharmony_ci error = aa_may_signal(current_cred(), cl, tc, tl, sig); 84562306a36Sopenharmony_ci __end_current_label_crit_section(cl); 84662306a36Sopenharmony_ci } 84762306a36Sopenharmony_ci aa_put_label(tl); 84862306a36Sopenharmony_ci put_cred(tc); 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci return error; 85162306a36Sopenharmony_ci} 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci/** 85462306a36Sopenharmony_ci * apparmor_sk_alloc_security - allocate and attach the sk_security field 85562306a36Sopenharmony_ci */ 85662306a36Sopenharmony_cistatic int apparmor_sk_alloc_security(struct sock *sk, int family, gfp_t flags) 85762306a36Sopenharmony_ci{ 85862306a36Sopenharmony_ci struct aa_sk_ctx *ctx; 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci ctx = kzalloc(sizeof(*ctx), flags); 86162306a36Sopenharmony_ci if (!ctx) 86262306a36Sopenharmony_ci return -ENOMEM; 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci SK_CTX(sk) = ctx; 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci return 0; 86762306a36Sopenharmony_ci} 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci/** 87062306a36Sopenharmony_ci * apparmor_sk_free_security - free the sk_security field 87162306a36Sopenharmony_ci */ 87262306a36Sopenharmony_cistatic void apparmor_sk_free_security(struct sock *sk) 87362306a36Sopenharmony_ci{ 87462306a36Sopenharmony_ci struct aa_sk_ctx *ctx = SK_CTX(sk); 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci SK_CTX(sk) = NULL; 87762306a36Sopenharmony_ci aa_put_label(ctx->label); 87862306a36Sopenharmony_ci aa_put_label(ctx->peer); 87962306a36Sopenharmony_ci kfree(ctx); 88062306a36Sopenharmony_ci} 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci/** 88362306a36Sopenharmony_ci * apparmor_sk_clone_security - clone the sk_security field 88462306a36Sopenharmony_ci */ 88562306a36Sopenharmony_cistatic void apparmor_sk_clone_security(const struct sock *sk, 88662306a36Sopenharmony_ci struct sock *newsk) 88762306a36Sopenharmony_ci{ 88862306a36Sopenharmony_ci struct aa_sk_ctx *ctx = SK_CTX(sk); 88962306a36Sopenharmony_ci struct aa_sk_ctx *new = SK_CTX(newsk); 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci if (new->label) 89262306a36Sopenharmony_ci aa_put_label(new->label); 89362306a36Sopenharmony_ci new->label = aa_get_label(ctx->label); 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci if (new->peer) 89662306a36Sopenharmony_ci aa_put_label(new->peer); 89762306a36Sopenharmony_ci new->peer = aa_get_label(ctx->peer); 89862306a36Sopenharmony_ci} 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci/** 90162306a36Sopenharmony_ci * apparmor_socket_create - check perms before creating a new socket 90262306a36Sopenharmony_ci */ 90362306a36Sopenharmony_cistatic int apparmor_socket_create(int family, int type, int protocol, int kern) 90462306a36Sopenharmony_ci{ 90562306a36Sopenharmony_ci struct aa_label *label; 90662306a36Sopenharmony_ci int error = 0; 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci AA_BUG(in_interrupt()); 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci label = begin_current_label_crit_section(); 91162306a36Sopenharmony_ci if (!(kern || unconfined(label))) 91262306a36Sopenharmony_ci error = af_select(family, 91362306a36Sopenharmony_ci create_perm(label, family, type, protocol), 91462306a36Sopenharmony_ci aa_af_perm(current_cred(), label, 91562306a36Sopenharmony_ci OP_CREATE, AA_MAY_CREATE, 91662306a36Sopenharmony_ci family, type, protocol)); 91762306a36Sopenharmony_ci end_current_label_crit_section(label); 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci return error; 92062306a36Sopenharmony_ci} 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci/** 92362306a36Sopenharmony_ci * apparmor_socket_post_create - setup the per-socket security struct 92462306a36Sopenharmony_ci * 92562306a36Sopenharmony_ci * Note: 92662306a36Sopenharmony_ci * - kernel sockets currently labeled unconfined but we may want to 92762306a36Sopenharmony_ci * move to a special kernel label 92862306a36Sopenharmony_ci * - socket may not have sk here if created with sock_create_lite or 92962306a36Sopenharmony_ci * sock_alloc. These should be accept cases which will be handled in 93062306a36Sopenharmony_ci * sock_graft. 93162306a36Sopenharmony_ci */ 93262306a36Sopenharmony_cistatic int apparmor_socket_post_create(struct socket *sock, int family, 93362306a36Sopenharmony_ci int type, int protocol, int kern) 93462306a36Sopenharmony_ci{ 93562306a36Sopenharmony_ci struct aa_label *label; 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci if (kern) { 93862306a36Sopenharmony_ci label = aa_get_label(kernel_t); 93962306a36Sopenharmony_ci } else 94062306a36Sopenharmony_ci label = aa_get_current_label(); 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci if (sock->sk) { 94362306a36Sopenharmony_ci struct aa_sk_ctx *ctx = SK_CTX(sock->sk); 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci aa_put_label(ctx->label); 94662306a36Sopenharmony_ci ctx->label = aa_get_label(label); 94762306a36Sopenharmony_ci } 94862306a36Sopenharmony_ci aa_put_label(label); 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci return 0; 95162306a36Sopenharmony_ci} 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci/** 95462306a36Sopenharmony_ci * apparmor_socket_bind - check perms before bind addr to socket 95562306a36Sopenharmony_ci */ 95662306a36Sopenharmony_cistatic int apparmor_socket_bind(struct socket *sock, 95762306a36Sopenharmony_ci struct sockaddr *address, int addrlen) 95862306a36Sopenharmony_ci{ 95962306a36Sopenharmony_ci AA_BUG(!sock); 96062306a36Sopenharmony_ci AA_BUG(!sock->sk); 96162306a36Sopenharmony_ci AA_BUG(!address); 96262306a36Sopenharmony_ci AA_BUG(in_interrupt()); 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci return af_select(sock->sk->sk_family, 96562306a36Sopenharmony_ci bind_perm(sock, address, addrlen), 96662306a36Sopenharmony_ci aa_sk_perm(OP_BIND, AA_MAY_BIND, sock->sk)); 96762306a36Sopenharmony_ci} 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci/** 97062306a36Sopenharmony_ci * apparmor_socket_connect - check perms before connecting @sock to @address 97162306a36Sopenharmony_ci */ 97262306a36Sopenharmony_cistatic int apparmor_socket_connect(struct socket *sock, 97362306a36Sopenharmony_ci struct sockaddr *address, int addrlen) 97462306a36Sopenharmony_ci{ 97562306a36Sopenharmony_ci AA_BUG(!sock); 97662306a36Sopenharmony_ci AA_BUG(!sock->sk); 97762306a36Sopenharmony_ci AA_BUG(!address); 97862306a36Sopenharmony_ci AA_BUG(in_interrupt()); 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci return af_select(sock->sk->sk_family, 98162306a36Sopenharmony_ci connect_perm(sock, address, addrlen), 98262306a36Sopenharmony_ci aa_sk_perm(OP_CONNECT, AA_MAY_CONNECT, sock->sk)); 98362306a36Sopenharmony_ci} 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci/** 98662306a36Sopenharmony_ci * apparmor_socket_listen - check perms before allowing listen 98762306a36Sopenharmony_ci */ 98862306a36Sopenharmony_cistatic int apparmor_socket_listen(struct socket *sock, int backlog) 98962306a36Sopenharmony_ci{ 99062306a36Sopenharmony_ci AA_BUG(!sock); 99162306a36Sopenharmony_ci AA_BUG(!sock->sk); 99262306a36Sopenharmony_ci AA_BUG(in_interrupt()); 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci return af_select(sock->sk->sk_family, 99562306a36Sopenharmony_ci listen_perm(sock, backlog), 99662306a36Sopenharmony_ci aa_sk_perm(OP_LISTEN, AA_MAY_LISTEN, sock->sk)); 99762306a36Sopenharmony_ci} 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci/** 100062306a36Sopenharmony_ci * apparmor_socket_accept - check perms before accepting a new connection. 100162306a36Sopenharmony_ci * 100262306a36Sopenharmony_ci * Note: while @newsock is created and has some information, the accept 100362306a36Sopenharmony_ci * has not been done. 100462306a36Sopenharmony_ci */ 100562306a36Sopenharmony_cistatic int apparmor_socket_accept(struct socket *sock, struct socket *newsock) 100662306a36Sopenharmony_ci{ 100762306a36Sopenharmony_ci AA_BUG(!sock); 100862306a36Sopenharmony_ci AA_BUG(!sock->sk); 100962306a36Sopenharmony_ci AA_BUG(!newsock); 101062306a36Sopenharmony_ci AA_BUG(in_interrupt()); 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci return af_select(sock->sk->sk_family, 101362306a36Sopenharmony_ci accept_perm(sock, newsock), 101462306a36Sopenharmony_ci aa_sk_perm(OP_ACCEPT, AA_MAY_ACCEPT, sock->sk)); 101562306a36Sopenharmony_ci} 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_cistatic int aa_sock_msg_perm(const char *op, u32 request, struct socket *sock, 101862306a36Sopenharmony_ci struct msghdr *msg, int size) 101962306a36Sopenharmony_ci{ 102062306a36Sopenharmony_ci AA_BUG(!sock); 102162306a36Sopenharmony_ci AA_BUG(!sock->sk); 102262306a36Sopenharmony_ci AA_BUG(!msg); 102362306a36Sopenharmony_ci AA_BUG(in_interrupt()); 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci return af_select(sock->sk->sk_family, 102662306a36Sopenharmony_ci msg_perm(op, request, sock, msg, size), 102762306a36Sopenharmony_ci aa_sk_perm(op, request, sock->sk)); 102862306a36Sopenharmony_ci} 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci/** 103162306a36Sopenharmony_ci * apparmor_socket_sendmsg - check perms before sending msg to another socket 103262306a36Sopenharmony_ci */ 103362306a36Sopenharmony_cistatic int apparmor_socket_sendmsg(struct socket *sock, 103462306a36Sopenharmony_ci struct msghdr *msg, int size) 103562306a36Sopenharmony_ci{ 103662306a36Sopenharmony_ci return aa_sock_msg_perm(OP_SENDMSG, AA_MAY_SEND, sock, msg, size); 103762306a36Sopenharmony_ci} 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci/** 104062306a36Sopenharmony_ci * apparmor_socket_recvmsg - check perms before receiving a message 104162306a36Sopenharmony_ci */ 104262306a36Sopenharmony_cistatic int apparmor_socket_recvmsg(struct socket *sock, 104362306a36Sopenharmony_ci struct msghdr *msg, int size, int flags) 104462306a36Sopenharmony_ci{ 104562306a36Sopenharmony_ci return aa_sock_msg_perm(OP_RECVMSG, AA_MAY_RECEIVE, sock, msg, size); 104662306a36Sopenharmony_ci} 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci/* revaliation, get/set attr, shutdown */ 104962306a36Sopenharmony_cistatic int aa_sock_perm(const char *op, u32 request, struct socket *sock) 105062306a36Sopenharmony_ci{ 105162306a36Sopenharmony_ci AA_BUG(!sock); 105262306a36Sopenharmony_ci AA_BUG(!sock->sk); 105362306a36Sopenharmony_ci AA_BUG(in_interrupt()); 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci return af_select(sock->sk->sk_family, 105662306a36Sopenharmony_ci sock_perm(op, request, sock), 105762306a36Sopenharmony_ci aa_sk_perm(op, request, sock->sk)); 105862306a36Sopenharmony_ci} 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci/** 106162306a36Sopenharmony_ci * apparmor_socket_getsockname - check perms before getting the local address 106262306a36Sopenharmony_ci */ 106362306a36Sopenharmony_cistatic int apparmor_socket_getsockname(struct socket *sock) 106462306a36Sopenharmony_ci{ 106562306a36Sopenharmony_ci return aa_sock_perm(OP_GETSOCKNAME, AA_MAY_GETATTR, sock); 106662306a36Sopenharmony_ci} 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci/** 106962306a36Sopenharmony_ci * apparmor_socket_getpeername - check perms before getting remote address 107062306a36Sopenharmony_ci */ 107162306a36Sopenharmony_cistatic int apparmor_socket_getpeername(struct socket *sock) 107262306a36Sopenharmony_ci{ 107362306a36Sopenharmony_ci return aa_sock_perm(OP_GETPEERNAME, AA_MAY_GETATTR, sock); 107462306a36Sopenharmony_ci} 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci/* revaliation, get/set attr, opt */ 107762306a36Sopenharmony_cistatic int aa_sock_opt_perm(const char *op, u32 request, struct socket *sock, 107862306a36Sopenharmony_ci int level, int optname) 107962306a36Sopenharmony_ci{ 108062306a36Sopenharmony_ci AA_BUG(!sock); 108162306a36Sopenharmony_ci AA_BUG(!sock->sk); 108262306a36Sopenharmony_ci AA_BUG(in_interrupt()); 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_ci return af_select(sock->sk->sk_family, 108562306a36Sopenharmony_ci opt_perm(op, request, sock, level, optname), 108662306a36Sopenharmony_ci aa_sk_perm(op, request, sock->sk)); 108762306a36Sopenharmony_ci} 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci/** 109062306a36Sopenharmony_ci * apparmor_socket_getsockopt - check perms before getting socket options 109162306a36Sopenharmony_ci */ 109262306a36Sopenharmony_cistatic int apparmor_socket_getsockopt(struct socket *sock, int level, 109362306a36Sopenharmony_ci int optname) 109462306a36Sopenharmony_ci{ 109562306a36Sopenharmony_ci return aa_sock_opt_perm(OP_GETSOCKOPT, AA_MAY_GETOPT, sock, 109662306a36Sopenharmony_ci level, optname); 109762306a36Sopenharmony_ci} 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci/** 110062306a36Sopenharmony_ci * apparmor_socket_setsockopt - check perms before setting socket options 110162306a36Sopenharmony_ci */ 110262306a36Sopenharmony_cistatic int apparmor_socket_setsockopt(struct socket *sock, int level, 110362306a36Sopenharmony_ci int optname) 110462306a36Sopenharmony_ci{ 110562306a36Sopenharmony_ci return aa_sock_opt_perm(OP_SETSOCKOPT, AA_MAY_SETOPT, sock, 110662306a36Sopenharmony_ci level, optname); 110762306a36Sopenharmony_ci} 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci/** 111062306a36Sopenharmony_ci * apparmor_socket_shutdown - check perms before shutting down @sock conn 111162306a36Sopenharmony_ci */ 111262306a36Sopenharmony_cistatic int apparmor_socket_shutdown(struct socket *sock, int how) 111362306a36Sopenharmony_ci{ 111462306a36Sopenharmony_ci return aa_sock_perm(OP_SHUTDOWN, AA_MAY_SHUTDOWN, sock); 111562306a36Sopenharmony_ci} 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci#ifdef CONFIG_NETWORK_SECMARK 111862306a36Sopenharmony_ci/** 111962306a36Sopenharmony_ci * apparmor_socket_sock_rcv_skb - check perms before associating skb to sk 112062306a36Sopenharmony_ci * 112162306a36Sopenharmony_ci * Note: can not sleep may be called with locks held 112262306a36Sopenharmony_ci * 112362306a36Sopenharmony_ci * dont want protocol specific in __skb_recv_datagram() 112462306a36Sopenharmony_ci * to deny an incoming connection socket_sock_rcv_skb() 112562306a36Sopenharmony_ci */ 112662306a36Sopenharmony_cistatic int apparmor_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) 112762306a36Sopenharmony_ci{ 112862306a36Sopenharmony_ci struct aa_sk_ctx *ctx = SK_CTX(sk); 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci if (!skb->secmark) 113162306a36Sopenharmony_ci return 0; 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_ci return apparmor_secmark_check(ctx->label, OP_RECVMSG, AA_MAY_RECEIVE, 113462306a36Sopenharmony_ci skb->secmark, sk); 113562306a36Sopenharmony_ci} 113662306a36Sopenharmony_ci#endif 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_cistatic struct aa_label *sk_peer_label(struct sock *sk) 114062306a36Sopenharmony_ci{ 114162306a36Sopenharmony_ci struct aa_sk_ctx *ctx = SK_CTX(sk); 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci if (ctx->peer) 114462306a36Sopenharmony_ci return ctx->peer; 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_ci return ERR_PTR(-ENOPROTOOPT); 114762306a36Sopenharmony_ci} 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_ci/** 115062306a36Sopenharmony_ci * apparmor_socket_getpeersec_stream - get security context of peer 115162306a36Sopenharmony_ci * 115262306a36Sopenharmony_ci * Note: for tcp only valid if using ipsec or cipso on lan 115362306a36Sopenharmony_ci */ 115462306a36Sopenharmony_cistatic int apparmor_socket_getpeersec_stream(struct socket *sock, 115562306a36Sopenharmony_ci sockptr_t optval, sockptr_t optlen, 115662306a36Sopenharmony_ci unsigned int len) 115762306a36Sopenharmony_ci{ 115862306a36Sopenharmony_ci char *name = NULL; 115962306a36Sopenharmony_ci int slen, error = 0; 116062306a36Sopenharmony_ci struct aa_label *label; 116162306a36Sopenharmony_ci struct aa_label *peer; 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_ci label = begin_current_label_crit_section(); 116462306a36Sopenharmony_ci peer = sk_peer_label(sock->sk); 116562306a36Sopenharmony_ci if (IS_ERR(peer)) { 116662306a36Sopenharmony_ci error = PTR_ERR(peer); 116762306a36Sopenharmony_ci goto done; 116862306a36Sopenharmony_ci } 116962306a36Sopenharmony_ci slen = aa_label_asxprint(&name, labels_ns(label), peer, 117062306a36Sopenharmony_ci FLAG_SHOW_MODE | FLAG_VIEW_SUBNS | 117162306a36Sopenharmony_ci FLAG_HIDDEN_UNCONFINED, GFP_KERNEL); 117262306a36Sopenharmony_ci /* don't include terminating \0 in slen, it breaks some apps */ 117362306a36Sopenharmony_ci if (slen < 0) { 117462306a36Sopenharmony_ci error = -ENOMEM; 117562306a36Sopenharmony_ci goto done; 117662306a36Sopenharmony_ci } 117762306a36Sopenharmony_ci if (slen > len) { 117862306a36Sopenharmony_ci error = -ERANGE; 117962306a36Sopenharmony_ci goto done_len; 118062306a36Sopenharmony_ci } 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci if (copy_to_sockptr(optval, name, slen)) 118362306a36Sopenharmony_ci error = -EFAULT; 118462306a36Sopenharmony_cidone_len: 118562306a36Sopenharmony_ci if (copy_to_sockptr(optlen, &slen, sizeof(slen))) 118662306a36Sopenharmony_ci error = -EFAULT; 118762306a36Sopenharmony_cidone: 118862306a36Sopenharmony_ci end_current_label_crit_section(label); 118962306a36Sopenharmony_ci kfree(name); 119062306a36Sopenharmony_ci return error; 119162306a36Sopenharmony_ci} 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci/** 119462306a36Sopenharmony_ci * apparmor_socket_getpeersec_dgram - get security label of packet 119562306a36Sopenharmony_ci * @sock: the peer socket 119662306a36Sopenharmony_ci * @skb: packet data 119762306a36Sopenharmony_ci * @secid: pointer to where to put the secid of the packet 119862306a36Sopenharmony_ci * 119962306a36Sopenharmony_ci * Sets the netlabel socket state on sk from parent 120062306a36Sopenharmony_ci */ 120162306a36Sopenharmony_cistatic int apparmor_socket_getpeersec_dgram(struct socket *sock, 120262306a36Sopenharmony_ci struct sk_buff *skb, u32 *secid) 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_ci{ 120562306a36Sopenharmony_ci /* TODO: requires secid support */ 120662306a36Sopenharmony_ci return -ENOPROTOOPT; 120762306a36Sopenharmony_ci} 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci/** 121062306a36Sopenharmony_ci * apparmor_sock_graft - Initialize newly created socket 121162306a36Sopenharmony_ci * @sk: child sock 121262306a36Sopenharmony_ci * @parent: parent socket 121362306a36Sopenharmony_ci * 121462306a36Sopenharmony_ci * Note: could set off of SOCK_CTX(parent) but need to track inode and we can 121562306a36Sopenharmony_ci * just set sk security information off of current creating process label 121662306a36Sopenharmony_ci * Labeling of sk for accept case - probably should be sock based 121762306a36Sopenharmony_ci * instead of task, because of the case where an implicitly labeled 121862306a36Sopenharmony_ci * socket is shared by different tasks. 121962306a36Sopenharmony_ci */ 122062306a36Sopenharmony_cistatic void apparmor_sock_graft(struct sock *sk, struct socket *parent) 122162306a36Sopenharmony_ci{ 122262306a36Sopenharmony_ci struct aa_sk_ctx *ctx = SK_CTX(sk); 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci if (!ctx->label) 122562306a36Sopenharmony_ci ctx->label = aa_get_current_label(); 122662306a36Sopenharmony_ci} 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci#ifdef CONFIG_NETWORK_SECMARK 122962306a36Sopenharmony_cistatic int apparmor_inet_conn_request(const struct sock *sk, struct sk_buff *skb, 123062306a36Sopenharmony_ci struct request_sock *req) 123162306a36Sopenharmony_ci{ 123262306a36Sopenharmony_ci struct aa_sk_ctx *ctx = SK_CTX(sk); 123362306a36Sopenharmony_ci 123462306a36Sopenharmony_ci if (!skb->secmark) 123562306a36Sopenharmony_ci return 0; 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci return apparmor_secmark_check(ctx->label, OP_CONNECT, AA_MAY_CONNECT, 123862306a36Sopenharmony_ci skb->secmark, sk); 123962306a36Sopenharmony_ci} 124062306a36Sopenharmony_ci#endif 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci/* 124362306a36Sopenharmony_ci * The cred blob is a pointer to, not an instance of, an aa_label. 124462306a36Sopenharmony_ci */ 124562306a36Sopenharmony_cistruct lsm_blob_sizes apparmor_blob_sizes __ro_after_init = { 124662306a36Sopenharmony_ci .lbs_cred = sizeof(struct aa_label *), 124762306a36Sopenharmony_ci .lbs_file = sizeof(struct aa_file_ctx), 124862306a36Sopenharmony_ci .lbs_task = sizeof(struct aa_task_ctx), 124962306a36Sopenharmony_ci}; 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_cistatic struct security_hook_list apparmor_hooks[] __ro_after_init = { 125262306a36Sopenharmony_ci LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check), 125362306a36Sopenharmony_ci LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme), 125462306a36Sopenharmony_ci LSM_HOOK_INIT(capget, apparmor_capget), 125562306a36Sopenharmony_ci LSM_HOOK_INIT(capable, apparmor_capable), 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci LSM_HOOK_INIT(move_mount, apparmor_move_mount), 125862306a36Sopenharmony_ci LSM_HOOK_INIT(sb_mount, apparmor_sb_mount), 125962306a36Sopenharmony_ci LSM_HOOK_INIT(sb_umount, apparmor_sb_umount), 126062306a36Sopenharmony_ci LSM_HOOK_INIT(sb_pivotroot, apparmor_sb_pivotroot), 126162306a36Sopenharmony_ci 126262306a36Sopenharmony_ci LSM_HOOK_INIT(path_link, apparmor_path_link), 126362306a36Sopenharmony_ci LSM_HOOK_INIT(path_unlink, apparmor_path_unlink), 126462306a36Sopenharmony_ci LSM_HOOK_INIT(path_symlink, apparmor_path_symlink), 126562306a36Sopenharmony_ci LSM_HOOK_INIT(path_mkdir, apparmor_path_mkdir), 126662306a36Sopenharmony_ci LSM_HOOK_INIT(path_rmdir, apparmor_path_rmdir), 126762306a36Sopenharmony_ci LSM_HOOK_INIT(path_mknod, apparmor_path_mknod), 126862306a36Sopenharmony_ci LSM_HOOK_INIT(path_rename, apparmor_path_rename), 126962306a36Sopenharmony_ci LSM_HOOK_INIT(path_chmod, apparmor_path_chmod), 127062306a36Sopenharmony_ci LSM_HOOK_INIT(path_chown, apparmor_path_chown), 127162306a36Sopenharmony_ci LSM_HOOK_INIT(path_truncate, apparmor_path_truncate), 127262306a36Sopenharmony_ci LSM_HOOK_INIT(inode_getattr, apparmor_inode_getattr), 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci LSM_HOOK_INIT(file_open, apparmor_file_open), 127562306a36Sopenharmony_ci LSM_HOOK_INIT(file_receive, apparmor_file_receive), 127662306a36Sopenharmony_ci LSM_HOOK_INIT(file_permission, apparmor_file_permission), 127762306a36Sopenharmony_ci LSM_HOOK_INIT(file_alloc_security, apparmor_file_alloc_security), 127862306a36Sopenharmony_ci LSM_HOOK_INIT(file_free_security, apparmor_file_free_security), 127962306a36Sopenharmony_ci LSM_HOOK_INIT(mmap_file, apparmor_mmap_file), 128062306a36Sopenharmony_ci LSM_HOOK_INIT(file_mprotect, apparmor_file_mprotect), 128162306a36Sopenharmony_ci LSM_HOOK_INIT(file_lock, apparmor_file_lock), 128262306a36Sopenharmony_ci LSM_HOOK_INIT(file_truncate, apparmor_file_truncate), 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_ci LSM_HOOK_INIT(getprocattr, apparmor_getprocattr), 128562306a36Sopenharmony_ci LSM_HOOK_INIT(setprocattr, apparmor_setprocattr), 128662306a36Sopenharmony_ci 128762306a36Sopenharmony_ci LSM_HOOK_INIT(sk_alloc_security, apparmor_sk_alloc_security), 128862306a36Sopenharmony_ci LSM_HOOK_INIT(sk_free_security, apparmor_sk_free_security), 128962306a36Sopenharmony_ci LSM_HOOK_INIT(sk_clone_security, apparmor_sk_clone_security), 129062306a36Sopenharmony_ci 129162306a36Sopenharmony_ci LSM_HOOK_INIT(socket_create, apparmor_socket_create), 129262306a36Sopenharmony_ci LSM_HOOK_INIT(socket_post_create, apparmor_socket_post_create), 129362306a36Sopenharmony_ci LSM_HOOK_INIT(socket_bind, apparmor_socket_bind), 129462306a36Sopenharmony_ci LSM_HOOK_INIT(socket_connect, apparmor_socket_connect), 129562306a36Sopenharmony_ci LSM_HOOK_INIT(socket_listen, apparmor_socket_listen), 129662306a36Sopenharmony_ci LSM_HOOK_INIT(socket_accept, apparmor_socket_accept), 129762306a36Sopenharmony_ci LSM_HOOK_INIT(socket_sendmsg, apparmor_socket_sendmsg), 129862306a36Sopenharmony_ci LSM_HOOK_INIT(socket_recvmsg, apparmor_socket_recvmsg), 129962306a36Sopenharmony_ci LSM_HOOK_INIT(socket_getsockname, apparmor_socket_getsockname), 130062306a36Sopenharmony_ci LSM_HOOK_INIT(socket_getpeername, apparmor_socket_getpeername), 130162306a36Sopenharmony_ci LSM_HOOK_INIT(socket_getsockopt, apparmor_socket_getsockopt), 130262306a36Sopenharmony_ci LSM_HOOK_INIT(socket_setsockopt, apparmor_socket_setsockopt), 130362306a36Sopenharmony_ci LSM_HOOK_INIT(socket_shutdown, apparmor_socket_shutdown), 130462306a36Sopenharmony_ci#ifdef CONFIG_NETWORK_SECMARK 130562306a36Sopenharmony_ci LSM_HOOK_INIT(socket_sock_rcv_skb, apparmor_socket_sock_rcv_skb), 130662306a36Sopenharmony_ci#endif 130762306a36Sopenharmony_ci LSM_HOOK_INIT(socket_getpeersec_stream, 130862306a36Sopenharmony_ci apparmor_socket_getpeersec_stream), 130962306a36Sopenharmony_ci LSM_HOOK_INIT(socket_getpeersec_dgram, 131062306a36Sopenharmony_ci apparmor_socket_getpeersec_dgram), 131162306a36Sopenharmony_ci LSM_HOOK_INIT(sock_graft, apparmor_sock_graft), 131262306a36Sopenharmony_ci#ifdef CONFIG_NETWORK_SECMARK 131362306a36Sopenharmony_ci LSM_HOOK_INIT(inet_conn_request, apparmor_inet_conn_request), 131462306a36Sopenharmony_ci#endif 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ci LSM_HOOK_INIT(cred_alloc_blank, apparmor_cred_alloc_blank), 131762306a36Sopenharmony_ci LSM_HOOK_INIT(cred_free, apparmor_cred_free), 131862306a36Sopenharmony_ci LSM_HOOK_INIT(cred_prepare, apparmor_cred_prepare), 131962306a36Sopenharmony_ci LSM_HOOK_INIT(cred_transfer, apparmor_cred_transfer), 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci LSM_HOOK_INIT(bprm_creds_for_exec, apparmor_bprm_creds_for_exec), 132262306a36Sopenharmony_ci LSM_HOOK_INIT(bprm_committing_creds, apparmor_bprm_committing_creds), 132362306a36Sopenharmony_ci LSM_HOOK_INIT(bprm_committed_creds, apparmor_bprm_committed_creds), 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_ci LSM_HOOK_INIT(task_free, apparmor_task_free), 132662306a36Sopenharmony_ci LSM_HOOK_INIT(task_alloc, apparmor_task_alloc), 132762306a36Sopenharmony_ci LSM_HOOK_INIT(current_getsecid_subj, apparmor_current_getsecid_subj), 132862306a36Sopenharmony_ci LSM_HOOK_INIT(task_getsecid_obj, apparmor_task_getsecid_obj), 132962306a36Sopenharmony_ci LSM_HOOK_INIT(task_setrlimit, apparmor_task_setrlimit), 133062306a36Sopenharmony_ci LSM_HOOK_INIT(task_kill, apparmor_task_kill), 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_ci#ifdef CONFIG_AUDIT 133362306a36Sopenharmony_ci LSM_HOOK_INIT(audit_rule_init, aa_audit_rule_init), 133462306a36Sopenharmony_ci LSM_HOOK_INIT(audit_rule_known, aa_audit_rule_known), 133562306a36Sopenharmony_ci LSM_HOOK_INIT(audit_rule_match, aa_audit_rule_match), 133662306a36Sopenharmony_ci LSM_HOOK_INIT(audit_rule_free, aa_audit_rule_free), 133762306a36Sopenharmony_ci#endif 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_ci LSM_HOOK_INIT(secid_to_secctx, apparmor_secid_to_secctx), 134062306a36Sopenharmony_ci LSM_HOOK_INIT(secctx_to_secid, apparmor_secctx_to_secid), 134162306a36Sopenharmony_ci LSM_HOOK_INIT(release_secctx, apparmor_release_secctx), 134262306a36Sopenharmony_ci}; 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_ci/* 134562306a36Sopenharmony_ci * AppArmor sysfs module parameters 134662306a36Sopenharmony_ci */ 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_cistatic int param_set_aabool(const char *val, const struct kernel_param *kp); 134962306a36Sopenharmony_cistatic int param_get_aabool(char *buffer, const struct kernel_param *kp); 135062306a36Sopenharmony_ci#define param_check_aabool param_check_bool 135162306a36Sopenharmony_cistatic const struct kernel_param_ops param_ops_aabool = { 135262306a36Sopenharmony_ci .flags = KERNEL_PARAM_OPS_FL_NOARG, 135362306a36Sopenharmony_ci .set = param_set_aabool, 135462306a36Sopenharmony_ci .get = param_get_aabool 135562306a36Sopenharmony_ci}; 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_cistatic int param_set_aauint(const char *val, const struct kernel_param *kp); 135862306a36Sopenharmony_cistatic int param_get_aauint(char *buffer, const struct kernel_param *kp); 135962306a36Sopenharmony_ci#define param_check_aauint param_check_uint 136062306a36Sopenharmony_cistatic const struct kernel_param_ops param_ops_aauint = { 136162306a36Sopenharmony_ci .set = param_set_aauint, 136262306a36Sopenharmony_ci .get = param_get_aauint 136362306a36Sopenharmony_ci}; 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_cistatic int param_set_aacompressionlevel(const char *val, 136662306a36Sopenharmony_ci const struct kernel_param *kp); 136762306a36Sopenharmony_cistatic int param_get_aacompressionlevel(char *buffer, 136862306a36Sopenharmony_ci const struct kernel_param *kp); 136962306a36Sopenharmony_ci#define param_check_aacompressionlevel param_check_int 137062306a36Sopenharmony_cistatic const struct kernel_param_ops param_ops_aacompressionlevel = { 137162306a36Sopenharmony_ci .set = param_set_aacompressionlevel, 137262306a36Sopenharmony_ci .get = param_get_aacompressionlevel 137362306a36Sopenharmony_ci}; 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_cistatic int param_set_aalockpolicy(const char *val, const struct kernel_param *kp); 137662306a36Sopenharmony_cistatic int param_get_aalockpolicy(char *buffer, const struct kernel_param *kp); 137762306a36Sopenharmony_ci#define param_check_aalockpolicy param_check_bool 137862306a36Sopenharmony_cistatic const struct kernel_param_ops param_ops_aalockpolicy = { 137962306a36Sopenharmony_ci .flags = KERNEL_PARAM_OPS_FL_NOARG, 138062306a36Sopenharmony_ci .set = param_set_aalockpolicy, 138162306a36Sopenharmony_ci .get = param_get_aalockpolicy 138262306a36Sopenharmony_ci}; 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_cistatic int param_set_audit(const char *val, const struct kernel_param *kp); 138562306a36Sopenharmony_cistatic int param_get_audit(char *buffer, const struct kernel_param *kp); 138662306a36Sopenharmony_ci 138762306a36Sopenharmony_cistatic int param_set_mode(const char *val, const struct kernel_param *kp); 138862306a36Sopenharmony_cistatic int param_get_mode(char *buffer, const struct kernel_param *kp); 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci/* Flag values, also controllable via /sys/module/apparmor/parameters 139162306a36Sopenharmony_ci * We define special types as we want to do additional mediation. 139262306a36Sopenharmony_ci */ 139362306a36Sopenharmony_ci 139462306a36Sopenharmony_ci/* AppArmor global enforcement switch - complain, enforce, kill */ 139562306a36Sopenharmony_cienum profile_mode aa_g_profile_mode = APPARMOR_ENFORCE; 139662306a36Sopenharmony_cimodule_param_call(mode, param_set_mode, param_get_mode, 139762306a36Sopenharmony_ci &aa_g_profile_mode, S_IRUSR | S_IWUSR); 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci/* whether policy verification hashing is enabled */ 140062306a36Sopenharmony_cibool aa_g_hash_policy = IS_ENABLED(CONFIG_SECURITY_APPARMOR_HASH_DEFAULT); 140162306a36Sopenharmony_ci#ifdef CONFIG_SECURITY_APPARMOR_HASH 140262306a36Sopenharmony_cimodule_param_named(hash_policy, aa_g_hash_policy, aabool, S_IRUSR | S_IWUSR); 140362306a36Sopenharmony_ci#endif 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ci/* whether policy exactly as loaded is retained for debug and checkpointing */ 140662306a36Sopenharmony_cibool aa_g_export_binary = IS_ENABLED(CONFIG_SECURITY_APPARMOR_EXPORT_BINARY); 140762306a36Sopenharmony_ci#ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY 140862306a36Sopenharmony_cimodule_param_named(export_binary, aa_g_export_binary, aabool, 0600); 140962306a36Sopenharmony_ci#endif 141062306a36Sopenharmony_ci 141162306a36Sopenharmony_ci/* policy loaddata compression level */ 141262306a36Sopenharmony_ciint aa_g_rawdata_compression_level = AA_DEFAULT_CLEVEL; 141362306a36Sopenharmony_cimodule_param_named(rawdata_compression_level, aa_g_rawdata_compression_level, 141462306a36Sopenharmony_ci aacompressionlevel, 0400); 141562306a36Sopenharmony_ci 141662306a36Sopenharmony_ci/* Debug mode */ 141762306a36Sopenharmony_cibool aa_g_debug = IS_ENABLED(CONFIG_SECURITY_APPARMOR_DEBUG_MESSAGES); 141862306a36Sopenharmony_cimodule_param_named(debug, aa_g_debug, aabool, S_IRUSR | S_IWUSR); 141962306a36Sopenharmony_ci 142062306a36Sopenharmony_ci/* Audit mode */ 142162306a36Sopenharmony_cienum audit_mode aa_g_audit; 142262306a36Sopenharmony_cimodule_param_call(audit, param_set_audit, param_get_audit, 142362306a36Sopenharmony_ci &aa_g_audit, S_IRUSR | S_IWUSR); 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_ci/* Determines if audit header is included in audited messages. This 142662306a36Sopenharmony_ci * provides more context if the audit daemon is not running 142762306a36Sopenharmony_ci */ 142862306a36Sopenharmony_cibool aa_g_audit_header = true; 142962306a36Sopenharmony_cimodule_param_named(audit_header, aa_g_audit_header, aabool, 143062306a36Sopenharmony_ci S_IRUSR | S_IWUSR); 143162306a36Sopenharmony_ci 143262306a36Sopenharmony_ci/* lock out loading/removal of policy 143362306a36Sopenharmony_ci * TODO: add in at boot loading of policy, which is the only way to 143462306a36Sopenharmony_ci * load policy, if lock_policy is set 143562306a36Sopenharmony_ci */ 143662306a36Sopenharmony_cibool aa_g_lock_policy; 143762306a36Sopenharmony_cimodule_param_named(lock_policy, aa_g_lock_policy, aalockpolicy, 143862306a36Sopenharmony_ci S_IRUSR | S_IWUSR); 143962306a36Sopenharmony_ci 144062306a36Sopenharmony_ci/* Syscall logging mode */ 144162306a36Sopenharmony_cibool aa_g_logsyscall; 144262306a36Sopenharmony_cimodule_param_named(logsyscall, aa_g_logsyscall, aabool, S_IRUSR | S_IWUSR); 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci/* Maximum pathname length before accesses will start getting rejected */ 144562306a36Sopenharmony_ciunsigned int aa_g_path_max = 2 * PATH_MAX; 144662306a36Sopenharmony_cimodule_param_named(path_max, aa_g_path_max, aauint, S_IRUSR); 144762306a36Sopenharmony_ci 144862306a36Sopenharmony_ci/* Determines how paranoid loading of policy is and how much verification 144962306a36Sopenharmony_ci * on the loaded policy is done. 145062306a36Sopenharmony_ci * DEPRECATED: read only as strict checking of load is always done now 145162306a36Sopenharmony_ci * that none root users (user namespaces) can load policy. 145262306a36Sopenharmony_ci */ 145362306a36Sopenharmony_cibool aa_g_paranoid_load = IS_ENABLED(CONFIG_SECURITY_APPARMOR_PARANOID_LOAD); 145462306a36Sopenharmony_cimodule_param_named(paranoid_load, aa_g_paranoid_load, aabool, S_IRUGO); 145562306a36Sopenharmony_ci 145662306a36Sopenharmony_cistatic int param_get_aaintbool(char *buffer, const struct kernel_param *kp); 145762306a36Sopenharmony_cistatic int param_set_aaintbool(const char *val, const struct kernel_param *kp); 145862306a36Sopenharmony_ci#define param_check_aaintbool param_check_int 145962306a36Sopenharmony_cistatic const struct kernel_param_ops param_ops_aaintbool = { 146062306a36Sopenharmony_ci .set = param_set_aaintbool, 146162306a36Sopenharmony_ci .get = param_get_aaintbool 146262306a36Sopenharmony_ci}; 146362306a36Sopenharmony_ci/* Boot time disable flag */ 146462306a36Sopenharmony_cistatic int apparmor_enabled __ro_after_init = 1; 146562306a36Sopenharmony_cimodule_param_named(enabled, apparmor_enabled, aaintbool, 0444); 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_cistatic int __init apparmor_enabled_setup(char *str) 146862306a36Sopenharmony_ci{ 146962306a36Sopenharmony_ci unsigned long enabled; 147062306a36Sopenharmony_ci int error = kstrtoul(str, 0, &enabled); 147162306a36Sopenharmony_ci if (!error) 147262306a36Sopenharmony_ci apparmor_enabled = enabled ? 1 : 0; 147362306a36Sopenharmony_ci return 1; 147462306a36Sopenharmony_ci} 147562306a36Sopenharmony_ci 147662306a36Sopenharmony_ci__setup("apparmor=", apparmor_enabled_setup); 147762306a36Sopenharmony_ci 147862306a36Sopenharmony_ci/* set global flag turning off the ability to load policy */ 147962306a36Sopenharmony_cistatic int param_set_aalockpolicy(const char *val, const struct kernel_param *kp) 148062306a36Sopenharmony_ci{ 148162306a36Sopenharmony_ci if (!apparmor_enabled) 148262306a36Sopenharmony_ci return -EINVAL; 148362306a36Sopenharmony_ci if (apparmor_initialized && !aa_current_policy_admin_capable(NULL)) 148462306a36Sopenharmony_ci return -EPERM; 148562306a36Sopenharmony_ci return param_set_bool(val, kp); 148662306a36Sopenharmony_ci} 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_cistatic int param_get_aalockpolicy(char *buffer, const struct kernel_param *kp) 148962306a36Sopenharmony_ci{ 149062306a36Sopenharmony_ci if (!apparmor_enabled) 149162306a36Sopenharmony_ci return -EINVAL; 149262306a36Sopenharmony_ci if (apparmor_initialized && !aa_current_policy_view_capable(NULL)) 149362306a36Sopenharmony_ci return -EPERM; 149462306a36Sopenharmony_ci return param_get_bool(buffer, kp); 149562306a36Sopenharmony_ci} 149662306a36Sopenharmony_ci 149762306a36Sopenharmony_cistatic int param_set_aabool(const char *val, const struct kernel_param *kp) 149862306a36Sopenharmony_ci{ 149962306a36Sopenharmony_ci if (!apparmor_enabled) 150062306a36Sopenharmony_ci return -EINVAL; 150162306a36Sopenharmony_ci if (apparmor_initialized && !aa_current_policy_admin_capable(NULL)) 150262306a36Sopenharmony_ci return -EPERM; 150362306a36Sopenharmony_ci return param_set_bool(val, kp); 150462306a36Sopenharmony_ci} 150562306a36Sopenharmony_ci 150662306a36Sopenharmony_cistatic int param_get_aabool(char *buffer, const struct kernel_param *kp) 150762306a36Sopenharmony_ci{ 150862306a36Sopenharmony_ci if (!apparmor_enabled) 150962306a36Sopenharmony_ci return -EINVAL; 151062306a36Sopenharmony_ci if (apparmor_initialized && !aa_current_policy_view_capable(NULL)) 151162306a36Sopenharmony_ci return -EPERM; 151262306a36Sopenharmony_ci return param_get_bool(buffer, kp); 151362306a36Sopenharmony_ci} 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_cistatic int param_set_aauint(const char *val, const struct kernel_param *kp) 151662306a36Sopenharmony_ci{ 151762306a36Sopenharmony_ci int error; 151862306a36Sopenharmony_ci 151962306a36Sopenharmony_ci if (!apparmor_enabled) 152062306a36Sopenharmony_ci return -EINVAL; 152162306a36Sopenharmony_ci /* file is ro but enforce 2nd line check */ 152262306a36Sopenharmony_ci if (apparmor_initialized) 152362306a36Sopenharmony_ci return -EPERM; 152462306a36Sopenharmony_ci 152562306a36Sopenharmony_ci error = param_set_uint(val, kp); 152662306a36Sopenharmony_ci aa_g_path_max = max_t(uint32_t, aa_g_path_max, sizeof(union aa_buffer)); 152762306a36Sopenharmony_ci pr_info("AppArmor: buffer size set to %d bytes\n", aa_g_path_max); 152862306a36Sopenharmony_ci 152962306a36Sopenharmony_ci return error; 153062306a36Sopenharmony_ci} 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_cistatic int param_get_aauint(char *buffer, const struct kernel_param *kp) 153362306a36Sopenharmony_ci{ 153462306a36Sopenharmony_ci if (!apparmor_enabled) 153562306a36Sopenharmony_ci return -EINVAL; 153662306a36Sopenharmony_ci if (apparmor_initialized && !aa_current_policy_view_capable(NULL)) 153762306a36Sopenharmony_ci return -EPERM; 153862306a36Sopenharmony_ci return param_get_uint(buffer, kp); 153962306a36Sopenharmony_ci} 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_ci/* Can only be set before AppArmor is initialized (i.e. on boot cmdline). */ 154262306a36Sopenharmony_cistatic int param_set_aaintbool(const char *val, const struct kernel_param *kp) 154362306a36Sopenharmony_ci{ 154462306a36Sopenharmony_ci struct kernel_param kp_local; 154562306a36Sopenharmony_ci bool value; 154662306a36Sopenharmony_ci int error; 154762306a36Sopenharmony_ci 154862306a36Sopenharmony_ci if (apparmor_initialized) 154962306a36Sopenharmony_ci return -EPERM; 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_ci /* Create local copy, with arg pointing to bool type. */ 155262306a36Sopenharmony_ci value = !!*((int *)kp->arg); 155362306a36Sopenharmony_ci memcpy(&kp_local, kp, sizeof(kp_local)); 155462306a36Sopenharmony_ci kp_local.arg = &value; 155562306a36Sopenharmony_ci 155662306a36Sopenharmony_ci error = param_set_bool(val, &kp_local); 155762306a36Sopenharmony_ci if (!error) 155862306a36Sopenharmony_ci *((int *)kp->arg) = *((bool *)kp_local.arg); 155962306a36Sopenharmony_ci return error; 156062306a36Sopenharmony_ci} 156162306a36Sopenharmony_ci 156262306a36Sopenharmony_ci/* 156362306a36Sopenharmony_ci * To avoid changing /sys/module/apparmor/parameters/enabled from Y/N to 156462306a36Sopenharmony_ci * 1/0, this converts the "int that is actually bool" back to bool for 156562306a36Sopenharmony_ci * display in the /sys filesystem, while keeping it "int" for the LSM 156662306a36Sopenharmony_ci * infrastructure. 156762306a36Sopenharmony_ci */ 156862306a36Sopenharmony_cistatic int param_get_aaintbool(char *buffer, const struct kernel_param *kp) 156962306a36Sopenharmony_ci{ 157062306a36Sopenharmony_ci struct kernel_param kp_local; 157162306a36Sopenharmony_ci bool value; 157262306a36Sopenharmony_ci 157362306a36Sopenharmony_ci /* Create local copy, with arg pointing to bool type. */ 157462306a36Sopenharmony_ci value = !!*((int *)kp->arg); 157562306a36Sopenharmony_ci memcpy(&kp_local, kp, sizeof(kp_local)); 157662306a36Sopenharmony_ci kp_local.arg = &value; 157762306a36Sopenharmony_ci 157862306a36Sopenharmony_ci return param_get_bool(buffer, &kp_local); 157962306a36Sopenharmony_ci} 158062306a36Sopenharmony_ci 158162306a36Sopenharmony_cistatic int param_set_aacompressionlevel(const char *val, 158262306a36Sopenharmony_ci const struct kernel_param *kp) 158362306a36Sopenharmony_ci{ 158462306a36Sopenharmony_ci int error; 158562306a36Sopenharmony_ci 158662306a36Sopenharmony_ci if (!apparmor_enabled) 158762306a36Sopenharmony_ci return -EINVAL; 158862306a36Sopenharmony_ci if (apparmor_initialized) 158962306a36Sopenharmony_ci return -EPERM; 159062306a36Sopenharmony_ci 159162306a36Sopenharmony_ci error = param_set_int(val, kp); 159262306a36Sopenharmony_ci 159362306a36Sopenharmony_ci aa_g_rawdata_compression_level = clamp(aa_g_rawdata_compression_level, 159462306a36Sopenharmony_ci AA_MIN_CLEVEL, AA_MAX_CLEVEL); 159562306a36Sopenharmony_ci pr_info("AppArmor: policy rawdata compression level set to %d\n", 159662306a36Sopenharmony_ci aa_g_rawdata_compression_level); 159762306a36Sopenharmony_ci 159862306a36Sopenharmony_ci return error; 159962306a36Sopenharmony_ci} 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_cistatic int param_get_aacompressionlevel(char *buffer, 160262306a36Sopenharmony_ci const struct kernel_param *kp) 160362306a36Sopenharmony_ci{ 160462306a36Sopenharmony_ci if (!apparmor_enabled) 160562306a36Sopenharmony_ci return -EINVAL; 160662306a36Sopenharmony_ci if (apparmor_initialized && !aa_current_policy_view_capable(NULL)) 160762306a36Sopenharmony_ci return -EPERM; 160862306a36Sopenharmony_ci return param_get_int(buffer, kp); 160962306a36Sopenharmony_ci} 161062306a36Sopenharmony_ci 161162306a36Sopenharmony_cistatic int param_get_audit(char *buffer, const struct kernel_param *kp) 161262306a36Sopenharmony_ci{ 161362306a36Sopenharmony_ci if (!apparmor_enabled) 161462306a36Sopenharmony_ci return -EINVAL; 161562306a36Sopenharmony_ci if (apparmor_initialized && !aa_current_policy_view_capable(NULL)) 161662306a36Sopenharmony_ci return -EPERM; 161762306a36Sopenharmony_ci return sprintf(buffer, "%s", audit_mode_names[aa_g_audit]); 161862306a36Sopenharmony_ci} 161962306a36Sopenharmony_ci 162062306a36Sopenharmony_cistatic int param_set_audit(const char *val, const struct kernel_param *kp) 162162306a36Sopenharmony_ci{ 162262306a36Sopenharmony_ci int i; 162362306a36Sopenharmony_ci 162462306a36Sopenharmony_ci if (!apparmor_enabled) 162562306a36Sopenharmony_ci return -EINVAL; 162662306a36Sopenharmony_ci if (!val) 162762306a36Sopenharmony_ci return -EINVAL; 162862306a36Sopenharmony_ci if (apparmor_initialized && !aa_current_policy_admin_capable(NULL)) 162962306a36Sopenharmony_ci return -EPERM; 163062306a36Sopenharmony_ci 163162306a36Sopenharmony_ci i = match_string(audit_mode_names, AUDIT_MAX_INDEX, val); 163262306a36Sopenharmony_ci if (i < 0) 163362306a36Sopenharmony_ci return -EINVAL; 163462306a36Sopenharmony_ci 163562306a36Sopenharmony_ci aa_g_audit = i; 163662306a36Sopenharmony_ci return 0; 163762306a36Sopenharmony_ci} 163862306a36Sopenharmony_ci 163962306a36Sopenharmony_cistatic int param_get_mode(char *buffer, const struct kernel_param *kp) 164062306a36Sopenharmony_ci{ 164162306a36Sopenharmony_ci if (!apparmor_enabled) 164262306a36Sopenharmony_ci return -EINVAL; 164362306a36Sopenharmony_ci if (apparmor_initialized && !aa_current_policy_view_capable(NULL)) 164462306a36Sopenharmony_ci return -EPERM; 164562306a36Sopenharmony_ci 164662306a36Sopenharmony_ci return sprintf(buffer, "%s", aa_profile_mode_names[aa_g_profile_mode]); 164762306a36Sopenharmony_ci} 164862306a36Sopenharmony_ci 164962306a36Sopenharmony_cistatic int param_set_mode(const char *val, const struct kernel_param *kp) 165062306a36Sopenharmony_ci{ 165162306a36Sopenharmony_ci int i; 165262306a36Sopenharmony_ci 165362306a36Sopenharmony_ci if (!apparmor_enabled) 165462306a36Sopenharmony_ci return -EINVAL; 165562306a36Sopenharmony_ci if (!val) 165662306a36Sopenharmony_ci return -EINVAL; 165762306a36Sopenharmony_ci if (apparmor_initialized && !aa_current_policy_admin_capable(NULL)) 165862306a36Sopenharmony_ci return -EPERM; 165962306a36Sopenharmony_ci 166062306a36Sopenharmony_ci i = match_string(aa_profile_mode_names, APPARMOR_MODE_NAMES_MAX_INDEX, 166162306a36Sopenharmony_ci val); 166262306a36Sopenharmony_ci if (i < 0) 166362306a36Sopenharmony_ci return -EINVAL; 166462306a36Sopenharmony_ci 166562306a36Sopenharmony_ci aa_g_profile_mode = i; 166662306a36Sopenharmony_ci return 0; 166762306a36Sopenharmony_ci} 166862306a36Sopenharmony_ci 166962306a36Sopenharmony_cichar *aa_get_buffer(bool in_atomic) 167062306a36Sopenharmony_ci{ 167162306a36Sopenharmony_ci union aa_buffer *aa_buf; 167262306a36Sopenharmony_ci bool try_again = true; 167362306a36Sopenharmony_ci gfp_t flags = (GFP_KERNEL | __GFP_RETRY_MAYFAIL | __GFP_NOWARN); 167462306a36Sopenharmony_ci 167562306a36Sopenharmony_ciretry: 167662306a36Sopenharmony_ci spin_lock(&aa_buffers_lock); 167762306a36Sopenharmony_ci if (buffer_count > reserve_count || 167862306a36Sopenharmony_ci (in_atomic && !list_empty(&aa_global_buffers))) { 167962306a36Sopenharmony_ci aa_buf = list_first_entry(&aa_global_buffers, union aa_buffer, 168062306a36Sopenharmony_ci list); 168162306a36Sopenharmony_ci list_del(&aa_buf->list); 168262306a36Sopenharmony_ci buffer_count--; 168362306a36Sopenharmony_ci spin_unlock(&aa_buffers_lock); 168462306a36Sopenharmony_ci return aa_buf->buffer; 168562306a36Sopenharmony_ci } 168662306a36Sopenharmony_ci if (in_atomic) { 168762306a36Sopenharmony_ci /* 168862306a36Sopenharmony_ci * out of reserve buffers and in atomic context so increase 168962306a36Sopenharmony_ci * how many buffers to keep in reserve 169062306a36Sopenharmony_ci */ 169162306a36Sopenharmony_ci reserve_count++; 169262306a36Sopenharmony_ci flags = GFP_ATOMIC; 169362306a36Sopenharmony_ci } 169462306a36Sopenharmony_ci spin_unlock(&aa_buffers_lock); 169562306a36Sopenharmony_ci 169662306a36Sopenharmony_ci if (!in_atomic) 169762306a36Sopenharmony_ci might_sleep(); 169862306a36Sopenharmony_ci aa_buf = kmalloc(aa_g_path_max, flags); 169962306a36Sopenharmony_ci if (!aa_buf) { 170062306a36Sopenharmony_ci if (try_again) { 170162306a36Sopenharmony_ci try_again = false; 170262306a36Sopenharmony_ci goto retry; 170362306a36Sopenharmony_ci } 170462306a36Sopenharmony_ci pr_warn_once("AppArmor: Failed to allocate a memory buffer.\n"); 170562306a36Sopenharmony_ci return NULL; 170662306a36Sopenharmony_ci } 170762306a36Sopenharmony_ci return aa_buf->buffer; 170862306a36Sopenharmony_ci} 170962306a36Sopenharmony_ci 171062306a36Sopenharmony_civoid aa_put_buffer(char *buf) 171162306a36Sopenharmony_ci{ 171262306a36Sopenharmony_ci union aa_buffer *aa_buf; 171362306a36Sopenharmony_ci 171462306a36Sopenharmony_ci if (!buf) 171562306a36Sopenharmony_ci return; 171662306a36Sopenharmony_ci aa_buf = container_of(buf, union aa_buffer, buffer[0]); 171762306a36Sopenharmony_ci 171862306a36Sopenharmony_ci spin_lock(&aa_buffers_lock); 171962306a36Sopenharmony_ci list_add(&aa_buf->list, &aa_global_buffers); 172062306a36Sopenharmony_ci buffer_count++; 172162306a36Sopenharmony_ci spin_unlock(&aa_buffers_lock); 172262306a36Sopenharmony_ci} 172362306a36Sopenharmony_ci 172462306a36Sopenharmony_ci/* 172562306a36Sopenharmony_ci * AppArmor init functions 172662306a36Sopenharmony_ci */ 172762306a36Sopenharmony_ci 172862306a36Sopenharmony_ci/** 172962306a36Sopenharmony_ci * set_init_ctx - set a task context and profile on the first task. 173062306a36Sopenharmony_ci * 173162306a36Sopenharmony_ci * TODO: allow setting an alternate profile than unconfined 173262306a36Sopenharmony_ci */ 173362306a36Sopenharmony_cistatic int __init set_init_ctx(void) 173462306a36Sopenharmony_ci{ 173562306a36Sopenharmony_ci struct cred *cred = (__force struct cred *)current->real_cred; 173662306a36Sopenharmony_ci 173762306a36Sopenharmony_ci set_cred_label(cred, aa_get_label(ns_unconfined(root_ns))); 173862306a36Sopenharmony_ci 173962306a36Sopenharmony_ci return 0; 174062306a36Sopenharmony_ci} 174162306a36Sopenharmony_ci 174262306a36Sopenharmony_cistatic void destroy_buffers(void) 174362306a36Sopenharmony_ci{ 174462306a36Sopenharmony_ci union aa_buffer *aa_buf; 174562306a36Sopenharmony_ci 174662306a36Sopenharmony_ci spin_lock(&aa_buffers_lock); 174762306a36Sopenharmony_ci while (!list_empty(&aa_global_buffers)) { 174862306a36Sopenharmony_ci aa_buf = list_first_entry(&aa_global_buffers, union aa_buffer, 174962306a36Sopenharmony_ci list); 175062306a36Sopenharmony_ci list_del(&aa_buf->list); 175162306a36Sopenharmony_ci spin_unlock(&aa_buffers_lock); 175262306a36Sopenharmony_ci kfree(aa_buf); 175362306a36Sopenharmony_ci spin_lock(&aa_buffers_lock); 175462306a36Sopenharmony_ci } 175562306a36Sopenharmony_ci spin_unlock(&aa_buffers_lock); 175662306a36Sopenharmony_ci} 175762306a36Sopenharmony_ci 175862306a36Sopenharmony_cistatic int __init alloc_buffers(void) 175962306a36Sopenharmony_ci{ 176062306a36Sopenharmony_ci union aa_buffer *aa_buf; 176162306a36Sopenharmony_ci int i, num; 176262306a36Sopenharmony_ci 176362306a36Sopenharmony_ci /* 176462306a36Sopenharmony_ci * A function may require two buffers at once. Usually the buffers are 176562306a36Sopenharmony_ci * used for a short period of time and are shared. On UP kernel buffers 176662306a36Sopenharmony_ci * two should be enough, with more CPUs it is possible that more 176762306a36Sopenharmony_ci * buffers will be used simultaneously. The preallocated pool may grow. 176862306a36Sopenharmony_ci * This preallocation has also the side-effect that AppArmor will be 176962306a36Sopenharmony_ci * disabled early at boot if aa_g_path_max is extremly high. 177062306a36Sopenharmony_ci */ 177162306a36Sopenharmony_ci if (num_online_cpus() > 1) 177262306a36Sopenharmony_ci num = 4 + RESERVE_COUNT; 177362306a36Sopenharmony_ci else 177462306a36Sopenharmony_ci num = 2 + RESERVE_COUNT; 177562306a36Sopenharmony_ci 177662306a36Sopenharmony_ci for (i = 0; i < num; i++) { 177762306a36Sopenharmony_ci 177862306a36Sopenharmony_ci aa_buf = kmalloc(aa_g_path_max, GFP_KERNEL | 177962306a36Sopenharmony_ci __GFP_RETRY_MAYFAIL | __GFP_NOWARN); 178062306a36Sopenharmony_ci if (!aa_buf) { 178162306a36Sopenharmony_ci destroy_buffers(); 178262306a36Sopenharmony_ci return -ENOMEM; 178362306a36Sopenharmony_ci } 178462306a36Sopenharmony_ci aa_put_buffer(aa_buf->buffer); 178562306a36Sopenharmony_ci } 178662306a36Sopenharmony_ci return 0; 178762306a36Sopenharmony_ci} 178862306a36Sopenharmony_ci 178962306a36Sopenharmony_ci#ifdef CONFIG_SYSCTL 179062306a36Sopenharmony_cistatic int apparmor_dointvec(struct ctl_table *table, int write, 179162306a36Sopenharmony_ci void *buffer, size_t *lenp, loff_t *ppos) 179262306a36Sopenharmony_ci{ 179362306a36Sopenharmony_ci if (!aa_current_policy_admin_capable(NULL)) 179462306a36Sopenharmony_ci return -EPERM; 179562306a36Sopenharmony_ci if (!apparmor_enabled) 179662306a36Sopenharmony_ci return -EINVAL; 179762306a36Sopenharmony_ci 179862306a36Sopenharmony_ci return proc_dointvec(table, write, buffer, lenp, ppos); 179962306a36Sopenharmony_ci} 180062306a36Sopenharmony_ci 180162306a36Sopenharmony_cistatic struct ctl_table apparmor_sysctl_table[] = { 180262306a36Sopenharmony_ci { 180362306a36Sopenharmony_ci .procname = "unprivileged_userns_apparmor_policy", 180462306a36Sopenharmony_ci .data = &unprivileged_userns_apparmor_policy, 180562306a36Sopenharmony_ci .maxlen = sizeof(int), 180662306a36Sopenharmony_ci .mode = 0600, 180762306a36Sopenharmony_ci .proc_handler = apparmor_dointvec, 180862306a36Sopenharmony_ci }, 180962306a36Sopenharmony_ci { 181062306a36Sopenharmony_ci .procname = "apparmor_display_secid_mode", 181162306a36Sopenharmony_ci .data = &apparmor_display_secid_mode, 181262306a36Sopenharmony_ci .maxlen = sizeof(int), 181362306a36Sopenharmony_ci .mode = 0600, 181462306a36Sopenharmony_ci .proc_handler = apparmor_dointvec, 181562306a36Sopenharmony_ci }, 181662306a36Sopenharmony_ci 181762306a36Sopenharmony_ci { } 181862306a36Sopenharmony_ci}; 181962306a36Sopenharmony_ci 182062306a36Sopenharmony_cistatic int __init apparmor_init_sysctl(void) 182162306a36Sopenharmony_ci{ 182262306a36Sopenharmony_ci return register_sysctl("kernel", apparmor_sysctl_table) ? 0 : -ENOMEM; 182362306a36Sopenharmony_ci} 182462306a36Sopenharmony_ci#else 182562306a36Sopenharmony_cistatic inline int apparmor_init_sysctl(void) 182662306a36Sopenharmony_ci{ 182762306a36Sopenharmony_ci return 0; 182862306a36Sopenharmony_ci} 182962306a36Sopenharmony_ci#endif /* CONFIG_SYSCTL */ 183062306a36Sopenharmony_ci 183162306a36Sopenharmony_ci#if defined(CONFIG_NETFILTER) && defined(CONFIG_NETWORK_SECMARK) 183262306a36Sopenharmony_cistatic unsigned int apparmor_ip_postroute(void *priv, 183362306a36Sopenharmony_ci struct sk_buff *skb, 183462306a36Sopenharmony_ci const struct nf_hook_state *state) 183562306a36Sopenharmony_ci{ 183662306a36Sopenharmony_ci struct aa_sk_ctx *ctx; 183762306a36Sopenharmony_ci struct sock *sk; 183862306a36Sopenharmony_ci 183962306a36Sopenharmony_ci if (!skb->secmark) 184062306a36Sopenharmony_ci return NF_ACCEPT; 184162306a36Sopenharmony_ci 184262306a36Sopenharmony_ci sk = skb_to_full_sk(skb); 184362306a36Sopenharmony_ci if (sk == NULL) 184462306a36Sopenharmony_ci return NF_ACCEPT; 184562306a36Sopenharmony_ci 184662306a36Sopenharmony_ci ctx = SK_CTX(sk); 184762306a36Sopenharmony_ci if (!apparmor_secmark_check(ctx->label, OP_SENDMSG, AA_MAY_SEND, 184862306a36Sopenharmony_ci skb->secmark, sk)) 184962306a36Sopenharmony_ci return NF_ACCEPT; 185062306a36Sopenharmony_ci 185162306a36Sopenharmony_ci return NF_DROP_ERR(-ECONNREFUSED); 185262306a36Sopenharmony_ci 185362306a36Sopenharmony_ci} 185462306a36Sopenharmony_ci 185562306a36Sopenharmony_cistatic const struct nf_hook_ops apparmor_nf_ops[] = { 185662306a36Sopenharmony_ci { 185762306a36Sopenharmony_ci .hook = apparmor_ip_postroute, 185862306a36Sopenharmony_ci .pf = NFPROTO_IPV4, 185962306a36Sopenharmony_ci .hooknum = NF_INET_POST_ROUTING, 186062306a36Sopenharmony_ci .priority = NF_IP_PRI_SELINUX_FIRST, 186162306a36Sopenharmony_ci }, 186262306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 186362306a36Sopenharmony_ci { 186462306a36Sopenharmony_ci .hook = apparmor_ip_postroute, 186562306a36Sopenharmony_ci .pf = NFPROTO_IPV6, 186662306a36Sopenharmony_ci .hooknum = NF_INET_POST_ROUTING, 186762306a36Sopenharmony_ci .priority = NF_IP6_PRI_SELINUX_FIRST, 186862306a36Sopenharmony_ci }, 186962306a36Sopenharmony_ci#endif 187062306a36Sopenharmony_ci}; 187162306a36Sopenharmony_ci 187262306a36Sopenharmony_cistatic int __net_init apparmor_nf_register(struct net *net) 187362306a36Sopenharmony_ci{ 187462306a36Sopenharmony_ci return nf_register_net_hooks(net, apparmor_nf_ops, 187562306a36Sopenharmony_ci ARRAY_SIZE(apparmor_nf_ops)); 187662306a36Sopenharmony_ci} 187762306a36Sopenharmony_ci 187862306a36Sopenharmony_cistatic void __net_exit apparmor_nf_unregister(struct net *net) 187962306a36Sopenharmony_ci{ 188062306a36Sopenharmony_ci nf_unregister_net_hooks(net, apparmor_nf_ops, 188162306a36Sopenharmony_ci ARRAY_SIZE(apparmor_nf_ops)); 188262306a36Sopenharmony_ci} 188362306a36Sopenharmony_ci 188462306a36Sopenharmony_cistatic struct pernet_operations apparmor_net_ops = { 188562306a36Sopenharmony_ci .init = apparmor_nf_register, 188662306a36Sopenharmony_ci .exit = apparmor_nf_unregister, 188762306a36Sopenharmony_ci}; 188862306a36Sopenharmony_ci 188962306a36Sopenharmony_cistatic int __init apparmor_nf_ip_init(void) 189062306a36Sopenharmony_ci{ 189162306a36Sopenharmony_ci int err; 189262306a36Sopenharmony_ci 189362306a36Sopenharmony_ci if (!apparmor_enabled) 189462306a36Sopenharmony_ci return 0; 189562306a36Sopenharmony_ci 189662306a36Sopenharmony_ci err = register_pernet_subsys(&apparmor_net_ops); 189762306a36Sopenharmony_ci if (err) 189862306a36Sopenharmony_ci panic("Apparmor: register_pernet_subsys: error %d\n", err); 189962306a36Sopenharmony_ci 190062306a36Sopenharmony_ci return 0; 190162306a36Sopenharmony_ci} 190262306a36Sopenharmony_ci__initcall(apparmor_nf_ip_init); 190362306a36Sopenharmony_ci#endif 190462306a36Sopenharmony_ci 190562306a36Sopenharmony_cistatic int __init apparmor_init(void) 190662306a36Sopenharmony_ci{ 190762306a36Sopenharmony_ci int error; 190862306a36Sopenharmony_ci 190962306a36Sopenharmony_ci error = aa_setup_dfa_engine(); 191062306a36Sopenharmony_ci if (error) { 191162306a36Sopenharmony_ci AA_ERROR("Unable to setup dfa engine\n"); 191262306a36Sopenharmony_ci goto alloc_out; 191362306a36Sopenharmony_ci } 191462306a36Sopenharmony_ci 191562306a36Sopenharmony_ci error = aa_alloc_root_ns(); 191662306a36Sopenharmony_ci if (error) { 191762306a36Sopenharmony_ci AA_ERROR("Unable to allocate default profile namespace\n"); 191862306a36Sopenharmony_ci goto alloc_out; 191962306a36Sopenharmony_ci } 192062306a36Sopenharmony_ci 192162306a36Sopenharmony_ci error = apparmor_init_sysctl(); 192262306a36Sopenharmony_ci if (error) { 192362306a36Sopenharmony_ci AA_ERROR("Unable to register sysctls\n"); 192462306a36Sopenharmony_ci goto alloc_out; 192562306a36Sopenharmony_ci 192662306a36Sopenharmony_ci } 192762306a36Sopenharmony_ci 192862306a36Sopenharmony_ci error = alloc_buffers(); 192962306a36Sopenharmony_ci if (error) { 193062306a36Sopenharmony_ci AA_ERROR("Unable to allocate work buffers\n"); 193162306a36Sopenharmony_ci goto alloc_out; 193262306a36Sopenharmony_ci } 193362306a36Sopenharmony_ci 193462306a36Sopenharmony_ci error = set_init_ctx(); 193562306a36Sopenharmony_ci if (error) { 193662306a36Sopenharmony_ci AA_ERROR("Failed to set context on init task\n"); 193762306a36Sopenharmony_ci aa_free_root_ns(); 193862306a36Sopenharmony_ci goto buffers_out; 193962306a36Sopenharmony_ci } 194062306a36Sopenharmony_ci security_add_hooks(apparmor_hooks, ARRAY_SIZE(apparmor_hooks), 194162306a36Sopenharmony_ci "apparmor"); 194262306a36Sopenharmony_ci 194362306a36Sopenharmony_ci /* Report that AppArmor successfully initialized */ 194462306a36Sopenharmony_ci apparmor_initialized = 1; 194562306a36Sopenharmony_ci if (aa_g_profile_mode == APPARMOR_COMPLAIN) 194662306a36Sopenharmony_ci aa_info_message("AppArmor initialized: complain mode enabled"); 194762306a36Sopenharmony_ci else if (aa_g_profile_mode == APPARMOR_KILL) 194862306a36Sopenharmony_ci aa_info_message("AppArmor initialized: kill mode enabled"); 194962306a36Sopenharmony_ci else 195062306a36Sopenharmony_ci aa_info_message("AppArmor initialized"); 195162306a36Sopenharmony_ci 195262306a36Sopenharmony_ci return error; 195362306a36Sopenharmony_ci 195462306a36Sopenharmony_cibuffers_out: 195562306a36Sopenharmony_ci destroy_buffers(); 195662306a36Sopenharmony_cialloc_out: 195762306a36Sopenharmony_ci aa_destroy_aafs(); 195862306a36Sopenharmony_ci aa_teardown_dfa_engine(); 195962306a36Sopenharmony_ci 196062306a36Sopenharmony_ci apparmor_enabled = false; 196162306a36Sopenharmony_ci return error; 196262306a36Sopenharmony_ci} 196362306a36Sopenharmony_ci 196462306a36Sopenharmony_ciDEFINE_LSM(apparmor) = { 196562306a36Sopenharmony_ci .name = "apparmor", 196662306a36Sopenharmony_ci .flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE, 196762306a36Sopenharmony_ci .enabled = &apparmor_enabled, 196862306a36Sopenharmony_ci .blobs = &apparmor_blob_sizes, 196962306a36Sopenharmony_ci .init = apparmor_init, 197062306a36Sopenharmony_ci}; 1971