Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'apparmor-pr-2019-12-03' of git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor

Pull apparmor updates from John Johansen:
"Features:

- increase left match history buffer size to provide improved
conflict resolution in overlapping execution rules.

- switch buffer allocation to use a memory pool and GFP_KERNEL where
possible.

- add compression of policy blobs to reduce memory usage.

Cleanups:

- fix spelling mistake "immutible" -> "immutable"

Bug fixes:

- fix unsigned len comparison in update_for_len macro

- fix sparse warning for type-casting of current->real_cred"

* tag 'apparmor-pr-2019-12-03' of git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor:
apparmor: make it so work buffers can be allocated from atomic context
apparmor: reduce rcu_read_lock scope for aa_file_perm mediation
apparmor: fix wrong buffer allocation in aa_new_mount
apparmor: fix unsigned len comparison with less than zero
apparmor: increase left match history buffer size
apparmor: Switch to GFP_KERNEL where possible
apparmor: Use a memory pool instead per-CPU caches
apparmor: Force type-casting of current->real_cred
apparmor: fix spelling mistake "immutible" -> "immutable"
apparmor: fix blob compression when ns is forced on a policy load
apparmor: fix missing ZLIB defines
apparmor: fix blob compression build failure on ppc
apparmor: Initial implementation of raw policy blob compression

