1*63e2b423SJohn Johansen /* 2*63e2b423SJohn Johansen * AppArmor security module 3*63e2b423SJohn Johansen * 4*63e2b423SJohn Johansen * This file contains AppArmor /sys/kernel/security/apparmor interface functions 5*63e2b423SJohn Johansen * 6*63e2b423SJohn Johansen * Copyright (C) 1998-2008 Novell/SUSE 7*63e2b423SJohn Johansen * Copyright 2009-2010 Canonical Ltd. 8*63e2b423SJohn Johansen * 9*63e2b423SJohn Johansen * This program is free software; you can redistribute it and/or 10*63e2b423SJohn Johansen * modify it under the terms of the GNU General Public License as 11*63e2b423SJohn Johansen * published by the Free Software Foundation, version 2 of the 12*63e2b423SJohn Johansen * License. 13*63e2b423SJohn Johansen */ 14*63e2b423SJohn Johansen 15*63e2b423SJohn Johansen #include <linux/security.h> 16*63e2b423SJohn Johansen #include <linux/vmalloc.h> 17*63e2b423SJohn Johansen #include <linux/module.h> 18*63e2b423SJohn Johansen #include <linux/seq_file.h> 19*63e2b423SJohn Johansen #include <linux/uaccess.h> 20*63e2b423SJohn Johansen #include <linux/namei.h> 21*63e2b423SJohn Johansen 22*63e2b423SJohn Johansen #include "include/apparmor.h" 23*63e2b423SJohn Johansen #include "include/apparmorfs.h" 24*63e2b423SJohn Johansen #include "include/audit.h" 25*63e2b423SJohn Johansen #include "include/context.h" 26*63e2b423SJohn Johansen #include "include/policy.h" 27*63e2b423SJohn Johansen 28*63e2b423SJohn Johansen /** 29*63e2b423SJohn Johansen * aa_simple_write_to_buffer - common routine for getting policy from user 30*63e2b423SJohn Johansen * @op: operation doing the user buffer copy 31*63e2b423SJohn Johansen * @userbuf: user buffer to copy data from (NOT NULL) 32*63e2b423SJohn Johansen * @alloc_size: size of user buffer 33*63e2b423SJohn Johansen * @copy_size: size of data to copy from user buffer 34*63e2b423SJohn Johansen * @pos: position write is at in the file (NOT NULL) 35*63e2b423SJohn Johansen * 36*63e2b423SJohn Johansen * Returns: kernel buffer containing copy of user buffer data or an 37*63e2b423SJohn Johansen * ERR_PTR on failure. 38*63e2b423SJohn Johansen */ 39*63e2b423SJohn Johansen static char *aa_simple_write_to_buffer(int op, const char __user *userbuf, 40*63e2b423SJohn Johansen size_t alloc_size, size_t copy_size, 41*63e2b423SJohn Johansen loff_t *pos) 42*63e2b423SJohn Johansen { 43*63e2b423SJohn Johansen char *data; 44*63e2b423SJohn Johansen 45*63e2b423SJohn Johansen if (*pos != 0) 46*63e2b423SJohn Johansen /* only writes from pos 0, that is complete writes */ 47*63e2b423SJohn Johansen return ERR_PTR(-ESPIPE); 48*63e2b423SJohn Johansen 49*63e2b423SJohn Johansen /* 50*63e2b423SJohn Johansen * Don't allow profile load/replace/remove from profiles that don't 51*63e2b423SJohn Johansen * have CAP_MAC_ADMIN 52*63e2b423SJohn Johansen */ 53*63e2b423SJohn Johansen if (!aa_may_manage_policy(op)) 54*63e2b423SJohn Johansen return ERR_PTR(-EACCES); 55*63e2b423SJohn Johansen 56*63e2b423SJohn Johansen /* freed by caller to simple_write_to_buffer */ 57*63e2b423SJohn Johansen data = kvmalloc(alloc_size); 58*63e2b423SJohn Johansen if (data == NULL) 59*63e2b423SJohn Johansen return ERR_PTR(-ENOMEM); 60*63e2b423SJohn Johansen 61*63e2b423SJohn Johansen if (copy_from_user(data, userbuf, copy_size)) { 62*63e2b423SJohn Johansen kvfree(data); 63*63e2b423SJohn Johansen return ERR_PTR(-EFAULT); 64*63e2b423SJohn Johansen } 65*63e2b423SJohn Johansen 66*63e2b423SJohn Johansen return data; 67*63e2b423SJohn Johansen } 68*63e2b423SJohn Johansen 69*63e2b423SJohn Johansen 70*63e2b423SJohn Johansen /* .load file hook fn to load policy */ 71*63e2b423SJohn Johansen static ssize_t profile_load(struct file *f, const char __user *buf, size_t size, 72*63e2b423SJohn Johansen loff_t *pos) 73*63e2b423SJohn Johansen { 74*63e2b423SJohn Johansen char *data; 75*63e2b423SJohn Johansen ssize_t error; 76*63e2b423SJohn Johansen 77*63e2b423SJohn Johansen data = aa_simple_write_to_buffer(OP_PROF_LOAD, buf, size, size, pos); 78*63e2b423SJohn Johansen 79*63e2b423SJohn Johansen error = PTR_ERR(data); 80*63e2b423SJohn Johansen if (!IS_ERR(data)) { 81*63e2b423SJohn Johansen error = aa_replace_profiles(data, size, PROF_ADD); 82*63e2b423SJohn Johansen kvfree(data); 83*63e2b423SJohn Johansen } 84*63e2b423SJohn Johansen 85*63e2b423SJohn Johansen return error; 86*63e2b423SJohn Johansen } 87*63e2b423SJohn Johansen 88*63e2b423SJohn Johansen static const struct file_operations aa_fs_profile_load = { 89*63e2b423SJohn Johansen .write = profile_load 90*63e2b423SJohn Johansen }; 91*63e2b423SJohn Johansen 92*63e2b423SJohn Johansen /* .replace file hook fn to load and/or replace policy */ 93*63e2b423SJohn Johansen static ssize_t profile_replace(struct file *f, const char __user *buf, 94*63e2b423SJohn Johansen size_t size, loff_t *pos) 95*63e2b423SJohn Johansen { 96*63e2b423SJohn Johansen char *data; 97*63e2b423SJohn Johansen ssize_t error; 98*63e2b423SJohn Johansen 99*63e2b423SJohn Johansen data = aa_simple_write_to_buffer(OP_PROF_REPL, buf, size, size, pos); 100*63e2b423SJohn Johansen error = PTR_ERR(data); 101*63e2b423SJohn Johansen if (!IS_ERR(data)) { 102*63e2b423SJohn Johansen error = aa_replace_profiles(data, size, PROF_REPLACE); 103*63e2b423SJohn Johansen kvfree(data); 104*63e2b423SJohn Johansen } 105*63e2b423SJohn Johansen 106*63e2b423SJohn Johansen return error; 107*63e2b423SJohn Johansen } 108*63e2b423SJohn Johansen 109*63e2b423SJohn Johansen static const struct file_operations aa_fs_profile_replace = { 110*63e2b423SJohn Johansen .write = profile_replace 111*63e2b423SJohn Johansen }; 112*63e2b423SJohn Johansen 113*63e2b423SJohn Johansen /* .remove file hook fn to remove loaded policy */ 114*63e2b423SJohn Johansen static ssize_t profile_remove(struct file *f, const char __user *buf, 115*63e2b423SJohn Johansen size_t size, loff_t *pos) 116*63e2b423SJohn Johansen { 117*63e2b423SJohn Johansen char *data; 118*63e2b423SJohn Johansen ssize_t error; 119*63e2b423SJohn Johansen 120*63e2b423SJohn Johansen /* 121*63e2b423SJohn Johansen * aa_remove_profile needs a null terminated string so 1 extra 122*63e2b423SJohn Johansen * byte is allocated and the copied data is null terminated. 123*63e2b423SJohn Johansen */ 124*63e2b423SJohn Johansen data = aa_simple_write_to_buffer(OP_PROF_RM, buf, size + 1, size, pos); 125*63e2b423SJohn Johansen 126*63e2b423SJohn Johansen error = PTR_ERR(data); 127*63e2b423SJohn Johansen if (!IS_ERR(data)) { 128*63e2b423SJohn Johansen data[size] = 0; 129*63e2b423SJohn Johansen error = aa_remove_profiles(data, size); 130*63e2b423SJohn Johansen kvfree(data); 131*63e2b423SJohn Johansen } 132*63e2b423SJohn Johansen 133*63e2b423SJohn Johansen return error; 134*63e2b423SJohn Johansen } 135*63e2b423SJohn Johansen 136*63e2b423SJohn Johansen static const struct file_operations aa_fs_profile_remove = { 137*63e2b423SJohn Johansen .write = profile_remove 138*63e2b423SJohn Johansen }; 139*63e2b423SJohn Johansen 140*63e2b423SJohn Johansen /** Base file system setup **/ 141*63e2b423SJohn Johansen 142*63e2b423SJohn Johansen static struct dentry *aa_fs_dentry __initdata; 143*63e2b423SJohn Johansen 144*63e2b423SJohn Johansen static void __init aafs_remove(const char *name) 145*63e2b423SJohn Johansen { 146*63e2b423SJohn Johansen struct dentry *dentry; 147*63e2b423SJohn Johansen 148*63e2b423SJohn Johansen dentry = lookup_one_len(name, aa_fs_dentry, strlen(name)); 149*63e2b423SJohn Johansen if (!IS_ERR(dentry)) { 150*63e2b423SJohn Johansen securityfs_remove(dentry); 151*63e2b423SJohn Johansen dput(dentry); 152*63e2b423SJohn Johansen } 153*63e2b423SJohn Johansen } 154*63e2b423SJohn Johansen 155*63e2b423SJohn Johansen /** 156*63e2b423SJohn Johansen * aafs_create - create an entry in the apparmor filesystem 157*63e2b423SJohn Johansen * @name: name of the entry (NOT NULL) 158*63e2b423SJohn Johansen * @mask: file permission mask of the file 159*63e2b423SJohn Johansen * @fops: file operations for the file (NOT NULL) 160*63e2b423SJohn Johansen * 161*63e2b423SJohn Johansen * Used aafs_remove to remove entries created with this fn. 162*63e2b423SJohn Johansen */ 163*63e2b423SJohn Johansen static int __init aafs_create(const char *name, int mask, 164*63e2b423SJohn Johansen const struct file_operations *fops) 165*63e2b423SJohn Johansen { 166*63e2b423SJohn Johansen struct dentry *dentry; 167*63e2b423SJohn Johansen 168*63e2b423SJohn Johansen dentry = securityfs_create_file(name, S_IFREG | mask, aa_fs_dentry, 169*63e2b423SJohn Johansen NULL, fops); 170*63e2b423SJohn Johansen 171*63e2b423SJohn Johansen return IS_ERR(dentry) ? PTR_ERR(dentry) : 0; 172*63e2b423SJohn Johansen } 173*63e2b423SJohn Johansen 174*63e2b423SJohn Johansen /** 175*63e2b423SJohn Johansen * aa_destroy_aafs - cleanup and free aafs 176*63e2b423SJohn Johansen * 177*63e2b423SJohn Johansen * releases dentries allocated by aa_create_aafs 178*63e2b423SJohn Johansen */ 179*63e2b423SJohn Johansen void __init aa_destroy_aafs(void) 180*63e2b423SJohn Johansen { 181*63e2b423SJohn Johansen if (aa_fs_dentry) { 182*63e2b423SJohn Johansen aafs_remove(".remove"); 183*63e2b423SJohn Johansen aafs_remove(".replace"); 184*63e2b423SJohn Johansen aafs_remove(".load"); 185*63e2b423SJohn Johansen 186*63e2b423SJohn Johansen securityfs_remove(aa_fs_dentry); 187*63e2b423SJohn Johansen aa_fs_dentry = NULL; 188*63e2b423SJohn Johansen } 189*63e2b423SJohn Johansen } 190*63e2b423SJohn Johansen 191*63e2b423SJohn Johansen /** 192*63e2b423SJohn Johansen * aa_create_aafs - create the apparmor security filesystem 193*63e2b423SJohn Johansen * 194*63e2b423SJohn Johansen * dentries created here are released by aa_destroy_aafs 195*63e2b423SJohn Johansen * 196*63e2b423SJohn Johansen * Returns: error on failure 197*63e2b423SJohn Johansen */ 198*63e2b423SJohn Johansen int __init aa_create_aafs(void) 199*63e2b423SJohn Johansen { 200*63e2b423SJohn Johansen int error; 201*63e2b423SJohn Johansen 202*63e2b423SJohn Johansen if (!apparmor_initialized) 203*63e2b423SJohn Johansen return 0; 204*63e2b423SJohn Johansen 205*63e2b423SJohn Johansen if (aa_fs_dentry) { 206*63e2b423SJohn Johansen AA_ERROR("%s: AppArmor securityfs already exists\n", __func__); 207*63e2b423SJohn Johansen return -EEXIST; 208*63e2b423SJohn Johansen } 209*63e2b423SJohn Johansen 210*63e2b423SJohn Johansen aa_fs_dentry = securityfs_create_dir("apparmor", NULL); 211*63e2b423SJohn Johansen if (IS_ERR(aa_fs_dentry)) { 212*63e2b423SJohn Johansen error = PTR_ERR(aa_fs_dentry); 213*63e2b423SJohn Johansen aa_fs_dentry = NULL; 214*63e2b423SJohn Johansen goto error; 215*63e2b423SJohn Johansen } 216*63e2b423SJohn Johansen 217*63e2b423SJohn Johansen error = aafs_create(".load", 0640, &aa_fs_profile_load); 218*63e2b423SJohn Johansen if (error) 219*63e2b423SJohn Johansen goto error; 220*63e2b423SJohn Johansen error = aafs_create(".replace", 0640, &aa_fs_profile_replace); 221*63e2b423SJohn Johansen if (error) 222*63e2b423SJohn Johansen goto error; 223*63e2b423SJohn Johansen error = aafs_create(".remove", 0640, &aa_fs_profile_remove); 224*63e2b423SJohn Johansen if (error) 225*63e2b423SJohn Johansen goto error; 226*63e2b423SJohn Johansen 227*63e2b423SJohn Johansen /* TODO: add support for apparmorfs_null and apparmorfs_mnt */ 228*63e2b423SJohn Johansen 229*63e2b423SJohn Johansen /* Report that AppArmor fs is enabled */ 230*63e2b423SJohn Johansen aa_info_message("AppArmor Filesystem Enabled"); 231*63e2b423SJohn Johansen return 0; 232*63e2b423SJohn Johansen 233*63e2b423SJohn Johansen error: 234*63e2b423SJohn Johansen aa_destroy_aafs(); 235*63e2b423SJohn Johansen AA_ERROR("Error creating AppArmor securityfs\n"); 236*63e2b423SJohn Johansen return error; 237*63e2b423SJohn Johansen } 238*63e2b423SJohn Johansen 239*63e2b423SJohn Johansen fs_initcall(aa_create_aafs); 240