ima_policy.c (3323eec921efd815178a23107ab63588c605c0b2) | ima_policy.c (4af4662fa4a9dc62289c580337ae2506339c4729) |
---|---|
1/* 2 * Copyright (C) 2008 IBM Corporation 3 * Author: Mimi Zohar <zohar@us.ibm.com> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, version 2 of the License. 8 * 9 * ima_policy.c 10 * - initialize default measure policy rules 11 * 12 */ 13#include <linux/module.h> 14#include <linux/list.h> 15#include <linux/audit.h> 16#include <linux/security.h> 17#include <linux/magic.h> | 1/* 2 * Copyright (C) 2008 IBM Corporation 3 * Author: Mimi Zohar <zohar@us.ibm.com> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, version 2 of the License. 8 * 9 * ima_policy.c 10 * - initialize default measure policy rules 11 * 12 */ 13#include <linux/module.h> 14#include <linux/list.h> 15#include <linux/audit.h> 16#include <linux/security.h> 17#include <linux/magic.h> |
18#include <linux/parser.h> |
|
18 19#include "ima.h" 20 21/* flags definitions */ 22#define IMA_FUNC 0x0001 23#define IMA_MASK 0x0002 24#define IMA_FSMAGIC 0x0004 25#define IMA_UID 0x0008 26 | 19 20#include "ima.h" 21 22/* flags definitions */ 23#define IMA_FUNC 0x0001 24#define IMA_MASK 0x0002 25#define IMA_FSMAGIC 0x0004 26#define IMA_UID 0x0008 27 |
27enum ima_action { DONT_MEASURE, MEASURE }; | 28enum ima_action { UNKNOWN = -1, DONT_MEASURE = 0, MEASURE }; |
28 | 29 |
30#define MAX_LSM_RULES 6 31enum lsm_rule_types { LSM_OBJ_USER, LSM_OBJ_ROLE, LSM_OBJ_TYPE, 32 LSM_SUBJ_USER, LSM_SUBJ_ROLE, LSM_SUBJ_TYPE 33}; 34 |
|
29struct ima_measure_rule_entry { 30 struct list_head list; 31 enum ima_action action; 32 unsigned int flags; 33 enum ima_hooks func; 34 int mask; 35 unsigned long fsmagic; 36 uid_t uid; | 35struct ima_measure_rule_entry { 36 struct list_head list; 37 enum ima_action action; 38 unsigned int flags; 39 enum ima_hooks func; 40 int mask; 41 unsigned long fsmagic; 42 uid_t uid; |
43 struct { 44 void *rule; /* LSM file metadata specific */ 45 int type; /* audit type */ 46 } lsm[MAX_LSM_RULES]; |
|
37}; 38 | 47}; 48 |
49/* Without LSM specific knowledge, the default policy can only be 50 * written in terms of .action, .func, .mask, .fsmagic, and .uid 51 */ |
|
39static struct ima_measure_rule_entry default_rules[] = { 40 {.action = DONT_MEASURE,.fsmagic = PROC_SUPER_MAGIC, 41 .flags = IMA_FSMAGIC}, 42 {.action = DONT_MEASURE,.fsmagic = SYSFS_MAGIC,.flags = IMA_FSMAGIC}, 43 {.action = DONT_MEASURE,.fsmagic = DEBUGFS_MAGIC,.flags = IMA_FSMAGIC}, 44 {.action = DONT_MEASURE,.fsmagic = TMPFS_MAGIC,.flags = IMA_FSMAGIC}, 45 {.action = DONT_MEASURE,.fsmagic = SECURITYFS_MAGIC, 46 .flags = IMA_FSMAGIC}, 47 {.action = DONT_MEASURE,.fsmagic = 0xF97CFF8C,.flags = IMA_FSMAGIC}, 48 {.action = MEASURE,.func = FILE_MMAP,.mask = MAY_EXEC, 49 .flags = IMA_FUNC | IMA_MASK}, 50 {.action = MEASURE,.func = BPRM_CHECK,.mask = MAY_EXEC, 51 .flags = IMA_FUNC | IMA_MASK}, 52 {.action = MEASURE,.func = PATH_CHECK,.mask = MAY_READ,.uid = 0, 53 .flags = IMA_FUNC | IMA_MASK | IMA_UID} 54}; 55 56static LIST_HEAD(measure_default_rules); | 52static struct ima_measure_rule_entry default_rules[] = { 53 {.action = DONT_MEASURE,.fsmagic = PROC_SUPER_MAGIC, 54 .flags = IMA_FSMAGIC}, 55 {.action = DONT_MEASURE,.fsmagic = SYSFS_MAGIC,.flags = IMA_FSMAGIC}, 56 {.action = DONT_MEASURE,.fsmagic = DEBUGFS_MAGIC,.flags = IMA_FSMAGIC}, 57 {.action = DONT_MEASURE,.fsmagic = TMPFS_MAGIC,.flags = IMA_FSMAGIC}, 58 {.action = DONT_MEASURE,.fsmagic = SECURITYFS_MAGIC, 59 .flags = IMA_FSMAGIC}, 60 {.action = DONT_MEASURE,.fsmagic = 0xF97CFF8C,.flags = IMA_FSMAGIC}, 61 {.action = MEASURE,.func = FILE_MMAP,.mask = MAY_EXEC, 62 .flags = IMA_FUNC | IMA_MASK}, 63 {.action = MEASURE,.func = BPRM_CHECK,.mask = MAY_EXEC, 64 .flags = IMA_FUNC | IMA_MASK}, 65 {.action = MEASURE,.func = PATH_CHECK,.mask = MAY_READ,.uid = 0, 66 .flags = IMA_FUNC | IMA_MASK | IMA_UID} 67}; 68 69static LIST_HEAD(measure_default_rules); |
70static LIST_HEAD(measure_policy_rules); |
|
57static struct list_head *ima_measure; 58 | 71static struct list_head *ima_measure; 72 |
73static DEFINE_MUTEX(ima_measure_mutex); 74 |
|
59/** 60 * ima_match_rules - determine whether an inode matches the measure rule. 61 * @rule: a pointer to a rule 62 * @inode: a pointer to an inode 63 * @func: LIM hook identifier 64 * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC) 65 * 66 * Returns true on rule match, false on failure. 67 */ 68static bool ima_match_rules(struct ima_measure_rule_entry *rule, 69 struct inode *inode, enum ima_hooks func, int mask) 70{ 71 struct task_struct *tsk = current; | 75/** 76 * ima_match_rules - determine whether an inode matches the measure rule. 77 * @rule: a pointer to a rule 78 * @inode: a pointer to an inode 79 * @func: LIM hook identifier 80 * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC) 81 * 82 * Returns true on rule match, false on failure. 83 */ 84static bool ima_match_rules(struct ima_measure_rule_entry *rule, 85 struct inode *inode, enum ima_hooks func, int mask) 86{ 87 struct task_struct *tsk = current; |
88 int i; |
|
72 73 if ((rule->flags & IMA_FUNC) && rule->func != func) 74 return false; 75 if ((rule->flags & IMA_MASK) && rule->mask != mask) 76 return false; 77 if ((rule->flags & IMA_FSMAGIC) 78 && rule->fsmagic != inode->i_sb->s_magic) 79 return false; 80 if ((rule->flags & IMA_UID) && rule->uid != tsk->cred->uid) 81 return false; | 89 90 if ((rule->flags & IMA_FUNC) && rule->func != func) 91 return false; 92 if ((rule->flags & IMA_MASK) && rule->mask != mask) 93 return false; 94 if ((rule->flags & IMA_FSMAGIC) 95 && rule->fsmagic != inode->i_sb->s_magic) 96 return false; 97 if ((rule->flags & IMA_UID) && rule->uid != tsk->cred->uid) 98 return false; |
99 for (i = 0; i < MAX_LSM_RULES; i++) { 100 int rc; 101 u32 osid, sid; 102 103 if (!rule->lsm[i].rule) 104 continue; 105 106 switch (i) { 107 case LSM_OBJ_USER: 108 case LSM_OBJ_ROLE: 109 case LSM_OBJ_TYPE: 110 security_inode_getsecid(inode, &osid); 111 rc = security_filter_rule_match(osid, 112 rule->lsm[i].type, 113 AUDIT_EQUAL, 114 rule->lsm[i].rule, 115 NULL); 116 break; 117 case LSM_SUBJ_USER: 118 case LSM_SUBJ_ROLE: 119 case LSM_SUBJ_TYPE: 120 security_task_getsecid(tsk, &sid); 121 rc = security_filter_rule_match(sid, 122 rule->lsm[i].type, 123 AUDIT_EQUAL, 124 rule->lsm[i].rule, 125 NULL); 126 default: 127 break; 128 } 129 if (!rc) 130 return false; 131 } |
|
82 return true; 83} 84 85/** 86 * ima_match_policy - decision based on LSM and other conditions 87 * @inode: pointer to an inode for which the policy decision is being made 88 * @func: IMA hook identifier 89 * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC) --- 17 unchanged lines hidden (view full) --- 107 return entry->action; 108 } 109 return 0; 110} 111 112/** 113 * ima_init_policy - initialize the default measure rules. 114 * | 132 return true; 133} 134 135/** 136 * ima_match_policy - decision based on LSM and other conditions 137 * @inode: pointer to an inode for which the policy decision is being made 138 * @func: IMA hook identifier 139 * @mask: requested action (MAY_READ | MAY_WRITE | MAY_APPEND | MAY_EXEC) --- 17 unchanged lines hidden (view full) --- 157 return entry->action; 158 } 159 return 0; 160} 161 162/** 163 * ima_init_policy - initialize the default measure rules. 164 * |
115 * (Could use the default_rules directly, but in policy patch | |
116 * ima_measure points to either the measure_default_rules or the | 165 * ima_measure points to either the measure_default_rules or the |
117 * the new measure_policy_rules.) | 166 * the new measure_policy_rules. |
118 */ 119void ima_init_policy(void) 120{ 121 int i; 122 123 for (i = 0; i < ARRAY_SIZE(default_rules); i++) 124 list_add_tail(&default_rules[i].list, &measure_default_rules); 125 ima_measure = &measure_default_rules; 126} | 167 */ 168void ima_init_policy(void) 169{ 170 int i; 171 172 for (i = 0; i < ARRAY_SIZE(default_rules); i++) 173 list_add_tail(&default_rules[i].list, &measure_default_rules); 174 ima_measure = &measure_default_rules; 175} |
176 177/** 178 * ima_update_policy - update default_rules with new measure rules 179 * 180 * Called on file .release to update the default rules with a complete new 181 * policy. Once updated, the policy is locked, no additional rules can be 182 * added to the policy. 183 */ 184void ima_update_policy(void) 185{ 186 const char *op = "policy_update"; 187 const char *cause = "already exists"; 188 int result = 1; 189 int audit_info = 0; 190 191 if (ima_measure == &measure_default_rules) { 192 ima_measure = &measure_policy_rules; 193 cause = "complete"; 194 result = 0; 195 } 196 integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, 197 NULL, op, cause, result, audit_info); 198} 199 200enum { 201 Opt_err = -1, 202 Opt_measure = 1, Opt_dont_measure, 203 Opt_obj_user, Opt_obj_role, Opt_obj_type, 204 Opt_subj_user, Opt_subj_role, Opt_subj_type, 205 Opt_func, Opt_mask, Opt_fsmagic, Opt_uid 206}; 207 208static match_table_t policy_tokens = { 209 {Opt_measure, "measure"}, 210 {Opt_dont_measure, "dont_measure"}, 211 {Opt_obj_user, "obj_user=%s"}, 212 {Opt_obj_role, "obj_role=%s"}, 213 {Opt_obj_type, "obj_type=%s"}, 214 {Opt_subj_user, "subj_user=%s"}, 215 {Opt_subj_role, "subj_role=%s"}, 216 {Opt_subj_type, "subj_type=%s"}, 217 {Opt_func, "func=%s"}, 218 {Opt_mask, "mask=%s"}, 219 {Opt_fsmagic, "fsmagic=%s"}, 220 {Opt_uid, "uid=%s"}, 221 {Opt_err, NULL} 222}; 223 224static int ima_lsm_rule_init(struct ima_measure_rule_entry *entry, 225 char *args, int lsm_rule, int audit_type) 226{ 227 int result; 228 229 entry->lsm[lsm_rule].type = audit_type; 230 result = security_filter_rule_init(entry->lsm[lsm_rule].type, 231 AUDIT_EQUAL, args, 232 &entry->lsm[lsm_rule].rule); 233 return result; 234} 235 236static int ima_parse_rule(char *rule, struct ima_measure_rule_entry *entry) 237{ 238 struct audit_buffer *ab; 239 char *p; 240 int result = 0; 241 242 ab = audit_log_start(current->audit_context, GFP_KERNEL, 243 AUDIT_INTEGRITY_STATUS); 244 245 entry->action = -1; 246 while ((p = strsep(&rule, " \n")) != NULL) { 247 substring_t args[MAX_OPT_ARGS]; 248 int token; 249 unsigned long lnum; 250 251 if (result < 0) 252 break; 253 if (!*p) 254 continue; 255 token = match_token(p, policy_tokens, args); 256 switch (token) { 257 case Opt_measure: 258 audit_log_format(ab, "%s ", "measure"); 259 entry->action = MEASURE; 260 break; 261 case Opt_dont_measure: 262 audit_log_format(ab, "%s ", "dont_measure"); 263 entry->action = DONT_MEASURE; 264 break; 265 case Opt_func: 266 audit_log_format(ab, "func=%s ", args[0].from); 267 if (strcmp(args[0].from, "PATH_CHECK") == 0) 268 entry->func = PATH_CHECK; 269 else if (strcmp(args[0].from, "FILE_MMAP") == 0) 270 entry->func = FILE_MMAP; 271 else if (strcmp(args[0].from, "BPRM_CHECK") == 0) 272 entry->func = BPRM_CHECK; 273 else 274 result = -EINVAL; 275 if (!result) 276 entry->flags |= IMA_FUNC; 277 break; 278 case Opt_mask: 279 audit_log_format(ab, "mask=%s ", args[0].from); 280 if ((strcmp(args[0].from, "MAY_EXEC")) == 0) 281 entry->mask = MAY_EXEC; 282 else if (strcmp(args[0].from, "MAY_WRITE") == 0) 283 entry->mask = MAY_WRITE; 284 else if (strcmp(args[0].from, "MAY_READ") == 0) 285 entry->mask = MAY_READ; 286 else if (strcmp(args[0].from, "MAY_APPEND") == 0) 287 entry->mask = MAY_APPEND; 288 else 289 result = -EINVAL; 290 if (!result) 291 entry->flags |= IMA_MASK; 292 break; 293 case Opt_fsmagic: 294 audit_log_format(ab, "fsmagic=%s ", args[0].from); 295 result = strict_strtoul(args[0].from, 16, 296 &entry->fsmagic); 297 if (!result) 298 entry->flags |= IMA_FSMAGIC; 299 break; 300 case Opt_uid: 301 audit_log_format(ab, "uid=%s ", args[0].from); 302 result = strict_strtoul(args[0].from, 10, &lnum); 303 if (!result) { 304 entry->uid = (uid_t) lnum; 305 if (entry->uid != lnum) 306 result = -EINVAL; 307 else 308 entry->flags |= IMA_UID; 309 } 310 break; 311 case Opt_obj_user: 312 audit_log_format(ab, "obj_user=%s ", args[0].from); 313 result = ima_lsm_rule_init(entry, args[0].from, 314 LSM_OBJ_USER, 315 AUDIT_OBJ_USER); 316 break; 317 case Opt_obj_role: 318 audit_log_format(ab, "obj_role=%s ", args[0].from); 319 result = ima_lsm_rule_init(entry, args[0].from, 320 LSM_OBJ_ROLE, 321 AUDIT_OBJ_ROLE); 322 break; 323 case Opt_obj_type: 324 audit_log_format(ab, "obj_type=%s ", args[0].from); 325 result = ima_lsm_rule_init(entry, args[0].from, 326 LSM_OBJ_TYPE, 327 AUDIT_OBJ_TYPE); 328 break; 329 case Opt_subj_user: 330 audit_log_format(ab, "subj_user=%s ", args[0].from); 331 result = ima_lsm_rule_init(entry, args[0].from, 332 LSM_SUBJ_USER, 333 AUDIT_SUBJ_USER); 334 break; 335 case Opt_subj_role: 336 audit_log_format(ab, "subj_role=%s ", args[0].from); 337 result = ima_lsm_rule_init(entry, args[0].from, 338 LSM_SUBJ_ROLE, 339 AUDIT_SUBJ_ROLE); 340 break; 341 case Opt_subj_type: 342 audit_log_format(ab, "subj_type=%s ", args[0].from); 343 result = ima_lsm_rule_init(entry, args[0].from, 344 LSM_SUBJ_TYPE, 345 AUDIT_SUBJ_TYPE); 346 break; 347 case Opt_err: 348 printk(KERN_INFO "%s: unknown token: %s\n", 349 __FUNCTION__, p); 350 break; 351 } 352 } 353 if (entry->action == UNKNOWN) 354 result = -EINVAL; 355 356 audit_log_format(ab, "res=%d", result); 357 audit_log_end(ab); 358 return result; 359} 360 361/** 362 * ima_parse_add_rule - add a rule to measure_policy_rules 363 * @rule - ima measurement policy rule 364 * 365 * Uses a mutex to protect the policy list from multiple concurrent writers. 366 * Returns 0 on success, an error code on failure. 367 */ 368int ima_parse_add_rule(char *rule) 369{ 370 const char *op = "add_rule"; 371 struct ima_measure_rule_entry *entry; 372 int result = 0; 373 int audit_info = 0; 374 375 /* Prevent installed policy from changing */ 376 if (ima_measure != &measure_default_rules) { 377 integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, 378 NULL, op, "already exists", 379 -EACCES, audit_info); 380 return -EACCES; 381 } 382 383 entry = kzalloc(sizeof(*entry), GFP_KERNEL); 384 if (!entry) { 385 integrity_audit_msg(AUDIT_INTEGRITY_STATUS, NULL, 386 NULL, op, "-ENOMEM", -ENOMEM, audit_info); 387 return -ENOMEM; 388 } 389 390 INIT_LIST_HEAD(&entry->list); 391 392 result = ima_parse_rule(rule, entry); 393 if (!result) { 394 mutex_lock(&ima_measure_mutex); 395 list_add_tail(&entry->list, &measure_policy_rules); 396 mutex_unlock(&ima_measure_mutex); 397 } else 398 kfree(entry); 399 return result; 400} 401 402/* ima_delete_rules called to cleanup invalid policy */ 403void ima_delete_rules() 404{ 405 struct ima_measure_rule_entry *entry, *tmp; 406 407 mutex_lock(&ima_measure_mutex); 408 list_for_each_entry_safe(entry, tmp, &measure_policy_rules, list) { 409 list_del(&entry->list); 410 kfree(entry); 411 } 412 mutex_unlock(&ima_measure_mutex); 413} |
|