+523 -162
+2
security/apparmor/Kconfig
··· 6 6 select SECURITY_PATH 7 7 select SECURITYFS 8 8 select SECURITY_NETWORK 9 + select ZLIB_INFLATE 10 + select ZLIB_DEFLATE 9 11 default n 10 12 help 11 13 This enables the AppArmor security module.
+124 -6
security/apparmor/apparmorfs.c
··· 21 21 #include <linux/fs.h> 22 22 #include <linux/fs_context.h> 23 23 #include <linux/poll.h> 24 + #include <linux/zlib.h> 24 25 #include <uapi/linux/major.h> 25 26 #include <uapi/linux/magic.h> 26 27 ··· 65 64 /* 66 65 * support fns 67 66 */ 67 + 68 + struct rawdata_f_data { 69 + struct aa_loaddata *loaddata; 70 + }; 71 + 72 + #define RAWDATA_F_DATA_BUF(p) (char *)(p + 1) 73 + 74 + static void rawdata_f_data_free(struct rawdata_f_data *private) 75 + { 76 + if (!private) 77 + return; 78 + 79 + aa_put_loaddata(private->loaddata); 80 + kvfree(private); 81 + } 82 + 83 + static struct rawdata_f_data *rawdata_f_data_alloc(size_t size) 84 + { 85 + struct rawdata_f_data *ret; 86 + 87 + if (size > SIZE_MAX - sizeof(*ret)) 88 + return ERR_PTR(-EINVAL); 89 + 90 + ret = kvzalloc(sizeof(*ret) + size, GFP_KERNEL); 91 + if (!ret) 92 + return ERR_PTR(-ENOMEM); 93 + 94 + return ret; 95 + } 68 96 69 97 /** 70 98 * aa_mangle_name - mangle a profile name to std profile layout form ··· 1310 1280 return 0; 1311 1281 } 1312 1282 1283 + static int seq_rawdata_compressed_size_show(struct seq_file *seq, void *v) 1284 + { 1285 + struct aa_loaddata *data = seq->private; 1286 + 1287 + seq_printf(seq, "%zu\n", data->compressed_size); 1288 + 1289 + return 0; 1290 + } 1291 + 1313 1292 SEQ_RAWDATA_FOPS(abi); 1314 1293 SEQ_RAWDATA_FOPS(revision); 1315 1294 SEQ_RAWDATA_FOPS(hash); 1295 + SEQ_RAWDATA_FOPS(compressed_size); 1296 + 1297 + static int deflate_decompress(char *src, size_t slen, char *dst, size_t dlen) 1298 + { 1299 + int error; 1300 + struct z_stream_s strm; 1301 + 1302 + if (aa_g_rawdata_compression_level == 0) { 1303 + if (dlen < slen) 1304 + return -EINVAL; 1305 + memcpy(dst, src, slen); 1306 + return 0; 1307 + } 1308 + 1309 + memset(&strm, 0, sizeof(strm)); 1310 + 1311 + strm.workspace = kvzalloc(zlib_inflate_workspacesize(), GFP_KERNEL); 1312 + if (!strm.workspace) 1313 + return -ENOMEM; 1314 + 1315 + strm.next_in = src; 1316 + strm.avail_in = slen; 1317 + 1318 + error = zlib_inflateInit(&strm); 1319 + if (error != Z_OK) { 1320 + error = -ENOMEM; 1321 + goto fail_inflate_init; 1322 + } 1323 + 1324 + strm.next_out = dst; 1325 + strm.avail_out = dlen; 1326 + 1327 + error = zlib_inflate(&strm, Z_FINISH); 1328 + if (error != Z_STREAM_END) 1329 + error = -EINVAL; 1330 + else 1331 + error = 0; 1332 + 1333 + zlib_inflateEnd(&strm); 1334 + fail_inflate_init: 1335 + kvfree(strm.workspace); 1336 + return error; 1337 + } 1316 1338 1317 1339 static ssize_t rawdata_read(struct file *file, char __user *buf, size_t size, 1318 1340 loff_t *ppos) 1319 1341 { 1320 - struct aa_loaddata *rawdata = file->private_data; 1342 + struct rawdata_f_data *private = file->private_data; 1321 1343 1322 - return simple_read_from_buffer(buf, size, ppos, rawdata->data, 1323 - rawdata->size); 1344 + return simple_read_from_buffer(buf, size, ppos, 1345 + RAWDATA_F_DATA_BUF(private), 1346 + private->loaddata->size); 1324 1347 } 1325 1348 1326 1349 static int rawdata_release(struct inode *inode, struct file *file) 1327 1350 { 1328 - aa_put_loaddata(file->private_data); 1351 + rawdata_f_data_free(file->private_data); 1329 1352 1330 1353 return 0; 1331 1354 } 1332 1355 1333 1356 static int rawdata_open(struct inode *inode, struct file *file) 1334 1357 { 1358 + int error; 1359 + struct aa_loaddata *loaddata; 1360 + struct rawdata_f_data *private; 1361 + 1335 1362 if (!policy_view_capable(NULL)) 1336 1363 return -EACCES; 1337 - file->private_data = __aa_get_loaddata(inode->i_private); 1338 - if (!file->private_data) 1364 + 1365 + loaddata = __aa_get_loaddata(inode->i_private); 1366 + if (!loaddata) 1339 1367 /* lost race: this entry is being reaped */ 1340 1368 return -ENOENT; 1341 1369 1370 + private = rawdata_f_data_alloc(loaddata->size); 1371 + if (IS_ERR(private)) { 1372 + error = PTR_ERR(private); 1373 + goto fail_private_alloc; 1374 + } 1375 + 1376 + private->loaddata = loaddata; 1377 + 1378 + error = deflate_decompress(loaddata->data, loaddata->compressed_size, 1379 + RAWDATA_F_DATA_BUF(private), 1380 + loaddata->size); 1381 + if (error) 1382 + goto fail_decompress; 1383 + 1384 + file->private_data = private; 1342 1385 return 0; 1386 + 1387 + fail_decompress: 1388 + rawdata_f_data_free(private); 1389 + return error; 1390 + 1391 + fail_private_alloc: 1392 + aa_put_loaddata(loaddata); 1393 + return error; 1343 1394 } 1344 1395 1345 1396 static const struct file_operations rawdata_fops = { ··· 1498 1387 goto fail; 1499 1388 rawdata->dents[AAFS_LOADDATA_HASH] = dent; 1500 1389 } 1390 + 1391 + dent = aafs_create_file("compressed_size", S_IFREG | 0444, dir, 1392 + rawdata, 1393 + &seq_rawdata_compressed_size_fops); 1394 + if (IS_ERR(dent)) 1395 + goto fail; 1396 + rawdata->dents[AAFS_LOADDATA_COMPRESSED_SIZE] = dent; 1501 1397 1502 1398 dent = aafs_create_file("raw_data", S_IFREG | 0444, 1503 1399 dir, rawdata, &rawdata_fops);
+19 -25
security/apparmor/domain.c
··· 520 520 label = &new_profile->label; 521 521 continue; 522 522 } 523 - label = aa_label_parse(&profile->label, *name, GFP_ATOMIC, 523 + label = aa_label_parse(&profile->label, *name, GFP_KERNEL, 524 524 true, false); 525 525 if (IS_ERR(label)) 526 526 label = NULL; ··· 600 600 /* base the stack on post domain transition */ 601 601 struct aa_label *base = new; 602 602 603 - new = aa_label_parse(base, stack, GFP_ATOMIC, true, false); 603 + new = aa_label_parse(base, stack, GFP_KERNEL, true, false); 604 604 if (IS_ERR(new)) 605 605 new = NULL; 606 606 aa_put_label(base); ··· 685 685 } else if (COMPLAIN_MODE(profile)) { 686 686 /* no exec permission - learning mode */ 687 687 struct aa_profile *new_profile = NULL; 688 - char *n = kstrdup(name, GFP_ATOMIC); 689 688 690 - if (n) { 691 - /* name is ptr into buffer */ 692 - long pos = name - buffer; 693 - /* break per cpu buffer hold */ 694 - put_buffers(buffer); 695 - new_profile = aa_new_null_profile(profile, false, n, 696 - GFP_KERNEL); 697 - get_buffers(buffer); 698 - name = buffer + pos; 699 - strcpy((char *)name, n); 700 - kfree(n); 701 - } 689 + new_profile = aa_new_null_profile(profile, false, name, 690 + GFP_KERNEL); 702 691 if (!new_profile) { 703 692 error = -ENOMEM; 704 693 info = "could not create null profile"; ··· 708 719 if (DEBUG_ON) { 709 720 dbg_printk("apparmor: scrubbing environment variables" 710 721 " for %s profile=", name); 711 - aa_label_printk(new, GFP_ATOMIC); 722 + aa_label_printk(new, GFP_KERNEL); 712 723 dbg_printk("\n"); 713 724 } 714 725 *secure_exec = true; ··· 784 795 if (DEBUG_ON) { 785 796 dbg_printk("apparmor: scrubbing environment " 786 797 "variables for %s label=", xname); 787 - aa_label_printk(onexec, GFP_ATOMIC); 798 + aa_label_printk(onexec, GFP_KERNEL); 788 799 dbg_printk("\n"); 789 800 } 790 801 *secure_exec = true; ··· 818 829 bprm, buffer, cond, unsafe)); 819 830 if (error) 820 831 return ERR_PTR(error); 821 - new = fn_label_build_in_ns(label, profile, GFP_ATOMIC, 832 + new = fn_label_build_in_ns(label, profile, GFP_KERNEL, 822 833 aa_get_newest_label(onexec), 823 834 profile_transition(profile, bprm, buffer, 824 835 cond, unsafe)); ··· 830 841 buffer, cond, unsafe)); 831 842 if (error) 832 843 return ERR_PTR(error); 833 - new = fn_label_build_in_ns(label, profile, GFP_ATOMIC, 844 + new = fn_label_build_in_ns(label, profile, GFP_KERNEL, 834 845 aa_label_merge(&profile->label, onexec, 835 - GFP_ATOMIC), 846 + GFP_KERNEL), 836 847 profile_transition(profile, bprm, buffer, 837 848 cond, unsafe)); 838 849 } ··· 892 903 ctx->nnp = aa_get_label(label); 893 904 894 905 /* buffer freed below, name is pointer into buffer */ 895 - get_buffers(buffer); 906 + buffer = aa_get_buffer(false); 907 + if (!buffer) { 908 + error = -ENOMEM; 909 + goto done; 910 + } 911 + 896 912 /* Test for onexec first as onexec override other x transitions. */ 897 913 if (ctx->onexec) 898 914 new = handle_onexec(label, ctx->onexec, ctx->token, 899 915 bprm, buffer, &cond, &unsafe); 900 916 else 901 - new = fn_label_build(label, profile, GFP_ATOMIC, 917 + new = fn_label_build(label, profile, GFP_KERNEL, 902 918 profile_transition(profile, bprm, buffer, 903 919 &cond, &unsafe)); 904 920 ··· 947 953 if (DEBUG_ON) { 948 954 dbg_printk("scrubbing environment variables for %s " 949 955 "label=", bprm->filename); 950 - aa_label_printk(new, GFP_ATOMIC); 956 + aa_label_printk(new, GFP_KERNEL); 951 957 dbg_printk("\n"); 952 958 } 953 959 bprm->secureexec = 1; ··· 958 964 if (DEBUG_ON) { 959 965 dbg_printk("apparmor: clearing unsafe personality " 960 966 "bits. %s label=", bprm->filename); 961 - aa_label_printk(new, GFP_ATOMIC); 967 + aa_label_printk(new, GFP_KERNEL); 962 968 dbg_printk("\n"); 963 969 } 964 970 bprm->per_clear |= PER_CLEAR_ON_SETID; ··· 969 975 970 976 done: 971 977 aa_put_label(label); 972 - put_buffers(buffer); 978 + aa_put_buffer(buffer); 973 979 974 980 return error; 975 981
+29 -16
security/apparmor/file.c
··· 76 76 if (aad(sa)->peer) { 77 77 audit_log_format(ab, " target="); 78 78 aa_label_xaudit(ab, labels_ns(aad(sa)->label), aad(sa)->peer, 79 - FLAG_VIEW_SUBNS, GFP_ATOMIC); 79 + FLAG_VIEW_SUBNS, GFP_KERNEL); 80 80 } else if (aad(sa)->fs.target) { 81 81 audit_log_format(ab, " target="); 82 82 audit_log_untrustedstring(ab, aad(sa)->fs.target); ··· 332 332 333 333 flags |= PATH_DELEGATE_DELETED | (S_ISDIR(cond->mode) ? PATH_IS_DIR : 334 334 0); 335 - get_buffers(buffer); 335 + buffer = aa_get_buffer(false); 336 + if (!buffer) 337 + return -ENOMEM; 336 338 error = fn_for_each_confined(label, profile, 337 339 profile_path_perm(op, profile, path, buffer, request, 338 340 cond, flags, &perms)); 339 341 340 - put_buffers(buffer); 342 + aa_put_buffer(buffer); 341 343 342 344 return error; 343 345 } ··· 477 475 int error; 478 476 479 477 /* buffer freed below, lname is pointer in buffer */ 480 - get_buffers(buffer, buffer2); 478 + buffer = aa_get_buffer(false); 479 + buffer2 = aa_get_buffer(false); 480 + error = -ENOMEM; 481 + if (!buffer || !buffer2) 482 + goto out; 483 + 481 484 error = fn_for_each_confined(label, profile, 482 485 profile_path_link(profile, &link, buffer, &target, 483 486 buffer2, &cond)); 484 - put_buffers(buffer, buffer2); 485 - 487 + out: 488 + aa_put_buffer(buffer); 489 + aa_put_buffer(buffer2); 486 490 return error; 487 491 } 488 492 ··· 515 507 516 508 static int __file_path_perm(const char *op, struct aa_label *label, 517 509 struct aa_label *flabel, struct file *file, 518 - u32 request, u32 denied) 510 + u32 request, u32 denied, bool in_atomic) 519 511 { 520 512 struct aa_profile *profile; 521 513 struct aa_perms perms = {}; ··· 532 524 return 0; 533 525 534 526 flags = PATH_DELEGATE_DELETED | (S_ISDIR(cond.mode) ? PATH_IS_DIR : 0); 535 - get_buffers(buffer); 527 + buffer = aa_get_buffer(in_atomic); 528 + if (!buffer) 529 + return -ENOMEM; 536 530 537 531 /* check every profile in task label not in current cache */ 538 532 error = fn_for_each_not_in_set(flabel, label, profile, ··· 563 553 if (!error) 564 554 update_file_ctx(file_ctx(file), label, request); 565 555 566 - put_buffers(buffer); 556 + aa_put_buffer(buffer); 567 557 568 558 return error; 569 559 } ··· 600 590 * @label: label being enforced (NOT NULL) 601 591 * @file: file to revalidate access permissions on (NOT NULL) 602 592 * @request: requested permissions 593 + * @in_atomic: whether allocations need to be done in atomic context 603 594 * 604 595 * Returns: %0 if access allowed else error 605 596 */ 606 597 int aa_file_perm(const char *op, struct aa_label *label, struct file *file, 607 - u32 request) 598 + u32 request, bool in_atomic) 608 599 { 609 600 struct aa_file_ctx *fctx; 610 601 struct aa_label *flabel; ··· 618 607 fctx = file_ctx(file); 619 608 620 609 rcu_read_lock(); 621 - flabel = rcu_dereference(fctx->label); 610 + flabel = aa_get_newest_label(rcu_dereference(fctx->label)); 611 + rcu_read_unlock(); 622 612 AA_BUG(!flabel); 623 613 624 614 /* revalidate access, if task is unconfined, or the cached cred ··· 638 626 639 627 if (file->f_path.mnt && path_mediated_fs(file->f_path.dentry)) 640 628 error = __file_path_perm(op, label, flabel, file, request, 641 - denied); 629 + denied, in_atomic); 642 630 643 631 else if (S_ISSOCK(file_inode(file)->i_mode)) 644 632 error = __file_sock_perm(op, label, flabel, file, request, 645 633 denied); 646 634 done: 647 - rcu_read_unlock(); 648 - 635 + aa_put_label(flabel); 649 636 return error; 650 637 } 651 638 ··· 666 655 struct tty_file_private, list); 667 656 file = file_priv->file; 668 657 669 - if (aa_file_perm(OP_INHERIT, label, file, MAY_READ | MAY_WRITE)) 658 + if (aa_file_perm(OP_INHERIT, label, file, MAY_READ | MAY_WRITE, 659 + IN_ATOMIC)) 670 660 drop_tty = 1; 671 661 } 672 662 spin_unlock(&tty->files_lock); ··· 681 669 { 682 670 struct aa_label *label = (struct aa_label *)p; 683 671 684 - if (aa_file_perm(OP_INHERIT, label, file, aa_map_file_to_perms(file))) 672 + if (aa_file_perm(OP_INHERIT, label, file, aa_map_file_to_perms(file), 673 + IN_ATOMIC)) 685 674 return fd + 1; 686 675 return 0; 687 676 }
+1
security/apparmor/include/apparmor.h
··· 36 36 extern bool aa_g_audit_header; 37 37 extern bool aa_g_debug; 38 38 extern bool aa_g_hash_policy; 39 + extern int aa_g_rawdata_compression_level; 39 40 extern bool aa_g_lock_policy; 40 41 extern bool aa_g_logsyscall; 41 42 extern bool aa_g_paranoid_load;
+1 -1
security/apparmor/include/file.h
··· 197 197 const struct path *new_dir, struct dentry *new_dentry); 198 198 199 199 int aa_file_perm(const char *op, struct aa_label *label, struct file *file, 200 - u32 request); 200 + u32 request, bool in_atomic); 201 201 202 202 void aa_inherit_files(const struct cred *cred, struct files_struct *files); 203 203
+1 -2
security/apparmor/include/match.h
··· 134 134 135 135 void aa_dfa_free_kref(struct kref *kref); 136 136 137 - #define WB_HISTORY_SIZE 8 137 + #define WB_HISTORY_SIZE 24 138 138 struct match_workbuf { 139 139 unsigned int count; 140 140 unsigned int pos; ··· 147 147 .count = 0, \ 148 148 .pos = 0, \ 149 149 .len = 0, \ 150 - .size = WB_HISTORY_SIZE, \ 151 150 } 152 151 153 152 unsigned int aa_dfa_leftmatch(struct aa_dfa *dfa, unsigned int start,
+3 -47
security/apparmor/include/path.h
··· 11 11 #ifndef __AA_PATH_H 12 12 #define __AA_PATH_H 13 13 14 - 15 14 enum path_flags { 16 15 PATH_IS_DIR = 0x1, /* path is a directory */ 17 16 PATH_CONNECT_PATH = 0x4, /* connect disconnected paths to / */ ··· 25 26 const char **name, const char **info, 26 27 const char *disconnected); 27 28 28 - #define MAX_PATH_BUFFERS 2 29 - 30 - /* Per cpu buffers used during mediation */ 31 - /* preallocated buffers to use during path lookups */ 32 - struct aa_buffers { 33 - char *buf[MAX_PATH_BUFFERS]; 34 - }; 35 - 36 - #include <linux/percpu.h> 37 - #include <linux/preempt.h> 38 - 39 - DECLARE_PER_CPU(struct aa_buffers, aa_buffers); 40 - 41 - #define ASSIGN(FN, A, X, N) ((X) = FN(A, N)) 42 - #define EVAL1(FN, A, X) ASSIGN(FN, A, X, 0) /*X = FN(0)*/ 43 - #define EVAL2(FN, A, X, Y...) \ 44 - do { ASSIGN(FN, A, X, 1); EVAL1(FN, A, Y); } while (0) 45 - #define EVAL(FN, A, X...) CONCATENATE(EVAL, COUNT_ARGS(X))(FN, A, X) 46 - 47 - #define for_each_cpu_buffer(I) for ((I) = 0; (I) < MAX_PATH_BUFFERS; (I)++) 48 - 49 - #ifdef CONFIG_DEBUG_PREEMPT 50 - #define AA_BUG_PREEMPT_ENABLED(X) AA_BUG(preempt_count() <= 0, X) 51 - #else 52 - #define AA_BUG_PREEMPT_ENABLED(X) /* nop */ 53 - #endif 54 - 55 - #define __get_buffer(C, N) ({ \ 56 - AA_BUG_PREEMPT_ENABLED("__get_buffer without preempt disabled"); \ 57 - (C)->buf[(N)]; }) 58 - 59 - #define __get_buffers(C, X...) EVAL(__get_buffer, C, X) 60 - 61 - #define __put_buffers(X, Y...) ((void)&(X)) 62 - 63 - #define get_buffers(X...) \ 64 - do { \ 65 - struct aa_buffers *__cpu_var = get_cpu_ptr(&aa_buffers); \ 66 - __get_buffers(__cpu_var, X); \ 67 - } while (0) 68 - 69 - #define put_buffers(X, Y...) \ 70 - do { \ 71 - __put_buffers(X, Y); \ 72 - put_cpu_ptr(&aa_buffers); \ 73 - } while (0) 29 + #define IN_ATOMIC true 30 + char *aa_get_buffer(bool in_atomic); 31 + void aa_put_buffer(char *buf); 74 32 75 33 #endif /* __AA_PATH_H */
+7 -1
security/apparmor/include/policy_unpack.h
··· 41 41 AAFS_LOADDATA_REVISION, 42 42 AAFS_LOADDATA_HASH, 43 43 AAFS_LOADDATA_DATA, 44 + AAFS_LOADDATA_COMPRESSED_SIZE, 44 45 AAFS_LOADDATA_DIR, /* must be last actual entry */ 45 46 AAFS_LOADDATA_NDENTS /* count of entries */ 46 47 }; ··· 62 61 struct dentry *dents[AAFS_LOADDATA_NDENTS]; 63 62 struct aa_ns *ns; 64 63 char *name; 65 - size_t size; 64 + size_t size; /* the original size of the payload */ 65 + size_t compressed_size; /* the compressed size of the payload */ 66 66 long revision; /* the ns policy revision this caused */ 67 67 int abi; 68 68 unsigned char *hash; 69 69 70 + /* Pointer to payload. If @compressed_size > 0, then this is the 71 + * compressed version of the payload, else it is the uncompressed 72 + * version (with the size indicated by @size). 73 + */ 70 74 char *data; 71 75 }; 72 76
+7 -5
security/apparmor/label.c
··· 1458 1458 /* helper macro for snprint routines */ 1459 1459 #define update_for_len(total, len, size, str) \ 1460 1460 do { \ 1461 + size_t ulen = len; \ 1462 + \ 1461 1463 AA_BUG(len < 0); \ 1462 - total += len; \ 1463 - len = min(len, size); \ 1464 - size -= len; \ 1465 - str += len; \ 1464 + total += ulen; \ 1465 + ulen = min(ulen, size); \ 1466 + size -= ulen; \ 1467 + str += ulen; \ 1466 1468 } while (0) 1467 1469 1468 1470 /** ··· 1599 1597 struct aa_ns *prev_ns = NULL; 1600 1598 struct label_it i; 1601 1599 int count = 0, total = 0; 1602 - size_t len; 1600 + ssize_t len; 1603 1601 1604 1602 AA_BUG(!str && size != 0); 1605 1603 AA_BUG(!label);
+159 -35
security/apparmor/lsm.c
··· 21 21 #include <linux/user_namespace.h> 22 22 #include <linux/netfilter_ipv4.h> 23 23 #include <linux/netfilter_ipv6.h> 24 + #include <linux/zlib.h> 24 25 #include <net/sock.h> 25 26 #include <uapi/linux/mount.h> 26 27 ··· 44 43 /* Flag indicating whether initialization completed */ 45 44 int apparmor_initialized; 46 45 47 - DEFINE_PER_CPU(struct aa_buffers, aa_buffers); 46 + union aa_buffer { 47 + struct list_head list; 48 + char buffer[1]; 49 + }; 48 50 51 + #define RESERVE_COUNT 2 52 + static int reserve_count = RESERVE_COUNT; 53 + static int buffer_count; 54 + 55 + static LIST_HEAD(aa_global_buffers); 56 + static DEFINE_SPINLOCK(aa_buffers_lock); 49 57 50 58 /* 51 59 * LSM hook functions ··· 452 442 aa_put_label(rcu_access_pointer(ctx->label)); 453 443 } 454 444 455 - static int common_file_perm(const char *op, struct file *file, u32 mask) 445 + static int common_file_perm(const char *op, struct file *file, u32 mask, 446 + bool in_atomic) 456 447 { 457 448 struct aa_label *label; 458 449 int error = 0; ··· 463 452 return -EACCES; 464 453 465 454 label = __begin_current_label_crit_section(); 466 - error = aa_file_perm(op, label, file, mask); 455 + error = aa_file_perm(op, label, file, mask, in_atomic); 467 456 __end_current_label_crit_section(label); 468 457 469 458 return error; ··· 471 460 472 461 static int apparmor_file_receive(struct file *file) 473 462 { 474 - return common_file_perm(OP_FRECEIVE, file, aa_map_file_to_perms(file)); 463 + return common_file_perm(OP_FRECEIVE, file, aa_map_file_to_perms(file), 464 + false); 475 465 } 476 466 477 467 static int apparmor_file_permission(struct file *file, int mask) 478 468 { 479 - return common_file_perm(OP_FPERM, file, mask); 469 + return common_file_perm(OP_FPERM, file, mask, false); 480 470 } 481 471 482 472 static int apparmor_file_lock(struct file *file, unsigned int cmd) ··· 487 475 if (cmd == F_WRLCK) 488 476 mask |= MAY_WRITE; 489 477 490 - return common_file_perm(OP_FLOCK, file, mask); 478 + return common_file_perm(OP_FLOCK, file, mask, false); 491 479 } 492 480 493 481 static int common_mmap(const char *op, struct file *file, unsigned long prot, 494 - unsigned long flags) 482 + unsigned long flags, bool in_atomic) 495 483 { 496 484 int mask = 0; 497 485 ··· 509 497 if (prot & PROT_EXEC) 510 498 mask |= AA_EXEC_MMAP; 511 499 512 - return common_file_perm(op, file, mask); 500 + return common_file_perm(op, file, mask, in_atomic); 513 501 } 514 502 515 503 static int apparmor_mmap_file(struct file *file, unsigned long reqprot, 516 504 unsigned long prot, unsigned long flags) 517 505 { 518 - return common_mmap(OP_FMMAP, file, prot, flags); 506 + return common_mmap(OP_FMMAP, file, prot, flags, GFP_ATOMIC); 519 507 } 520 508 521 509 static int apparmor_file_mprotect(struct vm_area_struct *vma, 522 510 unsigned long reqprot, unsigned long prot) 523 511 { 524 512 return common_mmap(OP_FMPROT, vma->vm_file, prot, 525 - !(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0); 513 + !(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0, 514 + false); 526 515 } 527 516 528 517 static int apparmor_sb_mount(const char *dev_name, const struct path *path, ··· 1275 1262 .get = param_get_aauint 1276 1263 }; 1277 1264 1265 + static int param_set_aacompressionlevel(const char *val, 1266 + const struct kernel_param *kp); 1267 + static int param_get_aacompressionlevel(char *buffer, 1268 + const struct kernel_param *kp); 1269 + #define param_check_aacompressionlevel param_check_int 1270 + static const struct kernel_param_ops param_ops_aacompressionlevel = { 1271 + .set = param_set_aacompressionlevel, 1272 + .get = param_get_aacompressionlevel 1273 + }; 1274 + 1278 1275 static int param_set_aalockpolicy(const char *val, const struct kernel_param *kp); 1279 1276 static int param_get_aalockpolicy(char *buffer, const struct kernel_param *kp); 1280 1277 #define param_check_aalockpolicy param_check_bool ··· 1314 1291 #ifdef CONFIG_SECURITY_APPARMOR_HASH 1315 1292 module_param_named(hash_policy, aa_g_hash_policy, aabool, S_IRUSR | S_IWUSR); 1316 1293 #endif 1294 + 1295 + /* policy loaddata compression level */ 1296 + int aa_g_rawdata_compression_level = Z_DEFAULT_COMPRESSION; 1297 + module_param_named(rawdata_compression_level, aa_g_rawdata_compression_level, 1298 + aacompressionlevel, 0400); 1317 1299 1318 1300 /* Debug mode */ 1319 1301 bool aa_g_debug = IS_ENABLED(CONFIG_SECURITY_APPARMOR_DEBUG_MESSAGES); ··· 1430 1402 return -EPERM; 1431 1403 1432 1404 error = param_set_uint(val, kp); 1405 + aa_g_path_max = max_t(uint32_t, aa_g_path_max, sizeof(union aa_buffer)); 1433 1406 pr_info("AppArmor: buffer size set to %d bytes\n", aa_g_path_max); 1434 1407 1435 1408 return error; ··· 1483 1454 kp_local.arg = &value; 1484 1455 1485 1456 return param_get_bool(buffer, &kp_local); 1457 + } 1458 + 1459 + static int param_set_aacompressionlevel(const char *val, 1460 + const struct kernel_param *kp) 1461 + { 1462 + int error; 1463 + 1464 + if (!apparmor_enabled) 1465 + return -EINVAL; 1466 + if (apparmor_initialized) 1467 + return -EPERM; 1468 + 1469 + error = param_set_int(val, kp); 1470 + 1471 + aa_g_rawdata_compression_level = clamp(aa_g_rawdata_compression_level, 1472 + Z_NO_COMPRESSION, 1473 + Z_BEST_COMPRESSION); 1474 + pr_info("AppArmor: policy rawdata compression level set to %u\n", 1475 + aa_g_rawdata_compression_level); 1476 + 1477 + return error; 1478 + } 1479 + 1480 + static int param_get_aacompressionlevel(char *buffer, 1481 + const struct kernel_param *kp) 1482 + { 1483 + if (!apparmor_enabled) 1484 + return -EINVAL; 1485 + if (apparmor_initialized && !policy_view_capable(NULL)) 1486 + return -EPERM; 1487 + return param_get_int(buffer, kp); 1486 1488 } 1487 1489 1488 1490 static int param_get_audit(char *buffer, const struct kernel_param *kp) ··· 1574 1514 return 0; 1575 1515 } 1576 1516 1517 + char *aa_get_buffer(bool in_atomic) 1518 + { 1519 + union aa_buffer *aa_buf; 1520 + bool try_again = true; 1521 + gfp_t flags = (GFP_KERNEL | __GFP_RETRY_MAYFAIL | __GFP_NOWARN); 1522 + 1523 + retry: 1524 + spin_lock(&aa_buffers_lock); 1525 + if (buffer_count > reserve_count || 1526 + (in_atomic && !list_empty(&aa_global_buffers))) { 1527 + aa_buf = list_first_entry(&aa_global_buffers, union aa_buffer, 1528 + list); 1529 + list_del(&aa_buf->list); 1530 + buffer_count--; 1531 + spin_unlock(&aa_buffers_lock); 1532 + return &aa_buf->buffer[0]; 1533 + } 1534 + if (in_atomic) { 1535 + /* 1536 + * out of reserve buffers and in atomic context so increase 1537 + * how many buffers to keep in reserve 1538 + */ 1539 + reserve_count++; 1540 + flags = GFP_ATOMIC; 1541 + } 1542 + spin_unlock(&aa_buffers_lock); 1543 + 1544 + if (!in_atomic) 1545 + might_sleep(); 1546 + aa_buf = kmalloc(aa_g_path_max, flags); 1547 + if (!aa_buf) { 1548 + if (try_again) { 1549 + try_again = false; 1550 + goto retry; 1551 + } 1552 + pr_warn_once("AppArmor: Failed to allocate a memory buffer.\n"); 1553 + return NULL; 1554 + } 1555 + return &aa_buf->buffer[0]; 1556 + } 1557 + 1558 + void aa_put_buffer(char *buf) 1559 + { 1560 + union aa_buffer *aa_buf; 1561 + 1562 + if (!buf) 1563 + return; 1564 + aa_buf = container_of(buf, union aa_buffer, buffer[0]); 1565 + 1566 + spin_lock(&aa_buffers_lock); 1567 + list_add(&aa_buf->list, &aa_global_buffers); 1568 + buffer_count++; 1569 + spin_unlock(&aa_buffers_lock); 1570 + } 1571 + 1577 1572 /* 1578 1573 * AppArmor init functions 1579 1574 */ ··· 1640 1525 */ 1641 1526 static int __init set_init_ctx(void) 1642 1527 { 1643 - struct cred *cred = (struct cred *)current->real_cred; 1528 + struct cred *cred = (__force struct cred *)current->real_cred; 1644 1529 1645 1530 set_cred_label(cred, aa_get_label(ns_unconfined(root_ns))); 1646 1531 ··· 1649 1534 1650 1535 static void destroy_buffers(void) 1651 1536 { 1652 - u32 i, j; 1537 + union aa_buffer *aa_buf; 1653 1538 1654 - for_each_possible_cpu(i) { 1655 - for_each_cpu_buffer(j) { 1656 - kfree(per_cpu(aa_buffers, i).buf[j]); 1657 - per_cpu(aa_buffers, i).buf[j] = NULL; 1658 - } 1539 + spin_lock(&aa_buffers_lock); 1540 + while (!list_empty(&aa_global_buffers)) { 1541 + aa_buf = list_first_entry(&aa_global_buffers, union aa_buffer, 1542 + list); 1543 + list_del(&aa_buf->list); 1544 + spin_unlock(&aa_buffers_lock); 1545 + kfree(aa_buf); 1546 + spin_lock(&aa_buffers_lock); 1659 1547 } 1548 + spin_unlock(&aa_buffers_lock); 1660 1549 } 1661 1550 1662 1551 static int __init alloc_buffers(void) 1663 1552 { 1664 - u32 i, j; 1553 + union aa_buffer *aa_buf; 1554 + int i, num; 1665 1555 1666 - for_each_possible_cpu(i) { 1667 - for_each_cpu_buffer(j) { 1668 - char *buffer; 1556 + /* 1557 + * A function may require two buffers at once. Usually the buffers are 1558 + * used for a short period of time and are shared. On UP kernel buffers 1559 + * two should be enough, with more CPUs it is possible that more 1560 + * buffers will be used simultaneously. The preallocated pool may grow. 1561 + * This preallocation has also the side-effect that AppArmor will be 1562 + * disabled early at boot if aa_g_path_max is extremly high. 1563 + */ 1564 + if (num_online_cpus() > 1) 1565 + num = 4 + RESERVE_COUNT; 1566 + else 1567 + num = 2 + RESERVE_COUNT; 1669 1568 1670 - if (cpu_to_node(i) > num_online_nodes()) 1671 - /* fallback to kmalloc for offline nodes */ 1672 - buffer = kmalloc(aa_g_path_max, GFP_KERNEL); 1673 - else 1674 - buffer = kmalloc_node(aa_g_path_max, GFP_KERNEL, 1675 - cpu_to_node(i)); 1676 - if (!buffer) { 1677 - destroy_buffers(); 1678 - return -ENOMEM; 1679 - } 1680 - per_cpu(aa_buffers, i).buf[j] = buffer; 1569 + for (i = 0; i < num; i++) { 1570 + 1571 + aa_buf = kmalloc(aa_g_path_max, GFP_KERNEL | 1572 + __GFP_RETRY_MAYFAIL | __GFP_NOWARN); 1573 + if (!aa_buf) { 1574 + destroy_buffers(); 1575 + return -ENOMEM; 1681 1576 } 1577 + aa_put_buffer(&aa_buf->buffer[0]); 1682 1578 } 1683 - 1684 1579 return 0; 1685 1580 } 1686 1581 ··· 1855 1730 error = alloc_buffers(); 1856 1731 if (error) { 1857 1732 AA_ERROR("Unable to allocate work buffers\n"); 1858 - goto buffers_out; 1733 + goto alloc_out; 1859 1734 } 1860 1735 1861 1736 error = set_init_ctx(); ··· 1880 1755 1881 1756 buffers_out: 1882 1757 destroy_buffers(); 1883 - 1884 1758 alloc_out: 1885 1759 aa_destroy_aafs(); 1886 1760 aa_teardown_dfa_engine();
+3 -3
security/apparmor/match.c
··· 616 616 617 617 #define inc_wb_pos(wb) \ 618 618 do { \ 619 - wb->pos = (wb->pos + 1) & (wb->size - 1); \ 620 - wb->len = (wb->len + 1) & (wb->size - 1); \ 619 + wb->pos = (wb->pos + 1) & (WB_HISTORY_SIZE - 1); \ 620 + wb->len = (wb->len + 1) & (WB_HISTORY_SIZE - 1); \ 621 621 } while (0) 622 622 623 623 /* For DFAs that don't support extended tagging of states */ ··· 636 636 return true; 637 637 } 638 638 if (pos == 0) 639 - pos = wb->size; 639 + pos = WB_HISTORY_SIZE; 640 640 pos--; 641 641 } 642 642
+52 -15
security/apparmor/mount.c
··· 408 408 409 409 binary = path->dentry->d_sb->s_type->fs_flags & FS_BINARY_MOUNTDATA; 410 410 411 - get_buffers(buffer); 411 + buffer = aa_get_buffer(false); 412 + if (!buffer) 413 + return -ENOMEM; 412 414 error = fn_for_each_confined(label, profile, 413 415 match_mnt(profile, path, buffer, NULL, NULL, NULL, 414 416 flags, data, binary)); 415 - put_buffers(buffer); 417 + aa_put_buffer(buffer); 416 418 417 419 return error; 418 420 } ··· 439 437 if (error) 440 438 return error; 441 439 442 - get_buffers(buffer, old_buffer); 440 + buffer = aa_get_buffer(false); 441 + old_buffer = aa_get_buffer(false); 442 + error = -ENOMEM; 443 + if (!buffer || old_buffer) 444 + goto out; 445 + 443 446 error = fn_for_each_confined(label, profile, 444 447 match_mnt(profile, path, buffer, &old_path, old_buffer, 445 448 NULL, flags, NULL, false)); 446 - put_buffers(buffer, old_buffer); 449 + out: 450 + aa_put_buffer(buffer); 451 + aa_put_buffer(old_buffer); 447 452 path_put(&old_path); 448 453 449 454 return error; ··· 470 461 flags &= (MS_REC | MS_SILENT | MS_SHARED | MS_PRIVATE | MS_SLAVE | 471 462 MS_UNBINDABLE); 472 463 473 - get_buffers(buffer); 464 + buffer = aa_get_buffer(false); 465 + if (!buffer) 466 + return -ENOMEM; 474 467 error = fn_for_each_confined(label, profile, 475 468 match_mnt(profile, path, buffer, NULL, NULL, NULL, 476 469 flags, NULL, false)); 477 - put_buffers(buffer); 470 + aa_put_buffer(buffer); 478 471 479 472 return error; 480 473 } ··· 499 488 if (error) 500 489 return error; 501 490 502 - get_buffers(buffer, old_buffer); 491 + buffer = aa_get_buffer(false); 492 + old_buffer = aa_get_buffer(false); 493 + error = -ENOMEM; 494 + if (!buffer || !old_buffer) 495 + goto out; 503 496 error = fn_for_each_confined(label, profile, 504 497 match_mnt(profile, path, buffer, &old_path, old_buffer, 505 498 NULL, MS_MOVE, NULL, false)); 506 - put_buffers(buffer, old_buffer); 499 + out: 500 + aa_put_buffer(buffer); 501 + aa_put_buffer(old_buffer); 507 502 path_put(&old_path); 508 503 509 504 return error; ··· 550 533 } 551 534 } 552 535 553 - get_buffers(buffer, dev_buffer); 536 + buffer = aa_get_buffer(false); 537 + if (!buffer) { 538 + error = -ENOMEM; 539 + goto out; 540 + } 554 541 if (dev_path) { 542 + dev_buffer = aa_get_buffer(false); 543 + if (!dev_buffer) { 544 + error = -ENOMEM; 545 + goto out; 546 + } 555 547 error = fn_for_each_confined(label, profile, 556 548 match_mnt(profile, path, buffer, dev_path, dev_buffer, 557 549 type, flags, data, binary)); ··· 569 543 match_mnt_path_str(profile, path, buffer, dev_name, 570 544 type, flags, data, binary, NULL)); 571 545 } 572 - put_buffers(buffer, dev_buffer); 546 + 547 + out: 548 + aa_put_buffer(buffer); 549 + aa_put_buffer(dev_buffer); 573 550 if (dev_path) 574 551 path_put(dev_path); 575 552 ··· 620 591 AA_BUG(!label); 621 592 AA_BUG(!mnt); 622 593 623 - get_buffers(buffer); 594 + buffer = aa_get_buffer(false); 595 + if (!buffer) 596 + return -ENOMEM; 597 + 624 598 error = fn_for_each_confined(label, profile, 625 599 profile_umount(profile, &path, buffer)); 626 - put_buffers(buffer); 600 + aa_put_buffer(buffer); 627 601 628 602 return error; 629 603 } ··· 699 667 AA_BUG(!old_path); 700 668 AA_BUG(!new_path); 701 669 702 - get_buffers(old_buffer, new_buffer); 703 - target = fn_label_build(label, profile, GFP_ATOMIC, 670 + old_buffer = aa_get_buffer(false); 671 + new_buffer = aa_get_buffer(false); 672 + error = -ENOMEM; 673 + if (!old_buffer || !new_buffer) 674 + goto out; 675 + target = fn_label_build(label, profile, GFP_KERNEL, 704 676 build_pivotroot(profile, new_path, new_buffer, 705 677 old_path, old_buffer)); 706 678 if (!target) { ··· 722 686 /* already audited error */ 723 687 error = PTR_ERR(target); 724 688 out: 725 - put_buffers(old_buffer, new_buffer); 689 + aa_put_buffer(old_buffer); 690 + aa_put_buffer(new_buffer); 726 691 727 692 return error; 728 693
+3 -2
security/apparmor/policy.c
··· 582 582 { 583 583 if (profile) { 584 584 if (profile->label.flags & FLAG_IMMUTIBLE) { 585 - *info = "cannot replace immutible profile"; 585 + *info = "cannot replace immutable profile"; 586 586 return -EPERM; 587 587 } else if (noreplace) { 588 588 *info = "profile already exists"; ··· 856 856 ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label, 857 857 u32 mask, struct aa_loaddata *udata) 858 858 { 859 - const char *ns_name, *info = NULL; 859 + const char *ns_name = NULL, *info = NULL; 860 860 struct aa_ns *ns = NULL; 861 861 struct aa_load_ent *ent, *tmp; 862 862 struct aa_loaddata *rawdata_ent; ··· 1043 1043 out: 1044 1044 aa_put_ns(ns); 1045 1045 aa_put_loaddata(udata); 1046 + kfree(ns_name); 1046 1047 1047 1048 if (error) 1048 1049 return error;
+112 -4
security/apparmor/policy_unpack.c
··· 16 16 #include <asm/unaligned.h> 17 17 #include <linux/ctype.h> 18 18 #include <linux/errno.h> 19 + #include <linux/zlib.h> 19 20 20 21 #include "include/apparmor.h" 21 22 #include "include/audit.h" ··· 140 139 { 141 140 if (l->size != r->size) 142 141 return false; 142 + if (l->compressed_size != r->compressed_size) 143 + return false; 143 144 if (aa_g_hash_policy && memcmp(l->hash, r->hash, aa_hash_size()) != 0) 144 145 return false; 145 - return memcmp(l->data, r->data, r->size) == 0; 146 + return memcmp(l->data, r->data, r->compressed_size ?: r->size) == 0; 146 147 } 147 148 148 149 /* ··· 971 968 e, error); 972 969 return error; 973 970 } 974 - if (*ns && strcmp(*ns, name)) 971 + if (*ns && strcmp(*ns, name)) { 975 972 audit_iface(NULL, NULL, NULL, "invalid ns change", e, 976 973 error); 977 - else if (!*ns) 978 - *ns = name; 974 + } else if (!*ns) { 975 + *ns = kstrdup(name, GFP_KERNEL); 976 + if (!*ns) 977 + return -ENOMEM; 978 + } 979 979 } 980 980 981 981 return 0; ··· 1043 1037 if (ent) 1044 1038 INIT_LIST_HEAD(&ent->list); 1045 1039 return ent; 1040 + } 1041 + 1042 + static int deflate_compress(const char *src, size_t slen, char **dst, 1043 + size_t *dlen) 1044 + { 1045 + int error; 1046 + struct z_stream_s strm; 1047 + void *stgbuf, *dstbuf; 1048 + size_t stglen = deflateBound(slen); 1049 + 1050 + memset(&strm, 0, sizeof(strm)); 1051 + 1052 + if (stglen < slen) 1053 + return -EFBIG; 1054 + 1055 + strm.workspace = kvzalloc(zlib_deflate_workspacesize(MAX_WBITS, 1056 + MAX_MEM_LEVEL), 1057 + GFP_KERNEL); 1058 + if (!strm.workspace) 1059 + return -ENOMEM; 1060 + 1061 + error = zlib_deflateInit(&strm, aa_g_rawdata_compression_level); 1062 + if (error != Z_OK) { 1063 + error = -ENOMEM; 1064 + goto fail_deflate_init; 1065 + } 1066 + 1067 + stgbuf = kvzalloc(stglen, GFP_KERNEL); 1068 + if (!stgbuf) { 1069 + error = -ENOMEM; 1070 + goto fail_stg_alloc; 1071 + } 1072 + 1073 + strm.next_in = src; 1074 + strm.avail_in = slen; 1075 + strm.next_out = stgbuf; 1076 + strm.avail_out = stglen; 1077 + 1078 + error = zlib_deflate(&strm, Z_FINISH); 1079 + if (error != Z_STREAM_END) { 1080 + error = -EINVAL; 1081 + goto fail_deflate; 1082 + } 1083 + error = 0; 1084 + 1085 + if (is_vmalloc_addr(stgbuf)) { 1086 + dstbuf = kvzalloc(strm.total_out, GFP_KERNEL); 1087 + if (dstbuf) { 1088 + memcpy(dstbuf, stgbuf, strm.total_out); 1089 + kvfree(stgbuf); 1090 + } 1091 + } else 1092 + /* 1093 + * If the staging buffer was kmalloc'd, then using krealloc is 1094 + * probably going to be faster. The destination buffer will 1095 + * always be smaller, so it's just shrunk, avoiding a memcpy 1096 + */ 1097 + dstbuf = krealloc(stgbuf, strm.total_out, GFP_KERNEL); 1098 + 1099 + if (!dstbuf) { 1100 + error = -ENOMEM; 1101 + goto fail_deflate; 1102 + } 1103 + 1104 + *dst = dstbuf; 1105 + *dlen = strm.total_out; 1106 + 1107 + fail_stg_alloc: 1108 + zlib_deflateEnd(&strm); 1109 + fail_deflate_init: 1110 + kvfree(strm.workspace); 1111 + return error; 1112 + 1113 + fail_deflate: 1114 + kvfree(stgbuf); 1115 + goto fail_stg_alloc; 1116 + } 1117 + 1118 + static int compress_loaddata(struct aa_loaddata *data) 1119 + { 1120 + 1121 + AA_BUG(data->compressed_size > 0); 1122 + 1123 + /* 1124 + * Shortcut the no compression case, else we increase the amount of 1125 + * storage required by a small amount 1126 + */ 1127 + if (aa_g_rawdata_compression_level != 0) { 1128 + void *udata = data->data; 1129 + int error = deflate_compress(udata, data->size, &data->data, 1130 + &data->compressed_size); 1131 + if (error) 1132 + return error; 1133 + 1134 + kvfree(udata); 1135 + } else 1136 + data->compressed_size = data->size; 1137 + 1138 + return 0; 1046 1139 } 1047 1140 1048 1141 /** ··· 1212 1107 goto fail; 1213 1108 } 1214 1109 } 1110 + error = compress_loaddata(udata); 1111 + if (error) 1112 + goto fail; 1215 1113 return 0; 1216 1114 1217 1115 fail_profile: