1*b5e95b48SJohn Johansen /* 2*b5e95b48SJohn Johansen * AppArmor security module 3*b5e95b48SJohn Johansen * 4*b5e95b48SJohn Johansen * This file contains AppArmor LSM hooks. 5*b5e95b48SJohn Johansen * 6*b5e95b48SJohn Johansen * Copyright (C) 1998-2008 Novell/SUSE 7*b5e95b48SJohn Johansen * Copyright 2009-2010 Canonical Ltd. 8*b5e95b48SJohn Johansen * 9*b5e95b48SJohn Johansen * This program is free software; you can redistribute it and/or 10*b5e95b48SJohn Johansen * modify it under the terms of the GNU General Public License as 11*b5e95b48SJohn Johansen * published by the Free Software Foundation, version 2 of the 12*b5e95b48SJohn Johansen * License. 13*b5e95b48SJohn Johansen */ 14*b5e95b48SJohn Johansen 15*b5e95b48SJohn Johansen #include <linux/security.h> 16*b5e95b48SJohn Johansen #include <linux/moduleparam.h> 17*b5e95b48SJohn Johansen #include <linux/mm.h> 18*b5e95b48SJohn Johansen #include <linux/mman.h> 19*b5e95b48SJohn Johansen #include <linux/mount.h> 20*b5e95b48SJohn Johansen #include <linux/namei.h> 21*b5e95b48SJohn Johansen #include <linux/ptrace.h> 22*b5e95b48SJohn Johansen #include <linux/ctype.h> 23*b5e95b48SJohn Johansen #include <linux/sysctl.h> 24*b5e95b48SJohn Johansen #include <linux/audit.h> 25*b5e95b48SJohn Johansen #include <net/sock.h> 26*b5e95b48SJohn Johansen 27*b5e95b48SJohn Johansen #include "include/apparmor.h" 28*b5e95b48SJohn Johansen #include "include/apparmorfs.h" 29*b5e95b48SJohn Johansen #include "include/audit.h" 30*b5e95b48SJohn Johansen #include "include/capability.h" 31*b5e95b48SJohn Johansen #include "include/context.h" 32*b5e95b48SJohn Johansen #include "include/file.h" 33*b5e95b48SJohn Johansen #include "include/ipc.h" 34*b5e95b48SJohn Johansen #include "include/path.h" 35*b5e95b48SJohn Johansen #include "include/policy.h" 36*b5e95b48SJohn Johansen #include "include/procattr.h" 37*b5e95b48SJohn Johansen 38*b5e95b48SJohn Johansen /* Flag indicating whether initialization completed */ 39*b5e95b48SJohn Johansen int apparmor_initialized __initdata; 40*b5e95b48SJohn Johansen 41*b5e95b48SJohn Johansen /* 42*b5e95b48SJohn Johansen * LSM hook functions 43*b5e95b48SJohn Johansen */ 44*b5e95b48SJohn Johansen 45*b5e95b48SJohn Johansen /* 46*b5e95b48SJohn Johansen * free the associated aa_task_cxt and put its profiles 47*b5e95b48SJohn Johansen */ 48*b5e95b48SJohn Johansen static void apparmor_cred_free(struct cred *cred) 49*b5e95b48SJohn Johansen { 50*b5e95b48SJohn Johansen aa_free_task_context(cred->security); 51*b5e95b48SJohn Johansen cred->security = NULL; 52*b5e95b48SJohn Johansen } 53*b5e95b48SJohn Johansen 54*b5e95b48SJohn Johansen /* 55*b5e95b48SJohn Johansen * allocate the apparmor part of blank credentials 56*b5e95b48SJohn Johansen */ 57*b5e95b48SJohn Johansen static int apparmor_cred_alloc_blank(struct cred *cred, gfp_t gfp) 58*b5e95b48SJohn Johansen { 59*b5e95b48SJohn Johansen /* freed by apparmor_cred_free */ 60*b5e95b48SJohn Johansen struct aa_task_cxt *cxt = aa_alloc_task_context(gfp); 61*b5e95b48SJohn Johansen if (!cxt) 62*b5e95b48SJohn Johansen return -ENOMEM; 63*b5e95b48SJohn Johansen 64*b5e95b48SJohn Johansen cred->security = cxt; 65*b5e95b48SJohn Johansen return 0; 66*b5e95b48SJohn Johansen } 67*b5e95b48SJohn Johansen 68*b5e95b48SJohn Johansen /* 69*b5e95b48SJohn Johansen * prepare new aa_task_cxt for modification by prepare_cred block 70*b5e95b48SJohn Johansen */ 71*b5e95b48SJohn Johansen static int apparmor_cred_prepare(struct cred *new, const struct cred *old, 72*b5e95b48SJohn Johansen gfp_t gfp) 73*b5e95b48SJohn Johansen { 74*b5e95b48SJohn Johansen /* freed by apparmor_cred_free */ 75*b5e95b48SJohn Johansen struct aa_task_cxt *cxt = aa_alloc_task_context(gfp); 76*b5e95b48SJohn Johansen if (!cxt) 77*b5e95b48SJohn Johansen return -ENOMEM; 78*b5e95b48SJohn Johansen 79*b5e95b48SJohn Johansen aa_dup_task_context(cxt, old->security); 80*b5e95b48SJohn Johansen new->security = cxt; 81*b5e95b48SJohn Johansen return 0; 82*b5e95b48SJohn Johansen } 83*b5e95b48SJohn Johansen 84*b5e95b48SJohn Johansen /* 85*b5e95b48SJohn Johansen * transfer the apparmor data to a blank set of creds 86*b5e95b48SJohn Johansen */ 87*b5e95b48SJohn Johansen static void apparmor_cred_transfer(struct cred *new, const struct cred *old) 88*b5e95b48SJohn Johansen { 89*b5e95b48SJohn Johansen const struct aa_task_cxt *old_cxt = old->security; 90*b5e95b48SJohn Johansen struct aa_task_cxt *new_cxt = new->security; 91*b5e95b48SJohn Johansen 92*b5e95b48SJohn Johansen aa_dup_task_context(new_cxt, old_cxt); 93*b5e95b48SJohn Johansen } 94*b5e95b48SJohn Johansen 95*b5e95b48SJohn Johansen static int apparmor_ptrace_access_check(struct task_struct *child, 96*b5e95b48SJohn Johansen unsigned int mode) 97*b5e95b48SJohn Johansen { 98*b5e95b48SJohn Johansen int error = cap_ptrace_access_check(child, mode); 99*b5e95b48SJohn Johansen if (error) 100*b5e95b48SJohn Johansen return error; 101*b5e95b48SJohn Johansen 102*b5e95b48SJohn Johansen return aa_ptrace(current, child, mode); 103*b5e95b48SJohn Johansen } 104*b5e95b48SJohn Johansen 105*b5e95b48SJohn Johansen static int apparmor_ptrace_traceme(struct task_struct *parent) 106*b5e95b48SJohn Johansen { 107*b5e95b48SJohn Johansen int error = cap_ptrace_traceme(parent); 108*b5e95b48SJohn Johansen if (error) 109*b5e95b48SJohn Johansen return error; 110*b5e95b48SJohn Johansen 111*b5e95b48SJohn Johansen return aa_ptrace(parent, current, PTRACE_MODE_ATTACH); 112*b5e95b48SJohn Johansen } 113*b5e95b48SJohn Johansen 114*b5e95b48SJohn Johansen /* Derived from security/commoncap.c:cap_capget */ 115*b5e95b48SJohn Johansen static int apparmor_capget(struct task_struct *target, kernel_cap_t *effective, 116*b5e95b48SJohn Johansen kernel_cap_t *inheritable, kernel_cap_t *permitted) 117*b5e95b48SJohn Johansen { 118*b5e95b48SJohn Johansen struct aa_profile *profile; 119*b5e95b48SJohn Johansen const struct cred *cred; 120*b5e95b48SJohn Johansen 121*b5e95b48SJohn Johansen rcu_read_lock(); 122*b5e95b48SJohn Johansen cred = __task_cred(target); 123*b5e95b48SJohn Johansen profile = aa_cred_profile(cred); 124*b5e95b48SJohn Johansen 125*b5e95b48SJohn Johansen *effective = cred->cap_effective; 126*b5e95b48SJohn Johansen *inheritable = cred->cap_inheritable; 127*b5e95b48SJohn Johansen *permitted = cred->cap_permitted; 128*b5e95b48SJohn Johansen 129*b5e95b48SJohn Johansen if (!unconfined(profile)) { 130*b5e95b48SJohn Johansen *effective = cap_intersect(*effective, profile->caps.allow); 131*b5e95b48SJohn Johansen *permitted = cap_intersect(*permitted, profile->caps.allow); 132*b5e95b48SJohn Johansen } 133*b5e95b48SJohn Johansen rcu_read_unlock(); 134*b5e95b48SJohn Johansen 135*b5e95b48SJohn Johansen return 0; 136*b5e95b48SJohn Johansen } 137*b5e95b48SJohn Johansen 138*b5e95b48SJohn Johansen static int apparmor_capable(struct task_struct *task, const struct cred *cred, 139*b5e95b48SJohn Johansen int cap, int audit) 140*b5e95b48SJohn Johansen { 141*b5e95b48SJohn Johansen struct aa_profile *profile; 142*b5e95b48SJohn Johansen /* cap_capable returns 0 on success, else -EPERM */ 143*b5e95b48SJohn Johansen int error = cap_capable(task, cred, cap, audit); 144*b5e95b48SJohn Johansen if (!error) { 145*b5e95b48SJohn Johansen profile = aa_cred_profile(cred); 146*b5e95b48SJohn Johansen if (!unconfined(profile)) 147*b5e95b48SJohn Johansen error = aa_capable(task, profile, cap, audit); 148*b5e95b48SJohn Johansen } 149*b5e95b48SJohn Johansen return error; 150*b5e95b48SJohn Johansen } 151*b5e95b48SJohn Johansen 152*b5e95b48SJohn Johansen /** 153*b5e95b48SJohn Johansen * common_perm - basic common permission check wrapper fn for paths 154*b5e95b48SJohn Johansen * @op: operation being checked 155*b5e95b48SJohn Johansen * @path: path to check permission of (NOT NULL) 156*b5e95b48SJohn Johansen * @mask: requested permissions mask 157*b5e95b48SJohn Johansen * @cond: conditional info for the permission request (NOT NULL) 158*b5e95b48SJohn Johansen * 159*b5e95b48SJohn Johansen * Returns: %0 else error code if error or permission denied 160*b5e95b48SJohn Johansen */ 161*b5e95b48SJohn Johansen static int common_perm(int op, struct path *path, u32 mask, 162*b5e95b48SJohn Johansen struct path_cond *cond) 163*b5e95b48SJohn Johansen { 164*b5e95b48SJohn Johansen struct aa_profile *profile; 165*b5e95b48SJohn Johansen int error = 0; 166*b5e95b48SJohn Johansen 167*b5e95b48SJohn Johansen profile = __aa_current_profile(); 168*b5e95b48SJohn Johansen if (!unconfined(profile)) 169*b5e95b48SJohn Johansen error = aa_path_perm(op, profile, path, 0, mask, cond); 170*b5e95b48SJohn Johansen 171*b5e95b48SJohn Johansen return error; 172*b5e95b48SJohn Johansen } 173*b5e95b48SJohn Johansen 174*b5e95b48SJohn Johansen /** 175*b5e95b48SJohn Johansen * common_perm_dir_dentry - common permission wrapper when path is dir, dentry 176*b5e95b48SJohn Johansen * @op: operation being checked 177*b5e95b48SJohn Johansen * @dir: directory of the dentry (NOT NULL) 178*b5e95b48SJohn Johansen * @dentry: dentry to check (NOT NULL) 179*b5e95b48SJohn Johansen * @mask: requested permissions mask 180*b5e95b48SJohn Johansen * @cond: conditional info for the permission request (NOT NULL) 181*b5e95b48SJohn Johansen * 182*b5e95b48SJohn Johansen * Returns: %0 else error code if error or permission denied 183*b5e95b48SJohn Johansen */ 184*b5e95b48SJohn Johansen static int common_perm_dir_dentry(int op, struct path *dir, 185*b5e95b48SJohn Johansen struct dentry *dentry, u32 mask, 186*b5e95b48SJohn Johansen struct path_cond *cond) 187*b5e95b48SJohn Johansen { 188*b5e95b48SJohn Johansen struct path path = { dir->mnt, dentry }; 189*b5e95b48SJohn Johansen 190*b5e95b48SJohn Johansen return common_perm(op, &path, mask, cond); 191*b5e95b48SJohn Johansen } 192*b5e95b48SJohn Johansen 193*b5e95b48SJohn Johansen /** 194*b5e95b48SJohn Johansen * common_perm_mnt_dentry - common permission wrapper when mnt, dentry 195*b5e95b48SJohn Johansen * @op: operation being checked 196*b5e95b48SJohn Johansen * @mnt: mount point of dentry (NOT NULL) 197*b5e95b48SJohn Johansen * @dentry: dentry to check (NOT NULL) 198*b5e95b48SJohn Johansen * @mask: requested permissions mask 199*b5e95b48SJohn Johansen * 200*b5e95b48SJohn Johansen * Returns: %0 else error code if error or permission denied 201*b5e95b48SJohn Johansen */ 202*b5e95b48SJohn Johansen static int common_perm_mnt_dentry(int op, struct vfsmount *mnt, 203*b5e95b48SJohn Johansen struct dentry *dentry, u32 mask) 204*b5e95b48SJohn Johansen { 205*b5e95b48SJohn Johansen struct path path = { mnt, dentry }; 206*b5e95b48SJohn Johansen struct path_cond cond = { dentry->d_inode->i_uid, 207*b5e95b48SJohn Johansen dentry->d_inode->i_mode 208*b5e95b48SJohn Johansen }; 209*b5e95b48SJohn Johansen 210*b5e95b48SJohn Johansen return common_perm(op, &path, mask, &cond); 211*b5e95b48SJohn Johansen } 212*b5e95b48SJohn Johansen 213*b5e95b48SJohn Johansen /** 214*b5e95b48SJohn Johansen * common_perm_rm - common permission wrapper for operations doing rm 215*b5e95b48SJohn Johansen * @op: operation being checked 216*b5e95b48SJohn Johansen * @dir: directory that the dentry is in (NOT NULL) 217*b5e95b48SJohn Johansen * @dentry: dentry being rm'd (NOT NULL) 218*b5e95b48SJohn Johansen * @mask: requested permission mask 219*b5e95b48SJohn Johansen * 220*b5e95b48SJohn Johansen * Returns: %0 else error code if error or permission denied 221*b5e95b48SJohn Johansen */ 222*b5e95b48SJohn Johansen static int common_perm_rm(int op, struct path *dir, 223*b5e95b48SJohn Johansen struct dentry *dentry, u32 mask) 224*b5e95b48SJohn Johansen { 225*b5e95b48SJohn Johansen struct inode *inode = dentry->d_inode; 226*b5e95b48SJohn Johansen struct path_cond cond = { }; 227*b5e95b48SJohn Johansen 228*b5e95b48SJohn Johansen if (!inode || !dir->mnt || !mediated_filesystem(inode)) 229*b5e95b48SJohn Johansen return 0; 230*b5e95b48SJohn Johansen 231*b5e95b48SJohn Johansen cond.uid = inode->i_uid; 232*b5e95b48SJohn Johansen cond.mode = inode->i_mode; 233*b5e95b48SJohn Johansen 234*b5e95b48SJohn Johansen return common_perm_dir_dentry(op, dir, dentry, mask, &cond); 235*b5e95b48SJohn Johansen } 236*b5e95b48SJohn Johansen 237*b5e95b48SJohn Johansen /** 238*b5e95b48SJohn Johansen * common_perm_create - common permission wrapper for operations doing create 239*b5e95b48SJohn Johansen * @op: operation being checked 240*b5e95b48SJohn Johansen * @dir: directory that dentry will be created in (NOT NULL) 241*b5e95b48SJohn Johansen * @dentry: dentry to create (NOT NULL) 242*b5e95b48SJohn Johansen * @mask: request permission mask 243*b5e95b48SJohn Johansen * @mode: created file mode 244*b5e95b48SJohn Johansen * 245*b5e95b48SJohn Johansen * Returns: %0 else error code if error or permission denied 246*b5e95b48SJohn Johansen */ 247*b5e95b48SJohn Johansen static int common_perm_create(int op, struct path *dir, struct dentry *dentry, 248*b5e95b48SJohn Johansen u32 mask, umode_t mode) 249*b5e95b48SJohn Johansen { 250*b5e95b48SJohn Johansen struct path_cond cond = { current_fsuid(), mode }; 251*b5e95b48SJohn Johansen 252*b5e95b48SJohn Johansen if (!dir->mnt || !mediated_filesystem(dir->dentry->d_inode)) 253*b5e95b48SJohn Johansen return 0; 254*b5e95b48SJohn Johansen 255*b5e95b48SJohn Johansen return common_perm_dir_dentry(op, dir, dentry, mask, &cond); 256*b5e95b48SJohn Johansen } 257*b5e95b48SJohn Johansen 258*b5e95b48SJohn Johansen static int apparmor_path_unlink(struct path *dir, struct dentry *dentry) 259*b5e95b48SJohn Johansen { 260*b5e95b48SJohn Johansen return common_perm_rm(OP_UNLINK, dir, dentry, AA_MAY_DELETE); 261*b5e95b48SJohn Johansen } 262*b5e95b48SJohn Johansen 263*b5e95b48SJohn Johansen static int apparmor_path_mkdir(struct path *dir, struct dentry *dentry, 264*b5e95b48SJohn Johansen int mode) 265*b5e95b48SJohn Johansen { 266*b5e95b48SJohn Johansen return common_perm_create(OP_MKDIR, dir, dentry, AA_MAY_CREATE, 267*b5e95b48SJohn Johansen S_IFDIR); 268*b5e95b48SJohn Johansen } 269*b5e95b48SJohn Johansen 270*b5e95b48SJohn Johansen static int apparmor_path_rmdir(struct path *dir, struct dentry *dentry) 271*b5e95b48SJohn Johansen { 272*b5e95b48SJohn Johansen return common_perm_rm(OP_RMDIR, dir, dentry, AA_MAY_DELETE); 273*b5e95b48SJohn Johansen } 274*b5e95b48SJohn Johansen 275*b5e95b48SJohn Johansen static int apparmor_path_mknod(struct path *dir, struct dentry *dentry, 276*b5e95b48SJohn Johansen int mode, unsigned int dev) 277*b5e95b48SJohn Johansen { 278*b5e95b48SJohn Johansen return common_perm_create(OP_MKNOD, dir, dentry, AA_MAY_CREATE, mode); 279*b5e95b48SJohn Johansen } 280*b5e95b48SJohn Johansen 281*b5e95b48SJohn Johansen static int apparmor_path_truncate(struct path *path, loff_t length, 282*b5e95b48SJohn Johansen unsigned int time_attrs) 283*b5e95b48SJohn Johansen { 284*b5e95b48SJohn Johansen struct path_cond cond = { path->dentry->d_inode->i_uid, 285*b5e95b48SJohn Johansen path->dentry->d_inode->i_mode 286*b5e95b48SJohn Johansen }; 287*b5e95b48SJohn Johansen 288*b5e95b48SJohn Johansen if (!path->mnt || !mediated_filesystem(path->dentry->d_inode)) 289*b5e95b48SJohn Johansen return 0; 290*b5e95b48SJohn Johansen 291*b5e95b48SJohn Johansen return common_perm(OP_TRUNC, path, MAY_WRITE | AA_MAY_META_WRITE, 292*b5e95b48SJohn Johansen &cond); 293*b5e95b48SJohn Johansen } 294*b5e95b48SJohn Johansen 295*b5e95b48SJohn Johansen static int apparmor_path_symlink(struct path *dir, struct dentry *dentry, 296*b5e95b48SJohn Johansen const char *old_name) 297*b5e95b48SJohn Johansen { 298*b5e95b48SJohn Johansen return common_perm_create(OP_SYMLINK, dir, dentry, AA_MAY_CREATE, 299*b5e95b48SJohn Johansen S_IFLNK); 300*b5e95b48SJohn Johansen } 301*b5e95b48SJohn Johansen 302*b5e95b48SJohn Johansen static int apparmor_path_link(struct dentry *old_dentry, struct path *new_dir, 303*b5e95b48SJohn Johansen struct dentry *new_dentry) 304*b5e95b48SJohn Johansen { 305*b5e95b48SJohn Johansen struct aa_profile *profile; 306*b5e95b48SJohn Johansen int error = 0; 307*b5e95b48SJohn Johansen 308*b5e95b48SJohn Johansen if (!mediated_filesystem(old_dentry->d_inode)) 309*b5e95b48SJohn Johansen return 0; 310*b5e95b48SJohn Johansen 311*b5e95b48SJohn Johansen profile = aa_current_profile(); 312*b5e95b48SJohn Johansen if (!unconfined(profile)) 313*b5e95b48SJohn Johansen error = aa_path_link(profile, old_dentry, new_dir, new_dentry); 314*b5e95b48SJohn Johansen return error; 315*b5e95b48SJohn Johansen } 316*b5e95b48SJohn Johansen 317*b5e95b48SJohn Johansen static int apparmor_path_rename(struct path *old_dir, struct dentry *old_dentry, 318*b5e95b48SJohn Johansen struct path *new_dir, struct dentry *new_dentry) 319*b5e95b48SJohn Johansen { 320*b5e95b48SJohn Johansen struct aa_profile *profile; 321*b5e95b48SJohn Johansen int error = 0; 322*b5e95b48SJohn Johansen 323*b5e95b48SJohn Johansen if (!mediated_filesystem(old_dentry->d_inode)) 324*b5e95b48SJohn Johansen return 0; 325*b5e95b48SJohn Johansen 326*b5e95b48SJohn Johansen profile = aa_current_profile(); 327*b5e95b48SJohn Johansen if (!unconfined(profile)) { 328*b5e95b48SJohn Johansen struct path old_path = { old_dir->mnt, old_dentry }; 329*b5e95b48SJohn Johansen struct path new_path = { new_dir->mnt, new_dentry }; 330*b5e95b48SJohn Johansen struct path_cond cond = { old_dentry->d_inode->i_uid, 331*b5e95b48SJohn Johansen old_dentry->d_inode->i_mode 332*b5e95b48SJohn Johansen }; 333*b5e95b48SJohn Johansen 334*b5e95b48SJohn Johansen error = aa_path_perm(OP_RENAME_SRC, profile, &old_path, 0, 335*b5e95b48SJohn Johansen MAY_READ | AA_MAY_META_READ | MAY_WRITE | 336*b5e95b48SJohn Johansen AA_MAY_META_WRITE | AA_MAY_DELETE, 337*b5e95b48SJohn Johansen &cond); 338*b5e95b48SJohn Johansen if (!error) 339*b5e95b48SJohn Johansen error = aa_path_perm(OP_RENAME_DEST, profile, &new_path, 340*b5e95b48SJohn Johansen 0, MAY_WRITE | AA_MAY_META_WRITE | 341*b5e95b48SJohn Johansen AA_MAY_CREATE, &cond); 342*b5e95b48SJohn Johansen 343*b5e95b48SJohn Johansen } 344*b5e95b48SJohn Johansen return error; 345*b5e95b48SJohn Johansen } 346*b5e95b48SJohn Johansen 347*b5e95b48SJohn Johansen static int apparmor_path_chmod(struct dentry *dentry, struct vfsmount *mnt, 348*b5e95b48SJohn Johansen mode_t mode) 349*b5e95b48SJohn Johansen { 350*b5e95b48SJohn Johansen if (!mediated_filesystem(dentry->d_inode)) 351*b5e95b48SJohn Johansen return 0; 352*b5e95b48SJohn Johansen 353*b5e95b48SJohn Johansen return common_perm_mnt_dentry(OP_CHMOD, mnt, dentry, AA_MAY_CHMOD); 354*b5e95b48SJohn Johansen } 355*b5e95b48SJohn Johansen 356*b5e95b48SJohn Johansen static int apparmor_path_chown(struct path *path, uid_t uid, gid_t gid) 357*b5e95b48SJohn Johansen { 358*b5e95b48SJohn Johansen struct path_cond cond = { path->dentry->d_inode->i_uid, 359*b5e95b48SJohn Johansen path->dentry->d_inode->i_mode 360*b5e95b48SJohn Johansen }; 361*b5e95b48SJohn Johansen 362*b5e95b48SJohn Johansen if (!mediated_filesystem(path->dentry->d_inode)) 363*b5e95b48SJohn Johansen return 0; 364*b5e95b48SJohn Johansen 365*b5e95b48SJohn Johansen return common_perm(OP_CHOWN, path, AA_MAY_CHOWN, &cond); 366*b5e95b48SJohn Johansen } 367*b5e95b48SJohn Johansen 368*b5e95b48SJohn Johansen static int apparmor_inode_getattr(struct vfsmount *mnt, struct dentry *dentry) 369*b5e95b48SJohn Johansen { 370*b5e95b48SJohn Johansen if (!mediated_filesystem(dentry->d_inode)) 371*b5e95b48SJohn Johansen return 0; 372*b5e95b48SJohn Johansen 373*b5e95b48SJohn Johansen return common_perm_mnt_dentry(OP_GETATTR, mnt, dentry, 374*b5e95b48SJohn Johansen AA_MAY_META_READ); 375*b5e95b48SJohn Johansen } 376*b5e95b48SJohn Johansen 377*b5e95b48SJohn Johansen static int apparmor_dentry_open(struct file *file, const struct cred *cred) 378*b5e95b48SJohn Johansen { 379*b5e95b48SJohn Johansen struct aa_file_cxt *fcxt = file->f_security; 380*b5e95b48SJohn Johansen struct aa_profile *profile; 381*b5e95b48SJohn Johansen int error = 0; 382*b5e95b48SJohn Johansen 383*b5e95b48SJohn Johansen if (!mediated_filesystem(file->f_path.dentry->d_inode)) 384*b5e95b48SJohn Johansen return 0; 385*b5e95b48SJohn Johansen 386*b5e95b48SJohn Johansen /* If in exec, permission is handled by bprm hooks. 387*b5e95b48SJohn Johansen * Cache permissions granted by the previous exec check, with 388*b5e95b48SJohn Johansen * implicit read and executable mmap which are required to 389*b5e95b48SJohn Johansen * actually execute the image. 390*b5e95b48SJohn Johansen */ 391*b5e95b48SJohn Johansen if (current->in_execve) { 392*b5e95b48SJohn Johansen fcxt->allow = MAY_EXEC | MAY_READ | AA_EXEC_MMAP; 393*b5e95b48SJohn Johansen return 0; 394*b5e95b48SJohn Johansen } 395*b5e95b48SJohn Johansen 396*b5e95b48SJohn Johansen profile = aa_cred_profile(cred); 397*b5e95b48SJohn Johansen if (!unconfined(profile)) { 398*b5e95b48SJohn Johansen struct inode *inode = file->f_path.dentry->d_inode; 399*b5e95b48SJohn Johansen struct path_cond cond = { inode->i_uid, inode->i_mode }; 400*b5e95b48SJohn Johansen 401*b5e95b48SJohn Johansen error = aa_path_perm(OP_OPEN, profile, &file->f_path, 0, 402*b5e95b48SJohn Johansen aa_map_file_to_perms(file), &cond); 403*b5e95b48SJohn Johansen /* todo cache full allowed permissions set and state */ 404*b5e95b48SJohn Johansen fcxt->allow = aa_map_file_to_perms(file); 405*b5e95b48SJohn Johansen } 406*b5e95b48SJohn Johansen 407*b5e95b48SJohn Johansen return error; 408*b5e95b48SJohn Johansen } 409*b5e95b48SJohn Johansen 410*b5e95b48SJohn Johansen static int apparmor_file_alloc_security(struct file *file) 411*b5e95b48SJohn Johansen { 412*b5e95b48SJohn Johansen /* freed by apparmor_file_free_security */ 413*b5e95b48SJohn Johansen file->f_security = aa_alloc_file_context(GFP_KERNEL); 414*b5e95b48SJohn Johansen if (!file->f_security) 415*b5e95b48SJohn Johansen return -ENOMEM; 416*b5e95b48SJohn Johansen return 0; 417*b5e95b48SJohn Johansen 418*b5e95b48SJohn Johansen } 419*b5e95b48SJohn Johansen 420*b5e95b48SJohn Johansen static void apparmor_file_free_security(struct file *file) 421*b5e95b48SJohn Johansen { 422*b5e95b48SJohn Johansen struct aa_file_cxt *cxt = file->f_security; 423*b5e95b48SJohn Johansen 424*b5e95b48SJohn Johansen aa_free_file_context(cxt); 425*b5e95b48SJohn Johansen } 426*b5e95b48SJohn Johansen 427*b5e95b48SJohn Johansen static int common_file_perm(int op, struct file *file, u32 mask) 428*b5e95b48SJohn Johansen { 429*b5e95b48SJohn Johansen struct aa_file_cxt *fcxt = file->f_security; 430*b5e95b48SJohn Johansen struct aa_profile *profile, *fprofile = aa_cred_profile(file->f_cred); 431*b5e95b48SJohn Johansen int error = 0; 432*b5e95b48SJohn Johansen 433*b5e95b48SJohn Johansen BUG_ON(!fprofile); 434*b5e95b48SJohn Johansen 435*b5e95b48SJohn Johansen if (!file->f_path.mnt || 436*b5e95b48SJohn Johansen !mediated_filesystem(file->f_path.dentry->d_inode)) 437*b5e95b48SJohn Johansen return 0; 438*b5e95b48SJohn Johansen 439*b5e95b48SJohn Johansen profile = __aa_current_profile(); 440*b5e95b48SJohn Johansen 441*b5e95b48SJohn Johansen /* revalidate access, if task is unconfined, or the cached cred 442*b5e95b48SJohn Johansen * doesn't match or if the request is for more permissions than 443*b5e95b48SJohn Johansen * was granted. 444*b5e95b48SJohn Johansen * 445*b5e95b48SJohn Johansen * Note: the test for !unconfined(fprofile) is to handle file 446*b5e95b48SJohn Johansen * delegation from unconfined tasks 447*b5e95b48SJohn Johansen */ 448*b5e95b48SJohn Johansen if (!unconfined(profile) && !unconfined(fprofile) && 449*b5e95b48SJohn Johansen ((fprofile != profile) || (mask & ~fcxt->allow))) 450*b5e95b48SJohn Johansen error = aa_file_perm(op, profile, file, mask); 451*b5e95b48SJohn Johansen 452*b5e95b48SJohn Johansen return error; 453*b5e95b48SJohn Johansen } 454*b5e95b48SJohn Johansen 455*b5e95b48SJohn Johansen static int apparmor_file_permission(struct file *file, int mask) 456*b5e95b48SJohn Johansen { 457*b5e95b48SJohn Johansen return common_file_perm(OP_FPERM, file, mask); 458*b5e95b48SJohn Johansen } 459*b5e95b48SJohn Johansen 460*b5e95b48SJohn Johansen static int apparmor_file_lock(struct file *file, unsigned int cmd) 461*b5e95b48SJohn Johansen { 462*b5e95b48SJohn Johansen u32 mask = AA_MAY_LOCK; 463*b5e95b48SJohn Johansen 464*b5e95b48SJohn Johansen if (cmd == F_WRLCK) 465*b5e95b48SJohn Johansen mask |= MAY_WRITE; 466*b5e95b48SJohn Johansen 467*b5e95b48SJohn Johansen return common_file_perm(OP_FLOCK, file, mask); 468*b5e95b48SJohn Johansen } 469*b5e95b48SJohn Johansen 470*b5e95b48SJohn Johansen static int common_mmap(int op, struct file *file, unsigned long prot, 471*b5e95b48SJohn Johansen unsigned long flags) 472*b5e95b48SJohn Johansen { 473*b5e95b48SJohn Johansen struct dentry *dentry; 474*b5e95b48SJohn Johansen int mask = 0; 475*b5e95b48SJohn Johansen 476*b5e95b48SJohn Johansen if (!file || !file->f_security) 477*b5e95b48SJohn Johansen return 0; 478*b5e95b48SJohn Johansen 479*b5e95b48SJohn Johansen if (prot & PROT_READ) 480*b5e95b48SJohn Johansen mask |= MAY_READ; 481*b5e95b48SJohn Johansen /* 482*b5e95b48SJohn Johansen * Private mappings don't require write perms since they don't 483*b5e95b48SJohn Johansen * write back to the files 484*b5e95b48SJohn Johansen */ 485*b5e95b48SJohn Johansen if ((prot & PROT_WRITE) && !(flags & MAP_PRIVATE)) 486*b5e95b48SJohn Johansen mask |= MAY_WRITE; 487*b5e95b48SJohn Johansen if (prot & PROT_EXEC) 488*b5e95b48SJohn Johansen mask |= AA_EXEC_MMAP; 489*b5e95b48SJohn Johansen 490*b5e95b48SJohn Johansen dentry = file->f_path.dentry; 491*b5e95b48SJohn Johansen return common_file_perm(op, file, mask); 492*b5e95b48SJohn Johansen } 493*b5e95b48SJohn Johansen 494*b5e95b48SJohn Johansen static int apparmor_file_mmap(struct file *file, unsigned long reqprot, 495*b5e95b48SJohn Johansen unsigned long prot, unsigned long flags, 496*b5e95b48SJohn Johansen unsigned long addr, unsigned long addr_only) 497*b5e95b48SJohn Johansen { 498*b5e95b48SJohn Johansen int rc = 0; 499*b5e95b48SJohn Johansen 500*b5e95b48SJohn Johansen /* do DAC check */ 501*b5e95b48SJohn Johansen rc = cap_file_mmap(file, reqprot, prot, flags, addr, addr_only); 502*b5e95b48SJohn Johansen if (rc || addr_only) 503*b5e95b48SJohn Johansen return rc; 504*b5e95b48SJohn Johansen 505*b5e95b48SJohn Johansen return common_mmap(OP_FMMAP, file, prot, flags); 506*b5e95b48SJohn Johansen } 507*b5e95b48SJohn Johansen 508*b5e95b48SJohn Johansen static int apparmor_file_mprotect(struct vm_area_struct *vma, 509*b5e95b48SJohn Johansen unsigned long reqprot, unsigned long prot) 510*b5e95b48SJohn Johansen { 511*b5e95b48SJohn Johansen return common_mmap(OP_FMPROT, vma->vm_file, prot, 512*b5e95b48SJohn Johansen !(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0); 513*b5e95b48SJohn Johansen } 514*b5e95b48SJohn Johansen 515*b5e95b48SJohn Johansen static int apparmor_getprocattr(struct task_struct *task, char *name, 516*b5e95b48SJohn Johansen char **value) 517*b5e95b48SJohn Johansen { 518*b5e95b48SJohn Johansen int error = -ENOENT; 519*b5e95b48SJohn Johansen struct aa_profile *profile; 520*b5e95b48SJohn Johansen /* released below */ 521*b5e95b48SJohn Johansen const struct cred *cred = get_task_cred(task); 522*b5e95b48SJohn Johansen struct aa_task_cxt *cxt = cred->security; 523*b5e95b48SJohn Johansen profile = aa_cred_profile(cred); 524*b5e95b48SJohn Johansen 525*b5e95b48SJohn Johansen if (strcmp(name, "current") == 0) 526*b5e95b48SJohn Johansen error = aa_getprocattr(aa_newest_version(cxt->profile), 527*b5e95b48SJohn Johansen value); 528*b5e95b48SJohn Johansen else if (strcmp(name, "prev") == 0 && cxt->previous) 529*b5e95b48SJohn Johansen error = aa_getprocattr(aa_newest_version(cxt->previous), 530*b5e95b48SJohn Johansen value); 531*b5e95b48SJohn Johansen else if (strcmp(name, "exec") == 0 && cxt->onexec) 532*b5e95b48SJohn Johansen error = aa_getprocattr(aa_newest_version(cxt->onexec), 533*b5e95b48SJohn Johansen value); 534*b5e95b48SJohn Johansen else 535*b5e95b48SJohn Johansen error = -EINVAL; 536*b5e95b48SJohn Johansen 537*b5e95b48SJohn Johansen put_cred(cred); 538*b5e95b48SJohn Johansen 539*b5e95b48SJohn Johansen return error; 540*b5e95b48SJohn Johansen } 541*b5e95b48SJohn Johansen 542*b5e95b48SJohn Johansen static int apparmor_setprocattr(struct task_struct *task, char *name, 543*b5e95b48SJohn Johansen void *value, size_t size) 544*b5e95b48SJohn Johansen { 545*b5e95b48SJohn Johansen char *command, *args = value; 546*b5e95b48SJohn Johansen size_t arg_size; 547*b5e95b48SJohn Johansen int error; 548*b5e95b48SJohn Johansen 549*b5e95b48SJohn Johansen if (size == 0) 550*b5e95b48SJohn Johansen return -EINVAL; 551*b5e95b48SJohn Johansen /* args points to a PAGE_SIZE buffer, AppArmor requires that 552*b5e95b48SJohn Johansen * the buffer must be null terminated or have size <= PAGE_SIZE -1 553*b5e95b48SJohn Johansen * so that AppArmor can null terminate them 554*b5e95b48SJohn Johansen */ 555*b5e95b48SJohn Johansen if (args[size - 1] != '\0') { 556*b5e95b48SJohn Johansen if (size == PAGE_SIZE) 557*b5e95b48SJohn Johansen return -EINVAL; 558*b5e95b48SJohn Johansen args[size] = '\0'; 559*b5e95b48SJohn Johansen } 560*b5e95b48SJohn Johansen 561*b5e95b48SJohn Johansen /* task can only write its own attributes */ 562*b5e95b48SJohn Johansen if (current != task) 563*b5e95b48SJohn Johansen return -EACCES; 564*b5e95b48SJohn Johansen 565*b5e95b48SJohn Johansen args = value; 566*b5e95b48SJohn Johansen args = strim(args); 567*b5e95b48SJohn Johansen command = strsep(&args, " "); 568*b5e95b48SJohn Johansen if (!args) 569*b5e95b48SJohn Johansen return -EINVAL; 570*b5e95b48SJohn Johansen args = skip_spaces(args); 571*b5e95b48SJohn Johansen if (!*args) 572*b5e95b48SJohn Johansen return -EINVAL; 573*b5e95b48SJohn Johansen 574*b5e95b48SJohn Johansen arg_size = size - (args - (char *) value); 575*b5e95b48SJohn Johansen if (strcmp(name, "current") == 0) { 576*b5e95b48SJohn Johansen if (strcmp(command, "changehat") == 0) { 577*b5e95b48SJohn Johansen error = aa_setprocattr_changehat(args, arg_size, 578*b5e95b48SJohn Johansen !AA_DO_TEST); 579*b5e95b48SJohn Johansen } else if (strcmp(command, "permhat") == 0) { 580*b5e95b48SJohn Johansen error = aa_setprocattr_changehat(args, arg_size, 581*b5e95b48SJohn Johansen AA_DO_TEST); 582*b5e95b48SJohn Johansen } else if (strcmp(command, "changeprofile") == 0) { 583*b5e95b48SJohn Johansen error = aa_setprocattr_changeprofile(args, !AA_ONEXEC, 584*b5e95b48SJohn Johansen !AA_DO_TEST); 585*b5e95b48SJohn Johansen } else if (strcmp(command, "permprofile") == 0) { 586*b5e95b48SJohn Johansen error = aa_setprocattr_changeprofile(args, !AA_ONEXEC, 587*b5e95b48SJohn Johansen AA_DO_TEST); 588*b5e95b48SJohn Johansen } else if (strcmp(command, "permipc") == 0) { 589*b5e95b48SJohn Johansen error = aa_setprocattr_permipc(args); 590*b5e95b48SJohn Johansen } else { 591*b5e95b48SJohn Johansen struct common_audit_data sa; 592*b5e95b48SJohn Johansen COMMON_AUDIT_DATA_INIT(&sa, NONE); 593*b5e95b48SJohn Johansen sa.aad.op = OP_SETPROCATTR; 594*b5e95b48SJohn Johansen sa.aad.info = name; 595*b5e95b48SJohn Johansen sa.aad.error = -EINVAL; 596*b5e95b48SJohn Johansen return aa_audit(AUDIT_APPARMOR_DENIED, NULL, GFP_KERNEL, 597*b5e95b48SJohn Johansen &sa, NULL); 598*b5e95b48SJohn Johansen } 599*b5e95b48SJohn Johansen } else if (strcmp(name, "exec") == 0) { 600*b5e95b48SJohn Johansen error = aa_setprocattr_changeprofile(args, AA_ONEXEC, 601*b5e95b48SJohn Johansen !AA_DO_TEST); 602*b5e95b48SJohn Johansen } else { 603*b5e95b48SJohn Johansen /* only support the "current" and "exec" process attributes */ 604*b5e95b48SJohn Johansen return -EINVAL; 605*b5e95b48SJohn Johansen } 606*b5e95b48SJohn Johansen if (!error) 607*b5e95b48SJohn Johansen error = size; 608*b5e95b48SJohn Johansen return error; 609*b5e95b48SJohn Johansen } 610*b5e95b48SJohn Johansen 611*b5e95b48SJohn Johansen static int apparmor_task_setrlimit(unsigned int resource, 612*b5e95b48SJohn Johansen struct rlimit *new_rlim) 613*b5e95b48SJohn Johansen { 614*b5e95b48SJohn Johansen struct aa_profile *profile = aa_current_profile(); 615*b5e95b48SJohn Johansen int error = 0; 616*b5e95b48SJohn Johansen 617*b5e95b48SJohn Johansen if (!unconfined(profile)) 618*b5e95b48SJohn Johansen error = aa_task_setrlimit(profile, resource, new_rlim); 619*b5e95b48SJohn Johansen 620*b5e95b48SJohn Johansen return error; 621*b5e95b48SJohn Johansen } 622*b5e95b48SJohn Johansen 623*b5e95b48SJohn Johansen static struct security_operations apparmor_ops = { 624*b5e95b48SJohn Johansen .name = "apparmor", 625*b5e95b48SJohn Johansen 626*b5e95b48SJohn Johansen .ptrace_access_check = apparmor_ptrace_access_check, 627*b5e95b48SJohn Johansen .ptrace_traceme = apparmor_ptrace_traceme, 628*b5e95b48SJohn Johansen .capget = apparmor_capget, 629*b5e95b48SJohn Johansen .capable = apparmor_capable, 630*b5e95b48SJohn Johansen 631*b5e95b48SJohn Johansen .path_link = apparmor_path_link, 632*b5e95b48SJohn Johansen .path_unlink = apparmor_path_unlink, 633*b5e95b48SJohn Johansen .path_symlink = apparmor_path_symlink, 634*b5e95b48SJohn Johansen .path_mkdir = apparmor_path_mkdir, 635*b5e95b48SJohn Johansen .path_rmdir = apparmor_path_rmdir, 636*b5e95b48SJohn Johansen .path_mknod = apparmor_path_mknod, 637*b5e95b48SJohn Johansen .path_rename = apparmor_path_rename, 638*b5e95b48SJohn Johansen .path_chmod = apparmor_path_chmod, 639*b5e95b48SJohn Johansen .path_chown = apparmor_path_chown, 640*b5e95b48SJohn Johansen .path_truncate = apparmor_path_truncate, 641*b5e95b48SJohn Johansen .dentry_open = apparmor_dentry_open, 642*b5e95b48SJohn Johansen .inode_getattr = apparmor_inode_getattr, 643*b5e95b48SJohn Johansen 644*b5e95b48SJohn Johansen .file_permission = apparmor_file_permission, 645*b5e95b48SJohn Johansen .file_alloc_security = apparmor_file_alloc_security, 646*b5e95b48SJohn Johansen .file_free_security = apparmor_file_free_security, 647*b5e95b48SJohn Johansen .file_mmap = apparmor_file_mmap, 648*b5e95b48SJohn Johansen .file_mprotect = apparmor_file_mprotect, 649*b5e95b48SJohn Johansen .file_lock = apparmor_file_lock, 650*b5e95b48SJohn Johansen 651*b5e95b48SJohn Johansen .getprocattr = apparmor_getprocattr, 652*b5e95b48SJohn Johansen .setprocattr = apparmor_setprocattr, 653*b5e95b48SJohn Johansen 654*b5e95b48SJohn Johansen .cred_alloc_blank = apparmor_cred_alloc_blank, 655*b5e95b48SJohn Johansen .cred_free = apparmor_cred_free, 656*b5e95b48SJohn Johansen .cred_prepare = apparmor_cred_prepare, 657*b5e95b48SJohn Johansen .cred_transfer = apparmor_cred_transfer, 658*b5e95b48SJohn Johansen 659*b5e95b48SJohn Johansen .bprm_set_creds = apparmor_bprm_set_creds, 660*b5e95b48SJohn Johansen .bprm_committing_creds = apparmor_bprm_committing_creds, 661*b5e95b48SJohn Johansen .bprm_committed_creds = apparmor_bprm_committed_creds, 662*b5e95b48SJohn Johansen .bprm_secureexec = apparmor_bprm_secureexec, 663*b5e95b48SJohn Johansen 664*b5e95b48SJohn Johansen .task_setrlimit = apparmor_task_setrlimit, 665*b5e95b48SJohn Johansen }; 666*b5e95b48SJohn Johansen 667*b5e95b48SJohn Johansen /* 668*b5e95b48SJohn Johansen * AppArmor sysfs module parameters 669*b5e95b48SJohn Johansen */ 670*b5e95b48SJohn Johansen 671*b5e95b48SJohn Johansen static int param_set_aabool(const char *val, struct kernel_param *kp); 672*b5e95b48SJohn Johansen static int param_get_aabool(char *buffer, struct kernel_param *kp); 673*b5e95b48SJohn Johansen #define param_check_aabool(name, p) __param_check(name, p, int) 674*b5e95b48SJohn Johansen 675*b5e95b48SJohn Johansen static int param_set_aauint(const char *val, struct kernel_param *kp); 676*b5e95b48SJohn Johansen static int param_get_aauint(char *buffer, struct kernel_param *kp); 677*b5e95b48SJohn Johansen #define param_check_aauint(name, p) __param_check(name, p, int) 678*b5e95b48SJohn Johansen 679*b5e95b48SJohn Johansen static int param_set_aalockpolicy(const char *val, struct kernel_param *kp); 680*b5e95b48SJohn Johansen static int param_get_aalockpolicy(char *buffer, struct kernel_param *kp); 681*b5e95b48SJohn Johansen #define param_check_aalockpolicy(name, p) __param_check(name, p, int) 682*b5e95b48SJohn Johansen 683*b5e95b48SJohn Johansen static int param_set_audit(const char *val, struct kernel_param *kp); 684*b5e95b48SJohn Johansen static int param_get_audit(char *buffer, struct kernel_param *kp); 685*b5e95b48SJohn Johansen #define param_check_audit(name, p) __param_check(name, p, int) 686*b5e95b48SJohn Johansen 687*b5e95b48SJohn Johansen static int param_set_mode(const char *val, struct kernel_param *kp); 688*b5e95b48SJohn Johansen static int param_get_mode(char *buffer, struct kernel_param *kp); 689*b5e95b48SJohn Johansen #define param_check_mode(name, p) __param_check(name, p, int) 690*b5e95b48SJohn Johansen 691*b5e95b48SJohn Johansen /* Flag values, also controllable via /sys/module/apparmor/parameters 692*b5e95b48SJohn Johansen * We define special types as we want to do additional mediation. 693*b5e95b48SJohn Johansen */ 694*b5e95b48SJohn Johansen 695*b5e95b48SJohn Johansen /* AppArmor global enforcement switch - complain, enforce, kill */ 696*b5e95b48SJohn Johansen enum profile_mode aa_g_profile_mode = APPARMOR_ENFORCE; 697*b5e95b48SJohn Johansen module_param_call(mode, param_set_mode, param_get_mode, 698*b5e95b48SJohn Johansen &aa_g_profile_mode, S_IRUSR | S_IWUSR); 699*b5e95b48SJohn Johansen 700*b5e95b48SJohn Johansen /* Debug mode */ 701*b5e95b48SJohn Johansen int aa_g_debug; 702*b5e95b48SJohn Johansen module_param_named(debug, aa_g_debug, aabool, S_IRUSR | S_IWUSR); 703*b5e95b48SJohn Johansen 704*b5e95b48SJohn Johansen /* Audit mode */ 705*b5e95b48SJohn Johansen enum audit_mode aa_g_audit; 706*b5e95b48SJohn Johansen module_param_call(audit, param_set_audit, param_get_audit, 707*b5e95b48SJohn Johansen &aa_g_audit, S_IRUSR | S_IWUSR); 708*b5e95b48SJohn Johansen 709*b5e95b48SJohn Johansen /* Determines if audit header is included in audited messages. This 710*b5e95b48SJohn Johansen * provides more context if the audit daemon is not running 711*b5e95b48SJohn Johansen */ 712*b5e95b48SJohn Johansen int aa_g_audit_header = 1; 713*b5e95b48SJohn Johansen module_param_named(audit_header, aa_g_audit_header, aabool, 714*b5e95b48SJohn Johansen S_IRUSR | S_IWUSR); 715*b5e95b48SJohn Johansen 716*b5e95b48SJohn Johansen /* lock out loading/removal of policy 717*b5e95b48SJohn Johansen * TODO: add in at boot loading of policy, which is the only way to 718*b5e95b48SJohn Johansen * load policy, if lock_policy is set 719*b5e95b48SJohn Johansen */ 720*b5e95b48SJohn Johansen int aa_g_lock_policy; 721*b5e95b48SJohn Johansen module_param_named(lock_policy, aa_g_lock_policy, aalockpolicy, 722*b5e95b48SJohn Johansen S_IRUSR | S_IWUSR); 723*b5e95b48SJohn Johansen 724*b5e95b48SJohn Johansen /* Syscall logging mode */ 725*b5e95b48SJohn Johansen int aa_g_logsyscall; 726*b5e95b48SJohn Johansen module_param_named(logsyscall, aa_g_logsyscall, aabool, S_IRUSR | S_IWUSR); 727*b5e95b48SJohn Johansen 728*b5e95b48SJohn Johansen /* Maximum pathname length before accesses will start getting rejected */ 729*b5e95b48SJohn Johansen unsigned int aa_g_path_max = 2 * PATH_MAX; 730*b5e95b48SJohn Johansen module_param_named(path_max, aa_g_path_max, aauint, S_IRUSR | S_IWUSR); 731*b5e95b48SJohn Johansen 732*b5e95b48SJohn Johansen /* Determines how paranoid loading of policy is and how much verification 733*b5e95b48SJohn Johansen * on the loaded policy is done. 734*b5e95b48SJohn Johansen */ 735*b5e95b48SJohn Johansen int aa_g_paranoid_load = 1; 736*b5e95b48SJohn Johansen module_param_named(paranoid_load, aa_g_paranoid_load, aabool, 737*b5e95b48SJohn Johansen S_IRUSR | S_IWUSR); 738*b5e95b48SJohn Johansen 739*b5e95b48SJohn Johansen /* Boot time disable flag */ 740*b5e95b48SJohn Johansen static unsigned int apparmor_enabled = CONFIG_SECURITY_APPARMOR_BOOTPARAM_VALUE; 741*b5e95b48SJohn Johansen module_param_named(enabled, apparmor_enabled, aabool, S_IRUSR); 742*b5e95b48SJohn Johansen 743*b5e95b48SJohn Johansen static int __init apparmor_enabled_setup(char *str) 744*b5e95b48SJohn Johansen { 745*b5e95b48SJohn Johansen unsigned long enabled; 746*b5e95b48SJohn Johansen int error = strict_strtoul(str, 0, &enabled); 747*b5e95b48SJohn Johansen if (!error) 748*b5e95b48SJohn Johansen apparmor_enabled = enabled ? 1 : 0; 749*b5e95b48SJohn Johansen return 1; 750*b5e95b48SJohn Johansen } 751*b5e95b48SJohn Johansen 752*b5e95b48SJohn Johansen __setup("apparmor=", apparmor_enabled_setup); 753*b5e95b48SJohn Johansen 754*b5e95b48SJohn Johansen /* set global flag turning off the ability to load policy */ 755*b5e95b48SJohn Johansen static int param_set_aalockpolicy(const char *val, struct kernel_param *kp) 756*b5e95b48SJohn Johansen { 757*b5e95b48SJohn Johansen if (!capable(CAP_MAC_ADMIN)) 758*b5e95b48SJohn Johansen return -EPERM; 759*b5e95b48SJohn Johansen if (aa_g_lock_policy) 760*b5e95b48SJohn Johansen return -EACCES; 761*b5e95b48SJohn Johansen return param_set_bool(val, kp); 762*b5e95b48SJohn Johansen } 763*b5e95b48SJohn Johansen 764*b5e95b48SJohn Johansen static int param_get_aalockpolicy(char *buffer, struct kernel_param *kp) 765*b5e95b48SJohn Johansen { 766*b5e95b48SJohn Johansen if (!capable(CAP_MAC_ADMIN)) 767*b5e95b48SJohn Johansen return -EPERM; 768*b5e95b48SJohn Johansen return param_get_bool(buffer, kp); 769*b5e95b48SJohn Johansen } 770*b5e95b48SJohn Johansen 771*b5e95b48SJohn Johansen static int param_set_aabool(const char *val, struct kernel_param *kp) 772*b5e95b48SJohn Johansen { 773*b5e95b48SJohn Johansen if (!capable(CAP_MAC_ADMIN)) 774*b5e95b48SJohn Johansen return -EPERM; 775*b5e95b48SJohn Johansen return param_set_bool(val, kp); 776*b5e95b48SJohn Johansen } 777*b5e95b48SJohn Johansen 778*b5e95b48SJohn Johansen static int param_get_aabool(char *buffer, struct kernel_param *kp) 779*b5e95b48SJohn Johansen { 780*b5e95b48SJohn Johansen if (!capable(CAP_MAC_ADMIN)) 781*b5e95b48SJohn Johansen return -EPERM; 782*b5e95b48SJohn Johansen return param_get_bool(buffer, kp); 783*b5e95b48SJohn Johansen } 784*b5e95b48SJohn Johansen 785*b5e95b48SJohn Johansen static int param_set_aauint(const char *val, struct kernel_param *kp) 786*b5e95b48SJohn Johansen { 787*b5e95b48SJohn Johansen if (!capable(CAP_MAC_ADMIN)) 788*b5e95b48SJohn Johansen return -EPERM; 789*b5e95b48SJohn Johansen return param_set_uint(val, kp); 790*b5e95b48SJohn Johansen } 791*b5e95b48SJohn Johansen 792*b5e95b48SJohn Johansen static int param_get_aauint(char *buffer, struct kernel_param *kp) 793*b5e95b48SJohn Johansen { 794*b5e95b48SJohn Johansen if (!capable(CAP_MAC_ADMIN)) 795*b5e95b48SJohn Johansen return -EPERM; 796*b5e95b48SJohn Johansen return param_get_uint(buffer, kp); 797*b5e95b48SJohn Johansen } 798*b5e95b48SJohn Johansen 799*b5e95b48SJohn Johansen static int param_get_audit(char *buffer, struct kernel_param *kp) 800*b5e95b48SJohn Johansen { 801*b5e95b48SJohn Johansen if (!capable(CAP_MAC_ADMIN)) 802*b5e95b48SJohn Johansen return -EPERM; 803*b5e95b48SJohn Johansen 804*b5e95b48SJohn Johansen if (!apparmor_enabled) 805*b5e95b48SJohn Johansen return -EINVAL; 806*b5e95b48SJohn Johansen 807*b5e95b48SJohn Johansen return sprintf(buffer, "%s", audit_mode_names[aa_g_audit]); 808*b5e95b48SJohn Johansen } 809*b5e95b48SJohn Johansen 810*b5e95b48SJohn Johansen static int param_set_audit(const char *val, struct kernel_param *kp) 811*b5e95b48SJohn Johansen { 812*b5e95b48SJohn Johansen int i; 813*b5e95b48SJohn Johansen if (!capable(CAP_MAC_ADMIN)) 814*b5e95b48SJohn Johansen return -EPERM; 815*b5e95b48SJohn Johansen 816*b5e95b48SJohn Johansen if (!apparmor_enabled) 817*b5e95b48SJohn Johansen return -EINVAL; 818*b5e95b48SJohn Johansen 819*b5e95b48SJohn Johansen if (!val) 820*b5e95b48SJohn Johansen return -EINVAL; 821*b5e95b48SJohn Johansen 822*b5e95b48SJohn Johansen for (i = 0; i < AUDIT_MAX_INDEX; i++) { 823*b5e95b48SJohn Johansen if (strcmp(val, audit_mode_names[i]) == 0) { 824*b5e95b48SJohn Johansen aa_g_audit = i; 825*b5e95b48SJohn Johansen return 0; 826*b5e95b48SJohn Johansen } 827*b5e95b48SJohn Johansen } 828*b5e95b48SJohn Johansen 829*b5e95b48SJohn Johansen return -EINVAL; 830*b5e95b48SJohn Johansen } 831*b5e95b48SJohn Johansen 832*b5e95b48SJohn Johansen static int param_get_mode(char *buffer, struct kernel_param *kp) 833*b5e95b48SJohn Johansen { 834*b5e95b48SJohn Johansen if (!capable(CAP_MAC_ADMIN)) 835*b5e95b48SJohn Johansen return -EPERM; 836*b5e95b48SJohn Johansen 837*b5e95b48SJohn Johansen if (!apparmor_enabled) 838*b5e95b48SJohn Johansen return -EINVAL; 839*b5e95b48SJohn Johansen 840*b5e95b48SJohn Johansen return sprintf(buffer, "%s", profile_mode_names[aa_g_profile_mode]); 841*b5e95b48SJohn Johansen } 842*b5e95b48SJohn Johansen 843*b5e95b48SJohn Johansen static int param_set_mode(const char *val, struct kernel_param *kp) 844*b5e95b48SJohn Johansen { 845*b5e95b48SJohn Johansen int i; 846*b5e95b48SJohn Johansen if (!capable(CAP_MAC_ADMIN)) 847*b5e95b48SJohn Johansen return -EPERM; 848*b5e95b48SJohn Johansen 849*b5e95b48SJohn Johansen if (!apparmor_enabled) 850*b5e95b48SJohn Johansen return -EINVAL; 851*b5e95b48SJohn Johansen 852*b5e95b48SJohn Johansen if (!val) 853*b5e95b48SJohn Johansen return -EINVAL; 854*b5e95b48SJohn Johansen 855*b5e95b48SJohn Johansen for (i = 0; i < APPARMOR_NAMES_MAX_INDEX; i++) { 856*b5e95b48SJohn Johansen if (strcmp(val, profile_mode_names[i]) == 0) { 857*b5e95b48SJohn Johansen aa_g_profile_mode = i; 858*b5e95b48SJohn Johansen return 0; 859*b5e95b48SJohn Johansen } 860*b5e95b48SJohn Johansen } 861*b5e95b48SJohn Johansen 862*b5e95b48SJohn Johansen return -EINVAL; 863*b5e95b48SJohn Johansen } 864*b5e95b48SJohn Johansen 865*b5e95b48SJohn Johansen /* 866*b5e95b48SJohn Johansen * AppArmor init functions 867*b5e95b48SJohn Johansen */ 868*b5e95b48SJohn Johansen 869*b5e95b48SJohn Johansen /** 870*b5e95b48SJohn Johansen * set_init_cxt - set a task context and profile on the first task. 871*b5e95b48SJohn Johansen * 872*b5e95b48SJohn Johansen * TODO: allow setting an alternate profile than unconfined 873*b5e95b48SJohn Johansen */ 874*b5e95b48SJohn Johansen static int __init set_init_cxt(void) 875*b5e95b48SJohn Johansen { 876*b5e95b48SJohn Johansen struct cred *cred = (struct cred *)current->real_cred; 877*b5e95b48SJohn Johansen struct aa_task_cxt *cxt; 878*b5e95b48SJohn Johansen 879*b5e95b48SJohn Johansen cxt = aa_alloc_task_context(GFP_KERNEL); 880*b5e95b48SJohn Johansen if (!cxt) 881*b5e95b48SJohn Johansen return -ENOMEM; 882*b5e95b48SJohn Johansen 883*b5e95b48SJohn Johansen cxt->profile = aa_get_profile(root_ns->unconfined); 884*b5e95b48SJohn Johansen cred->security = cxt; 885*b5e95b48SJohn Johansen 886*b5e95b48SJohn Johansen return 0; 887*b5e95b48SJohn Johansen } 888*b5e95b48SJohn Johansen 889*b5e95b48SJohn Johansen static int __init apparmor_init(void) 890*b5e95b48SJohn Johansen { 891*b5e95b48SJohn Johansen int error; 892*b5e95b48SJohn Johansen 893*b5e95b48SJohn Johansen if (!apparmor_enabled || !security_module_enable(&apparmor_ops)) { 894*b5e95b48SJohn Johansen aa_info_message("AppArmor disabled by boot time parameter"); 895*b5e95b48SJohn Johansen apparmor_enabled = 0; 896*b5e95b48SJohn Johansen return 0; 897*b5e95b48SJohn Johansen } 898*b5e95b48SJohn Johansen 899*b5e95b48SJohn Johansen error = aa_alloc_root_ns(); 900*b5e95b48SJohn Johansen if (error) { 901*b5e95b48SJohn Johansen AA_ERROR("Unable to allocate default profile namespace\n"); 902*b5e95b48SJohn Johansen goto alloc_out; 903*b5e95b48SJohn Johansen } 904*b5e95b48SJohn Johansen 905*b5e95b48SJohn Johansen error = set_init_cxt(); 906*b5e95b48SJohn Johansen if (error) { 907*b5e95b48SJohn Johansen AA_ERROR("Failed to set context on init task\n"); 908*b5e95b48SJohn Johansen goto register_security_out; 909*b5e95b48SJohn Johansen } 910*b5e95b48SJohn Johansen 911*b5e95b48SJohn Johansen error = register_security(&apparmor_ops); 912*b5e95b48SJohn Johansen if (error) { 913*b5e95b48SJohn Johansen AA_ERROR("Unable to register AppArmor\n"); 914*b5e95b48SJohn Johansen goto register_security_out; 915*b5e95b48SJohn Johansen } 916*b5e95b48SJohn Johansen 917*b5e95b48SJohn Johansen /* Report that AppArmor successfully initialized */ 918*b5e95b48SJohn Johansen apparmor_initialized = 1; 919*b5e95b48SJohn Johansen if (aa_g_profile_mode == APPARMOR_COMPLAIN) 920*b5e95b48SJohn Johansen aa_info_message("AppArmor initialized: complain mode enabled"); 921*b5e95b48SJohn Johansen else if (aa_g_profile_mode == APPARMOR_KILL) 922*b5e95b48SJohn Johansen aa_info_message("AppArmor initialized: kill mode enabled"); 923*b5e95b48SJohn Johansen else 924*b5e95b48SJohn Johansen aa_info_message("AppArmor initialized"); 925*b5e95b48SJohn Johansen 926*b5e95b48SJohn Johansen return error; 927*b5e95b48SJohn Johansen 928*b5e95b48SJohn Johansen register_security_out: 929*b5e95b48SJohn Johansen aa_free_root_ns(); 930*b5e95b48SJohn Johansen 931*b5e95b48SJohn Johansen alloc_out: 932*b5e95b48SJohn Johansen aa_destroy_aafs(); 933*b5e95b48SJohn Johansen 934*b5e95b48SJohn Johansen apparmor_enabled = 0; 935*b5e95b48SJohn Johansen return error; 936*b5e95b48SJohn Johansen 937*b5e95b48SJohn Johansen } 938*b5e95b48SJohn Johansen 939*b5e95b48SJohn Johansen security_initcall(apparmor_init); 940