| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * AppArmor security module |
|---|
| 3 | 4 | * |
|---|
| .. | .. |
|---|
| 7 | 8 | * Copyright (C) 1998-2008 Novell/SUSE |
|---|
| 8 | 9 | * Copyright 2009-2010 Canonical Ltd. |
|---|
| 9 | 10 | * |
|---|
| 10 | | - * This program is free software; you can redistribute it and/or |
|---|
| 11 | | - * modify it under the terms of the GNU General Public License as |
|---|
| 12 | | - * published by the Free Software Foundation, version 2 of the |
|---|
| 13 | | - * License. |
|---|
| 14 | | - * |
|---|
| 15 | 11 | * AppArmor uses a serialized binary format for loading policy. To find |
|---|
| 16 | 12 | * policy format documentation see Documentation/admin-guide/LSM/apparmor.rst |
|---|
| 17 | 13 | * All policy is validated before it is used. |
|---|
| .. | .. |
|---|
| 20 | 16 | #include <asm/unaligned.h> |
|---|
| 21 | 17 | #include <linux/ctype.h> |
|---|
| 22 | 18 | #include <linux/errno.h> |
|---|
| 19 | +#include <linux/zlib.h> |
|---|
| 23 | 20 | |
|---|
| 24 | 21 | #include "include/apparmor.h" |
|---|
| 25 | 22 | #include "include/audit.h" |
|---|
| .. | .. |
|---|
| 143 | 140 | { |
|---|
| 144 | 141 | if (l->size != r->size) |
|---|
| 145 | 142 | return false; |
|---|
| 143 | + if (l->compressed_size != r->compressed_size) |
|---|
| 144 | + return false; |
|---|
| 146 | 145 | if (aa_g_hash_policy && memcmp(l->hash, r->hash, aa_hash_size()) != 0) |
|---|
| 147 | 146 | return false; |
|---|
| 148 | | - return memcmp(l->data, r->data, r->size) == 0; |
|---|
| 147 | + return memcmp(l->data, r->data, r->compressed_size ?: r->size) == 0; |
|---|
| 149 | 148 | } |
|---|
| 150 | 149 | |
|---|
| 151 | 150 | /* |
|---|
| .. | .. |
|---|
| 164 | 163 | aa_put_ns(ns); |
|---|
| 165 | 164 | } |
|---|
| 166 | 165 | |
|---|
| 167 | | - kzfree(d->hash); |
|---|
| 168 | | - kzfree(d->name); |
|---|
| 166 | + kfree_sensitive(d->hash); |
|---|
| 167 | + kfree_sensitive(d->name); |
|---|
| 169 | 168 | kvfree(d->data); |
|---|
| 170 | | - kzfree(d); |
|---|
| 169 | + kfree_sensitive(d); |
|---|
| 171 | 170 | } |
|---|
| 172 | 171 | |
|---|
| 173 | 172 | void aa_loaddata_kref(struct kref *kref) |
|---|
| .. | .. |
|---|
| 244 | 243 | static bool unpack_X(struct aa_ext *e, enum aa_code code) |
|---|
| 245 | 244 | { |
|---|
| 246 | 245 | if (!inbounds(e, 1)) |
|---|
| 247 | | - return 0; |
|---|
| 246 | + return false; |
|---|
| 248 | 247 | if (*(u8 *) e->pos != code) |
|---|
| 249 | | - return 0; |
|---|
| 248 | + return false; |
|---|
| 250 | 249 | e->pos++; |
|---|
| 251 | | - return 1; |
|---|
| 250 | + return true; |
|---|
| 252 | 251 | } |
|---|
| 253 | 252 | |
|---|
| 254 | 253 | /** |
|---|
| .. | .. |
|---|
| 262 | 261 | * name element in the stream. If @name is NULL any name element will be |
|---|
| 263 | 262 | * skipped and only the typecode will be tested. |
|---|
| 264 | 263 | * |
|---|
| 265 | | - * Returns 1 on success (both type code and name tests match) and the read |
|---|
| 264 | + * Returns true on success (both type code and name tests match) and the read |
|---|
| 266 | 265 | * head is advanced past the headers |
|---|
| 267 | 266 | * |
|---|
| 268 | | - * Returns: 0 if either match fails, the read head does not move |
|---|
| 267 | + * Returns: false if either match fails, the read head does not move |
|---|
| 269 | 268 | */ |
|---|
| 270 | 269 | static bool unpack_nameX(struct aa_ext *e, enum aa_code code, const char *name) |
|---|
| 271 | 270 | { |
|---|
| .. | .. |
|---|
| 290 | 289 | |
|---|
| 291 | 290 | /* now check if type code matches */ |
|---|
| 292 | 291 | if (unpack_X(e, code)) |
|---|
| 293 | | - return 1; |
|---|
| 292 | + return true; |
|---|
| 294 | 293 | |
|---|
| 295 | 294 | fail: |
|---|
| 296 | 295 | e->pos = pos; |
|---|
| 297 | | - return 0; |
|---|
| 296 | + return false; |
|---|
| 297 | +} |
|---|
| 298 | + |
|---|
| 299 | +static bool unpack_u8(struct aa_ext *e, u8 *data, const char *name) |
|---|
| 300 | +{ |
|---|
| 301 | + void *pos = e->pos; |
|---|
| 302 | + |
|---|
| 303 | + if (unpack_nameX(e, AA_U8, name)) { |
|---|
| 304 | + if (!inbounds(e, sizeof(u8))) |
|---|
| 305 | + goto fail; |
|---|
| 306 | + if (data) |
|---|
| 307 | + *data = get_unaligned((u8 *)e->pos); |
|---|
| 308 | + e->pos += sizeof(u8); |
|---|
| 309 | + return true; |
|---|
| 310 | + } |
|---|
| 311 | + |
|---|
| 312 | +fail: |
|---|
| 313 | + e->pos = pos; |
|---|
| 314 | + return false; |
|---|
| 298 | 315 | } |
|---|
| 299 | 316 | |
|---|
| 300 | 317 | static bool unpack_u32(struct aa_ext *e, u32 *data, const char *name) |
|---|
| .. | .. |
|---|
| 307 | 324 | if (data) |
|---|
| 308 | 325 | *data = le32_to_cpu(get_unaligned((__le32 *) e->pos)); |
|---|
| 309 | 326 | e->pos += sizeof(u32); |
|---|
| 310 | | - return 1; |
|---|
| 327 | + return true; |
|---|
| 311 | 328 | } |
|---|
| 312 | 329 | |
|---|
| 313 | 330 | fail: |
|---|
| 314 | 331 | e->pos = pos; |
|---|
| 315 | | - return 0; |
|---|
| 332 | + return false; |
|---|
| 316 | 333 | } |
|---|
| 317 | 334 | |
|---|
| 318 | 335 | static bool unpack_u64(struct aa_ext *e, u64 *data, const char *name) |
|---|
| .. | .. |
|---|
| 325 | 342 | if (data) |
|---|
| 326 | 343 | *data = le64_to_cpu(get_unaligned((__le64 *) e->pos)); |
|---|
| 327 | 344 | e->pos += sizeof(u64); |
|---|
| 328 | | - return 1; |
|---|
| 345 | + return true; |
|---|
| 329 | 346 | } |
|---|
| 330 | 347 | |
|---|
| 331 | 348 | fail: |
|---|
| 332 | 349 | e->pos = pos; |
|---|
| 333 | | - return 0; |
|---|
| 350 | + return false; |
|---|
| 334 | 351 | } |
|---|
| 335 | 352 | |
|---|
| 336 | 353 | static size_t unpack_array(struct aa_ext *e, const char *name) |
|---|
| .. | .. |
|---|
| 455 | 472 | * @e: serialized data extent information (NOT NULL) |
|---|
| 456 | 473 | * @profile: profile to add the accept table to (NOT NULL) |
|---|
| 457 | 474 | * |
|---|
| 458 | | - * Returns: 1 if table successfully unpacked |
|---|
| 475 | + * Returns: true if table successfully unpacked |
|---|
| 459 | 476 | */ |
|---|
| 460 | 477 | static bool unpack_trans_table(struct aa_ext *e, struct aa_profile *profile) |
|---|
| 461 | 478 | { |
|---|
| .. | .. |
|---|
| 518 | 535 | if (!unpack_nameX(e, AA_STRUCTEND, NULL)) |
|---|
| 519 | 536 | goto fail; |
|---|
| 520 | 537 | } |
|---|
| 521 | | - return 1; |
|---|
| 538 | + return true; |
|---|
| 522 | 539 | |
|---|
| 523 | 540 | fail: |
|---|
| 524 | 541 | aa_free_domain_entries(&profile->file.trans); |
|---|
| 525 | 542 | e->pos = saved_pos; |
|---|
| 526 | | - return 0; |
|---|
| 543 | + return false; |
|---|
| 527 | 544 | } |
|---|
| 528 | 545 | |
|---|
| 529 | 546 | static bool unpack_xattrs(struct aa_ext *e, struct aa_profile *profile) |
|---|
| .. | .. |
|---|
| 548 | 565 | goto fail; |
|---|
| 549 | 566 | } |
|---|
| 550 | 567 | |
|---|
| 551 | | - return 1; |
|---|
| 568 | + return true; |
|---|
| 552 | 569 | |
|---|
| 553 | 570 | fail: |
|---|
| 554 | 571 | e->pos = pos; |
|---|
| 555 | | - return 0; |
|---|
| 572 | + return false; |
|---|
| 573 | +} |
|---|
| 574 | + |
|---|
| 575 | +static bool unpack_secmark(struct aa_ext *e, struct aa_profile *profile) |
|---|
| 576 | +{ |
|---|
| 577 | + void *pos = e->pos; |
|---|
| 578 | + int i, size; |
|---|
| 579 | + |
|---|
| 580 | + if (unpack_nameX(e, AA_STRUCT, "secmark")) { |
|---|
| 581 | + size = unpack_array(e, NULL); |
|---|
| 582 | + |
|---|
| 583 | + profile->secmark = kcalloc(size, sizeof(struct aa_secmark), |
|---|
| 584 | + GFP_KERNEL); |
|---|
| 585 | + if (!profile->secmark) |
|---|
| 586 | + goto fail; |
|---|
| 587 | + |
|---|
| 588 | + profile->secmark_count = size; |
|---|
| 589 | + |
|---|
| 590 | + for (i = 0; i < size; i++) { |
|---|
| 591 | + if (!unpack_u8(e, &profile->secmark[i].audit, NULL)) |
|---|
| 592 | + goto fail; |
|---|
| 593 | + if (!unpack_u8(e, &profile->secmark[i].deny, NULL)) |
|---|
| 594 | + goto fail; |
|---|
| 595 | + if (!unpack_strdup(e, &profile->secmark[i].label, NULL)) |
|---|
| 596 | + goto fail; |
|---|
| 597 | + } |
|---|
| 598 | + if (!unpack_nameX(e, AA_ARRAYEND, NULL)) |
|---|
| 599 | + goto fail; |
|---|
| 600 | + if (!unpack_nameX(e, AA_STRUCTEND, NULL)) |
|---|
| 601 | + goto fail; |
|---|
| 602 | + } |
|---|
| 603 | + |
|---|
| 604 | + return true; |
|---|
| 605 | + |
|---|
| 606 | +fail: |
|---|
| 607 | + if (profile->secmark) { |
|---|
| 608 | + for (i = 0; i < size; i++) |
|---|
| 609 | + kfree(profile->secmark[i].label); |
|---|
| 610 | + kfree(profile->secmark); |
|---|
| 611 | + profile->secmark_count = 0; |
|---|
| 612 | + profile->secmark = NULL; |
|---|
| 613 | + } |
|---|
| 614 | + |
|---|
| 615 | + e->pos = pos; |
|---|
| 616 | + return false; |
|---|
| 556 | 617 | } |
|---|
| 557 | 618 | |
|---|
| 558 | 619 | static bool unpack_rlimits(struct aa_ext *e, struct aa_profile *profile) |
|---|
| .. | .. |
|---|
| 582 | 643 | if (!unpack_nameX(e, AA_STRUCTEND, NULL)) |
|---|
| 583 | 644 | goto fail; |
|---|
| 584 | 645 | } |
|---|
| 585 | | - return 1; |
|---|
| 646 | + return true; |
|---|
| 586 | 647 | |
|---|
| 587 | 648 | fail: |
|---|
| 588 | 649 | e->pos = pos; |
|---|
| 589 | | - return 0; |
|---|
| 650 | + return false; |
|---|
| 590 | 651 | } |
|---|
| 591 | 652 | |
|---|
| 592 | 653 | static u32 strhash(const void *data, u32 len, u32 seed) |
|---|
| .. | .. |
|---|
| 685 | 746 | profile->label.flags |= FLAG_HAT; |
|---|
| 686 | 747 | if (!unpack_u32(e, &tmp, NULL)) |
|---|
| 687 | 748 | goto fail; |
|---|
| 688 | | - if (tmp == PACKED_MODE_COMPLAIN || (e->version & FORCE_COMPLAIN_FLAG)) |
|---|
| 749 | + if (tmp == PACKED_MODE_COMPLAIN || (e->version & FORCE_COMPLAIN_FLAG)) { |
|---|
| 689 | 750 | profile->mode = APPARMOR_COMPLAIN; |
|---|
| 690 | | - else if (tmp == PACKED_MODE_KILL) |
|---|
| 751 | + } else if (tmp == PACKED_MODE_ENFORCE) { |
|---|
| 752 | + profile->mode = APPARMOR_ENFORCE; |
|---|
| 753 | + } else if (tmp == PACKED_MODE_KILL) { |
|---|
| 691 | 754 | profile->mode = APPARMOR_KILL; |
|---|
| 692 | | - else if (tmp == PACKED_MODE_UNCONFINED) |
|---|
| 755 | + } else if (tmp == PACKED_MODE_UNCONFINED) { |
|---|
| 693 | 756 | profile->mode = APPARMOR_UNCONFINED; |
|---|
| 757 | + profile->label.flags |= FLAG_UNCONFINED; |
|---|
| 758 | + } else { |
|---|
| 759 | + goto fail; |
|---|
| 760 | + } |
|---|
| 694 | 761 | if (!unpack_u32(e, &tmp, NULL)) |
|---|
| 695 | 762 | goto fail; |
|---|
| 696 | 763 | if (tmp) |
|---|
| .. | .. |
|---|
| 750 | 817 | |
|---|
| 751 | 818 | if (!unpack_rlimits(e, profile)) { |
|---|
| 752 | 819 | info = "failed to unpack profile rlimits"; |
|---|
| 820 | + goto fail; |
|---|
| 821 | + } |
|---|
| 822 | + |
|---|
| 823 | + if (!unpack_secmark(e, profile)) { |
|---|
| 824 | + info = "failed to unpack profile secmark rules"; |
|---|
| 753 | 825 | goto fail; |
|---|
| 754 | 826 | } |
|---|
| 755 | 827 | |
|---|
| .. | .. |
|---|
| 824 | 896 | while (unpack_strdup(e, &key, NULL)) { |
|---|
| 825 | 897 | data = kzalloc(sizeof(*data), GFP_KERNEL); |
|---|
| 826 | 898 | if (!data) { |
|---|
| 827 | | - kzfree(key); |
|---|
| 899 | + kfree_sensitive(key); |
|---|
| 828 | 900 | goto fail; |
|---|
| 829 | 901 | } |
|---|
| 830 | 902 | |
|---|
| .. | .. |
|---|
| 832 | 904 | data->size = unpack_blob(e, &data->data, NULL); |
|---|
| 833 | 905 | data->data = kvmemdup(data->data, data->size); |
|---|
| 834 | 906 | if (data->size && !data->data) { |
|---|
| 835 | | - kzfree(data->key); |
|---|
| 836 | | - kzfree(data); |
|---|
| 907 | + kfree_sensitive(data->key); |
|---|
| 908 | + kfree_sensitive(data); |
|---|
| 837 | 909 | goto fail; |
|---|
| 838 | 910 | } |
|---|
| 839 | 911 | |
|---|
| 840 | | - rhashtable_insert_fast(profile->data, &data->head, |
|---|
| 841 | | - profile->data->p); |
|---|
| 912 | + if (rhashtable_insert_fast(profile->data, &data->head, |
|---|
| 913 | + profile->data->p)) { |
|---|
| 914 | + kfree_sensitive(data->key); |
|---|
| 915 | + kfree_sensitive(data); |
|---|
| 916 | + info = "failed to insert data to table"; |
|---|
| 917 | + goto fail; |
|---|
| 918 | + } |
|---|
| 842 | 919 | } |
|---|
| 843 | 920 | |
|---|
| 844 | 921 | if (!unpack_nameX(e, AA_STRUCTEND, NULL)) { |
|---|
| .. | .. |
|---|
| 892 | 969 | * if not specified use previous version |
|---|
| 893 | 970 | * Mask off everything that is not kernel abi version |
|---|
| 894 | 971 | */ |
|---|
| 895 | | - if (VERSION_LT(e->version, v5) || VERSION_GT(e->version, v7)) { |
|---|
| 972 | + if (VERSION_LT(e->version, v5) || VERSION_GT(e->version, v8)) { |
|---|
| 896 | 973 | audit_iface(NULL, NULL, NULL, "unsupported interface version", |
|---|
| 897 | 974 | e, error); |
|---|
| 898 | 975 | return error; |
|---|
| .. | .. |
|---|
| 905 | 982 | e, error); |
|---|
| 906 | 983 | return error; |
|---|
| 907 | 984 | } |
|---|
| 908 | | - if (*ns && strcmp(*ns, name)) |
|---|
| 985 | + if (*ns && strcmp(*ns, name)) { |
|---|
| 909 | 986 | audit_iface(NULL, NULL, NULL, "invalid ns change", e, |
|---|
| 910 | 987 | error); |
|---|
| 911 | | - else if (!*ns) |
|---|
| 912 | | - *ns = name; |
|---|
| 988 | + } else if (!*ns) { |
|---|
| 989 | + *ns = kstrdup(name, GFP_KERNEL); |
|---|
| 990 | + if (!*ns) |
|---|
| 991 | + return -ENOMEM; |
|---|
| 992 | + } |
|---|
| 913 | 993 | } |
|---|
| 914 | 994 | |
|---|
| 915 | 995 | return 0; |
|---|
| .. | .. |
|---|
| 921 | 1001 | xtype = xindex & AA_X_TYPE_MASK; |
|---|
| 922 | 1002 | index = xindex & AA_X_INDEX_MASK; |
|---|
| 923 | 1003 | if (xtype == AA_X_TABLE && index >= table_size) |
|---|
| 924 | | - return 0; |
|---|
| 925 | | - return 1; |
|---|
| 1004 | + return false; |
|---|
| 1005 | + return true; |
|---|
| 926 | 1006 | } |
|---|
| 927 | 1007 | |
|---|
| 928 | 1008 | /* verify dfa xindexes are in range of transition tables */ |
|---|
| .. | .. |
|---|
| 931 | 1011 | int i; |
|---|
| 932 | 1012 | for (i = 0; i < dfa->tables[YYTD_ID_ACCEPT]->td_lolen; i++) { |
|---|
| 933 | 1013 | if (!verify_xindex(dfa_user_xindex(dfa, i), table_size)) |
|---|
| 934 | | - return 0; |
|---|
| 1014 | + return false; |
|---|
| 935 | 1015 | if (!verify_xindex(dfa_other_xindex(dfa, i), table_size)) |
|---|
| 936 | | - return 0; |
|---|
| 1016 | + return false; |
|---|
| 937 | 1017 | } |
|---|
| 938 | | - return 1; |
|---|
| 1018 | + return true; |
|---|
| 939 | 1019 | } |
|---|
| 940 | 1020 | |
|---|
| 941 | 1021 | /** |
|---|
| .. | .. |
|---|
| 964 | 1044 | aa_put_profile(ent->old); |
|---|
| 965 | 1045 | aa_put_profile(ent->new); |
|---|
| 966 | 1046 | kfree(ent->ns_name); |
|---|
| 967 | | - kzfree(ent); |
|---|
| 1047 | + kfree_sensitive(ent); |
|---|
| 968 | 1048 | } |
|---|
| 969 | 1049 | } |
|---|
| 970 | 1050 | |
|---|
| .. | .. |
|---|
| 974 | 1054 | if (ent) |
|---|
| 975 | 1055 | INIT_LIST_HEAD(&ent->list); |
|---|
| 976 | 1056 | return ent; |
|---|
| 1057 | +} |
|---|
| 1058 | + |
|---|
| 1059 | +static int deflate_compress(const char *src, size_t slen, char **dst, |
|---|
| 1060 | + size_t *dlen) |
|---|
| 1061 | +{ |
|---|
| 1062 | + int error; |
|---|
| 1063 | + struct z_stream_s strm; |
|---|
| 1064 | + void *stgbuf, *dstbuf; |
|---|
| 1065 | + size_t stglen = deflateBound(slen); |
|---|
| 1066 | + |
|---|
| 1067 | + memset(&strm, 0, sizeof(strm)); |
|---|
| 1068 | + |
|---|
| 1069 | + if (stglen < slen) |
|---|
| 1070 | + return -EFBIG; |
|---|
| 1071 | + |
|---|
| 1072 | + strm.workspace = kvzalloc(zlib_deflate_workspacesize(MAX_WBITS, |
|---|
| 1073 | + MAX_MEM_LEVEL), |
|---|
| 1074 | + GFP_KERNEL); |
|---|
| 1075 | + if (!strm.workspace) |
|---|
| 1076 | + return -ENOMEM; |
|---|
| 1077 | + |
|---|
| 1078 | + error = zlib_deflateInit(&strm, aa_g_rawdata_compression_level); |
|---|
| 1079 | + if (error != Z_OK) { |
|---|
| 1080 | + error = -ENOMEM; |
|---|
| 1081 | + goto fail_deflate_init; |
|---|
| 1082 | + } |
|---|
| 1083 | + |
|---|
| 1084 | + stgbuf = kvzalloc(stglen, GFP_KERNEL); |
|---|
| 1085 | + if (!stgbuf) { |
|---|
| 1086 | + error = -ENOMEM; |
|---|
| 1087 | + goto fail_stg_alloc; |
|---|
| 1088 | + } |
|---|
| 1089 | + |
|---|
| 1090 | + strm.next_in = src; |
|---|
| 1091 | + strm.avail_in = slen; |
|---|
| 1092 | + strm.next_out = stgbuf; |
|---|
| 1093 | + strm.avail_out = stglen; |
|---|
| 1094 | + |
|---|
| 1095 | + error = zlib_deflate(&strm, Z_FINISH); |
|---|
| 1096 | + if (error != Z_STREAM_END) { |
|---|
| 1097 | + error = -EINVAL; |
|---|
| 1098 | + goto fail_deflate; |
|---|
| 1099 | + } |
|---|
| 1100 | + error = 0; |
|---|
| 1101 | + |
|---|
| 1102 | + if (is_vmalloc_addr(stgbuf)) { |
|---|
| 1103 | + dstbuf = kvzalloc(strm.total_out, GFP_KERNEL); |
|---|
| 1104 | + if (dstbuf) { |
|---|
| 1105 | + memcpy(dstbuf, stgbuf, strm.total_out); |
|---|
| 1106 | + kvfree(stgbuf); |
|---|
| 1107 | + } |
|---|
| 1108 | + } else |
|---|
| 1109 | + /* |
|---|
| 1110 | + * If the staging buffer was kmalloc'd, then using krealloc is |
|---|
| 1111 | + * probably going to be faster. The destination buffer will |
|---|
| 1112 | + * always be smaller, so it's just shrunk, avoiding a memcpy |
|---|
| 1113 | + */ |
|---|
| 1114 | + dstbuf = krealloc(stgbuf, strm.total_out, GFP_KERNEL); |
|---|
| 1115 | + |
|---|
| 1116 | + if (!dstbuf) { |
|---|
| 1117 | + error = -ENOMEM; |
|---|
| 1118 | + goto fail_deflate; |
|---|
| 1119 | + } |
|---|
| 1120 | + |
|---|
| 1121 | + *dst = dstbuf; |
|---|
| 1122 | + *dlen = strm.total_out; |
|---|
| 1123 | + |
|---|
| 1124 | +fail_stg_alloc: |
|---|
| 1125 | + zlib_deflateEnd(&strm); |
|---|
| 1126 | +fail_deflate_init: |
|---|
| 1127 | + kvfree(strm.workspace); |
|---|
| 1128 | + return error; |
|---|
| 1129 | + |
|---|
| 1130 | +fail_deflate: |
|---|
| 1131 | + kvfree(stgbuf); |
|---|
| 1132 | + goto fail_stg_alloc; |
|---|
| 1133 | +} |
|---|
| 1134 | + |
|---|
| 1135 | +static int compress_loaddata(struct aa_loaddata *data) |
|---|
| 1136 | +{ |
|---|
| 1137 | + |
|---|
| 1138 | + AA_BUG(data->compressed_size > 0); |
|---|
| 1139 | + |
|---|
| 1140 | + /* |
|---|
| 1141 | + * Shortcut the no compression case, else we increase the amount of |
|---|
| 1142 | + * storage required by a small amount |
|---|
| 1143 | + */ |
|---|
| 1144 | + if (aa_g_rawdata_compression_level != 0) { |
|---|
| 1145 | + void *udata = data->data; |
|---|
| 1146 | + int error = deflate_compress(udata, data->size, &data->data, |
|---|
| 1147 | + &data->compressed_size); |
|---|
| 1148 | + if (error) |
|---|
| 1149 | + return error; |
|---|
| 1150 | + |
|---|
| 1151 | + kvfree(udata); |
|---|
| 1152 | + } else |
|---|
| 1153 | + data->compressed_size = data->size; |
|---|
| 1154 | + |
|---|
| 1155 | + return 0; |
|---|
| 977 | 1156 | } |
|---|
| 978 | 1157 | |
|---|
| 979 | 1158 | /** |
|---|
| .. | .. |
|---|
| 1044 | 1223 | goto fail; |
|---|
| 1045 | 1224 | } |
|---|
| 1046 | 1225 | } |
|---|
| 1226 | + error = compress_loaddata(udata); |
|---|
| 1227 | + if (error) |
|---|
| 1228 | + goto fail; |
|---|
| 1047 | 1229 | return 0; |
|---|
| 1048 | 1230 | |
|---|
| 1049 | 1231 | fail_profile: |
|---|
| .. | .. |
|---|
| 1057 | 1239 | |
|---|
| 1058 | 1240 | return error; |
|---|
| 1059 | 1241 | } |
|---|
| 1242 | + |
|---|
| 1243 | +#ifdef CONFIG_SECURITY_APPARMOR_KUNIT_TEST |
|---|
| 1244 | +#include "policy_unpack_test.c" |
|---|
| 1245 | +#endif /* CONFIG_SECURITY_APPARMOR_KUNIT_TEST */ |
|---|