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 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 if (*pos != 0) 46 /* only writes from pos 0, that is complete writes */ 47 return ERR_PTR(-ESPIPE); 48 49 /* 50 * Don't allow profile load/replace/remove from profiles that don't 51 * have CAP_MAC_ADMIN 52 */ 53 if (!aa_may_manage_policy(op)) 54 return ERR_PTR(-EACCES); 55 56 /* freed by caller to simple_write_to_buffer */ 57 data = kvmalloc(alloc_size); 58 if (data == NULL) 59 return ERR_PTR(-ENOMEM); 60 61 if (copy_from_user(data, userbuf, copy_size)) { 62 kvfree(data); 63 return ERR_PTR(-EFAULT); 64 } 65 66 return data; 67 } 68 69 70 /* .load file hook fn to load policy */ 71 static ssize_t profile_load(struct file *f, const char __user *buf, size_t size, 72 loff_t *pos) 73 { 74 char *data; 75 ssize_t error; 76 77 data = aa_simple_write_to_buffer(OP_PROF_LOAD, buf, size, size, pos); 78 79 error = PTR_ERR(data); 80 if (!IS_ERR(data)) { 81 error = aa_replace_profiles(data, size, PROF_ADD); 82 kvfree(data); 83 } 84 85 return error; 86 } 87 88 static const struct file_operations aa_fs_profile_load = { 89 .write = profile_load 90 }; 91 92 /* .replace file hook fn to load and/or replace policy */ 93 static ssize_t profile_replace(struct file *f, const char __user *buf, 94 size_t size, loff_t *pos) 95 { 96 char *data; 97 ssize_t error; 98 99 data = aa_simple_write_to_buffer(OP_PROF_REPL, buf, size, size, pos); 100 error = PTR_ERR(data); 101 if (!IS_ERR(data)) { 102 error = aa_replace_profiles(data, size, PROF_REPLACE); 103 kvfree(data); 104 } 105 106 return error; 107 } 108 109 static const struct file_operations aa_fs_profile_replace = { 110 .write = profile_replace 111 }; 112 113 /* .remove file hook fn to remove loaded policy */ 114 static ssize_t profile_remove(struct file *f, const char __user *buf, 115 size_t size, loff_t *pos) 116 { 117 char *data; 118 ssize_t error; 119 120 /* 121 * aa_remove_profile needs a null terminated string so 1 extra 122 * byte is allocated and the copied data is null terminated. 123 */ 124 data = aa_simple_write_to_buffer(OP_PROF_RM, buf, size + 1, size, pos); 125 126 error = PTR_ERR(data); 127 if (!IS_ERR(data)) { 128 data[size] = 0; 129 error = aa_remove_profiles(data, size); 130 kvfree(data); 131 } 132 133 return error; 134 } 135 136 static const struct file_operations aa_fs_profile_remove = { 137 .write = profile_remove 138 }; 139 140 /** Base file system setup **/ 141 142 static struct dentry *aa_fs_dentry __initdata; 143 144 static void __init aafs_remove(const char *name) 145 { 146 struct dentry *dentry; 147 148 dentry = lookup_one_len(name, aa_fs_dentry, strlen(name)); 149 if (!IS_ERR(dentry)) { 150 securityfs_remove(dentry); 151 dput(dentry); 152 } 153 } 154 155 /** 156 * aafs_create - create an entry in the apparmor filesystem 157 * @name: name of the entry (NOT NULL) 158 * @mask: file permission mask of the file 159 * @fops: file operations for the file (NOT NULL) 160 * 161 * Used aafs_remove to remove entries created with this fn. 162 */ 163 static int __init aafs_create(const char *name, int mask, 164 const struct file_operations *fops) 165 { 166 struct dentry *dentry; 167 168 dentry = securityfs_create_file(name, S_IFREG | mask, aa_fs_dentry, 169 NULL, fops); 170 171 return IS_ERR(dentry) ? PTR_ERR(dentry) : 0; 172 } 173 174 /** 175 * aa_destroy_aafs - cleanup and free aafs 176 * 177 * releases dentries allocated by aa_create_aafs 178 */ 179 void __init aa_destroy_aafs(void) 180 { 181 if (aa_fs_dentry) { 182 aafs_remove(".remove"); 183 aafs_remove(".replace"); 184 aafs_remove(".load"); 185 186 securityfs_remove(aa_fs_dentry); 187 aa_fs_dentry = NULL; 188 } 189 } 190 191 /** 192 * aa_create_aafs - create the apparmor security filesystem 193 * 194 * dentries created here are released by aa_destroy_aafs 195 * 196 * Returns: error on failure 197 */ 198 int __init aa_create_aafs(void) 199 { 200 int error; 201 202 if (!apparmor_initialized) 203 return 0; 204 205 if (aa_fs_dentry) { 206 AA_ERROR("%s: AppArmor securityfs already exists\n", __func__); 207 return -EEXIST; 208 } 209 210 aa_fs_dentry = securityfs_create_dir("apparmor", NULL); 211 if (IS_ERR(aa_fs_dentry)) { 212 error = PTR_ERR(aa_fs_dentry); 213 aa_fs_dentry = NULL; 214 goto error; 215 } 216 217 error = aafs_create(".load", 0640, &aa_fs_profile_load); 218 if (error) 219 goto error; 220 error = aafs_create(".replace", 0640, &aa_fs_profile_replace); 221 if (error) 222 goto error; 223 error = aafs_create(".remove", 0640, &aa_fs_profile_remove); 224 if (error) 225 goto error; 226 227 /* TODO: add support for apparmorfs_null and apparmorfs_mnt */ 228 229 /* Report that AppArmor fs is enabled */ 230 aa_info_message("AppArmor Filesystem Enabled"); 231 return 0; 232 233 error: 234 aa_destroy_aafs(); 235 AA_ERROR("Error creating AppArmor securityfs\n"); 236 return error; 237 } 238 239 fs_initcall(aa_create_aafs); 240