Skip to content

Commit 93761c9

Browse files
committed
Merge tag 'apparmor-pr-2022-12-14' of git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor
Pull apparmor updates from John Johansen: "Features: - switch to zstd compression for profile raw data Cleanups: - simplify obtaining the newest label on a cred - remove useless static inline functions - compute permission conversion on policy unpack - refactor code to share common permissins - refactor unpack to group policy backwards compatiblity code - add __init annotation to aa_{setup/teardown}_dfa_engine() Bug Fixes: - fix a memleak in - multi_transaction_new() - free_ruleset() - unpack_profile() - alloc_ns() - fix lockdep warning when removing a namespace - fix regression in stacking due to label flags - fix loading of child before parent - fix kernel-doc comments that differ from fns - fix spelling errors in comments - store return value of unpack_perms_table() to signed variable" * tag 'apparmor-pr-2022-12-14' of git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor: (64 commits) apparmor: Fix uninitialized symbol 'array_size' in policy_unpack_test.c apparmor: Add __init annotation to aa_{setup/teardown}_dfa_engine() apparmor: Fix memleak in alloc_ns() apparmor: Fix memleak issue in unpack_profile() apparmor: fix a memleak in free_ruleset() apparmor: Fix spelling of function name in comment block apparmor: Use pointer to struct aa_label for lbs_cred AppArmor: Fix kernel-doc LSM: Fix kernel-doc AppArmor: Fix kernel-doc apparmor: Fix loading of child before parent apparmor: refactor code that alloc null profiles apparmor: fix obsoleted comments for aa_getprocattr() and audit_resource() apparmor: remove useless static inline functions apparmor: Fix unpack_profile() warn: passing zero to 'ERR_PTR' apparmor: fix uninitialize table variable in error in unpack_trans_table apparmor: store return value of unpack_perms_table() to signed variable apparmor: Fix kunit test for out of bounds array apparmor: Fix decompression of rawdata for read back to userspace apparmor: Fix undefined references to zstd_ symbols ...
2 parents 64e7003 + 4295c60 commit 93761c9

35 files changed

+1632
-914
lines changed

security/apparmor/Kconfig

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,8 @@ config SECURITY_APPARMOR_HASH_DEFAULT
8585
config SECURITY_APPARMOR_EXPORT_BINARY
8686
bool "Allow exporting the raw binary policy"
8787
depends on SECURITY_APPARMOR_INTROSPECT_POLICY
88-
select ZLIB_INFLATE
89-
select ZLIB_DEFLATE
88+
select ZSTD_COMPRESS
89+
select ZSTD_DECOMPRESS
9090
default y
9191
help
9292
This option allows reading back binary policy as it was loaded.

security/apparmor/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ obj-$(CONFIG_SECURITY_APPARMOR) += apparmor.o
55

66
apparmor-y := apparmorfs.o audit.o capability.o task.o ipc.o lib.o match.o \
77
path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \
8-
resource.o secid.o file.o policy_ns.o label.o mount.o net.o
8+
resource.o secid.o file.o policy_ns.o label.o mount.o net.o \
9+
policy_compat.o
910
apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o
1011

1112
obj-$(CONFIG_SECURITY_APPARMOR_KUNIT_TEST) += apparmor_policy_unpack_test.o

security/apparmor/apparmorfs.c

Lines changed: 63 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
#include <linux/fs.h>
2222
#include <linux/fs_context.h>
2323
#include <linux/poll.h>
24-
#include <linux/zlib.h>
24+
#include <linux/zstd.h>
2525
#include <uapi/linux/major.h>
2626
#include <uapi/linux/magic.h>
2727

