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