1 /* 2 * Copyright (C) 2007 Casey Schaufler <casey@schaufler-ca.com> 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation, version 2. 7 * 8 * Author: 9 * Casey Schaufler <casey@schaufler-ca.com> 10 * 11 */ 12 13 #include <linux/types.h> 14 #include <linux/slab.h> 15 #include <linux/fs.h> 16 #include <linux/sched.h> 17 #include "smack.h" 18 19 struct smack_known smack_known_huh = { 20 .smk_known = "?", 21 .smk_secid = 2, 22 .smk_cipso = NULL, 23 }; 24 25 struct smack_known smack_known_hat = { 26 .smk_known = "^", 27 .smk_secid = 3, 28 .smk_cipso = NULL, 29 }; 30 31 struct smack_known smack_known_star = { 32 .smk_known = "*", 33 .smk_secid = 4, 34 .smk_cipso = NULL, 35 }; 36 37 struct smack_known smack_known_floor = { 38 .smk_known = "_", 39 .smk_secid = 5, 40 .smk_cipso = NULL, 41 }; 42 43 struct smack_known smack_known_invalid = { 44 .smk_known = "", 45 .smk_secid = 6, 46 .smk_cipso = NULL, 47 }; 48 49 struct smack_known smack_known_web = { 50 .smk_known = "@", 51 .smk_secid = 7, 52 .smk_cipso = NULL, 53 }; 54 55 LIST_HEAD(smack_known_list); 56 57 /* 58 * The initial value needs to be bigger than any of the 59 * known values above. 60 */ 61 static u32 smack_next_secid = 10; 62 63 /* 64 * what events do we log 65 * can be overwritten at run-time by /smack/logging 66 */ 67 int log_policy = SMACK_AUDIT_DENIED; 68 69 /** 70 * smk_access_entry - look up matching access rule 71 * @subject_label: a pointer to the subject's Smack label 72 * @object_label: a pointer to the object's Smack label 73 * 74 * This function looks up the subject/object pair in the 75 * access rule list and returns pointer to the matching rule if found, 76 * NULL otherwise. 77 * 78 * NOTE: 79 * Even though Smack labels are usually shared on smack_list 80 * labels that come in off the network can't be imported 81 * and added to the list for locking reasons. 82 * 83 * Therefore, it is necessary to check the contents of the labels, 84 * not just the pointer values. Of course, in most cases the labels 85 * will be on the list, so checking the pointers may be a worthwhile 86 * optimization. 87 */ 88 int smk_access_entry(char *subject_label, char *object_label) 89 { 90 u32 may = MAY_NOT; 91 struct smack_rule *srp; 92 93 rcu_read_lock(); 94 list_for_each_entry_rcu(srp, &smack_rule_list, list) { 95 if (srp->smk_subject == subject_label || 96 strcmp(srp->smk_subject, subject_label) == 0) { 97 if (srp->smk_object == object_label || 98 strcmp(srp->smk_object, object_label) == 0) { 99 may = srp->smk_access; 100 break; 101 } 102 } 103 } 104 rcu_read_unlock(); 105 106 return may; 107 } 108 109 /** 110 * smk_access - determine if a subject has a specific access to an object 111 * @subject_label: a pointer to the subject's Smack label 112 * @object_label: a pointer to the object's Smack label 113 * @request: the access requested, in "MAY" format 114 * @a : a pointer to the audit data 115 * 116 * This function looks up the subject/object pair in the 117 * access rule list and returns 0 if the access is permitted, 118 * non zero otherwise. 119 * 120 * Even though Smack labels are usually shared on smack_list 121 * labels that come in off the network can't be imported 122 * and added to the list for locking reasons. 123 * 124 * Therefore, it is necessary to check the contents of the labels, 125 * not just the pointer values. Of course, in most cases the labels 126 * will be on the list, so checking the pointers may be a worthwhile 127 * optimization. 128 */ 129 int smk_access(char *subject_label, char *object_label, int request, 130 struct smk_audit_info *a) 131 { 132 u32 may = MAY_NOT; 133 int rc = 0; 134 135 /* 136 * Hardcoded comparisons. 137 * 138 * A star subject can't access any object. 139 */ 140 if (subject_label == smack_known_star.smk_known || 141 strcmp(subject_label, smack_known_star.smk_known) == 0) { 142 rc = -EACCES; 143 goto out_audit; 144 } 145 /* 146 * An internet object can be accessed by any subject. 147 * Tasks cannot be assigned the internet label. 148 * An internet subject can access any object. 149 */ 150 if (object_label == smack_known_web.smk_known || 151 subject_label == smack_known_web.smk_known || 152 strcmp(object_label, smack_known_web.smk_known) == 0 || 153 strcmp(subject_label, smack_known_web.smk_known) == 0) 154 goto out_audit; 155 /* 156 * A star object can be accessed by any subject. 157 */ 158 if (object_label == smack_known_star.smk_known || 159 strcmp(object_label, smack_known_star.smk_known) == 0) 160 goto out_audit; 161 /* 162 * An object can be accessed in any way by a subject 163 * with the same label. 164 */ 165 if (subject_label == object_label || 166 strcmp(subject_label, object_label) == 0) 167 goto out_audit; 168 /* 169 * A hat subject can read any object. 170 * A floor object can be read by any subject. 171 */ 172 if ((request & MAY_ANYREAD) == request) { 173 if (object_label == smack_known_floor.smk_known || 174 strcmp(object_label, smack_known_floor.smk_known) == 0) 175 goto out_audit; 176 if (subject_label == smack_known_hat.smk_known || 177 strcmp(subject_label, smack_known_hat.smk_known) == 0) 178 goto out_audit; 179 } 180 /* 181 * Beyond here an explicit relationship is required. 182 * If the requested access is contained in the available 183 * access (e.g. read is included in readwrite) it's 184 * good. 185 */ 186 may = smk_access_entry(subject_label, object_label); 187 /* 188 * This is a bit map operation. 189 */ 190 if ((request & may) == request) 191 goto out_audit; 192 193 rc = -EACCES; 194 out_audit: 195 #ifdef CONFIG_AUDIT 196 if (a) 197 smack_log(subject_label, object_label, request, rc, a); 198 #endif 199 return rc; 200 } 201 202 /** 203 * smk_curacc - determine if current has a specific access to an object 204 * @obj_label: a pointer to the object's Smack label 205 * @mode: the access requested, in "MAY" format 206 * @a : common audit data 207 * 208 * This function checks the current subject label/object label pair 209 * in the access rule list and returns 0 if the access is permitted, 210 * non zero otherwise. It allows that current may have the capability 211 * to override the rules. 212 */ 213 int smk_curacc(char *obj_label, u32 mode, struct smk_audit_info *a) 214 { 215 int rc; 216 char *sp = smk_of_current(); 217 218 rc = smk_access(sp, obj_label, mode, NULL); 219 if (rc == 0) 220 goto out_audit; 221 222 /* 223 * Return if a specific label has been designated as the 224 * only one that gets privilege and current does not 225 * have that label. 226 */ 227 if (smack_onlycap != NULL && smack_onlycap != sp) 228 goto out_audit; 229 230 if (capable(CAP_MAC_OVERRIDE)) 231 return 0; 232 233 out_audit: 234 #ifdef CONFIG_AUDIT 235 if (a) 236 smack_log(sp, obj_label, mode, rc, a); 237 #endif 238 return rc; 239 } 240 241 #ifdef CONFIG_AUDIT 242 /** 243 * smack_str_from_perm : helper to transalate an int to a 244 * readable string 245 * @string : the string to fill 246 * @access : the int 247 * 248 */ 249 static inline void smack_str_from_perm(char *string, int access) 250 { 251 int i = 0; 252 if (access & MAY_READ) 253 string[i++] = 'r'; 254 if (access & MAY_WRITE) 255 string[i++] = 'w'; 256 if (access & MAY_EXEC) 257 string[i++] = 'x'; 258 if (access & MAY_APPEND) 259 string[i++] = 'a'; 260 string[i] = '\0'; 261 } 262 /** 263 * smack_log_callback - SMACK specific information 264 * will be called by generic audit code 265 * @ab : the audit_buffer 266 * @a : audit_data 267 * 268 */ 269 static void smack_log_callback(struct audit_buffer *ab, void *a) 270 { 271 struct common_audit_data *ad = a; 272 struct smack_audit_data *sad = &ad->smack_audit_data; 273 audit_log_format(ab, "lsm=SMACK fn=%s action=%s", 274 ad->smack_audit_data.function, 275 sad->result ? "denied" : "granted"); 276 audit_log_format(ab, " subject="); 277 audit_log_untrustedstring(ab, sad->subject); 278 audit_log_format(ab, " object="); 279 audit_log_untrustedstring(ab, sad->object); 280 audit_log_format(ab, " requested=%s", sad->request); 281 } 282 283 /** 284 * smack_log - Audit the granting or denial of permissions. 285 * @subject_label : smack label of the requester 286 * @object_label : smack label of the object being accessed 287 * @request: requested permissions 288 * @result: result from smk_access 289 * @a: auxiliary audit data 290 * 291 * Audit the granting or denial of permissions in accordance 292 * with the policy. 293 */ 294 void smack_log(char *subject_label, char *object_label, int request, 295 int result, struct smk_audit_info *ad) 296 { 297 char request_buffer[SMK_NUM_ACCESS_TYPE + 1]; 298 struct smack_audit_data *sad; 299 struct common_audit_data *a = &ad->a; 300 301 /* check if we have to log the current event */ 302 if (result != 0 && (log_policy & SMACK_AUDIT_DENIED) == 0) 303 return; 304 if (result == 0 && (log_policy & SMACK_AUDIT_ACCEPT) == 0) 305 return; 306 307 if (a->smack_audit_data.function == NULL) 308 a->smack_audit_data.function = "unknown"; 309 310 /* end preparing the audit data */ 311 sad = &a->smack_audit_data; 312 smack_str_from_perm(request_buffer, request); 313 sad->subject = subject_label; 314 sad->object = object_label; 315 sad->request = request_buffer; 316 sad->result = result; 317 a->lsm_pre_audit = smack_log_callback; 318 319 common_lsm_audit(a); 320 } 321 #else /* #ifdef CONFIG_AUDIT */ 322 void smack_log(char *subject_label, char *object_label, int request, 323 int result, struct smk_audit_info *ad) 324 { 325 } 326 #endif 327 328 static DEFINE_MUTEX(smack_known_lock); 329 330 /** 331 * smk_import_entry - import a label, return the list entry 332 * @string: a text string that might be a Smack label 333 * @len: the maximum size, or zero if it is NULL terminated. 334 * 335 * Returns a pointer to the entry in the label list that 336 * matches the passed string, adding it if necessary. 337 */ 338 struct smack_known *smk_import_entry(const char *string, int len) 339 { 340 struct smack_known *skp; 341 char smack[SMK_LABELLEN]; 342 int found; 343 int i; 344 345 if (len <= 0 || len > SMK_MAXLEN) 346 len = SMK_MAXLEN; 347 348 for (i = 0, found = 0; i < SMK_LABELLEN; i++) { 349 if (found) 350 smack[i] = '\0'; 351 else if (i >= len || string[i] > '~' || string[i] <= ' ' || 352 string[i] == '/' || string[i] == '"' || 353 string[i] == '\\' || string[i] == '\'') { 354 smack[i] = '\0'; 355 found = 1; 356 } else 357 smack[i] = string[i]; 358 } 359 360 if (smack[0] == '\0') 361 return NULL; 362 363 mutex_lock(&smack_known_lock); 364 365 found = 0; 366 list_for_each_entry_rcu(skp, &smack_known_list, list) { 367 if (strncmp(skp->smk_known, smack, SMK_MAXLEN) == 0) { 368 found = 1; 369 break; 370 } 371 } 372 373 if (found == 0) { 374 skp = kzalloc(sizeof(struct smack_known), GFP_KERNEL); 375 if (skp != NULL) { 376 strncpy(skp->smk_known, smack, SMK_MAXLEN); 377 skp->smk_secid = smack_next_secid++; 378 skp->smk_cipso = NULL; 379 spin_lock_init(&skp->smk_cipsolock); 380 /* 381 * Make sure that the entry is actually 382 * filled before putting it on the list. 383 */ 384 list_add_rcu(&skp->list, &smack_known_list); 385 } 386 } 387 388 mutex_unlock(&smack_known_lock); 389 390 return skp; 391 } 392 393 /** 394 * smk_import - import a smack label 395 * @string: a text string that might be a Smack label 396 * @len: the maximum size, or zero if it is NULL terminated. 397 * 398 * Returns a pointer to the label in the label list that 399 * matches the passed string, adding it if necessary. 400 */ 401 char *smk_import(const char *string, int len) 402 { 403 struct smack_known *skp; 404 405 /* labels cannot begin with a '-' */ 406 if (string[0] == '-') 407 return NULL; 408 skp = smk_import_entry(string, len); 409 if (skp == NULL) 410 return NULL; 411 return skp->smk_known; 412 } 413 414 /** 415 * smack_from_secid - find the Smack label associated with a secid 416 * @secid: an integer that might be associated with a Smack label 417 * 418 * Returns a pointer to the appropraite Smack label if there is one, 419 * otherwise a pointer to the invalid Smack label. 420 */ 421 char *smack_from_secid(const u32 secid) 422 { 423 struct smack_known *skp; 424 425 rcu_read_lock(); 426 list_for_each_entry_rcu(skp, &smack_known_list, list) { 427 if (skp->smk_secid == secid) { 428 rcu_read_unlock(); 429 return skp->smk_known; 430 } 431 } 432 433 /* 434 * If we got this far someone asked for the translation 435 * of a secid that is not on the list. 436 */ 437 rcu_read_unlock(); 438 return smack_known_invalid.smk_known; 439 } 440 441 /** 442 * smack_to_secid - find the secid associated with a Smack label 443 * @smack: the Smack label 444 * 445 * Returns the appropriate secid if there is one, 446 * otherwise 0 447 */ 448 u32 smack_to_secid(const char *smack) 449 { 450 struct smack_known *skp; 451 452 rcu_read_lock(); 453 list_for_each_entry_rcu(skp, &smack_known_list, list) { 454 if (strncmp(skp->smk_known, smack, SMK_MAXLEN) == 0) { 455 rcu_read_unlock(); 456 return skp->smk_secid; 457 } 458 } 459 rcu_read_unlock(); 460 return 0; 461 } 462 463 /** 464 * smack_from_cipso - find the Smack label associated with a CIPSO option 465 * @level: Bell & LaPadula level from the network 466 * @cp: Bell & LaPadula categories from the network 467 * @result: where to put the Smack value 468 * 469 * This is a simple lookup in the label table. 470 * 471 * This is an odd duck as far as smack handling goes in that 472 * it sends back a copy of the smack label rather than a pointer 473 * to the master list. This is done because it is possible for 474 * a foreign host to send a smack label that is new to this 475 * machine and hence not on the list. That would not be an 476 * issue except that adding an entry to the master list can't 477 * be done at that point. 478 */ 479 void smack_from_cipso(u32 level, char *cp, char *result) 480 { 481 struct smack_known *kp; 482 char *final = NULL; 483 484 rcu_read_lock(); 485 list_for_each_entry(kp, &smack_known_list, list) { 486 if (kp->smk_cipso == NULL) 487 continue; 488 489 spin_lock_bh(&kp->smk_cipsolock); 490 491 if (kp->smk_cipso->smk_level == level && 492 memcmp(kp->smk_cipso->smk_catset, cp, SMK_LABELLEN) == 0) 493 final = kp->smk_known; 494 495 spin_unlock_bh(&kp->smk_cipsolock); 496 } 497 rcu_read_unlock(); 498 if (final == NULL) 499 final = smack_known_huh.smk_known; 500 strncpy(result, final, SMK_MAXLEN); 501 return; 502 } 503 504 /** 505 * smack_to_cipso - find the CIPSO option to go with a Smack label 506 * @smack: a pointer to the smack label in question 507 * @cp: where to put the result 508 * 509 * Returns zero if a value is available, non-zero otherwise. 510 */ 511 int smack_to_cipso(const char *smack, struct smack_cipso *cp) 512 { 513 struct smack_known *kp; 514 int found = 0; 515 516 rcu_read_lock(); 517 list_for_each_entry_rcu(kp, &smack_known_list, list) { 518 if (kp->smk_known == smack || 519 strcmp(kp->smk_known, smack) == 0) { 520 found = 1; 521 break; 522 } 523 } 524 rcu_read_unlock(); 525 526 if (found == 0 || kp->smk_cipso == NULL) 527 return -ENOENT; 528 529 memcpy(cp, kp->smk_cipso, sizeof(struct smack_cipso)); 530 return 0; 531 } 532