@@ -611,29 +611,30 @@ static const struct file_operations aa_fs_ns_revision_fops = {
611611
static void profile_query_cb(struct aa_profile *profile, struct aa_perms *perms,
612612
const char *match_str, size_t match_len)
613613
{
614+
struct aa_ruleset *rules = list_first_entry(&profile->rules,
615+
typeof(*rules), list);
614616
struct aa_perms tmp = { };
615-
struct aa_dfa *dfa;
616-
unsigned int state = 0;
617+
aa_state_t state = DFA_NOMATCH;
617618

618619
if (profile_unconfined(profile))
619620
return;
620-
if (profile->file.dfa && *match_str == AA_CLASS_FILE) {
621-
dfa = profile->file.dfa;
622-
state = aa_dfa_match_len(dfa, profile->file.start,
621+
if (rules->file.dfa && *match_str == AA_CLASS_FILE) {
622+
state = aa_dfa_match_len(rules->file.dfa,
623+
rules->file.start[AA_CLASS_FILE],
623624
match_str + 1, match_len - 1);
624625
if (state) {
625626
struct path_cond cond = { };
626627

627-
tmp = aa_compute_fperms(dfa, state, &cond);
628+
tmp = *(aa_lookup_fperms(&(rules->file), state, &cond));
628629
}
629-
} else if (profile->policy.dfa) {
630-
if (!PROFILE_MEDIATES(profile, *match_str))
630+
} else if (rules->policy.dfa) {
631+
if (!RULE_MEDIATES(rules, *match_str))
631632
return; /* no change to current perms */
632-
dfa = profile->policy.dfa;
633-
state = aa_dfa_match_len(dfa, profile->policy.start[0],
633+
state = aa_dfa_match_len(rules->policy.dfa,
634+
rules->policy.start[0],
634635
match_str, match_len);
635636
if (state)
636-
aa_compute_perms(dfa, state, &tmp);
637+
tmp = *aa_lookup_perms(&rules->policy, state);
637638
}
638639
aa_apply_modes_to_perms(profile, &tmp);
639640
aa_perms_accum_raw(perms, &tmp);
@@ -868,8 +869,10 @@ static struct multi_transaction *multi_transaction_new(struct file *file,
868869
if (!t)
869870
return ERR_PTR(-ENOMEM);
870871
kref_init(&t->count);
871-
if (copy_from_user(t->data, buf, size))
872+
if (copy_from_user(t->data, buf, size)) {
873+
put_multi_transaction(t);
872874
return ERR_PTR(-EFAULT);
875+
}
873876

874877
return t;
875878
}
@@ -1090,9 +1093,9 @@ static int seq_profile_attach_show(struct seq_file *seq, void *v)
10901093
struct aa_proxy *proxy = seq->private;
10911094
struct aa_label *label = aa_get_label_rcu(&proxy->label);
10921095
struct aa_profile *profile = labels_profile(label);
1093-
if (profile->attach)
1094-
seq_printf(seq, "%s\n", profile->attach);
1095-
else if (profile->xmatch)
1096+
if (profile->attach.xmatch_str)
1097+
seq_printf(seq, "%s\n", profile->attach.xmatch_str);
1098+
else if (profile->attach.xmatch.dfa)
10961099
seq_puts(seq, "<unknown>\n");
10971100
else
10981101
seq_printf(seq, "%s\n", profile->base.name);
@@ -1197,10 +1200,24 @@ static int seq_ns_name_show(struct seq_file *seq, void *v)
11971200
return 0;
11981201
}
11991202

1203+
static int seq_ns_compress_min_show(struct seq_file *seq, void *v)
1204+
{
1205+
seq_printf(seq, "%d\n", AA_MIN_CLEVEL);
1206+
return 0;
1207+
}
1208+
1209+
static int seq_ns_compress_max_show(struct seq_file *seq, void *v)
1210+
{
1211+
seq_printf(seq, "%d\n", AA_MAX_CLEVEL);
1212+
return 0;
1213+
}
1214+
12001215
SEQ_NS_FOPS(stacked);
12011216
SEQ_NS_FOPS(nsstacked);
12021217
SEQ_NS_FOPS(level);
12031218
SEQ_NS_FOPS(name);
1219+
SEQ_NS_FOPS(compress_min);
1220+
SEQ_NS_FOPS(compress_max);
12041221

12051222

12061223
/* policy/raw_data/ * file ops */
@@ -1295,42 +1312,34 @@ SEQ_RAWDATA_FOPS(revision);
12951312
SEQ_RAWDATA_FOPS(hash);
12961313
SEQ_RAWDATA_FOPS(compressed_size);
12971314

1298-
static int deflate_decompress(char *src, size_t slen, char *dst, size_t dlen)
1315+
static int decompress_zstd(char *src, size_t slen, char *dst, size_t dlen)
12991316
{
13001317
#ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY
1301-
if (aa_g_rawdata_compression_level != 0) {
1302-
int error = 0;
1303-
struct z_stream_s strm;
1304-
1305-
memset(&strm, 0, sizeof(strm));
1306-
1307-
strm.workspace = kvzalloc(zlib_inflate_workspacesize(), GFP_KERNEL);
1308-
if (!strm.workspace)
1309-
return -ENOMEM;
1310-
1311-
strm.next_in = src;
1312-
strm.avail_in = slen;
1313-
1314-
error = zlib_inflateInit(&strm);
1315-
if (error != Z_OK) {
1316-
error = -ENOMEM;
1317-
goto fail_inflate_init;
1318+
if (slen < dlen) {
1319+
const size_t wksp_len = zstd_dctx_workspace_bound();
1320+
zstd_dctx *ctx;
1321+
void *wksp;
1322+
size_t out_len;
1323+
int ret = 0;
1324+
1325+
wksp = kvzalloc(wksp_len, GFP_KERNEL);
1326+
if (!wksp) {
1327+
ret = -ENOMEM;
1328+
goto cleanup;
13181329
}
1319-
1320-
strm.next_out = dst;
1321-
strm.avail_out = dlen;
1322-
1323-
error = zlib_inflate(&strm, Z_FINISH);
1324-
if (error != Z_STREAM_END)
1325-
error = -EINVAL;
1326-
else
1327-
error = 0;
1328-
1329-
zlib_inflateEnd(&strm);
1330-
fail_inflate_init:
1331-
kvfree(strm.workspace);
1332-
1333-
return error;
1330+
ctx = zstd_init_dctx(wksp, wksp_len);
1331+
if (ctx == NULL) {
1332+
ret = -ENOMEM;
1333+
goto cleanup;
1334+
}
1335+
out_len = zstd_decompress_dctx(ctx, dst, dlen, src, slen);
1336+
if (zstd_is_error(out_len)) {
1337+
ret = -EINVAL;
1338+
goto cleanup;
1339+
}
1340+
cleanup:
1341+
kvfree(wksp);
1342+
return ret;
13341343
}
13351344
#endif
13361345

@@ -1379,9 +1388,9 @@ static int rawdata_open(struct inode *inode, struct file *file)
13791388

13801389
private->loaddata = loaddata;
13811390

1382-
error = deflate_decompress(loaddata->data, loaddata->compressed_size,
1383-
RAWDATA_F_DATA_BUF(private),
1384-
loaddata->size);
1391+
error = decompress_zstd(loaddata->data, loaddata->compressed_size,
1392+
RAWDATA_F_DATA_BUF(private),
1393+
loaddata->size);
13851394
if (error)
13861395
goto fail_decompress;
13871396

@@ -2392,6 +2401,8 @@ static struct aa_sfs_entry aa_sfs_entry_apparmor[] = {
23922401
AA_SFS_FILE_FOPS(".ns_level", 0444, &seq_ns_level_fops),
23932402
AA_SFS_FILE_FOPS(".ns_name", 0444, &seq_ns_name_fops),
23942403
AA_SFS_FILE_FOPS("profiles", 0444, &aa_sfs_profiles_fops),
2404+
AA_SFS_FILE_FOPS("raw_data_compression_level_min", 0444, &seq_ns_compress_min_fops),
2405+
AA_SFS_FILE_FOPS("raw_data_compression_level_max", 0444, &seq_ns_compress_max_fops),
23952406
AA_SFS_DIR("features", aa_sfs_entry_features),
23962407
{ }
23972408
};

security/apparmor/audit.c

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,43 @@ static const char *const aa_audit_type[] = {
3636
"AUTO"
3737
};
3838

39+
static const char *const aa_class_names[] = {
40+
"none",
41+
"unknown",
42+
"file",
43+
"cap",
44+
"net",
45+
"rlimits",
46+
"domain",
47+
"mount",
48+
"unknown",
49+
"ptrace",
50+
"signal",
51+
"xmatch",
52+
"unknown",
53+
"unknown",
54+
"net",
55+
"unknown",
56+
"label",
57+
"posix_mqueue",
58+
"io_uring",
59+
"module",
60+
"lsm",
61+
"unknown",
62+
"unknown",
63+
"unknown",
64+
"unknown",
65+
"unknown",
66+
"unknown",
67+
"unknown",
68+
"unknown",
69+
"unknown",
70+
"unknown",
71+
"X",
72+
"dbus",
73+
};
74+
75+
3976
/*
4077
* Currently AppArmor auditing is fed straight into the audit framework.
4178
*
@@ -46,7 +83,7 @@ static const char *const aa_audit_type[] = {
4683
*/
4784

4885
/**
49-
* audit_base - core AppArmor function.
86+
* audit_pre() - core AppArmor function.
5087
* @ab: audit buffer to fill (NOT NULL)
5188
* @ca: audit structure containing data to audit (NOT NULL)
5289
*
@@ -65,6 +102,12 @@ static void audit_pre(struct audit_buffer *ab, void *ca)
65102
audit_log_format(ab, " operation=\"%s\"", aad(sa)->op);
66103
}
67104

105+
if (aad(sa)->class)
106+
audit_log_format(ab, " class=\"%s\"",
107+
aad(sa)->class <= AA_CLASS_LAST ?
108+
aa_class_names[aad(sa)->class] :
109+
"unknown");
110+
68111
if (aad(sa)->info) {
69112
audit_log_format(ab, " info=\"%s\"", aad(sa)->info);
70113
if (aad(sa)->error)

security/apparmor/capability.c

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ static void audit_cb(struct audit_buffer *ab, void *va)
6464
static int audit_caps(struct common_audit_data *sa, struct aa_profile *profile,
6565
int cap, int error)
6666
{
67+
struct aa_ruleset *rules = list_first_entry(&profile->rules,
68+
typeof(*rules), list);
6769
struct audit_cache *ent;
6870
int type = AUDIT_APPARMOR_AUTO;
6971

@@ -72,13 +74,13 @@ static int audit_caps(struct common_audit_data *sa, struct aa_profile *profile,
7274
if (likely(!error)) {
7375
/* test if auditing is being forced */
7476
if (likely((AUDIT_MODE(profile) != AUDIT_ALL) &&
75-
!cap_raised(profile->caps.audit, cap)))
77+
!cap_raised(rules->caps.audit, cap)))
7678
return 0;
7779
type = AUDIT_APPARMOR_AUDIT;
7880
} else if (KILL_MODE(profile) ||
79-
cap_raised(profile->caps.kill, cap)) {
81+
cap_raised(rules->caps.kill, cap)) {
8082
type = AUDIT_APPARMOR_KILL;
81-
} else if (cap_raised(profile->caps.quiet, cap) &&
83+
} else if (cap_raised(rules->caps.quiet, cap) &&
8284
AUDIT_MODE(profile) != AUDIT_NOQUIET &&
8385
AUDIT_MODE(profile) != AUDIT_ALL) {
8486
/* quiet auditing */
@@ -114,10 +116,12 @@ static int audit_caps(struct common_audit_data *sa, struct aa_profile *profile,
114116
static int profile_capable(struct aa_profile *profile, int cap,
115117
unsigned int opts, struct common_audit_data *sa)
116118
{
119+
struct aa_ruleset *rules = list_first_entry(&profile->rules,
120+
typeof(*rules), list);
117121
int error;
118122

119-
if (cap_raised(profile->caps.allow, cap) &&
120-
!cap_raised(profile->caps.denied, cap))
123+
if (cap_raised(rules->caps.allow, cap) &&
124+
!cap_raised(rules->caps.denied, cap))
121125
error = 0;
122126
else
123127
error = -EPERM;
@@ -148,7 +152,7 @@ int aa_capable(struct aa_label *label, int cap, unsigned int opts)
148152
{
149153
struct aa_profile *profile;
150154
int error = 0;
151-
DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_CAP, OP_CAPABLE);
155+
DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_CAP, AA_CLASS_CAP, OP_CAPABLE);
152156

153157
sa.u.cap = cap;
154158
error = fn_for_each_confined(label, profile,

0 commit comments

Comments
 (0)