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

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'apparmor-pr-2025-08-04' of git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor

Pull apparmor updates from John Johansen:
"This has one major feature, it pulls in a cleaned up version of
af_unix mediation that Ubuntu has been carrying for years. It is
placed behind a new abi to ensure that it does cause policy
regressions. With pulling in the af_unix mediation there have been
cleanups and some refactoring of network socket mediation. This
accounts for the majority of the changes in the diff.

In addition there are a few improvements providing minor code
optimizations. several code cleanups, and bug fixes.

Features:
- improve debug printing
- carry mediation check on label (optimization)
- improve ability for compiler to optimize
__begin_current_label_crit_section
- transition for a linked list of rulesets to a vector of rulesets
- don't hardcode profile signal, allow it to be set by policy
- ability to mediate caps via the state machine instead of lut
- Add Ubuntu af_unix mediation, put it behind new v9 abi

Cleanups:
- fix typos and spelling errors
- cleanup kernel doc and code inconsistencies
- remove redundant checks/code
- remove unused variables
- Use str_yes_no() helper function
- mark tables static where appropriate
- make all generated string array headers const char *const
- refactor to doc semantics of file_perm checks
- replace macro calls to network/socket fns with explicit calls
- refactor/cleanup socket mediation code preparing for finer grained
mediation of different network families
- several updates to kernel doc comments

Bug fixes:
- fix incorrect profile->signal range check
- idmap mount fixes
- policy unpack unaligned access fixes
- kfree_sensitive() where appropriate
- fix oops when freeing policy
- fix conflicting attachment resolution
- fix exec table look-ups when stacking isn't first
- fix exec auditing
- mitigate userspace generating overly large xtables"

* tag 'apparmor-pr-2025-08-04' of git://git.kernel.org/pub/scm/linux/kernel/git/jj/linux-apparmor: (60 commits)
apparmor: fix: oops when trying to free null ruleset
apparmor: fix Regression on linux-next (next-20250721)
apparmor: fix test error: WARNING in apparmor_unix_stream_connect
apparmor: Remove the unused variable rules
apparmor: fix: accept2 being specifie even when permission table is presnt
apparmor: transition from a list of rules to a vector of rules
apparmor: fix documentation mismatches in val_mask_to_str and socket functions
apparmor: remove redundant perms.allow MAY_EXEC bitflag set
apparmor: fix kernel doc warnings for kernel test robot
apparmor: Fix unaligned memory accesses in KUnit test
apparmor: Fix 8-byte alignment for initial dfa blob streams
apparmor: shift uid when mediating af_unix in userns
apparmor: shift ouid when mediating hard links in userns
apparmor: make sure unix socket labeling is correctly updated.
apparmor: fix regression in fs based unix sockets when using old abi
apparmor: fix AA_DEBUG_LABEL()
apparmor: fix af_unix auditing to include all address information
apparmor: Remove use of the double lock
apparmor: update kernel doc comments for xxx_label_crit_section
apparmor: make __begin_current_label_crit_section() indicate whether put is needed
...

+2179 -431
+3 -3
security/apparmor/Makefile
··· 6 6 apparmor-y := apparmorfs.o audit.o capability.o task.o ipc.o lib.o match.o \ 7 7 path.o domain.o policy.o policy_unpack.o procattr.o lsm.o \ 8 8 resource.o secid.o file.o policy_ns.o label.o mount.o net.o \ 9 - policy_compat.o 9 + policy_compat.o af_unix.o 10 10 apparmor-$(CONFIG_SECURITY_APPARMOR_HASH) += crypto.o 11 11 12 12 obj-$(CONFIG_SECURITY_APPARMOR_KUNIT_TEST) += apparmor_policy_unpack_test.o ··· 28 28 # to 29 29 # #define AA_SFS_AF_MASK "local inet" 30 30 quiet_cmd_make-af = GEN $@ 31 - cmd_make-af = echo "static const char *address_family_names[] = {" > $@ ;\ 31 + cmd_make-af = echo "static const char *const address_family_names[] = {" > $@ ;\ 32 32 sed $< >>$@ -r -n -e "/AF_MAX/d" -e "/AF_LOCAL/d" -e "/AF_ROUTE/d" -e \ 33 33 's/^\#define[ \t]+AF_([A-Z0-9_]+)[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\ 34 34 echo "};" >> $@ ;\ ··· 43 43 # to 44 44 # [1] = "stream", 45 45 quiet_cmd_make-sock = GEN $@ 46 - cmd_make-sock = echo "static const char *sock_type_names[] = {" >> $@ ;\ 46 + cmd_make-sock = echo "static const char *const sock_type_names[] = {" >> $@ ;\ 47 47 sed $^ >>$@ -r -n \ 48 48 -e 's/^\tSOCK_([A-Z0-9_]+)[\t]+=[ \t]+([0-9]+)(.*)/[\2] = "\L\1",/p';\ 49 49 echo "};" >> $@
+799
security/apparmor/af_unix.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * AppArmor security module 4 + * 5 + * This file contains AppArmor af_unix fine grained mediation 6 + * 7 + * Copyright 2023 Canonical Ltd. 8 + * 9 + * This program is free software; you can redistribute it and/or 10 + * modify it under the terms of the GNU General Public License as 11 + * published by the Free Software Foundation, version 2 of the 12 + * License. 13 + */ 14 + 15 + #include <linux/fs.h> 16 + #include <net/tcp_states.h> 17 + 18 + #include "include/audit.h" 19 + #include "include/af_unix.h" 20 + #include "include/apparmor.h" 21 + #include "include/file.h" 22 + #include "include/label.h" 23 + #include "include/path.h" 24 + #include "include/policy.h" 25 + #include "include/cred.h" 26 + 27 + 28 + static inline struct sock *aa_unix_sk(struct unix_sock *u) 29 + { 30 + return &u->sk; 31 + } 32 + 33 + static int unix_fs_perm(const char *op, u32 mask, const struct cred *subj_cred, 34 + struct aa_label *label, struct path *path) 35 + { 36 + AA_BUG(!label); 37 + AA_BUG(!path); 38 + 39 + if (unconfined(label) || !label_mediates(label, AA_CLASS_FILE)) 40 + return 0; 41 + 42 + mask &= NET_FS_PERMS; 43 + /* if !u->path.dentry socket is being shutdown - implicit delegation 44 + * until obj delegation is supported 45 + */ 46 + if (path->dentry) { 47 + /* the sunpath may not be valid for this ns so use the path */ 48 + struct inode *inode = path->dentry->d_inode; 49 + vfsuid_t vfsuid = i_uid_into_vfsuid(mnt_idmap(path->mnt), inode); 50 + struct path_cond cond = { 51 + .uid = vfsuid_into_kuid(vfsuid), 52 + .mode = inode->i_mode, 53 + }; 54 + 55 + return aa_path_perm(op, subj_cred, label, path, 56 + PATH_SOCK_COND, mask, &cond); 57 + } /* else implicitly delegated */ 58 + 59 + return 0; 60 + } 61 + 62 + /* match_addr special constants */ 63 + #define ABSTRACT_ADDR "\x00" /* abstract socket addr */ 64 + #define ANONYMOUS_ADDR "\x01" /* anonymous endpoint, no addr */ 65 + #define DISCONNECTED_ADDR "\x02" /* addr is another namespace */ 66 + #define SHUTDOWN_ADDR "\x03" /* path addr is shutdown and cleared */ 67 + #define FS_ADDR "/" /* path addr in fs */ 68 + 69 + static aa_state_t match_addr(struct aa_dfa *dfa, aa_state_t state, 70 + struct sockaddr_un *addr, int addrlen) 71 + { 72 + if (addr) 73 + /* include leading \0 */ 74 + state = aa_dfa_match_len(dfa, state, addr->sun_path, 75 + unix_addr_len(addrlen)); 76 + else 77 + state = aa_dfa_match_len(dfa, state, ANONYMOUS_ADDR, 1); 78 + /* todo: could change to out of band for cleaner separation */ 79 + state = aa_dfa_null_transition(dfa, state); 80 + 81 + return state; 82 + } 83 + 84 + static aa_state_t match_to_local(struct aa_policydb *policy, 85 + aa_state_t state, u32 request, 86 + int type, int protocol, 87 + struct sockaddr_un *addr, int addrlen, 88 + struct aa_perms **p, 89 + const char **info) 90 + { 91 + state = aa_match_to_prot(policy, state, request, PF_UNIX, type, 92 + protocol, NULL, info); 93 + if (state) { 94 + state = match_addr(policy->dfa, state, addr, addrlen); 95 + if (state) { 96 + /* todo: local label matching */ 97 + state = aa_dfa_null_transition(policy->dfa, state); 98 + if (!state) 99 + *info = "failed local label match"; 100 + } else { 101 + *info = "failed local address match"; 102 + } 103 + } 104 + 105 + return state; 106 + } 107 + 108 + struct sockaddr_un *aa_sunaddr(const struct unix_sock *u, int *addrlen) 109 + { 110 + struct unix_address *addr; 111 + 112 + /* memory barrier is sufficient see note in net/unix/af_unix.c */ 113 + addr = smp_load_acquire(&u->addr); 114 + if (addr) { 115 + *addrlen = addr->len; 116 + return addr->name; 117 + } 118 + *addrlen = 0; 119 + return NULL; 120 + } 121 + 122 + static aa_state_t match_to_sk(struct aa_policydb *policy, 123 + aa_state_t state, u32 request, 124 + struct unix_sock *u, struct aa_perms **p, 125 + const char **info) 126 + { 127 + int addrlen; 128 + struct sockaddr_un *addr = aa_sunaddr(u, &addrlen); 129 + 130 + return match_to_local(policy, state, request, u->sk.sk_type, 131 + u->sk.sk_protocol, addr, addrlen, p, info); 132 + } 133 + 134 + #define CMD_ADDR 1 135 + #define CMD_LISTEN 2 136 + #define CMD_OPT 4 137 + 138 + static aa_state_t match_to_cmd(struct aa_policydb *policy, aa_state_t state, 139 + u32 request, struct unix_sock *u, 140 + char cmd, struct aa_perms **p, 141 + const char **info) 142 + { 143 + AA_BUG(!p); 144 + 145 + state = match_to_sk(policy, state, request, u, p, info); 146 + if (state && !*p) { 147 + state = aa_dfa_match_len(policy->dfa, state, &cmd, 1); 148 + if (!state) 149 + *info = "failed cmd selection match"; 150 + } 151 + 152 + return state; 153 + } 154 + 155 + static aa_state_t match_to_peer(struct aa_policydb *policy, aa_state_t state, 156 + u32 request, struct unix_sock *u, 157 + struct sockaddr_un *peer_addr, int peer_addrlen, 158 + struct aa_perms **p, const char **info) 159 + { 160 + AA_BUG(!p); 161 + 162 + state = match_to_cmd(policy, state, request, u, CMD_ADDR, p, info); 163 + if (state && !*p) { 164 + state = match_addr(policy->dfa, state, peer_addr, peer_addrlen); 165 + if (!state) 166 + *info = "failed peer address match"; 167 + } 168 + 169 + return state; 170 + } 171 + 172 + static aa_state_t match_label(struct aa_profile *profile, 173 + struct aa_ruleset *rule, aa_state_t state, 174 + u32 request, struct aa_profile *peer, 175 + struct aa_perms *p, 176 + struct apparmor_audit_data *ad) 177 + { 178 + AA_BUG(!profile); 179 + AA_BUG(!peer); 180 + 181 + ad->peer = &peer->label; 182 + 183 + if (state && !p) { 184 + state = aa_dfa_match(rule->policy->dfa, state, 185 + peer->base.hname); 186 + if (!state) 187 + ad->info = "failed peer label match"; 188 + 189 + } 190 + 191 + return aa_do_perms(profile, rule->policy, state, request, p, ad); 192 + } 193 + 194 + 195 + /* unix sock creation comes before we know if the socket will be an fs 196 + * socket 197 + * v6 - semantics are handled by mapping in profile load 198 + * v7 - semantics require sock create for tasks creating an fs socket. 199 + * v8 - same as v7 200 + */ 201 + static int profile_create_perm(struct aa_profile *profile, int family, 202 + int type, int protocol, 203 + struct apparmor_audit_data *ad) 204 + { 205 + struct aa_ruleset *rules = profile->label.rules[0]; 206 + aa_state_t state; 207 + 208 + AA_BUG(!profile); 209 + AA_BUG(profile_unconfined(profile)); 210 + 211 + state = RULE_MEDIATES_v9NET(rules); 212 + if (state) { 213 + state = aa_match_to_prot(rules->policy, state, AA_MAY_CREATE, 214 + PF_UNIX, type, protocol, NULL, 215 + &ad->info); 216 + 217 + return aa_do_perms(profile, rules->policy, state, AA_MAY_CREATE, 218 + NULL, ad); 219 + } 220 + 221 + return aa_profile_af_perm(profile, ad, AA_MAY_CREATE, family, type, 222 + protocol); 223 + } 224 + 225 + static int profile_sk_perm(struct aa_profile *profile, 226 + struct apparmor_audit_data *ad, 227 + u32 request, struct sock *sk, struct path *path) 228 + { 229 + struct aa_ruleset *rules = profile->label.rules[0]; 230 + struct aa_perms *p = NULL; 231 + aa_state_t state; 232 + 233 + AA_BUG(!profile); 234 + AA_BUG(!sk); 235 + AA_BUG(profile_unconfined(profile)); 236 + 237 + state = RULE_MEDIATES_v9NET(rules); 238 + if (state) { 239 + if (is_unix_fs(sk)) 240 + return unix_fs_perm(ad->op, request, ad->subj_cred, 241 + &profile->label, 242 + &unix_sk(sk)->path); 243 + 244 + state = match_to_sk(rules->policy, state, request, unix_sk(sk), 245 + &p, &ad->info); 246 + 247 + return aa_do_perms(profile, rules->policy, state, request, p, 248 + ad); 249 + } 250 + 251 + return aa_profile_af_sk_perm(profile, ad, request, sk); 252 + } 253 + 254 + static int profile_bind_perm(struct aa_profile *profile, struct sock *sk, 255 + struct apparmor_audit_data *ad) 256 + { 257 + struct aa_ruleset *rules = profile->label.rules[0]; 258 + struct aa_perms *p = NULL; 259 + aa_state_t state; 260 + 261 + AA_BUG(!profile); 262 + AA_BUG(!sk); 263 + AA_BUG(!ad); 264 + AA_BUG(profile_unconfined(profile)); 265 + 266 + state = RULE_MEDIATES_v9NET(rules); 267 + if (state) { 268 + if (is_unix_addr_fs(ad->net.addr, ad->net.addrlen)) 269 + /* under v7-9 fs hook handles bind */ 270 + return 0; 271 + /* bind for abstract socket */ 272 + state = match_to_local(rules->policy, state, AA_MAY_BIND, 273 + sk->sk_type, sk->sk_protocol, 274 + unix_addr(ad->net.addr), 275 + ad->net.addrlen, 276 + &p, &ad->info); 277 + 278 + return aa_do_perms(profile, rules->policy, state, AA_MAY_BIND, 279 + p, ad); 280 + } 281 + 282 + return aa_profile_af_sk_perm(profile, ad, AA_MAY_BIND, sk); 283 + } 284 + 285 + static int profile_listen_perm(struct aa_profile *profile, struct sock *sk, 286 + int backlog, struct apparmor_audit_data *ad) 287 + { 288 + struct aa_ruleset *rules = profile->label.rules[0]; 289 + struct aa_perms *p = NULL; 290 + aa_state_t state; 291 + 292 + AA_BUG(!profile); 293 + AA_BUG(!sk); 294 + AA_BUG(!ad); 295 + AA_BUG(profile_unconfined(profile)); 296 + 297 + state = RULE_MEDIATES_v9NET(rules); 298 + if (state) { 299 + __be16 b = cpu_to_be16(backlog); 300 + 301 + if (is_unix_fs(sk)) 302 + return unix_fs_perm(ad->op, AA_MAY_LISTEN, 303 + ad->subj_cred, &profile->label, 304 + &unix_sk(sk)->path); 305 + 306 + state = match_to_cmd(rules->policy, state, AA_MAY_LISTEN, 307 + unix_sk(sk), CMD_LISTEN, &p, &ad->info); 308 + if (state && !p) { 309 + state = aa_dfa_match_len(rules->policy->dfa, state, 310 + (char *) &b, 2); 311 + if (!state) 312 + ad->info = "failed listen backlog match"; 313 + } 314 + return aa_do_perms(profile, rules->policy, state, AA_MAY_LISTEN, 315 + p, ad); 316 + } 317 + 318 + return aa_profile_af_sk_perm(profile, ad, AA_MAY_LISTEN, sk); 319 + } 320 + 321 + static int profile_accept_perm(struct aa_profile *profile, 322 + struct sock *sk, 323 + struct apparmor_audit_data *ad) 324 + { 325 + struct aa_ruleset *rules = profile->label.rules[0]; 326 + struct aa_perms *p = NULL; 327 + aa_state_t state; 328 + 329 + AA_BUG(!profile); 330 + AA_BUG(!sk); 331 + AA_BUG(!ad); 332 + AA_BUG(profile_unconfined(profile)); 333 + 334 + state = RULE_MEDIATES_v9NET(rules); 335 + if (state) { 336 + if (is_unix_fs(sk)) 337 + return unix_fs_perm(ad->op, AA_MAY_ACCEPT, 338 + ad->subj_cred, &profile->label, 339 + &unix_sk(sk)->path); 340 + 341 + state = match_to_sk(rules->policy, state, AA_MAY_ACCEPT, 342 + unix_sk(sk), &p, &ad->info); 343 + 344 + return aa_do_perms(profile, rules->policy, state, AA_MAY_ACCEPT, 345 + p, ad); 346 + } 347 + 348 + return aa_profile_af_sk_perm(profile, ad, AA_MAY_ACCEPT, sk); 349 + } 350 + 351 + static int profile_opt_perm(struct aa_profile *profile, u32 request, 352 + struct sock *sk, int optname, 353 + struct apparmor_audit_data *ad) 354 + { 355 + struct aa_ruleset *rules = profile->label.rules[0]; 356 + struct aa_perms *p = NULL; 357 + aa_state_t state; 358 + 359 + AA_BUG(!profile); 360 + AA_BUG(!sk); 361 + AA_BUG(!ad); 362 + AA_BUG(profile_unconfined(profile)); 363 + 364 + state = RULE_MEDIATES_v9NET(rules); 365 + if (state) { 366 + __be16 b = cpu_to_be16(optname); 367 + if (is_unix_fs(sk)) 368 + return unix_fs_perm(ad->op, request, 369 + ad->subj_cred, &profile->label, 370 + &unix_sk(sk)->path); 371 + 372 + state = match_to_cmd(rules->policy, state, request, unix_sk(sk), 373 + CMD_OPT, &p, &ad->info); 374 + if (state && !p) { 375 + state = aa_dfa_match_len(rules->policy->dfa, state, 376 + (char *) &b, 2); 377 + if (!state) 378 + ad->info = "failed sockopt match"; 379 + } 380 + return aa_do_perms(profile, rules->policy, state, request, p, 381 + ad); 382 + } 383 + 384 + return aa_profile_af_sk_perm(profile, ad, request, sk); 385 + } 386 + 387 + /* null peer_label is allowed, in which case the peer_sk label is used */ 388 + static int profile_peer_perm(struct aa_profile *profile, u32 request, 389 + struct sock *sk, struct path *path, 390 + struct sockaddr_un *peer_addr, 391 + int peer_addrlen, struct path *peer_path, 392 + struct aa_label *peer_label, 393 + struct apparmor_audit_data *ad) 394 + { 395 + struct aa_ruleset *rules = profile->label.rules[0]; 396 + struct aa_perms *p = NULL; 397 + aa_state_t state; 398 + 399 + AA_BUG(!profile); 400 + AA_BUG(profile_unconfined(profile)); 401 + AA_BUG(!sk); 402 + AA_BUG(!peer_label); 403 + AA_BUG(!ad); 404 + 405 + state = RULE_MEDIATES_v9NET(rules); 406 + if (state) { 407 + struct aa_profile *peerp; 408 + 409 + if (peer_path) 410 + return unix_fs_perm(ad->op, request, ad->subj_cred, 411 + &profile->label, peer_path); 412 + else if (path) 413 + return unix_fs_perm(ad->op, request, ad->subj_cred, 414 + &profile->label, path); 415 + state = match_to_peer(rules->policy, state, request, 416 + unix_sk(sk), 417 + peer_addr, peer_addrlen, &p, &ad->info); 418 + 419 + return fn_for_each_in_ns(peer_label, peerp, 420 + match_label(profile, rules, state, request, 421 + peerp, p, ad)); 422 + } 423 + 424 + return aa_profile_af_sk_perm(profile, ad, request, sk); 425 + } 426 + 427 + /* -------------------------------- */ 428 + 429 + int aa_unix_create_perm(struct aa_label *label, int family, int type, 430 + int protocol) 431 + { 432 + if (!unconfined(label)) { 433 + struct aa_profile *profile; 434 + DEFINE_AUDIT_NET(ad, OP_CREATE, current_cred(), NULL, family, 435 + type, protocol); 436 + 437 + return fn_for_each_confined(label, profile, 438 + profile_create_perm(profile, family, type, 439 + protocol, &ad)); 440 + } 441 + 442 + return 0; 443 + } 444 + 445 + static int aa_unix_label_sk_perm(const struct cred *subj_cred, 446 + struct aa_label *label, 447 + const char *op, u32 request, struct sock *sk, 448 + struct path *path) 449 + { 450 + if (!unconfined(label)) { 451 + struct aa_profile *profile; 452 + DEFINE_AUDIT_SK(ad, op, subj_cred, sk); 453 + 454 + return fn_for_each_confined(label, profile, 455 + profile_sk_perm(profile, &ad, request, sk, 456 + path)); 457 + } 458 + return 0; 459 + } 460 + 461 + /* revalidation, get/set attr, shutdown */ 462 + int aa_unix_sock_perm(const char *op, u32 request, struct socket *sock) 463 + { 464 + struct aa_label *label; 465 + int error; 466 + 467 + label = begin_current_label_crit_section(); 468 + error = aa_unix_label_sk_perm(current_cred(), label, op, 469 + request, sock->sk, 470 + is_unix_fs(sock->sk) ? &unix_sk(sock->sk)->path : NULL); 471 + end_current_label_crit_section(label); 472 + 473 + return error; 474 + } 475 + 476 + static int valid_addr(struct sockaddr *addr, int addr_len) 477 + { 478 + struct sockaddr_un *sunaddr = unix_addr(addr); 479 + 480 + /* addr_len == offsetof(struct sockaddr_un, sun_path) is autobind */ 481 + if (addr_len < offsetof(struct sockaddr_un, sun_path) || 482 + addr_len > sizeof(*sunaddr)) 483 + return -EINVAL; 484 + return 0; 485 + } 486 + 487 + int aa_unix_bind_perm(struct socket *sock, struct sockaddr *addr, 488 + int addrlen) 489 + { 490 + struct aa_profile *profile; 491 + struct aa_label *label; 492 + int error = 0; 493 + 494 + error = valid_addr(addr, addrlen); 495 + if (error) 496 + return error; 497 + 498 + label = begin_current_label_crit_section(); 499 + /* fs bind is handled by mknod */ 500 + if (!unconfined(label)) { 501 + DEFINE_AUDIT_SK(ad, OP_BIND, current_cred(), sock->sk); 502 + 503 + ad.net.addr = unix_addr(addr); 504 + ad.net.addrlen = addrlen; 505 + 506 + error = fn_for_each_confined(label, profile, 507 + profile_bind_perm(profile, sock->sk, &ad)); 508 + } 509 + end_current_label_crit_section(label); 510 + 511 + return error; 512 + } 513 + 514 + /* 515 + * unix connections are covered by the 516 + * - unix_stream_connect (stream) and unix_may_send hooks (dgram) 517 + * - fs connect is handled by open 518 + * This is just here to document this is not needed for af_unix 519 + * 520 + int aa_unix_connect_perm(struct socket *sock, struct sockaddr *address, 521 + int addrlen) 522 + { 523 + return 0; 524 + } 525 + */ 526 + 527 + int aa_unix_listen_perm(struct socket *sock, int backlog) 528 + { 529 + struct aa_profile *profile; 530 + struct aa_label *label; 531 + int error = 0; 532 + 533 + label = begin_current_label_crit_section(); 534 + if (!unconfined(label)) { 535 + DEFINE_AUDIT_SK(ad, OP_LISTEN, current_cred(), sock->sk); 536 + 537 + error = fn_for_each_confined(label, profile, 538 + profile_listen_perm(profile, sock->sk, 539 + backlog, &ad)); 540 + } 541 + end_current_label_crit_section(label); 542 + 543 + return error; 544 + } 545 + 546 + 547 + /* ability of sock to connect, not peer address binding */ 548 + int aa_unix_accept_perm(struct socket *sock, struct socket *newsock) 549 + { 550 + struct aa_profile *profile; 551 + struct aa_label *label; 552 + int error = 0; 553 + 554 + label = begin_current_label_crit_section(); 555 + if (!unconfined(label)) { 556 + DEFINE_AUDIT_SK(ad, OP_ACCEPT, current_cred(), sock->sk); 557 + 558 + error = fn_for_each_confined(label, profile, 559 + profile_accept_perm(profile, sock->sk, &ad)); 560 + } 561 + end_current_label_crit_section(label); 562 + 563 + return error; 564 + } 565 + 566 + 567 + /* 568 + * dgram handled by unix_may_sendmsg, right to send on stream done at connect 569 + * could do per msg unix_stream here, but connect + socket transfer is 570 + * sufficient. This is just here to document this is not needed for af_unix 571 + * 572 + * sendmsg, recvmsg 573 + int aa_unix_msg_perm(const char *op, u32 request, struct socket *sock, 574 + struct msghdr *msg, int size) 575 + { 576 + return 0; 577 + } 578 + */ 579 + 580 + int aa_unix_opt_perm(const char *op, u32 request, struct socket *sock, 581 + int level, int optname) 582 + { 583 + struct aa_profile *profile; 584 + struct aa_label *label; 585 + int error = 0; 586 + 587 + label = begin_current_label_crit_section(); 588 + if (!unconfined(label)) { 589 + DEFINE_AUDIT_SK(ad, op, current_cred(), sock->sk); 590 + 591 + error = fn_for_each_confined(label, profile, 592 + profile_opt_perm(profile, request, sock->sk, 593 + optname, &ad)); 594 + } 595 + end_current_label_crit_section(label); 596 + 597 + return error; 598 + } 599 + 600 + static int unix_peer_perm(const struct cred *subj_cred, 601 + struct aa_label *label, const char *op, u32 request, 602 + struct sock *sk, struct path *path, 603 + struct sockaddr_un *peer_addr, int peer_addrlen, 604 + struct path *peer_path, struct aa_label *peer_label) 605 + { 606 + struct aa_profile *profile; 607 + DEFINE_AUDIT_SK(ad, op, subj_cred, sk); 608 + 609 + ad.net.peer.addr = peer_addr; 610 + ad.net.peer.addrlen = peer_addrlen; 611 + 612 + return fn_for_each_confined(label, profile, 613 + profile_peer_perm(profile, request, sk, path, 614 + peer_addr, peer_addrlen, peer_path, 615 + peer_label, &ad)); 616 + } 617 + 618 + /** 619 + * 620 + * Requires: lock held on both @sk and @peer_sk 621 + * called by unix_stream_connect, unix_may_send 622 + */ 623 + int aa_unix_peer_perm(const struct cred *subj_cred, 624 + struct aa_label *label, const char *op, u32 request, 625 + struct sock *sk, struct sock *peer_sk, 626 + struct aa_label *peer_label) 627 + { 628 + struct unix_sock *peeru = unix_sk(peer_sk); 629 + struct unix_sock *u = unix_sk(sk); 630 + int plen; 631 + struct sockaddr_un *paddr = aa_sunaddr(unix_sk(peer_sk), &plen); 632 + 633 + AA_BUG(!label); 634 + AA_BUG(!sk); 635 + AA_BUG(!peer_sk); 636 + AA_BUG(!peer_label); 637 + 638 + return unix_peer_perm(subj_cred, label, op, request, sk, 639 + is_unix_fs(sk) ? &u->path : NULL, 640 + paddr, plen, 641 + is_unix_fs(peer_sk) ? &peeru->path : NULL, 642 + peer_label); 643 + } 644 + 645 + /* sk_plabel for comparison only */ 646 + static void update_sk_ctx(struct sock *sk, struct aa_label *label, 647 + struct aa_label *plabel) 648 + { 649 + struct aa_label *l, *old; 650 + struct aa_sk_ctx *ctx = aa_sock(sk); 651 + bool update_sk; 652 + 653 + rcu_read_lock(); 654 + update_sk = (plabel && 655 + (plabel != rcu_access_pointer(ctx->peer_lastupdate) || 656 + !aa_label_is_subset(plabel, rcu_dereference(ctx->peer)))) || 657 + !__aa_subj_label_is_cached(label, rcu_dereference(ctx->label)); 658 + rcu_read_unlock(); 659 + if (!update_sk) 660 + return; 661 + 662 + spin_lock(&unix_sk(sk)->lock); 663 + old = rcu_dereference_protected(ctx->label, 664 + lockdep_is_held(&unix_sk(sk)->lock)); 665 + l = aa_label_merge(old, label, GFP_ATOMIC); 666 + if (l) { 667 + if (l != old) { 668 + rcu_assign_pointer(ctx->label, l); 669 + aa_put_label(old); 670 + } else 671 + aa_put_label(l); 672 + } 673 + if (plabel && rcu_access_pointer(ctx->peer_lastupdate) != plabel) { 674 + old = rcu_dereference_protected(ctx->peer, lockdep_is_held(&unix_sk(sk)->lock)); 675 + 676 + if (old == plabel) { 677 + rcu_assign_pointer(ctx->peer_lastupdate, plabel); 678 + } else if (aa_label_is_subset(plabel, old)) { 679 + rcu_assign_pointer(ctx->peer_lastupdate, plabel); 680 + rcu_assign_pointer(ctx->peer, aa_get_label(plabel)); 681 + aa_put_label(old); 682 + } /* else race or a subset - don't update */ 683 + } 684 + spin_unlock(&unix_sk(sk)->lock); 685 + } 686 + 687 + static void update_peer_ctx(struct sock *sk, struct aa_sk_ctx *ctx, 688 + struct aa_label *label) 689 + { 690 + struct aa_label *l, *old; 691 + 692 + spin_lock(&unix_sk(sk)->lock); 693 + old = rcu_dereference_protected(ctx->peer, 694 + lockdep_is_held(&unix_sk(sk)->lock)); 695 + l = aa_label_merge(old, label, GFP_ATOMIC); 696 + if (l) { 697 + if (l != old) { 698 + rcu_assign_pointer(ctx->peer, l); 699 + aa_put_label(old); 700 + } else 701 + aa_put_label(l); 702 + } 703 + spin_unlock(&unix_sk(sk)->lock); 704 + } 705 + 706 + /* This fn is only checked if something has changed in the security 707 + * boundaries. Otherwise cached info off file is sufficient 708 + */ 709 + int aa_unix_file_perm(const struct cred *subj_cred, struct aa_label *label, 710 + const char *op, u32 request, struct file *file) 711 + { 712 + struct socket *sock = (struct socket *) file->private_data; 713 + struct sockaddr_un *addr, *peer_addr; 714 + int addrlen, peer_addrlen; 715 + struct aa_label *plabel = NULL; 716 + struct sock *peer_sk = NULL; 717 + u32 sk_req = request & ~NET_PEER_MASK; 718 + struct path path; 719 + bool is_sk_fs; 720 + int error = 0; 721 + 722 + AA_BUG(!label); 723 + AA_BUG(!sock); 724 + AA_BUG(!sock->sk); 725 + AA_BUG(sock->sk->sk_family != PF_UNIX); 726 + 727 + /* investigate only using lock via unix_peer_get() 728 + * addr only needs the memory barrier, but need to investigate 729 + * path 730 + */ 731 + unix_state_lock(sock->sk); 732 + peer_sk = unix_peer(sock->sk); 733 + if (peer_sk) 734 + sock_hold(peer_sk); 735 + 736 + is_sk_fs = is_unix_fs(sock->sk); 737 + addr = aa_sunaddr(unix_sk(sock->sk), &addrlen); 738 + path = unix_sk(sock->sk)->path; 739 + unix_state_unlock(sock->sk); 740 + 741 + if (is_sk_fs && peer_sk) 742 + sk_req = request; 743 + if (sk_req) { 744 + error = aa_unix_label_sk_perm(subj_cred, label, op, 745 + sk_req, sock->sk, 746 + is_sk_fs ? &path : NULL); 747 + } 748 + if (!peer_sk) 749 + goto out; 750 + 751 + peer_addr = aa_sunaddr(unix_sk(peer_sk), &peer_addrlen); 752 + 753 + struct path peer_path; 754 + 755 + peer_path = unix_sk(peer_sk)->path; 756 + if (!is_sk_fs && is_unix_fs(peer_sk)) { 757 + last_error(error, 758 + unix_fs_perm(op, request, subj_cred, label, 759 + is_unix_fs(peer_sk) ? &peer_path : NULL)); 760 + } else if (!is_sk_fs) { 761 + struct aa_label *plabel; 762 + struct aa_sk_ctx *pctx = aa_sock(peer_sk); 763 + 764 + rcu_read_lock(); 765 + plabel = aa_get_label_rcu(&pctx->label); 766 + rcu_read_unlock(); 767 + /* no fs check of aa_unix_peer_perm because conditions above 768 + * ensure they will never be done 769 + */ 770 + last_error(error, 771 + xcheck(unix_peer_perm(subj_cred, label, op, 772 + MAY_READ | MAY_WRITE, sock->sk, 773 + is_sk_fs ? &path : NULL, 774 + peer_addr, peer_addrlen, 775 + is_unix_fs(peer_sk) ? 776 + &peer_path : NULL, 777 + plabel), 778 + unix_peer_perm(file->f_cred, plabel, op, 779 + MAY_READ | MAY_WRITE, peer_sk, 780 + is_unix_fs(peer_sk) ? 781 + &peer_path : NULL, 782 + addr, addrlen, 783 + is_sk_fs ? &path : NULL, 784 + label))); 785 + if (!error && !__aa_subj_label_is_cached(plabel, label)) 786 + update_peer_ctx(peer_sk, pctx, label); 787 + } 788 + sock_put(peer_sk); 789 + 790 + out: 791 + 792 + /* update peer cache to latest successful perm check */ 793 + if (error == 0) 794 + update_sk_ctx(sock->sk, label, plabel); 795 + aa_put_label(plabel); 796 + 797 + return error; 798 + } 799 +
+28 -11
security/apparmor/apparmorfs.c
··· 43 43 * The interface is split into two main components based on their function 44 44 * a securityfs component: 45 45 * used for static files that are always available, and which allows 46 - * userspace to specificy the location of the security filesystem. 46 + * userspace to specify the location of the security filesystem. 47 47 * 48 48 * fns and data are prefixed with 49 49 * aa_sfs_ ··· 204 204 /** 205 205 * __aafs_setup_d_inode - basic inode setup for apparmorfs 206 206 * @dir: parent directory for the dentry 207 - * @dentry: dentry we are seting the inode up for 207 + * @dentry: dentry we are setting the inode up for 208 208 * @mode: permissions the file should have 209 209 * @data: data to store on inode.i_private, available in open() 210 210 * @link: if symlink, symlink target string ··· 612 612 static void profile_query_cb(struct aa_profile *profile, struct aa_perms *perms, 613 613 const char *match_str, size_t match_len) 614 614 { 615 - struct aa_ruleset *rules = list_first_entry(&profile->rules, 616 - typeof(*rules), list); 615 + struct aa_ruleset *rules = profile->label.rules[0]; 617 616 struct aa_perms tmp = { }; 618 617 aa_state_t state = DFA_NOMATCH; 619 618 ··· 625 626 if (state) { 626 627 struct path_cond cond = { }; 627 628 628 - tmp = *(aa_lookup_fperms(rules->file, state, &cond)); 629 + tmp = *(aa_lookup_condperms(current_fsuid(), 630 + rules->file, state, &cond)); 629 631 } 630 632 } else if (rules->policy->dfa) { 631 633 if (!RULE_MEDIATES(rules, *match_str)) 632 634 return; /* no change to current perms */ 635 + /* old user space does not correctly detect dbus mediation 636 + * support so we may get dbus policy and requests when 637 + * the abi doesn't support it. This can cause mediation 638 + * regressions, so explicitly test for this situation. 639 + */ 640 + if (*match_str == AA_CLASS_DBUS && 641 + !RULE_MEDIATES_v9NET(rules)) 642 + return; /* no change to current perms */ 633 643 state = aa_dfa_match_len(rules->policy->dfa, 634 644 rules->policy->start[0], 635 645 match_str, match_len); ··· 1005 997 1006 998 switch (fs_file->v_type) { 1007 999 case AA_SFS_TYPE_BOOLEAN: 1008 - seq_printf(seq, "%s\n", fs_file->v.boolean ? "yes" : "no"); 1000 + seq_printf(seq, "%s\n", str_yes_no(fs_file->v.boolean)); 1009 1001 break; 1010 1002 case AA_SFS_TYPE_STRING: 1011 1003 seq_printf(seq, "%s\n", fs_file->v.string); ··· 1014 1006 seq_printf(seq, "%#08lx\n", fs_file->v.u64); 1015 1007 break; 1016 1008 default: 1017 - /* Ignore unpritable entry types. */ 1009 + /* Ignore unprintable entry types. */ 1018 1010 break; 1019 1011 } 1020 1012 ··· 1160 1152 struct aa_label *label; 1161 1153 1162 1154 label = begin_current_label_crit_section(); 1163 - seq_printf(seq, "%s\n", label->size > 1 ? "yes" : "no"); 1155 + seq_printf(seq, "%s\n", str_yes_no(label->size > 1)); 1164 1156 end_current_label_crit_section(label); 1165 1157 1166 1158 return 0; ··· 1183 1175 } 1184 1176 } 1185 1177 1186 - seq_printf(seq, "%s\n", count > 1 ? "yes" : "no"); 1178 + seq_printf(seq, "%s\n", str_yes_no(count > 1)); 1187 1179 end_current_label_crit_section(label); 1188 1180 1189 1181 return 0; ··· 2252 2244 /** 2253 2245 * p_stop - stop depth first traversal 2254 2246 * @f: seq_file we are filling 2255 - * @p: the last profile writen 2247 + * @p: the last profile written 2256 2248 * 2257 2249 * Release all locking done by p_start/p_next on namespace tree 2258 2250 */ ··· 2340 2332 static struct aa_sfs_entry aa_sfs_entry_domain[] = { 2341 2333 AA_SFS_FILE_BOOLEAN("change_hat", 1), 2342 2334 AA_SFS_FILE_BOOLEAN("change_hatv", 1), 2335 + AA_SFS_FILE_BOOLEAN("unconfined_allowed_children", 1), 2343 2336 AA_SFS_FILE_BOOLEAN("change_onexec", 1), 2344 2337 AA_SFS_FILE_BOOLEAN("change_profile", 1), 2345 2338 AA_SFS_FILE_BOOLEAN("stack", 1), ··· 2349 2340 AA_SFS_FILE_BOOLEAN("computed_longest_left", 1), 2350 2341 AA_SFS_DIR("attach_conditions", aa_sfs_entry_attach), 2351 2342 AA_SFS_FILE_BOOLEAN("disconnected.path", 1), 2343 + AA_SFS_FILE_BOOLEAN("kill.signal", 1), 2352 2344 AA_SFS_FILE_STRING("version", "1.2"), 2353 2345 { } 2354 2346 }; ··· 2374 2364 AA_SFS_FILE_BOOLEAN("set_load", 1), 2375 2365 /* number of out of band transitions supported */ 2376 2366 AA_SFS_FILE_U64("outofband", MAX_OOB_SUPPORTED), 2377 - AA_SFS_FILE_U64("permstable32_version", 1), 2367 + AA_SFS_FILE_U64("permstable32_version", 3), 2378 2368 AA_SFS_FILE_STRING("permstable32", PERMS32STR), 2379 2369 AA_SFS_FILE_U64("state32", 1), 2380 2370 AA_SFS_DIR("unconfined_restrictions", aa_sfs_entry_unconfined), ··· 2391 2381 AA_SFS_FILE_BOOLEAN("profile", 1), 2392 2382 AA_SFS_FILE_BOOLEAN("pivot_root", 0), 2393 2383 AA_SFS_FILE_STRING("mask", "userns_create"), 2384 + { } 2385 + }; 2386 + 2387 + static struct aa_sfs_entry aa_sfs_entry_dbus[] = { 2388 + AA_SFS_FILE_STRING("mask", "acquire send receive"), 2394 2389 { } 2395 2390 }; 2396 2391 ··· 2421 2406 AA_SFS_DIR("domain", aa_sfs_entry_domain), 2422 2407 AA_SFS_DIR("file", aa_sfs_entry_file), 2423 2408 AA_SFS_DIR("network_v8", aa_sfs_entry_network), 2409 + AA_SFS_DIR("network_v9", aa_sfs_entry_networkv9), 2424 2410 AA_SFS_DIR("mount", aa_sfs_entry_mount), 2425 2411 AA_SFS_DIR("namespaces", aa_sfs_entry_ns), 2426 2412 AA_SFS_FILE_U64("capability", VFS_CAP_FLAGS_MASK), ··· 2429 2413 AA_SFS_DIR("caps", aa_sfs_entry_caps), 2430 2414 AA_SFS_DIR("ptrace", aa_sfs_entry_ptrace), 2431 2415 AA_SFS_DIR("signal", aa_sfs_entry_signal), 2416 + AA_SFS_DIR("dbus", aa_sfs_entry_dbus), 2432 2417 AA_SFS_DIR("query", aa_sfs_entry_query), 2433 2418 AA_SFS_DIR("io_uring", aa_sfs_entry_io_uring), 2434 2419 { }
+1 -1
security/apparmor/audit.c
··· 192 192 aa_audit_msg(type, ad, cb); 193 193 194 194 if (ad->type == AUDIT_APPARMOR_KILL) 195 - (void)send_sig_info(SIGKILL, NULL, 195 + (void)send_sig_info(profile->signal, NULL, 196 196 ad->common.type == LSM_AUDIT_DATA_TASK && 197 197 ad->common.u.tsk ? ad->common.u.tsk : current); 198 198
+57 -4
security/apparmor/capability.c
··· 27 27 28 28 struct aa_sfs_entry aa_sfs_entry_caps[] = { 29 29 AA_SFS_FILE_STRING("mask", AA_SFS_CAPS_MASK), 30 + AA_SFS_FILE_BOOLEAN("extended", 1), 30 31 { } 31 32 }; 32 33 ··· 69 68 { 70 69 const u64 AUDIT_CACHE_TIMEOUT_NS = 1000*1000*1000; /* 1 second */ 71 70 72 - struct aa_ruleset *rules = list_first_entry(&profile->rules, 73 - typeof(*rules), list); 71 + struct aa_ruleset *rules = profile->label.rules[0]; 74 72 struct audit_cache *ent; 75 73 int type = AUDIT_APPARMOR_AUTO; 76 74 ··· 121 121 static int profile_capable(struct aa_profile *profile, int cap, 122 122 unsigned int opts, struct apparmor_audit_data *ad) 123 123 { 124 - struct aa_ruleset *rules = list_first_entry(&profile->rules, 125 - typeof(*rules), list); 124 + struct aa_ruleset *rules = profile->label.rules[0]; 125 + aa_state_t state; 126 126 int error; 127 127 128 + state = RULE_MEDIATES(rules, ad->class); 129 + if (state) { 130 + struct aa_perms perms = { }; 131 + u32 request; 132 + 133 + /* caps broken into 256 x 32 bit permission chunks */ 134 + state = aa_dfa_next(rules->policy->dfa, state, cap >> 5); 135 + request = 1 << (cap & 0x1f); 136 + perms = *aa_lookup_perms(rules->policy, state); 137 + aa_apply_modes_to_perms(profile, &perms); 138 + 139 + if (opts & CAP_OPT_NOAUDIT) { 140 + if (perms.complain & request) 141 + ad->info = "optional: no audit"; 142 + else 143 + ad = NULL; 144 + } 145 + return aa_check_perms(profile, &perms, request, ad, 146 + audit_cb); 147 + } 148 + 149 + /* fallback to old caps mediation that doesn't support conditionals */ 128 150 if (cap_raised(rules->caps.allow, cap) && 129 151 !cap_raised(rules->caps.denied, cap)) 130 152 error = 0; ··· 189 167 profile_capable(profile, cap, opts, &ad)); 190 168 191 169 return error; 170 + } 171 + 172 + kernel_cap_t aa_profile_capget(struct aa_profile *profile) 173 + { 174 + struct aa_ruleset *rules = profile->label.rules[0]; 175 + aa_state_t state; 176 + 177 + state = RULE_MEDIATES(rules, AA_CLASS_CAP); 178 + if (state) { 179 + kernel_cap_t caps = CAP_EMPTY_SET; 180 + int i; 181 + 182 + /* caps broken into up to 256, 32 bit permission chunks */ 183 + for (i = 0; i < (CAP_LAST_CAP >> 5); i++) { 184 + struct aa_perms perms = { }; 185 + aa_state_t tmp; 186 + 187 + tmp = aa_dfa_next(rules->policy->dfa, state, i); 188 + perms = *aa_lookup_perms(rules->policy, tmp); 189 + aa_apply_modes_to_perms(profile, &perms); 190 + caps.val |= ((u64)(perms.allow)) << (i * 5); 191 + caps.val |= ((u64)(perms.complain)) << (i * 5); 192 + } 193 + return caps; 194 + } 195 + 196 + /* fallback to old caps */ 197 + if (COMPLAIN_MODE(profile)) 198 + return CAP_FULL_SET; 199 + 200 + return rules->caps.allow; 192 201 }
+137 -66
security/apparmor/domain.c
··· 28 28 #include "include/policy.h" 29 29 #include "include/policy_ns.h" 30 30 31 + static const char * const CONFLICTING_ATTACH_STR = "conflicting profile attachments"; 32 + static const char * const CONFLICTING_ATTACH_STR_IX = 33 + "conflicting profile attachments - ix fallback"; 34 + static const char * const CONFLICTING_ATTACH_STR_UX = 35 + "conflicting profile attachments - ux fallback"; 36 + 31 37 /** 32 38 * may_change_ptraced_domain - check if can change profile on ptraced task 33 39 * @to_cred: cred of task changing domain ··· 93 87 struct aa_profile *tp, 94 88 bool stack, aa_state_t state) 95 89 { 96 - struct aa_ruleset *rules = list_first_entry(&profile->rules, 97 - typeof(*rules), list); 90 + struct aa_ruleset *rules = profile->label.rules[0]; 98 91 const char *ns_name; 99 92 100 93 if (stack) ··· 130 125 aa_state_t state, bool subns, u32 request, 131 126 struct aa_perms *perms) 132 127 { 133 - struct aa_ruleset *rules = list_first_entry(&profile->rules, 134 - typeof(*rules), list); 128 + struct aa_ruleset *rules = profile->label.rules[0]; 135 129 struct aa_profile *tp; 136 130 struct label_it i; 137 131 struct path_cond cond = { }; ··· 158 154 if (!state) 159 155 goto fail; 160 156 } 161 - *perms = *(aa_lookup_fperms(rules->file, state, &cond)); 157 + *perms = *(aa_lookup_condperms(current_fsuid(), rules->file, state, 158 + &cond)); 162 159 aa_apply_modes_to_perms(profile, perms); 163 160 if ((perms->allow & request) != request) 164 161 return -EACCES; ··· 192 187 aa_state_t start, bool subns, u32 request, 193 188 struct aa_perms *perms) 194 189 { 195 - struct aa_ruleset *rules = list_first_entry(&profile->rules, 196 - typeof(*rules), list); 190 + struct aa_ruleset *rules = profile->label.rules[0]; 197 191 struct aa_profile *tp; 198 192 struct label_it i; 199 193 struct aa_perms tmp; ··· 213 209 return 0; 214 210 215 211 next: 216 - tmp = *(aa_lookup_fperms(rules->file, state, &cond)); 212 + tmp = *(aa_lookup_condperms(current_fsuid(), rules->file, state, 213 + &cond)); 217 214 aa_apply_modes_to_perms(profile, &tmp); 218 215 aa_perms_accum(perms, &tmp); 219 216 label_for_each_cont(i, label, tp) { ··· 223 218 state = match_component(profile, tp, stack, start); 224 219 if (!state) 225 220 goto fail; 226 - tmp = *(aa_lookup_fperms(rules->file, state, &cond)); 221 + tmp = *(aa_lookup_condperms(current_fsuid(), rules->file, state, 222 + &cond)); 227 223 aa_apply_modes_to_perms(profile, &tmp); 228 224 aa_perms_accum(perms, &tmp); 229 225 } ··· 329 323 size = vfs_getxattr_alloc(&nop_mnt_idmap, d, attach->xattrs[i], 330 324 &value, value_size, GFP_KERNEL); 331 325 if (size >= 0) { 332 - u32 index, perm; 326 + struct aa_perms *perms; 333 327 334 328 /* 335 329 * Check the xattr presence before value. This ensure ··· 341 335 /* Check xattr value */ 342 336 state = aa_dfa_match_len(attach->xmatch->dfa, state, 343 337 value, size); 344 - index = ACCEPT_TABLE(attach->xmatch->dfa)[state]; 345 - perm = attach->xmatch->perms[index].allow; 346 - if (!(perm & MAY_EXEC)) { 338 + perms = aa_lookup_perms(attach->xmatch, state); 339 + if (!(perms->allow & MAY_EXEC)) { 347 340 ret = -EINVAL; 348 341 goto out; 349 342 } ··· 420 415 if (attach->xmatch->dfa) { 421 416 unsigned int count; 422 417 aa_state_t state; 423 - u32 index, perm; 418 + struct aa_perms *perms; 424 419 425 420 state = aa_dfa_leftmatch(attach->xmatch->dfa, 426 421 attach->xmatch->start[AA_CLASS_XMATCH], 427 422 name, &count); 428 - index = ACCEPT_TABLE(attach->xmatch->dfa)[state]; 429 - perm = attach->xmatch->perms[index].allow; 423 + perms = aa_lookup_perms(attach->xmatch, state); 430 424 /* any accepting state means a valid match. */ 431 - if (perm & MAY_EXEC) { 425 + if (perms->allow & MAY_EXEC) { 432 426 int ret = 0; 433 427 434 428 if (count < candidate_len) ··· 488 484 489 485 if (!candidate || conflict) { 490 486 if (conflict) 491 - *info = "conflicting profile attachments"; 487 + *info = CONFLICTING_ATTACH_STR; 492 488 rcu_read_unlock(); 493 489 return NULL; 494 490 } ··· 512 508 * @name: returns: name tested to find label (NOT NULL) 513 509 * 514 510 * Returns: refcounted label, or NULL on failure (MAYBE NULL) 511 + * @name will always be set with the last name tried 515 512 */ 516 513 struct aa_label *x_table_lookup(struct aa_profile *profile, u32 xindex, 517 514 const char **name) 518 515 { 519 - struct aa_ruleset *rules = list_first_entry(&profile->rules, 520 - typeof(*rules), list); 516 + struct aa_ruleset *rules = profile->label.rules[0]; 521 517 struct aa_label *label = NULL; 522 518 u32 xtype = xindex & AA_X_TYPE_MASK; 523 519 int index = xindex & AA_X_INDEX_MASK; 520 + const char *next; 524 521 525 522 AA_BUG(!name); 526 523 ··· 529 524 /* TODO: move lookup parsing to unpack time so this is a straight 530 525 * index into the resultant label 531 526 */ 532 - for (*name = rules->file->trans.table[index]; !label && *name; 533 - *name = next_name(xtype, *name)) { 527 + for (next = rules->file->trans.table[index]; next; 528 + next = next_name(xtype, next)) { 529 + const char *lookup = (*next == '&') ? next + 1 : next; 530 + *name = next; 534 531 if (xindex & AA_X_CHILD) { 535 - struct aa_profile *new_profile; 536 - /* release by caller */ 537 - new_profile = aa_find_child(profile, *name); 538 - if (new_profile) 539 - label = &new_profile->label; 532 + /* TODO: switich to parse to get stack of child */ 533 + struct aa_profile *new = aa_find_child(profile, lookup); 534 + 535 + if (new) 536 + /* release by caller */ 537 + return &new->label; 540 538 continue; 541 539 } 542 - label = aa_label_parse(&profile->label, *name, GFP_KERNEL, 540 + label = aa_label_parse(&profile->label, lookup, GFP_KERNEL, 543 541 true, false); 544 - if (IS_ERR(label)) 545 - label = NULL; 542 + if (!IS_ERR_OR_NULL(label)) 543 + /* release by caller */ 544 + return label; 546 545 } 547 546 548 - /* released by caller */ 549 - 550 - return label; 547 + return NULL; 551 548 } 552 549 553 550 /** ··· 571 564 const char **lookupname, 572 565 const char **info) 573 566 { 574 - struct aa_ruleset *rules = list_first_entry(&profile->rules, 575 - typeof(*rules), list); 576 567 struct aa_label *new = NULL; 568 + struct aa_label *stack = NULL; 577 569 struct aa_ns *ns = profile->ns; 578 570 u32 xtype = xindex & AA_X_TYPE_MASK; 579 - const char *stack = NULL; 571 + /* Used for info checks during fallback handling */ 572 + const char *old_info = NULL; 580 573 581 574 switch (xtype) { 582 575 case AA_X_NONE: ··· 585 578 break; 586 579 case AA_X_TABLE: 587 580 /* TODO: fix when perm mapping done at unload */ 588 - stack = rules->file->trans.table[xindex & AA_X_INDEX_MASK]; 589 - if (*stack != '&') { 590 - /* released by caller */ 591 - new = x_table_lookup(profile, xindex, lookupname); 592 - stack = NULL; 581 + /* released by caller 582 + * if null for both stack and direct want to try fallback 583 + */ 584 + new = x_table_lookup(profile, xindex, lookupname); 585 + if (!new || **lookupname != '&') 593 586 break; 594 - } 587 + stack = new; 588 + new = NULL; 595 589 fallthrough; /* to X_NAME */ 596 590 case AA_X_NAME: 597 591 if (xindex & AA_X_CHILD) ··· 607 599 break; 608 600 } 609 601 602 + /* fallback transition check */ 610 603 if (!new) { 611 604 if (xindex & AA_X_INHERIT) { 612 605 /* (p|c|n)ix - don't change profile but do 613 606 * use the newest version 614 607 */ 615 - *info = "ix fallback"; 608 + if (*info == CONFLICTING_ATTACH_STR) { 609 + *info = CONFLICTING_ATTACH_STR_IX; 610 + } else { 611 + old_info = *info; 612 + *info = "ix fallback"; 613 + } 616 614 /* no profile && no error */ 617 615 new = aa_get_newest_label(&profile->label); 618 616 } else if (xindex & AA_X_UNCONFINED) { 619 617 new = aa_get_newest_label(ns_unconfined(profile->ns)); 620 - *info = "ux fallback"; 618 + if (*info == CONFLICTING_ATTACH_STR) { 619 + *info = CONFLICTING_ATTACH_STR_UX; 620 + } else { 621 + old_info = *info; 622 + *info = "ux fallback"; 623 + } 624 + } 625 + /* We set old_info on the code paths above where overwriting 626 + * could have happened, so now check if info was set by 627 + * find_attach as well (i.e. whether we actually overwrote) 628 + * and warn accordingly. 629 + */ 630 + if (old_info && old_info != CONFLICTING_ATTACH_STR) { 631 + pr_warn_ratelimited( 632 + "AppArmor: find_attach (from profile %s) audit info \"%s\" dropped", 633 + profile->base.hname, old_info); 621 634 } 622 635 } 623 636 ··· 646 617 /* base the stack on post domain transition */ 647 618 struct aa_label *base = new; 648 619 649 - new = aa_label_parse(base, stack, GFP_KERNEL, true, false); 650 - if (IS_ERR(new)) 651 - new = NULL; 620 + new = aa_label_merge(base, stack, GFP_KERNEL); 621 + /* null on error */ 652 622 aa_put_label(base); 653 623 } 654 624 625 + aa_put_label(stack); 655 626 /* released by caller */ 656 627 return new; 657 628 } ··· 662 633 char *buffer, struct path_cond *cond, 663 634 bool *secure_exec) 664 635 { 665 - struct aa_ruleset *rules = list_first_entry(&profile->rules, 666 - typeof(*rules), list); 636 + struct aa_ruleset *rules = profile->label.rules[0]; 667 637 struct aa_label *new = NULL; 668 638 struct aa_profile *new_profile = NULL; 669 639 const char *info = NULL, *name = NULL, *target = NULL; ··· 680 652 if (error) { 681 653 if (profile_unconfined(profile) || 682 654 (profile->label.flags & FLAG_IX_ON_NAME_ERROR)) { 683 - AA_DEBUG("name lookup ix on error"); 655 + AA_DEBUG(DEBUG_DOMAIN, "name lookup ix on error"); 684 656 error = 0; 685 657 new = aa_get_newest_label(&profile->label); 686 658 } ··· 691 663 if (profile_unconfined(profile)) { 692 664 new = find_attach(bprm, profile->ns, 693 665 &profile->ns->base.profiles, name, &info); 666 + /* info set -> something unusual that we should report 667 + * Currently this is only conflicting attachments, but other 668 + * infos added in the future should also be logged by default 669 + * and only excluded on a case-by-case basis 670 + */ 671 + if (info) { 672 + /* Because perms is never used again after this audit 673 + * we don't need to care about clobbering it 674 + */ 675 + perms.audit |= MAY_EXEC; 676 + perms.allow |= MAY_EXEC; 677 + /* Don't cause error if auditing fails */ 678 + (void) aa_audit_file(subj_cred, profile, &perms, 679 + OP_EXEC, MAY_EXEC, name, target, new, cond->uid, 680 + info, error); 681 + } 694 682 if (new) { 695 - AA_DEBUG("unconfined attached to new label"); 683 + AA_DEBUG(DEBUG_DOMAIN, "unconfined attached to new label"); 696 684 return new; 697 685 } 698 - AA_DEBUG("unconfined exec no attachment"); 686 + AA_DEBUG(DEBUG_DOMAIN, "unconfined exec no attachment"); 699 687 return aa_get_newest_label(&profile->label); 700 688 } 701 689 ··· 722 678 new = x_to_label(profile, bprm, name, perms.xindex, &target, 723 679 &info); 724 680 if (new && new->proxy == profile->label.proxy && info) { 681 + /* Force audit on conflicting attachment fallback 682 + * Because perms is never used again after this audit 683 + * we don't need to care about clobbering it 684 + */ 685 + if (info == CONFLICTING_ATTACH_STR_IX 686 + || info == CONFLICTING_ATTACH_STR_UX) 687 + perms.audit |= MAY_EXEC; 725 688 /* hack ix fallback - improve how this is detected */ 726 689 goto audit; 727 690 } else if (!new) { 691 + if (info) { 692 + pr_warn_ratelimited( 693 + "AppArmor: %s (from profile %s) audit info \"%s\" dropped on missing transition", 694 + __func__, profile->base.hname, info); 695 + } 728 696 info = "profile transition not found"; 729 697 /* remove MAY_EXEC to audit as failure or complaint */ 730 698 perms.allow &= ~MAY_EXEC; ··· 795 739 char *buffer, struct path_cond *cond, 796 740 bool *secure_exec) 797 741 { 798 - struct aa_ruleset *rules = list_first_entry(&profile->rules, 799 - typeof(*rules), list); 742 + struct aa_ruleset *rules = profile->label.rules[0]; 800 743 aa_state_t state = rules->file->start[AA_CLASS_FILE]; 801 744 struct aa_perms perms = {}; 802 745 const char *xname = NULL, *info = "change_profile onexec"; ··· 810 755 /* change_profile on exec already granted */ 811 756 /* 812 757 * NOTE: Domain transitions from unconfined are allowed 813 - * even when no_new_privs is set because this aways results 758 + * even when no_new_privs is set because this always results 814 759 * in a further reduction of permissions. 815 760 */ 816 761 return 0; ··· 821 766 if (error) { 822 767 if (profile_unconfined(profile) || 823 768 (profile->label.flags & FLAG_IX_ON_NAME_ERROR)) { 824 - AA_DEBUG("name lookup ix on error"); 769 + AA_DEBUG(DEBUG_DOMAIN, "name lookup ix on error"); 825 770 error = 0; 826 771 } 827 772 xname = bprm->filename; ··· 981 926 * 982 927 * NOTE: Domain transitions from unconfined and to stacked 983 928 * subsets are allowed even when no_new_privs is set because this 984 - * aways results in a further reduction of permissions. 929 + * always results in a further reduction of permissions. 985 930 */ 986 931 if ((bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS) && 987 932 !unconfined(label) && ··· 1243 1188 if (task_no_new_privs(current) && !unconfined(label) && !ctx->nnp) 1244 1189 ctx->nnp = aa_get_label(label); 1245 1190 1191 + /* return -EPERM when unconfined doesn't have children to avoid 1192 + * changing the traditional error code for unconfined. 1193 + */ 1246 1194 if (unconfined(label)) { 1247 - info = "unconfined can not change_hat"; 1248 - error = -EPERM; 1249 - goto fail; 1195 + struct label_it i; 1196 + bool empty = true; 1197 + 1198 + rcu_read_lock(); 1199 + label_for_each_in_ns(i, labels_ns(label), label, profile) { 1200 + empty &= list_empty(&profile->base.profiles); 1201 + } 1202 + rcu_read_unlock(); 1203 + 1204 + if (empty) { 1205 + info = "unconfined can not change_hat"; 1206 + error = -EPERM; 1207 + goto fail; 1208 + } 1250 1209 } 1251 1210 1252 1211 if (count) { ··· 1285 1216 if (task_no_new_privs(current) && !unconfined(label) && 1286 1217 !aa_label_is_unconfined_subset(new, ctx->nnp)) { 1287 1218 /* not an apparmor denial per se, so don't log it */ 1288 - AA_DEBUG("no_new_privs - change_hat denied"); 1219 + AA_DEBUG(DEBUG_DOMAIN, 1220 + "no_new_privs - change_hat denied"); 1289 1221 error = -EPERM; 1290 1222 goto out; 1291 1223 } ··· 1307 1237 if (task_no_new_privs(current) && !unconfined(label) && 1308 1238 !aa_label_is_unconfined_subset(previous, ctx->nnp)) { 1309 1239 /* not an apparmor denial per se, so don't log it */ 1310 - AA_DEBUG("no_new_privs - change_hat denied"); 1240 + AA_DEBUG(DEBUG_DOMAIN, 1241 + "no_new_privs - change_hat denied"); 1311 1242 error = -EPERM; 1312 1243 goto out; 1313 1244 } ··· 1353 1282 struct aa_label *target, bool stack, 1354 1283 u32 request, struct aa_perms *perms) 1355 1284 { 1356 - struct aa_ruleset *rules = list_first_entry(&profile->rules, 1357 - typeof(*rules), list); 1285 + struct aa_ruleset *rules = profile->label.rules[0]; 1358 1286 const char *info = NULL; 1359 1287 int error = 0; 1360 1288 ··· 1413 1343 1414 1344 if (!fqname || !*fqname) { 1415 1345 aa_put_label(label); 1416 - AA_DEBUG("no profile name"); 1346 + AA_DEBUG(DEBUG_DOMAIN, "no profile name"); 1417 1347 return -EINVAL; 1418 1348 } 1419 1349 ··· 1532 1462 if (task_no_new_privs(current) && !unconfined(label) && 1533 1463 !aa_label_is_unconfined_subset(new, ctx->nnp)) { 1534 1464 /* not an apparmor denial per se, so don't log it */ 1535 - AA_DEBUG("no_new_privs - change_hat denied"); 1465 + AA_DEBUG(DEBUG_DOMAIN, 1466 + "no_new_privs - change_hat denied"); 1536 1467 error = -EPERM; 1537 1468 goto out; 1538 1469 }
+63 -29
security/apparmor/file.c
··· 14 14 #include <linux/fs.h> 15 15 #include <linux/mount.h> 16 16 17 + #include "include/af_unix.h" 17 18 #include "include/apparmor.h" 18 19 #include "include/audit.h" 19 20 #include "include/cred.h" ··· 169 168 170 169 struct aa_perms default_perms = {}; 171 170 /** 172 - * aa_lookup_fperms - convert dfa compressed perms to internal perms 173 - * @file_rules: the aa_policydb to lookup perms for (NOT NULL) 171 + * aa_lookup_condperms - convert dfa compressed perms to internal perms 172 + * @subj_uid: uid to use for subject owner test 173 + * @rules: the aa_policydb to lookup perms for (NOT NULL) 174 174 * @state: state in dfa 175 175 * @cond: conditions to consider (NOT NULL) 176 176 * ··· 179 177 * 180 178 * Returns: a pointer to a file permission set 181 179 */ 182 - struct aa_perms *aa_lookup_fperms(struct aa_policydb *file_rules, 183 - aa_state_t state, struct path_cond *cond) 180 + struct aa_perms *aa_lookup_condperms(kuid_t subj_uid, struct aa_policydb *rules, 181 + aa_state_t state, struct path_cond *cond) 184 182 { 185 - unsigned int index = ACCEPT_TABLE(file_rules->dfa)[state]; 183 + unsigned int index = ACCEPT_TABLE(rules->dfa)[state]; 186 184 187 - if (!(file_rules->perms)) 185 + if (!(rules->perms)) 188 186 return &default_perms; 189 187 190 - if (uid_eq(current_fsuid(), cond->uid)) 191 - return &(file_rules->perms[index]); 188 + if ((ACCEPT_TABLE2(rules->dfa)[state] & ACCEPT_FLAG_OWNER)) { 189 + if (uid_eq(subj_uid, cond->uid)) 190 + return &(rules->perms[index]); 191 + return &(rules->perms[index + 1]); 192 + } 192 193 193 - return &(file_rules->perms[index + 1]); 194 + return &(rules->perms[index]); 194 195 } 195 196 196 197 /** ··· 212 207 { 213 208 aa_state_t state; 214 209 state = aa_dfa_match(file_rules->dfa, start, name); 215 - *perms = *(aa_lookup_fperms(file_rules, state, cond)); 210 + *perms = *(aa_lookup_condperms(current_fsuid(), file_rules, state, 211 + cond)); 216 212 217 213 return state; 218 214 } 219 215 220 - static int __aa_path_perm(const char *op, const struct cred *subj_cred, 221 - struct aa_profile *profile, const char *name, 222 - u32 request, struct path_cond *cond, int flags, 223 - struct aa_perms *perms) 216 + int __aa_path_perm(const char *op, const struct cred *subj_cred, 217 + struct aa_profile *profile, const char *name, 218 + u32 request, struct path_cond *cond, int flags, 219 + struct aa_perms *perms) 224 220 { 225 - struct aa_ruleset *rules = list_first_entry(&profile->rules, 226 - typeof(*rules), list); 221 + struct aa_ruleset *rules = profile->label.rules[0]; 227 222 int e = 0; 228 223 229 - if (profile_unconfined(profile)) 224 + if (profile_unconfined(profile) || 225 + ((flags & PATH_SOCK_COND) && !RULE_MEDIATES_v9NET(rules))) 230 226 return 0; 231 227 aa_str_perms(rules->file, rules->file->start[AA_CLASS_FILE], 232 228 name, cond, perms); ··· 322 316 const struct path *target, char *buffer2, 323 317 struct path_cond *cond) 324 318 { 325 - struct aa_ruleset *rules = list_first_entry(&profile->rules, 326 - typeof(*rules), list); 319 + struct aa_ruleset *rules = profile->label.rules[0]; 327 320 const char *lname, *tname = NULL; 328 321 struct aa_perms lperms = {}, perms; 329 322 const char *info = NULL; ··· 428 423 { 429 424 struct path link = { .mnt = new_dir->mnt, .dentry = new_dentry }; 430 425 struct path target = { .mnt = new_dir->mnt, .dentry = old_dentry }; 426 + struct inode *inode = d_backing_inode(old_dentry); 427 + vfsuid_t vfsuid = i_uid_into_vfsuid(mnt_idmap(target.mnt), inode); 431 428 struct path_cond cond = { 432 - d_backing_inode(old_dentry)->i_uid, 433 - d_backing_inode(old_dentry)->i_mode 429 + .uid = vfsuid_into_kuid(vfsuid), 430 + .mode = inode->i_mode, 434 431 }; 435 432 char *buffer = NULL, *buffer2 = NULL; 436 433 struct aa_profile *profile; ··· 541 534 struct aa_label *flabel, struct file *file, 542 535 u32 request, u32 denied) 543 536 { 544 - struct socket *sock = (struct socket *) file->private_data; 545 537 int error; 546 - 547 - AA_BUG(!sock); 548 538 549 539 /* revalidation due to label out of date. No revocation at this time */ 550 540 if (!denied && aa_label_is_subset(flabel, label)) 551 541 return 0; 552 542 553 543 /* TODO: improve to skip profiles cached in flabel */ 554 - error = aa_sock_file_perm(subj_cred, label, op, request, sock); 544 + error = aa_sock_file_perm(subj_cred, label, op, request, file); 555 545 if (denied) { 556 546 /* TODO: improve to skip profiles checked above */ 557 547 /* check every profile in file label to is cached */ 558 548 last_error(error, aa_sock_file_perm(subj_cred, flabel, op, 559 - request, sock)); 549 + request, file)); 560 550 } 561 551 if (!error) 562 552 update_file_ctx(file_ctx(file), label, request); 563 553 564 554 return error; 555 + } 556 + 557 + /* for now separate fn to indicate semantics of the check */ 558 + static bool __file_is_delegated(struct aa_label *obj_label) 559 + { 560 + return unconfined(obj_label); 561 + } 562 + 563 + static bool __unix_needs_revalidation(struct file *file, struct aa_label *label, 564 + u32 request) 565 + { 566 + struct socket *sock = (struct socket *) file->private_data; 567 + 568 + lockdep_assert_in_rcu_read_lock(); 569 + 570 + if (!S_ISSOCK(file_inode(file)->i_mode)) 571 + return false; 572 + if (request & NET_PEER_MASK) 573 + return false; 574 + if (sock->sk->sk_family == PF_UNIX) { 575 + struct aa_sk_ctx *ctx = aa_sock(sock->sk); 576 + 577 + if (rcu_access_pointer(ctx->peer) != 578 + rcu_access_pointer(ctx->peer_lastupdate)) 579 + return true; 580 + return !__aa_subj_label_is_cached(rcu_dereference(ctx->label), 581 + label); 582 + } 583 + return false; 565 584 } 566 585 567 586 /** ··· 627 594 * delegation from unconfined tasks 628 595 */ 629 596 denied = request & ~fctx->allow; 630 - if (unconfined(label) || unconfined(flabel) || 631 - (!denied && aa_label_is_subset(flabel, label))) { 597 + if (unconfined(label) || __file_is_delegated(flabel) || 598 + __unix_needs_revalidation(file, label, request) || 599 + (!denied && __aa_subj_label_is_cached(label, flabel))) { 632 600 rcu_read_unlock(); 633 601 goto done; 634 602 } 635 603 604 + /* slow path - revalidate access */ 636 605 flabel = aa_get_newest_label(flabel); 637 606 rcu_read_unlock(); 638 - /* TODO: label cross check */ 639 607 640 608 if (path_mediated_fs(file->f_path.dentry)) 641 609 error = __file_path_perm(op, subj_cred, label, flabel, file,
+55
security/apparmor/include/af_unix.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* 3 + * AppArmor security module 4 + * 5 + * This file contains AppArmor af_unix fine grained mediation 6 + * 7 + * Copyright 2023 Canonical Ltd. 8 + * 9 + * This program is free software; you can redistribute it and/or 10 + * modify it under the terms of the GNU General Public License as 11 + * published by the Free Software Foundation, version 2 of the 12 + * License. 13 + */ 14 + #ifndef __AA_AF_UNIX_H 15 + 16 + #include <net/af_unix.h> 17 + 18 + #include "label.h" 19 + 20 + #define unix_addr(A) ((struct sockaddr_un *)(A)) 21 + #define unix_addr_len(L) ((L) - sizeof(sa_family_t)) 22 + #define unix_peer(sk) (unix_sk(sk)->peer) 23 + #define is_unix_addr_abstract_name(B) ((B)[0] == 0) 24 + #define is_unix_addr_anon(A, L) ((A) && unix_addr_len(L) <= 0) 25 + #define is_unix_addr_fs(A, L) (!is_unix_addr_anon(A, L) && \ 26 + !is_unix_addr_abstract_name(unix_addr(A)->sun_path)) 27 + 28 + #define is_unix_anonymous(U) (!unix_sk(U)->addr) 29 + #define is_unix_fs(U) (!is_unix_anonymous(U) && \ 30 + unix_sk(U)->addr->name->sun_path[0]) 31 + #define is_unix_connected(S) ((S)->state == SS_CONNECTED) 32 + 33 + 34 + struct sockaddr_un *aa_sunaddr(const struct unix_sock *u, int *addrlen); 35 + int aa_unix_peer_perm(const struct cred *subj_cred, 36 + struct aa_label *label, const char *op, u32 request, 37 + struct sock *sk, struct sock *peer_sk, 38 + struct aa_label *peer_label); 39 + int aa_unix_sock_perm(const char *op, u32 request, struct socket *sock); 40 + int aa_unix_create_perm(struct aa_label *label, int family, int type, 41 + int protocol); 42 + int aa_unix_bind_perm(struct socket *sock, struct sockaddr *address, 43 + int addrlen); 44 + int aa_unix_connect_perm(struct socket *sock, struct sockaddr *address, 45 + int addrlen); 46 + int aa_unix_listen_perm(struct socket *sock, int backlog); 47 + int aa_unix_accept_perm(struct socket *sock, struct socket *newsock); 48 + int aa_unix_msg_perm(const char *op, u32 request, struct socket *sock, 49 + struct msghdr *msg, int size); 50 + int aa_unix_opt_perm(const char *op, u32 request, struct socket *sock, int level, 51 + int optname); 52 + int aa_unix_file_perm(const struct cred *subj_cred, struct aa_label *label, 53 + const char *op, u32 request, struct file *file); 54 + 55 + #endif /* __AA_AF_UNIX_H */
+3 -1
security/apparmor/include/apparmor.h
··· 28 28 #define AA_CLASS_SIGNAL 10 29 29 #define AA_CLASS_XMATCH 11 30 30 #define AA_CLASS_NET 14 31 + #define AA_CLASS_NETV9 15 31 32 #define AA_CLASS_LABEL 16 32 33 #define AA_CLASS_POSIX_MQUEUE 17 33 34 #define AA_CLASS_MODULE 19 ··· 39 38 #define AA_CLASS_X 31 40 39 #define AA_CLASS_DBUS 32 41 40 41 + /* NOTE: if AA_CLASS_LAST > 63 need to update label->mediates */ 42 42 #define AA_CLASS_LAST AA_CLASS_DBUS 43 43 44 44 /* Control parameters settable through module/boot flags */ 45 45 extern enum audit_mode aa_g_audit; 46 46 extern bool aa_g_audit_header; 47 - extern bool aa_g_debug; 47 + extern int aa_g_debug; 48 48 extern bool aa_g_hash_policy; 49 49 extern bool aa_g_export_binary; 50 50 extern int aa_g_rawdata_compression_level;
+4 -1
security/apparmor/include/audit.h
··· 138 138 }; 139 139 struct { 140 140 int type, protocol; 141 - struct sock *peer_sk; 142 141 void *addr; 143 142 int addrlen; 143 + struct { 144 + void *addr; 145 + int addrlen; 146 + } peer; 144 147 } net; 145 148 }; 146 149 };
+1
security/apparmor/include/capability.h
··· 36 36 37 37 extern struct aa_sfs_entry aa_sfs_entry_caps[]; 38 38 39 + kernel_cap_t aa_profile_capget(struct aa_profile *profile); 39 40 int aa_capable(const struct cred *subj_cred, struct aa_label *label, 40 41 int cap, unsigned int opts); 41 42
+24 -7
security/apparmor/include/cred.h
··· 114 114 return aa_get_label(l); 115 115 } 116 116 117 - #define __end_current_label_crit_section(X) end_current_label_crit_section(X) 117 + /** 118 + * __end_current_label_crit_section - end crit section begun with __begin_... 119 + * @label: label obtained from __begin_current_label_crit_section 120 + * @needput: output: bool set by __begin_current_label_crit_section 121 + * 122 + * Returns: label to use for this crit section 123 + */ 124 + static inline void __end_current_label_crit_section(struct aa_label *label, 125 + bool needput) 126 + { 127 + if (unlikely(needput)) 128 + aa_put_label(label); 129 + } 118 130 119 131 /** 120 - * end_label_crit_section - put a reference found with begin_current_label.. 132 + * end_current_label_crit_section - put a reference found with begin_current_label.. 121 133 * @label: label reference to put 122 134 * 123 135 * Should only be used with a reference obtained with ··· 144 132 145 133 /** 146 134 * __begin_current_label_crit_section - current's confining label 135 + * @needput: store whether the label needs to be put when ending crit section 147 136 * 148 137 * Returns: up to date confining label or the ns unconfined label (NOT NULL) 149 138 * ··· 155 142 * critical section between __begin_current_label_crit_section() .. 156 143 * __end_current_label_crit_section() 157 144 */ 158 - static inline struct aa_label *__begin_current_label_crit_section(void) 145 + static inline struct aa_label *__begin_current_label_crit_section(bool *needput) 159 146 { 160 147 struct aa_label *label = aa_current_raw_label(); 161 148 162 - if (label_is_stale(label)) 163 - label = aa_get_newest_label(label); 149 + if (label_is_stale(label)) { 150 + *needput = true; 151 + return aa_get_newest_label(label); 152 + } 164 153 154 + *needput = false; 165 155 return label; 166 156 } 167 157 ··· 200 184 { 201 185 struct aa_label *label; 202 186 struct aa_ns *ns; 187 + bool needput; 203 188 204 - label = __begin_current_label_crit_section(); 189 + label = __begin_current_label_crit_section(&needput); 205 190 ns = aa_get_ns(labels_ns(label)); 206 - __end_current_label_crit_section(label); 191 + __end_current_label_crit_section(label, needput); 207 192 208 193 return ns; 209 194 }
+8 -3
security/apparmor/include/file.h
··· 77 77 const char *target, struct aa_label *tlabel, kuid_t ouid, 78 78 const char *info, int error); 79 79 80 - struct aa_perms *aa_lookup_fperms(struct aa_policydb *file_rules, 81 - aa_state_t state, struct path_cond *cond); 80 + struct aa_perms *aa_lookup_condperms(kuid_t subj_uid, 81 + struct aa_policydb *file_rules, 82 + aa_state_t state, struct path_cond *cond); 82 83 aa_state_t aa_str_perms(struct aa_policydb *file_rules, aa_state_t start, 83 84 const char *name, struct path_cond *cond, 84 85 struct aa_perms *perms); 85 86 87 + int __aa_path_perm(const char *op, const struct cred *subj_cred, 88 + struct aa_profile *profile, const char *name, 89 + u32 request, struct path_cond *cond, int flags, 90 + struct aa_perms *perms); 86 91 int aa_path_perm(const char *op, const struct cred *subj_cred, 87 92 struct aa_label *label, const struct path *path, 88 93 int flags, u32 request, struct path_cond *cond); ··· 104 99 105 100 106 101 /** 107 - * aa_map_file_perms - map file flags to AppArmor permissions 102 + * aa_map_file_to_perms - map file flags to AppArmor permissions 108 103 * @file: open file to map flags to AppArmor permissions 109 104 * 110 105 * Returns: apparmor permission set for the file
+3
security/apparmor/include/ipc.h
··· 13 13 14 14 #include <linux/sched.h> 15 15 16 + #define SIGUNKNOWN 0 17 + #define MAXMAPPED_SIG 35 18 + 16 19 int aa_may_signal(const struct cred *subj_cred, struct aa_label *sender, 17 20 const struct cred *target_cred, struct aa_label *target, 18 21 int sig);
+35 -16
security/apparmor/include/label.h
··· 19 19 #include "lib.h" 20 20 21 21 struct aa_ns; 22 + struct aa_ruleset; 22 23 23 24 #define LOCAL_VEC_ENTRIES 8 24 25 #define DEFINE_VEC(T, V) \ ··· 110 109 int i, j; 111 110 }; 112 111 113 - /* struct aa_label - lazy labeling struct 112 + /* struct aa_label_base - base info of label 114 113 * @count: ref count of active users 115 114 * @node: rbtree position 116 115 * @rcu: rcu callback struct ··· 119 118 * @flags: stale and other flags - values may change under label set lock 120 119 * @secid: secid that references this label 121 120 * @size: number of entries in @ent[] 122 - * @ent: set of profiles for label, actual size determined by @size 121 + * @mediates: bitmask for label_mediates 122 + * profile: label vec when embedded in a profile FLAG_PROFILE is set 123 + * rules: variable length rules in a profile FLAG_PROFILE is set 124 + * vec: vector of profiles comprising the compound label 123 125 */ 124 126 struct aa_label { 125 127 struct kref count; ··· 133 129 long flags; 134 130 u32 secid; 135 131 int size; 136 - struct aa_profile *vec[]; 132 + u64 mediates; 133 + union { 134 + struct { 135 + /* only used is the label is a profile, size of 136 + * rules[] is determined by the profile 137 + * profile[1] is poison or null as guard 138 + */ 139 + struct aa_profile *profile[2]; 140 + DECLARE_FLEX_ARRAY(struct aa_ruleset *, rules); 141 + }; 142 + DECLARE_FLEX_ARRAY(struct aa_profile *, vec); 143 + }; 137 144 }; 138 145 139 146 #define last_error(E, FN) \ ··· 246 231 #define fn_for_each_not_in_set(L1, L2, P, FN) \ 247 232 fn_for_each2_XXX((L1), (L2), P, FN, _not_in_set) 248 233 249 - #define LABEL_MEDIATES(L, C) \ 250 - ({ \ 251 - struct aa_profile *profile; \ 252 - struct label_it i; \ 253 - int ret = 0; \ 254 - label_for_each(i, (L), profile) { \ 255 - if (RULE_MEDIATES(&profile->rules, (C))) { \ 256 - ret = 1; \ 257 - break; \ 258 - } \ 259 - } \ 260 - ret; \ 261 - }) 234 + static inline bool label_mediates(struct aa_label *L, unsigned char C) 235 + { 236 + return (L)->mediates & (((u64) 1) << (C)); 237 + } 262 238 239 + static inline bool label_mediates_safe(struct aa_label *L, unsigned char C) 240 + { 241 + if (C > AA_CLASS_LAST) 242 + return false; 243 + return label_mediates(L, C); 244 + } 263 245 264 246 void aa_labelset_destroy(struct aa_labelset *ls); 265 247 void aa_labelset_init(struct aa_labelset *ls); ··· 427 415 { 428 416 if (l) 429 417 kref_put(&l->count, aa_label_kref); 418 + } 419 + 420 + /* wrapper fn to indicate semantics of the check */ 421 + static inline bool __aa_subj_label_is_cached(struct aa_label *subj_label, 422 + struct aa_label *obj_label) 423 + { 424 + return aa_label_is_subset(obj_label, subj_label); 430 425 } 431 426 432 427
+33 -13
security/apparmor/include/lib.h
··· 19 19 extern struct aa_dfa *stacksplitdfa; 20 20 21 21 /* 22 - * DEBUG remains global (no per profile flag) since it is mostly used in sysctl 23 - * which is not related to profile accesses. 24 - */ 25 - 26 - #define DEBUG_ON (aa_g_debug) 27 - /* 28 22 * split individual debug cases out in preparation for finer grained 29 23 * debug controls in the future. 30 24 */ 31 - #define AA_DEBUG_LABEL DEBUG_ON 32 25 #define dbg_printk(__fmt, __args...) pr_debug(__fmt, ##__args) 33 - #define AA_DEBUG(fmt, args...) \ 26 + 27 + #define DEBUG_NONE 0 28 + #define DEBUG_LABEL_ABS_ROOT 1 29 + #define DEBUG_LABEL 2 30 + #define DEBUG_DOMAIN 4 31 + #define DEBUG_POLICY 8 32 + #define DEBUG_INTERFACE 0x10 33 + 34 + #define DEBUG_ALL 0x1f /* update if new DEBUG_X added */ 35 + #define DEBUG_PARSE_ERROR (-1) 36 + 37 + #define DEBUG_ON (aa_g_debug != DEBUG_NONE) 38 + #define DEBUG_ABS_ROOT (aa_g_debug & DEBUG_LABEL_ABS_ROOT) 39 + 40 + #define AA_DEBUG(opt, fmt, args...) \ 34 41 do { \ 35 - if (DEBUG_ON) \ 36 - pr_debug_ratelimited("AppArmor: " fmt, ##args); \ 42 + if (aa_g_debug & opt) \ 43 + pr_warn_ratelimited("%s: " fmt, __func__, ##args); \ 37 44 } while (0) 45 + #define AA_DEBUG_LABEL(LAB, X, fmt, args...) \ 46 + do { \ 47 + if ((LAB)->flags & FLAG_DEBUG1) \ 48 + AA_DEBUG(X, fmt, args); \ 49 + } while (0) 38 50 39 51 #define AA_WARN(X) WARN((X), "APPARMOR WARN %s: %s\n", __func__, #X) 40 52 ··· 60 48 #define AA_BUG_FMT(X, fmt, args...) \ 61 49 WARN((X), "AppArmor WARN %s: (" #X "): " fmt, __func__, ##args) 62 50 #else 63 - #define AA_BUG_FMT(X, fmt, args...) no_printk(fmt, ##args) 51 + #define AA_BUG_FMT(X, fmt, args...) \ 52 + do { \ 53 + BUILD_BUG_ON_INVALID(X); \ 54 + no_printk(fmt, ##args); \ 55 + } while (0) 64 56 #endif 57 + 58 + int aa_parse_debug_params(const char *str); 59 + int aa_print_debug_params(char *buffer); 65 60 66 61 #define AA_ERROR(fmt, args...) \ 67 62 pr_err_ratelimited("AppArmor: " fmt, ##args) ··· 125 106 }; 126 107 127 108 void aa_free_str_table(struct aa_str_table *table); 109 + bool aa_resize_str_table(struct aa_str_table *t, int newsize, gfp_t gfp); 128 110 129 111 struct counted_str { 130 112 struct kref count; ··· 171 151 172 152 /** 173 153 * basename - find the last component of an hname 174 - * @name: hname to find the base profile name component of (NOT NULL) 154 + * @hname: hname to find the base profile name component of (NOT NULL) 175 155 * 176 156 * Returns: the tail (base profile name) name component of an hname 177 157 */ ··· 301 281 } \ 302 282 __done: \ 303 283 if (!__new_) \ 304 - AA_DEBUG("label build failed\n"); \ 284 + AA_DEBUG(DEBUG_LABEL, "label build failed\n"); \ 305 285 (__new_); \ 306 286 }) 307 287
+4 -6
security/apparmor/include/match.h
··· 17 17 #define DFA_START 1 18 18 19 19 20 - /** 20 + /* 21 21 * The format used for transition tables is based on the GNU flex table 22 22 * file format (--tables-file option; see Table File Format in the flex 23 23 * info pages and the flex sources for documentation). The magic number ··· 137 137 138 138 void aa_dfa_free_kref(struct kref *kref); 139 139 140 - #define WB_HISTORY_SIZE 24 140 + /* This needs to be a power of 2 */ 141 + #define WB_HISTORY_SIZE 32 141 142 struct match_workbuf { 142 - unsigned int count; 143 143 unsigned int pos; 144 144 unsigned int len; 145 - unsigned int size; /* power of 2, same as history size */ 146 - unsigned int history[WB_HISTORY_SIZE]; 145 + aa_state_t history[WB_HISTORY_SIZE]; 147 146 }; 148 147 #define DEFINE_MATCH_WB(N) \ 149 148 struct match_workbuf N = { \ 150 - .count = 0, \ 151 149 .pos = 0, \ 152 150 .len = 0, \ 153 151 }
+18 -18
security/apparmor/include/net.h
··· 47 47 #define NET_PEER_MASK (AA_MAY_SEND | AA_MAY_RECEIVE | AA_MAY_CONNECT | \ 48 48 AA_MAY_ACCEPT) 49 49 struct aa_sk_ctx { 50 - struct aa_label *label; 51 - struct aa_label *peer; 50 + struct aa_label __rcu *label; 51 + struct aa_label __rcu *peer; 52 + struct aa_label __rcu *peer_lastupdate; /* ptr cmp only, no deref */ 52 53 }; 53 54 54 55 static inline struct aa_sk_ctx *aa_sock(const struct sock *sk) ··· 57 56 return sk->sk_security + apparmor_blob_sizes.lbs_sock; 58 57 } 59 58 60 - #define DEFINE_AUDIT_NET(NAME, OP, SK, F, T, P) \ 59 + #define DEFINE_AUDIT_NET(NAME, OP, CRED, SK, F, T, P) \ 61 60 struct lsm_network_audit NAME ## _net = { .sk = (SK), \ 62 61 .family = (F)}; \ 63 62 DEFINE_AUDIT_DATA(NAME, \ ··· 66 65 AA_CLASS_NET, \ 67 66 OP); \ 68 67 NAME.common.u.net = &(NAME ## _net); \ 68 + NAME.subj_cred = (CRED); \ 69 69 NAME.net.type = (T); \ 70 70 NAME.net.protocol = (P) 71 71 72 - #define DEFINE_AUDIT_SK(NAME, OP, SK) \ 73 - DEFINE_AUDIT_NET(NAME, OP, SK, (SK)->sk_family, (SK)->sk_type, \ 72 + #define DEFINE_AUDIT_SK(NAME, OP, CRED, SK) \ 73 + DEFINE_AUDIT_NET(NAME, OP, CRED, SK, (SK)->sk_family, (SK)->sk_type, \ 74 74 (SK)->sk_protocol) 75 75 76 - 77 - #define af_select(FAMILY, FN, DEF_FN) \ 78 - ({ \ 79 - int __e; \ 80 - switch ((FAMILY)) { \ 81 - default: \ 82 - __e = DEF_FN; \ 83 - } \ 84 - __e; \ 85 - }) 86 76 87 77 struct aa_secmark { 88 78 u8 audit; ··· 83 91 }; 84 92 85 93 extern struct aa_sfs_entry aa_sfs_entry_network[]; 94 + extern struct aa_sfs_entry aa_sfs_entry_networkv9[]; 86 95 96 + int aa_do_perms(struct aa_profile *profile, struct aa_policydb *policy, 97 + aa_state_t state, u32 request, struct aa_perms *p, 98 + struct apparmor_audit_data *ad); 99 + /* passing in state returned by XXX_mediates_AF() */ 100 + aa_state_t aa_match_to_prot(struct aa_policydb *policy, aa_state_t state, 101 + u32 request, u16 af, int type, int protocol, 102 + struct aa_perms **p, const char **info); 87 103 void audit_net_cb(struct audit_buffer *ab, void *va); 88 104 int aa_profile_af_perm(struct aa_profile *profile, 89 105 struct apparmor_audit_data *ad, 90 - u32 request, u16 family, int type); 106 + u32 request, u16 family, int type, int protocol); 91 107 int aa_af_perm(const struct cred *subj_cred, struct aa_label *label, 92 108 const char *op, u32 request, u16 family, 93 109 int type, int protocol); ··· 105 105 struct sock *sk) 106 106 { 107 107 return aa_profile_af_perm(profile, ad, request, sk->sk_family, 108 - sk->sk_type); 108 + sk->sk_type, sk->sk_protocol); 109 109 } 110 110 int aa_sk_perm(const char *op, u32 request, struct sock *sk); 111 111 112 112 int aa_sock_file_perm(const struct cred *subj_cred, struct aa_label *label, 113 113 const char *op, u32 request, 114 - struct socket *sock); 114 + struct file *file); 115 115 116 116 int apparmor_secmark_check(struct aa_label *label, char *op, u32 request, 117 117 u32 secid, const struct sock *sk);
+1
security/apparmor/include/path.h
··· 13 13 14 14 enum path_flags { 15 15 PATH_IS_DIR = 0x1, /* path is a directory */ 16 + PATH_SOCK_COND = 0x2, 16 17 PATH_CONNECT_PATH = 0x4, /* connect disconnected paths to / */ 17 18 PATH_CHROOT_REL = 0x8, /* do path lookup relative to chroot */ 18 19 PATH_CHROOT_NSCONNECT = 0x10, /* connect paths that are at ns root */
+4 -4
security/apparmor/include/perms.h
··· 101 101 102 102 /** 103 103 * aa_perms_accum_raw - accumulate perms with out masking off overlapping perms 104 - * @accum - perms struct to accumulate into 105 - * @addend - perms struct to add to @accum 104 + * @accum: perms struct to accumulate into 105 + * @addend: perms struct to add to @accum 106 106 */ 107 107 static inline void aa_perms_accum_raw(struct aa_perms *accum, 108 108 struct aa_perms *addend) ··· 128 128 129 129 /** 130 130 * aa_perms_accum - accumulate perms, masking off overlapping perms 131 - * @accum - perms struct to accumulate into 132 - * @addend - perms struct to add to @accum 131 + * @accum: perms struct to accumulate into 132 + * @addend: perms struct to add to @accum 133 133 */ 134 134 static inline void aa_perms_accum(struct aa_perms *accum, 135 135 struct aa_perms *addend)
+45 -18
security/apparmor/include/policy.h
··· 59 59 60 60 #define on_list_rcu(X) (!list_empty(X) && (X)->prev != LIST_POISON2) 61 61 62 + /* flags in the dfa accept2 table */ 63 + enum dfa_accept_flags { 64 + ACCEPT_FLAG_OWNER = 1, 65 + }; 66 + 62 67 /* 63 68 * FIXME: currently need a clean way to replace and remove profiles as a 64 69 * set. It should be done at the namespace level. ··· 129 124 kref_put(&pdb->count, aa_pdb_free_kref); 130 125 } 131 126 127 + /* lookup perm that doesn't have and object conditional */ 132 128 static inline struct aa_perms *aa_lookup_perms(struct aa_policydb *policy, 133 129 aa_state_t state) 134 130 { ··· 140 134 141 135 return &(policy->perms[index]); 142 136 } 143 - 144 137 145 138 /* struct aa_data - generic data structure 146 139 * key: name for retrieving this data ··· 165 160 * @secmark: secmark label match info 166 161 */ 167 162 struct aa_ruleset { 168 - struct list_head list; 169 - 170 163 int size; 171 164 172 165 /* TODO: merge policy and file */ ··· 177 174 int secmark_count; 178 175 struct aa_secmark *secmark; 179 176 }; 177 + 180 178 181 179 /* struct aa_attachment - data and rules for a profiles attachment 182 180 * @list: ··· 197 193 198 194 /* struct aa_profile - basic confinement data 199 195 * @base - base components of the profile (name, refcount, lists, lock ...) 200 - * @label - label this profile is an extension of 201 196 * @parent: parent of profile 202 197 * @ns: namespace the profile is in 203 198 * @rename: optional profile name that this profile renamed ··· 204 201 * @audit: the auditing mode of the profile 205 202 * @mode: the enforcement mode of the profile 206 203 * @path_flags: flags controlling path generation behavior 204 + * @signal: the signal that should be used when kill is used 207 205 * @disconnected: what to prepend if attach_disconnected is specified 208 206 * @attach: attachment rules for the profile 209 207 * @rules: rules to be enforced 210 208 * 209 + * learning_cache: the accesses learned in complain mode 210 + * raw_data: rawdata of the loaded profile policy 211 + * hash: cryptographic hash of the profile 211 212 * @dents: dentries for the profiles file entries in apparmorfs 212 213 * @dirname: name of the profile dir in apparmorfs 214 + * @dents: set of dentries associated with the profile 213 215 * @data: hashtable for free-form policy aa_data 216 + * @label - label this profile is an extension of 217 + * @rules - label with the rule vec on its end 214 218 * 215 219 * The AppArmor profile contains the basic confinement data. Each profile 216 220 * has a name, and exists in a namespace. The @name and @exec_match are ··· 241 231 enum audit_mode audit; 242 232 long mode; 243 233 u32 path_flags; 234 + int signal; 244 235 const char *disconnected; 245 236 246 237 struct aa_attachment attach; 247 - struct list_head rules; 248 238 249 239 struct aa_loaddata *rawdata; 250 240 unsigned char *hash; 251 241 char *dirname; 252 242 struct dentry *dents[AAFS_PROF_SIZEOF]; 253 243 struct rhashtable *data; 244 + 245 + int n_rules; 246 + /* special - variable length must be last entry in profile */ 254 247 struct aa_label label; 255 248 }; 256 249 ··· 311 298 rules->policy->start[0], &class, 1); 312 299 } 313 300 314 - static inline aa_state_t RULE_MEDIATES_AF(struct aa_ruleset *rules, u16 AF) 301 + static inline aa_state_t RULE_MEDIATES_v9NET(struct aa_ruleset *rules) 315 302 { 316 - aa_state_t state = RULE_MEDIATES(rules, AA_CLASS_NET); 317 - __be16 be_af = cpu_to_be16(AF); 318 - 319 - if (!state) 320 - return DFA_NOMATCH; 321 - return aa_dfa_match_len(rules->policy->dfa, state, (char *) &be_af, 2); 303 + return RULE_MEDIATES(rules, AA_CLASS_NETV9); 322 304 } 323 305 324 - static inline aa_state_t ANY_RULE_MEDIATES(struct list_head *head, 325 - unsigned char class) 306 + static inline aa_state_t RULE_MEDIATES_NET(struct aa_ruleset *rules) 326 307 { 327 - struct aa_ruleset *rule; 308 + /* can not use RULE_MEDIATE_v9AF here, because AF match fail 309 + * can not be distiguished from class match fail, and we only 310 + * fallback to checking older class on class match failure 311 + */ 312 + aa_state_t state = RULE_MEDIATES(rules, AA_CLASS_NETV9); 328 313 329 - /* TODO: change to list walk */ 330 - rule = list_first_entry(head, typeof(*rule), list); 331 - return RULE_MEDIATES(rule, class); 314 + /* fallback and check v7/8 if v9 is NOT mediated */ 315 + if (!state) 316 + state = RULE_MEDIATES(rules, AA_CLASS_NET); 317 + 318 + return state; 319 + } 320 + 321 + 322 + void aa_compute_profile_mediates(struct aa_profile *profile); 323 + static inline bool profile_mediates(struct aa_profile *profile, 324 + unsigned char class) 325 + { 326 + return label_mediates(&profile->label, class); 327 + } 328 + 329 + static inline bool profile_mediates_safe(struct aa_profile *profile, 330 + unsigned char class) 331 + { 332 + return label_mediates_safe(&profile->label, class); 332 333 } 333 334 334 335 /**
+1 -5
security/apparmor/include/sig_names.h
··· 1 1 #include <linux/signal.h> 2 - 3 - #define SIGUNKNOWN 0 4 - #define MAXMAPPED_SIG 35 5 - #define MAXMAPPED_SIGNAME (MAXMAPPED_SIG + 1) 6 - #define SIGRT_BASE 128 2 + #include "signal.h" 7 3 8 4 /* provide a mapping of arch signal to internal signal # for mediation 9 5 * those that are always an alias SIGCLD for SIGCLHD and SIGPOLL for SIGIO
+19
security/apparmor/include/signal.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* 3 + * AppArmor security module 4 + * 5 + * This file contains AppArmor ipc mediation function definitions. 6 + * 7 + * Copyright 2023 Canonical Ltd. 8 + */ 9 + 10 + #ifndef __AA_SIGNAL_H 11 + #define __AA_SIGNAL_H 12 + 13 + #define SIGUNKNOWN 0 14 + #define MAXMAPPED_SIG 35 15 + 16 + #define MAXMAPPED_SIGNAME (MAXMAPPED_SIG + 1) 17 + #define SIGRT_BASE 128 18 + 19 + #endif /* __AA_SIGNAL_H */
+6 -7
security/apparmor/ipc.c
··· 80 80 struct aa_label *peer, u32 request, 81 81 struct apparmor_audit_data *ad) 82 82 { 83 - struct aa_ruleset *rules = list_first_entry(&profile->rules, 84 - typeof(*rules), list); 83 + struct aa_ruleset *rules = profile->label.rules[0]; 85 84 struct aa_perms perms; 86 85 aa_state_t state; 87 86 88 - if (profile_unconfined(profile) || 89 - !ANY_RULE_MEDIATES(&profile->rules, AA_CLASS_SIGNAL)) 87 + if (profile_unconfined(profile)) 90 88 return 0; 91 89 92 90 ad->subj_cred = cred; 93 91 ad->peer = peer; 94 92 /* TODO: secondary cache check <profile, profile, perm> */ 95 - state = aa_dfa_next(rules->policy->dfa, 96 - rules->policy->start[AA_CLASS_SIGNAL], 97 - ad->signal); 93 + state = RULE_MEDIATES(rules, AA_CLASS_SIGNAL); 94 + if (!state) 95 + return 0; 96 + state = aa_dfa_next(rules->policy->dfa, state, ad->signal); 98 97 aa_label_match(profile, rules, peer, state, false, request, &perms); 99 98 aa_apply_modes_to_perms(profile, &perms); 100 99 return aa_check_perms(profile, &perms, request, ad, audit_signal_cb);
+21 -16
security/apparmor/label.c
··· 198 198 return false; 199 199 } 200 200 201 - static long accum_vec_flags(struct aa_profile **vec, int n) 201 + static void accum_label_info(struct aa_label *new) 202 202 { 203 203 long u = FLAG_UNCONFINED; 204 204 int i; 205 205 206 - AA_BUG(!vec); 206 + AA_BUG(!new); 207 207 208 - for (i = 0; i < n; i++) { 209 - u |= vec[i]->label.flags & (FLAG_DEBUG1 | FLAG_DEBUG2 | 210 - FLAG_STALE); 211 - if (!(u & vec[i]->label.flags & FLAG_UNCONFINED)) 208 + /* size == 1 is a profile and flags must be set as part of creation */ 209 + if (new->size == 1) 210 + return; 211 + 212 + for (i = 0; i < new->size; i++) { 213 + u |= new->vec[i]->label.flags & (FLAG_DEBUG1 | FLAG_DEBUG2 | 214 + FLAG_STALE); 215 + if (!(u & new->vec[i]->label.flags & FLAG_UNCONFINED)) 212 216 u &= ~FLAG_UNCONFINED; 217 + new->mediates |= new->vec[i]->label.mediates; 213 218 } 214 - 215 - return u; 219 + new->flags |= u; 216 220 } 217 221 218 222 static int sort_cmp(const void *a, const void *b) ··· 435 431 436 432 /* + 1 for null terminator entry on vec */ 437 433 new = kzalloc(struct_size(new, vec, size + 1), gfp); 438 - AA_DEBUG("%s (%p)\n", __func__, new); 434 + AA_DEBUG(DEBUG_LABEL, "%s (%p)\n", __func__, new); 439 435 if (!new) 440 436 goto fail; 441 437 ··· 649 645 rb_replace_node(&old->node, &new->node, &ls->root); 650 646 old->flags &= ~FLAG_IN_TREE; 651 647 new->flags |= FLAG_IN_TREE; 648 + accum_label_info(new); 652 649 return true; 653 650 } 654 651 ··· 710 705 rb_link_node(&label->node, parent, new); 711 706 rb_insert_color(&label->node, &ls->root); 712 707 label->flags |= FLAG_IN_TREE; 708 + accum_label_info(label); 713 709 714 710 return aa_get_label(label); 715 711 } ··· 1091 1085 else if (k == b->size) 1092 1086 return aa_get_label(b); 1093 1087 } 1094 - new->flags |= accum_vec_flags(new->vec, new->size); 1095 1088 ls = labels_set(new); 1096 1089 write_lock_irqsave(&ls->lock, flags); 1097 1090 label = __label_insert(labels_set(new), new, false); ··· 1461 1456 1462 1457 /* 1463 1458 * cached label name is present and visible 1464 - * @label->hname only exists if label is namespace hierachical 1459 + * @label->hname only exists if label is namespace hierarchical 1465 1460 */ 1466 1461 static inline bool use_label_hname(struct aa_ns *ns, struct aa_label *label, 1467 1462 int flags) ··· 1622 1617 AA_BUG(!str && size != 0); 1623 1618 AA_BUG(!label); 1624 1619 1625 - if (AA_DEBUG_LABEL && (flags & FLAG_ABS_ROOT)) { 1620 + if (DEBUG_ABS_ROOT && (flags & FLAG_ABS_ROOT)) { 1626 1621 ns = root_ns; 1627 1622 len = snprintf(str, size, "_"); 1628 1623 update_for_len(total, len, size, str); ··· 1736 1731 display_mode(ns, label, flags)) { 1737 1732 len = aa_label_asxprint(&name, ns, label, flags, gfp); 1738 1733 if (len < 0) { 1739 - AA_DEBUG("label print error"); 1734 + AA_DEBUG(DEBUG_LABEL, "label print error"); 1740 1735 return; 1741 1736 } 1742 1737 str = name; ··· 1764 1759 1765 1760 len = aa_label_asxprint(&str, ns, label, flags, gfp); 1766 1761 if (len < 0) { 1767 - AA_DEBUG("label print error"); 1762 + AA_DEBUG(DEBUG_LABEL, "label print error"); 1768 1763 return; 1769 1764 } 1770 1765 seq_puts(f, str); ··· 1787 1782 1788 1783 len = aa_label_asxprint(&str, ns, label, flags, gfp); 1789 1784 if (len < 0) { 1790 - AA_DEBUG("label print error"); 1785 + AA_DEBUG(DEBUG_LABEL, "label print error"); 1791 1786 return; 1792 1787 } 1793 1788 pr_info("%s", str); ··· 1870 1865 AA_BUG(!str); 1871 1866 1872 1867 str = skipn_spaces(str, n); 1873 - if (str == NULL || (AA_DEBUG_LABEL && *str == '_' && 1868 + if (str == NULL || (DEBUG_ABS_ROOT && *str == '_' && 1874 1869 base != &root_ns->unconfined->label)) 1875 1870 return ERR_PTR(-EINVAL); 1876 1871
+114
security/apparmor/lib.c
··· 25 25 .quiet = ALL_PERMS_MASK, 26 26 .hide = ALL_PERMS_MASK }; 27 27 28 + struct val_table_ent { 29 + const char *str; 30 + int value; 31 + }; 32 + 33 + static struct val_table_ent debug_values_table[] = { 34 + { "N", DEBUG_NONE }, 35 + { "none", DEBUG_NONE }, 36 + { "n", DEBUG_NONE }, 37 + { "0", DEBUG_NONE }, 38 + { "all", DEBUG_ALL }, 39 + { "Y", DEBUG_ALL }, 40 + { "y", DEBUG_ALL }, 41 + { "1", DEBUG_ALL }, 42 + { "abs_root", DEBUG_LABEL_ABS_ROOT }, 43 + { "label", DEBUG_LABEL }, 44 + { "domain", DEBUG_DOMAIN }, 45 + { "policy", DEBUG_POLICY }, 46 + { "interface", DEBUG_INTERFACE }, 47 + { NULL, 0 } 48 + }; 49 + 50 + static struct val_table_ent *val_table_find_ent(struct val_table_ent *table, 51 + const char *name, size_t len) 52 + { 53 + struct val_table_ent *entry; 54 + 55 + for (entry = table; entry->str != NULL; entry++) { 56 + if (strncmp(entry->str, name, len) == 0 && 57 + strlen(entry->str) == len) 58 + return entry; 59 + } 60 + return NULL; 61 + } 62 + 63 + int aa_parse_debug_params(const char *str) 64 + { 65 + struct val_table_ent *ent; 66 + const char *next; 67 + int val = 0; 68 + 69 + do { 70 + size_t n = strcspn(str, "\r\n,"); 71 + 72 + next = str + n; 73 + ent = val_table_find_ent(debug_values_table, str, next - str); 74 + if (ent) 75 + val |= ent->value; 76 + else 77 + AA_DEBUG(DEBUG_INTERFACE, "unknown debug type '%.*s'", 78 + (int)(next - str), str); 79 + str = next + 1; 80 + } while (*next != 0); 81 + return val; 82 + } 83 + 84 + /** 85 + * val_mask_to_str - convert a perm mask to its short string 86 + * @str: character buffer to store string in (at least 10 characters) 87 + * @size: size of the @str buffer 88 + * @table: NUL-terminated character buffer of permission characters (NOT NULL) 89 + * @mask: permission mask to convert 90 + */ 91 + static int val_mask_to_str(char *str, size_t size, 92 + const struct val_table_ent *table, u32 mask) 93 + { 94 + const struct val_table_ent *ent; 95 + int total = 0; 96 + 97 + for (ent = table; ent->str; ent++) { 98 + if (ent->value && (ent->value & mask) == ent->value) { 99 + int len = scnprintf(str, size, "%s%s", total ? "," : "", 100 + ent->str); 101 + size -= len; 102 + str += len; 103 + total += len; 104 + mask &= ~ent->value; 105 + } 106 + } 107 + 108 + return total; 109 + } 110 + 111 + int aa_print_debug_params(char *buffer) 112 + { 113 + if (!aa_g_debug) 114 + return sprintf(buffer, "N"); 115 + return val_mask_to_str(buffer, PAGE_SIZE, debug_values_table, 116 + aa_g_debug); 117 + } 118 + 119 + bool aa_resize_str_table(struct aa_str_table *t, int newsize, gfp_t gfp) 120 + { 121 + char **n; 122 + int i; 123 + 124 + if (t->size == newsize) 125 + return true; 126 + n = kcalloc(newsize, sizeof(*n), gfp); 127 + if (!n) 128 + return false; 129 + for (i = 0; i < min(t->size, newsize); i++) 130 + n[i] = t->table[i]; 131 + for (; i < t->size; i++) 132 + kfree_sensitive(t->table[i]); 133 + if (newsize > t->size) 134 + memset(&n[t->size], 0, (newsize-t->size)*sizeof(*n)); 135 + kfree_sensitive(t->table); 136 + t->table = n; 137 + t->size = newsize; 138 + 139 + return true; 140 + } 141 + 28 142 /** 29 143 * aa_free_str_table - free entries str table 30 144 * @t: the string table to free (MAYBE NULL)
+374 -94
security/apparmor/lsm.c
··· 26 26 #include <uapi/linux/mount.h> 27 27 #include <uapi/linux/lsm.h> 28 28 29 + #include "include/af_unix.h" 29 30 #include "include/apparmor.h" 30 31 #include "include/apparmorfs.h" 31 32 #include "include/audit.h" ··· 127 126 struct aa_label *tracer, *tracee; 128 127 const struct cred *cred; 129 128 int error; 129 + bool needput; 130 130 131 131 cred = get_task_cred(child); 132 132 tracee = cred_label(cred); /* ref count on cred */ 133 - tracer = __begin_current_label_crit_section(); 133 + tracer = __begin_current_label_crit_section(&needput); 134 134 error = aa_may_ptrace(current_cred(), tracer, cred, tracee, 135 135 (mode & PTRACE_MODE_READ) ? AA_PTRACE_READ 136 136 : AA_PTRACE_TRACE); 137 - __end_current_label_crit_section(tracer); 137 + __end_current_label_crit_section(tracer, needput); 138 138 put_cred(cred); 139 139 140 140 return error; ··· 146 144 struct aa_label *tracer, *tracee; 147 145 const struct cred *cred; 148 146 int error; 147 + bool needput; 149 148 150 - tracee = __begin_current_label_crit_section(); 149 + tracee = __begin_current_label_crit_section(&needput); 151 150 cred = get_task_cred(parent); 152 151 tracer = cred_label(cred); /* ref count on cred */ 153 152 error = aa_may_ptrace(cred, tracer, current_cred(), tracee, 154 153 AA_PTRACE_TRACE); 155 154 put_cred(cred); 156 - __end_current_label_crit_section(tracee); 155 + __end_current_label_crit_section(tracee, needput); 157 156 158 157 return error; 159 158 } ··· 179 176 struct label_it i; 180 177 181 178 label_for_each_confined(i, label, profile) { 182 - struct aa_ruleset *rules; 183 - if (COMPLAIN_MODE(profile)) 184 - continue; 185 - rules = list_first_entry(&profile->rules, 186 - typeof(*rules), list); 187 - *effective = cap_intersect(*effective, 188 - rules->caps.allow); 189 - *permitted = cap_intersect(*permitted, 190 - rules->caps.allow); 179 + kernel_cap_t allowed; 180 + 181 + allowed = aa_profile_capget(profile); 182 + *effective = cap_intersect(*effective, allowed); 183 + *permitted = cap_intersect(*permitted, allowed); 191 184 } 192 185 } 193 186 rcu_read_unlock(); ··· 220 221 { 221 222 struct aa_label *label; 222 223 int error = 0; 224 + bool needput; 223 225 224 - label = __begin_current_label_crit_section(); 226 + label = __begin_current_label_crit_section(&needput); 225 227 if (!unconfined(label)) 226 228 error = aa_path_perm(op, current_cred(), label, path, 0, mask, 227 229 cond); 228 - __end_current_label_crit_section(label); 230 + __end_current_label_crit_section(label, needput); 229 231 230 232 return error; 231 233 } ··· 524 524 { 525 525 struct aa_label *label; 526 526 int error = 0; 527 + bool needput; 527 528 528 529 /* don't reaudit files closed during inheritance */ 529 - if (file->f_path.dentry == aa_null.dentry) 530 + if (unlikely(file->f_path.dentry == aa_null.dentry)) 530 531 return -EACCES; 531 532 532 - label = __begin_current_label_crit_section(); 533 + label = __begin_current_label_crit_section(&needput); 533 534 error = aa_file_perm(op, current_cred(), label, file, mask, in_atomic); 534 - __end_current_label_crit_section(label); 535 + __end_current_label_crit_section(label, needput); 535 536 536 537 return error; 537 538 } ··· 634 633 635 634 AA_BUG(!profile); 636 635 637 - rules = list_first_entry(&profile->rules, typeof(*rules), list); 636 + rules = profile->label.rules[0]; 638 637 state = RULE_MEDIATES(rules, AA_CLASS_IO_URING); 639 638 if (state) { 640 639 struct aa_perms perms = { }; ··· 665 664 struct aa_profile *profile; 666 665 struct aa_label *label; 667 666 int error; 667 + bool needput; 668 668 DEFINE_AUDIT_DATA(ad, LSM_AUDIT_DATA_NONE, AA_CLASS_IO_URING, 669 669 OP_URING_OVERRIDE); 670 670 671 671 ad.uring.target = cred_label(new); 672 - label = __begin_current_label_crit_section(); 672 + label = __begin_current_label_crit_section(&needput); 673 673 error = fn_for_each(label, profile, 674 674 profile_uring(profile, AA_MAY_OVERRIDE_CRED, 675 675 cred_label(new), CAP_SYS_ADMIN, &ad)); 676 - __end_current_label_crit_section(label); 676 + __end_current_label_crit_section(label, needput); 677 677 678 678 return error; 679 679 } ··· 690 688 struct aa_profile *profile; 691 689 struct aa_label *label; 692 690 int error; 691 + bool needput; 693 692 DEFINE_AUDIT_DATA(ad, LSM_AUDIT_DATA_NONE, AA_CLASS_IO_URING, 694 693 OP_URING_SQPOLL); 695 694 696 - label = __begin_current_label_crit_section(); 695 + label = __begin_current_label_crit_section(&needput); 697 696 error = fn_for_each(label, profile, 698 697 profile_uring(profile, AA_MAY_CREATE_SQPOLL, 699 698 NULL, CAP_SYS_ADMIN, &ad)); 700 - __end_current_label_crit_section(label); 699 + __end_current_label_crit_section(label, needput); 701 700 702 701 return error; 703 702 } ··· 709 706 { 710 707 struct aa_label *label; 711 708 int error = 0; 709 + bool needput; 712 710 713 711 /* Discard magic */ 714 712 if ((flags & MS_MGC_MSK) == MS_MGC_VAL) ··· 717 713 718 714 flags &= ~AA_MS_IGNORE_MASK; 719 715 720 - label = __begin_current_label_crit_section(); 716 + label = __begin_current_label_crit_section(&needput); 721 717 if (!unconfined(label)) { 722 718 if (flags & MS_REMOUNT) 723 719 error = aa_remount(current_cred(), label, path, flags, ··· 736 732 error = aa_new_mount(current_cred(), label, dev_name, 737 733 path, type, flags, data); 738 734 } 739 - __end_current_label_crit_section(label); 735 + __end_current_label_crit_section(label, needput); 740 736 741 737 return error; 742 738 } ··· 746 742 { 747 743 struct aa_label *label; 748 744 int error = 0; 745 + bool needput; 749 746 750 - label = __begin_current_label_crit_section(); 747 + label = __begin_current_label_crit_section(&needput); 751 748 if (!unconfined(label)) 752 749 error = aa_move_mount(current_cred(), label, from_path, 753 750 to_path); 754 - __end_current_label_crit_section(label); 751 + __end_current_label_crit_section(label, needput); 755 752 756 753 return error; 757 754 } ··· 761 756 { 762 757 struct aa_label *label; 763 758 int error = 0; 759 + bool needput; 764 760 765 - label = __begin_current_label_crit_section(); 761 + label = __begin_current_label_crit_section(&needput); 766 762 if (!unconfined(label)) 767 763 error = aa_umount(current_cred(), label, mnt, flags); 768 - __end_current_label_crit_section(label); 764 + __end_current_label_crit_section(label, needput); 769 765 770 766 return error; 771 767 } ··· 990 984 991 985 static void apparmor_current_getlsmprop_subj(struct lsm_prop *prop) 992 986 { 993 - struct aa_label *label = __begin_current_label_crit_section(); 987 + struct aa_label *label; 988 + bool needput; 994 989 990 + label = __begin_current_label_crit_section(&needput); 995 991 prop->apparmor.label = label; 996 - __end_current_label_crit_section(label); 992 + __end_current_label_crit_section(label, needput); 997 993 } 998 994 999 995 static void apparmor_task_getlsmprop_obj(struct task_struct *p, ··· 1010 1002 static int apparmor_task_setrlimit(struct task_struct *task, 1011 1003 unsigned int resource, struct rlimit *new_rlim) 1012 1004 { 1013 - struct aa_label *label = __begin_current_label_crit_section(); 1005 + struct aa_label *label; 1014 1006 int error = 0; 1007 + bool needput; 1008 + 1009 + label = __begin_current_label_crit_section(&needput); 1015 1010 1016 1011 if (!unconfined(label)) 1017 1012 error = aa_task_setrlimit(current_cred(), label, task, 1018 1013 resource, new_rlim); 1019 - __end_current_label_crit_section(label); 1014 + __end_current_label_crit_section(label, needput); 1020 1015 1021 1016 return error; 1022 1017 } ··· 1030 1019 const struct cred *tc; 1031 1020 struct aa_label *cl, *tl; 1032 1021 int error; 1022 + bool needput; 1033 1023 1034 1024 tc = get_task_cred(target); 1035 1025 tl = aa_get_newest_cred_label(tc); ··· 1042 1030 error = aa_may_signal(cred, cl, tc, tl, sig); 1043 1031 aa_put_label(cl); 1044 1032 } else { 1045 - cl = __begin_current_label_crit_section(); 1033 + cl = __begin_current_label_crit_section(&needput); 1046 1034 error = aa_may_signal(current_cred(), cl, tc, tl, sig); 1047 - __end_current_label_crit_section(cl); 1035 + __end_current_label_crit_section(cl, needput); 1048 1036 } 1049 1037 aa_put_label(tl); 1050 1038 put_cred(tc); ··· 1073 1061 return error; 1074 1062 } 1075 1063 1064 + static int apparmor_sk_alloc_security(struct sock *sk, int family, gfp_t gfp) 1065 + { 1066 + struct aa_sk_ctx *ctx = aa_sock(sk); 1067 + struct aa_label *label; 1068 + bool needput; 1069 + 1070 + label = __begin_current_label_crit_section(&needput); 1071 + //spin_lock_init(&ctx->lock); 1072 + rcu_assign_pointer(ctx->label, aa_get_label(label)); 1073 + rcu_assign_pointer(ctx->peer, NULL); 1074 + rcu_assign_pointer(ctx->peer_lastupdate, NULL); 1075 + __end_current_label_crit_section(label, needput); 1076 + return 0; 1077 + } 1078 + 1076 1079 static void apparmor_sk_free_security(struct sock *sk) 1077 1080 { 1078 1081 struct aa_sk_ctx *ctx = aa_sock(sk); 1079 1082 1080 - aa_put_label(ctx->label); 1081 - aa_put_label(ctx->peer); 1083 + /* dead these won't be updated any more */ 1084 + aa_put_label(rcu_dereference_protected(ctx->label, true)); 1085 + aa_put_label(rcu_dereference_protected(ctx->peer, true)); 1086 + aa_put_label(rcu_dereference_protected(ctx->peer_lastupdate, true)); 1082 1087 } 1083 1088 1084 1089 /** ··· 1109 1080 struct aa_sk_ctx *ctx = aa_sock(sk); 1110 1081 struct aa_sk_ctx *new = aa_sock(newsk); 1111 1082 1112 - if (new->label) 1113 - aa_put_label(new->label); 1114 - new->label = aa_get_label(ctx->label); 1083 + /* not actually in use yet */ 1084 + if (rcu_access_pointer(ctx->label) != rcu_access_pointer(new->label)) { 1085 + aa_put_label(rcu_dereference_protected(new->label, true)); 1086 + rcu_assign_pointer(new->label, aa_get_label_rcu(&ctx->label)); 1087 + } 1115 1088 1116 - if (new->peer) 1117 - aa_put_label(new->peer); 1118 - new->peer = aa_get_label(ctx->peer); 1089 + if (rcu_access_pointer(ctx->peer) != rcu_access_pointer(new->peer)) { 1090 + aa_put_label(rcu_dereference_protected(new->peer, true)); 1091 + rcu_assign_pointer(new->peer, aa_get_label_rcu(&ctx->peer)); 1092 + } 1093 + 1094 + if (rcu_access_pointer(ctx->peer_lastupdate) != rcu_access_pointer(new->peer_lastupdate)) { 1095 + aa_put_label(rcu_dereference_protected(new->peer_lastupdate, true)); 1096 + rcu_assign_pointer(new->peer_lastupdate, 1097 + aa_get_label_rcu(&ctx->peer_lastupdate)); 1098 + } 1099 + } 1100 + 1101 + static int unix_connect_perm(const struct cred *cred, struct aa_label *label, 1102 + struct sock *sk, struct sock *peer_sk) 1103 + { 1104 + struct aa_sk_ctx *peer_ctx = aa_sock(peer_sk); 1105 + int error; 1106 + 1107 + error = aa_unix_peer_perm(cred, label, OP_CONNECT, 1108 + (AA_MAY_CONNECT | AA_MAY_SEND | AA_MAY_RECEIVE), 1109 + sk, peer_sk, 1110 + rcu_dereference_protected(peer_ctx->label, 1111 + lockdep_is_held(&unix_sk(peer_sk)->lock))); 1112 + if (!is_unix_fs(peer_sk)) { 1113 + last_error(error, 1114 + aa_unix_peer_perm(cred, 1115 + rcu_dereference_protected(peer_ctx->label, 1116 + lockdep_is_held(&unix_sk(peer_sk)->lock)), 1117 + OP_CONNECT, 1118 + (AA_MAY_ACCEPT | AA_MAY_SEND | AA_MAY_RECEIVE), 1119 + peer_sk, sk, label)); 1120 + } 1121 + 1122 + return error; 1123 + } 1124 + 1125 + /* lockdep check in unix_connect_perm - push sks here to check */ 1126 + static void unix_connect_peers(struct aa_sk_ctx *sk_ctx, 1127 + struct aa_sk_ctx *peer_ctx) 1128 + { 1129 + /* Cross reference the peer labels for SO_PEERSEC */ 1130 + struct aa_label *label = rcu_dereference_protected(sk_ctx->label, true); 1131 + 1132 + aa_get_label(label); 1133 + aa_put_label(rcu_dereference_protected(peer_ctx->peer, 1134 + true)); 1135 + rcu_assign_pointer(peer_ctx->peer, label); /* transfer cnt */ 1136 + 1137 + label = aa_get_label(rcu_dereference_protected(peer_ctx->label, 1138 + true)); 1139 + //spin_unlock(&peer_ctx->lock); 1140 + 1141 + //spin_lock(&sk_ctx->lock); 1142 + aa_put_label(rcu_dereference_protected(sk_ctx->peer, 1143 + true)); 1144 + aa_put_label(rcu_dereference_protected(sk_ctx->peer_lastupdate, 1145 + true)); 1146 + 1147 + rcu_assign_pointer(sk_ctx->peer, aa_get_label(label)); 1148 + rcu_assign_pointer(sk_ctx->peer_lastupdate, label); /* transfer cnt */ 1149 + //spin_unlock(&sk_ctx->lock); 1150 + } 1151 + 1152 + /** 1153 + * apparmor_unix_stream_connect - check perms before making unix domain conn 1154 + * @sk: sk attempting to connect 1155 + * @peer_sk: sk that is accepting the connection 1156 + * @newsk: new sk created for this connection 1157 + * peer is locked when this hook is called 1158 + * 1159 + * Return: 1160 + * 0 if connection is permitted 1161 + * error code on denial or failure 1162 + */ 1163 + static int apparmor_unix_stream_connect(struct sock *sk, struct sock *peer_sk, 1164 + struct sock *newsk) 1165 + { 1166 + struct aa_sk_ctx *sk_ctx = aa_sock(sk); 1167 + struct aa_sk_ctx *peer_ctx = aa_sock(peer_sk); 1168 + struct aa_sk_ctx *new_ctx = aa_sock(newsk); 1169 + struct aa_label *label; 1170 + int error; 1171 + bool needput; 1172 + 1173 + label = __begin_current_label_crit_section(&needput); 1174 + error = unix_connect_perm(current_cred(), label, sk, peer_sk); 1175 + __end_current_label_crit_section(label, needput); 1176 + 1177 + if (error) 1178 + return error; 1179 + 1180 + /* newsk doesn't go through post_create, but does go through 1181 + * security_sk_alloc() 1182 + */ 1183 + rcu_assign_pointer(new_ctx->label, 1184 + aa_get_label(rcu_dereference_protected(peer_ctx->label, 1185 + true))); 1186 + 1187 + /* Cross reference the peer labels for SO_PEERSEC */ 1188 + unix_connect_peers(sk_ctx, new_ctx); 1189 + 1190 + return 0; 1191 + } 1192 + 1193 + /** 1194 + * apparmor_unix_may_send - check perms before conn or sending unix dgrams 1195 + * @sock: socket sending the message 1196 + * @peer: socket message is being send to 1197 + * 1198 + * Performs bidirectional permission checks for Unix domain socket communication: 1199 + * 1. Verifies sender has AA_MAY_SEND to target socket 1200 + * 2. Verifies receiver has AA_MAY_RECEIVE from source socket 1201 + * 1202 + * sock and peer are locked when this hook is called 1203 + * called by: dgram_connect peer setup but path not copied to newsk 1204 + * 1205 + * Return: 1206 + * 0 if transmission is permitted 1207 + * error code on denial or failure 1208 + */ 1209 + static int apparmor_unix_may_send(struct socket *sock, struct socket *peer) 1210 + { 1211 + struct aa_sk_ctx *peer_ctx = aa_sock(peer->sk); 1212 + struct aa_label *label; 1213 + int error; 1214 + bool needput; 1215 + 1216 + label = __begin_current_label_crit_section(&needput); 1217 + error = xcheck(aa_unix_peer_perm(current_cred(), 1218 + label, OP_SENDMSG, AA_MAY_SEND, 1219 + sock->sk, peer->sk, 1220 + rcu_dereference_protected(peer_ctx->label, 1221 + true)), 1222 + aa_unix_peer_perm(peer->file ? peer->file->f_cred : NULL, 1223 + rcu_dereference_protected(peer_ctx->label, 1224 + true), 1225 + OP_SENDMSG, AA_MAY_RECEIVE, peer->sk, 1226 + sock->sk, label)); 1227 + __end_current_label_crit_section(label, needput); 1228 + 1229 + return error; 1119 1230 } 1120 1231 1121 1232 static int apparmor_socket_create(int family, int type, int protocol, int kern) ··· 1265 1096 1266 1097 AA_BUG(in_interrupt()); 1267 1098 1099 + if (kern) 1100 + return 0; 1101 + 1268 1102 label = begin_current_label_crit_section(); 1269 - if (!(kern || unconfined(label))) 1270 - error = af_select(family, 1271 - create_perm(label, family, type, protocol), 1272 - aa_af_perm(current_cred(), label, 1273 - OP_CREATE, AA_MAY_CREATE, 1274 - family, type, protocol)); 1103 + if (!unconfined(label)) { 1104 + if (family == PF_UNIX) 1105 + error = aa_unix_create_perm(label, family, type, 1106 + protocol); 1107 + else 1108 + error = aa_af_perm(current_cred(), label, OP_CREATE, 1109 + AA_MAY_CREATE, family, type, 1110 + protocol); 1111 + } 1275 1112 end_current_label_crit_section(label); 1276 1113 1277 1114 return error; ··· 1310 1135 if (sock->sk) { 1311 1136 struct aa_sk_ctx *ctx = aa_sock(sock->sk); 1312 1137 1313 - aa_put_label(ctx->label); 1314 - ctx->label = aa_get_label(label); 1138 + /* still not live */ 1139 + aa_put_label(rcu_dereference_protected(ctx->label, true)); 1140 + rcu_assign_pointer(ctx->label, aa_get_label(label)); 1315 1141 } 1316 1142 aa_put_label(label); 1317 1143 1318 1144 return 0; 1319 1145 } 1320 1146 1147 + static int apparmor_socket_socketpair(struct socket *socka, 1148 + struct socket *sockb) 1149 + { 1150 + struct aa_sk_ctx *a_ctx = aa_sock(socka->sk); 1151 + struct aa_sk_ctx *b_ctx = aa_sock(sockb->sk); 1152 + struct aa_label *label; 1153 + 1154 + /* socks not live yet - initial values set in sk_alloc */ 1155 + label = begin_current_label_crit_section(); 1156 + if (rcu_access_pointer(a_ctx->label) != label) { 1157 + AA_BUG("a_ctx != label"); 1158 + aa_put_label(rcu_dereference_protected(a_ctx->label, true)); 1159 + rcu_assign_pointer(a_ctx->label, aa_get_label(label)); 1160 + } 1161 + if (rcu_access_pointer(b_ctx->label) != label) { 1162 + AA_BUG("b_ctx != label"); 1163 + aa_put_label(rcu_dereference_protected(b_ctx->label, true)); 1164 + rcu_assign_pointer(b_ctx->label, aa_get_label(label)); 1165 + } 1166 + 1167 + if (socka->sk->sk_family == PF_UNIX) { 1168 + /* unix socket pairs by-pass unix_stream_connect */ 1169 + unix_connect_peers(a_ctx, b_ctx); 1170 + } 1171 + end_current_label_crit_section(label); 1172 + 1173 + return 0; 1174 + } 1175 + 1176 + /** 1177 + * apparmor_socket_bind - check perms before bind addr to socket 1178 + * @sock: socket to bind the address to (must be non-NULL) 1179 + * @address: address that is being bound (must be non-NULL) 1180 + * @addrlen: length of @address 1181 + * 1182 + * Performs security checks before allowing a socket to bind to an address. 1183 + * Handles Unix domain sockets specially through aa_unix_bind_perm(). 1184 + * For other socket families, uses generic permission check via aa_sk_perm(). 1185 + * 1186 + * Return: 1187 + * 0 if binding is permitted 1188 + * error code on denial or invalid parameters 1189 + */ 1321 1190 static int apparmor_socket_bind(struct socket *sock, 1322 1191 struct sockaddr *address, int addrlen) 1323 1192 { ··· 1370 1151 AA_BUG(!address); 1371 1152 AA_BUG(in_interrupt()); 1372 1153 1373 - return af_select(sock->sk->sk_family, 1374 - bind_perm(sock, address, addrlen), 1375 - aa_sk_perm(OP_BIND, AA_MAY_BIND, sock->sk)); 1154 + if (sock->sk->sk_family == PF_UNIX) 1155 + return aa_unix_bind_perm(sock, address, addrlen); 1156 + return aa_sk_perm(OP_BIND, AA_MAY_BIND, sock->sk); 1376 1157 } 1377 1158 1378 1159 static int apparmor_socket_connect(struct socket *sock, ··· 1383 1164 AA_BUG(!address); 1384 1165 AA_BUG(in_interrupt()); 1385 1166 1386 - return af_select(sock->sk->sk_family, 1387 - connect_perm(sock, address, addrlen), 1388 - aa_sk_perm(OP_CONNECT, AA_MAY_CONNECT, sock->sk)); 1167 + /* PF_UNIX goes through unix_stream_connect && unix_may_send */ 1168 + if (sock->sk->sk_family == PF_UNIX) 1169 + return 0; 1170 + return aa_sk_perm(OP_CONNECT, AA_MAY_CONNECT, sock->sk); 1389 1171 } 1390 1172 1391 1173 static int apparmor_socket_listen(struct socket *sock, int backlog) ··· 1395 1175 AA_BUG(!sock->sk); 1396 1176 AA_BUG(in_interrupt()); 1397 1177 1398 - return af_select(sock->sk->sk_family, 1399 - listen_perm(sock, backlog), 1400 - aa_sk_perm(OP_LISTEN, AA_MAY_LISTEN, sock->sk)); 1178 + if (sock->sk->sk_family == PF_UNIX) 1179 + return aa_unix_listen_perm(sock, backlog); 1180 + return aa_sk_perm(OP_LISTEN, AA_MAY_LISTEN, sock->sk); 1401 1181 } 1402 1182 1403 1183 /* ··· 1411 1191 AA_BUG(!newsock); 1412 1192 AA_BUG(in_interrupt()); 1413 1193 1414 - return af_select(sock->sk->sk_family, 1415 - accept_perm(sock, newsock), 1416 - aa_sk_perm(OP_ACCEPT, AA_MAY_ACCEPT, sock->sk)); 1194 + if (sock->sk->sk_family == PF_UNIX) 1195 + return aa_unix_accept_perm(sock, newsock); 1196 + return aa_sk_perm(OP_ACCEPT, AA_MAY_ACCEPT, sock->sk); 1417 1197 } 1418 1198 1419 1199 static int aa_sock_msg_perm(const char *op, u32 request, struct socket *sock, ··· 1424 1204 AA_BUG(!msg); 1425 1205 AA_BUG(in_interrupt()); 1426 1206 1427 - return af_select(sock->sk->sk_family, 1428 - msg_perm(op, request, sock, msg, size), 1429 - aa_sk_perm(op, request, sock->sk)); 1207 + /* PF_UNIX goes through unix_may_send */ 1208 + if (sock->sk->sk_family == PF_UNIX) 1209 + return 0; 1210 + return aa_sk_perm(op, request, sock->sk); 1430 1211 } 1431 1212 1432 1213 static int apparmor_socket_sendmsg(struct socket *sock, ··· 1449 1228 AA_BUG(!sock->sk); 1450 1229 AA_BUG(in_interrupt()); 1451 1230 1452 - return af_select(sock->sk->sk_family, 1453 - sock_perm(op, request, sock), 1454 - aa_sk_perm(op, request, sock->sk)); 1231 + if (sock->sk->sk_family == PF_UNIX) 1232 + return aa_unix_sock_perm(op, request, sock); 1233 + return aa_sk_perm(op, request, sock->sk); 1455 1234 } 1456 1235 1457 1236 static int apparmor_socket_getsockname(struct socket *sock) ··· 1472 1251 AA_BUG(!sock->sk); 1473 1252 AA_BUG(in_interrupt()); 1474 1253 1475 - return af_select(sock->sk->sk_family, 1476 - opt_perm(op, request, sock, level, optname), 1477 - aa_sk_perm(op, request, sock->sk)); 1254 + if (sock->sk->sk_family == PF_UNIX) 1255 + return aa_unix_opt_perm(op, request, sock, level, optname); 1256 + return aa_sk_perm(op, request, sock->sk); 1478 1257 } 1479 1258 1480 1259 static int apparmor_socket_getsockopt(struct socket *sock, int level, ··· 1510 1289 static int apparmor_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) 1511 1290 { 1512 1291 struct aa_sk_ctx *ctx = aa_sock(sk); 1292 + int error; 1513 1293 1514 1294 if (!skb->secmark) 1515 1295 return 0; ··· 1519 1297 * If reach here before socket_post_create hook is called, in which 1520 1298 * case label is null, drop the packet. 1521 1299 */ 1522 - if (!ctx->label) 1300 + if (!rcu_access_pointer(ctx->label)) 1523 1301 return -EACCES; 1524 1302 1525 - return apparmor_secmark_check(ctx->label, OP_RECVMSG, AA_MAY_RECEIVE, 1526 - skb->secmark, sk); 1303 + rcu_read_lock(); 1304 + error = apparmor_secmark_check(rcu_dereference(ctx->label), OP_RECVMSG, 1305 + AA_MAY_RECEIVE, skb->secmark, sk); 1306 + rcu_read_unlock(); 1307 + 1308 + return error; 1527 1309 } 1528 1310 #endif 1529 1311 1530 1312 1531 - static struct aa_label *sk_peer_label(struct sock *sk) 1313 + static struct aa_label *sk_peer_get_label(struct sock *sk) 1532 1314 { 1533 1315 struct aa_sk_ctx *ctx = aa_sock(sk); 1316 + struct aa_label *label = ERR_PTR(-ENOPROTOOPT); 1534 1317 1535 - if (ctx->peer) 1536 - return ctx->peer; 1318 + if (rcu_access_pointer(ctx->peer)) 1319 + return aa_get_label_rcu(&ctx->peer); 1537 1320 1538 - return ERR_PTR(-ENOPROTOOPT); 1321 + if (sk->sk_family != PF_UNIX) 1322 + return ERR_PTR(-ENOPROTOOPT); 1323 + 1324 + return label; 1539 1325 } 1540 1326 1541 1327 /** ··· 1565 1335 struct aa_label *label; 1566 1336 struct aa_label *peer; 1567 1337 1568 - label = begin_current_label_crit_section(); 1569 - peer = sk_peer_label(sock->sk); 1338 + peer = sk_peer_get_label(sock->sk); 1570 1339 if (IS_ERR(peer)) { 1571 1340 error = PTR_ERR(peer); 1572 1341 goto done; 1573 1342 } 1343 + label = begin_current_label_crit_section(); 1574 1344 slen = aa_label_asxprint(&name, labels_ns(label), peer, 1575 1345 FLAG_SHOW_MODE | FLAG_VIEW_SUBNS | 1576 1346 FLAG_HIDDEN_UNCONFINED, GFP_KERNEL); 1577 1347 /* don't include terminating \0 in slen, it breaks some apps */ 1578 1348 if (slen < 0) { 1579 1349 error = -ENOMEM; 1580 - goto done; 1350 + goto done_put; 1581 1351 } 1582 1352 if (slen > len) { 1583 1353 error = -ERANGE; ··· 1589 1359 done_len: 1590 1360 if (copy_to_sockptr(optlen, &slen, sizeof(slen))) 1591 1361 error = -EFAULT; 1592 - done: 1362 + 1363 + done_put: 1593 1364 end_current_label_crit_section(label); 1365 + aa_put_label(peer); 1366 + done: 1594 1367 kfree(name); 1595 1368 return error; 1596 1369 } ··· 1629 1396 { 1630 1397 struct aa_sk_ctx *ctx = aa_sock(sk); 1631 1398 1632 - if (!ctx->label) 1633 - ctx->label = aa_get_current_label(); 1399 + /* setup - not live */ 1400 + if (!rcu_access_pointer(ctx->label)) 1401 + rcu_assign_pointer(ctx->label, aa_get_current_label()); 1634 1402 } 1635 1403 1636 1404 #ifdef CONFIG_NETWORK_SECMARK ··· 1639 1405 struct request_sock *req) 1640 1406 { 1641 1407 struct aa_sk_ctx *ctx = aa_sock(sk); 1408 + int error; 1642 1409 1643 1410 if (!skb->secmark) 1644 1411 return 0; 1645 1412 1646 - return apparmor_secmark_check(ctx->label, OP_CONNECT, AA_MAY_CONNECT, 1647 - skb->secmark, sk); 1413 + rcu_read_lock(); 1414 + error = apparmor_secmark_check(rcu_dereference(ctx->label), OP_CONNECT, 1415 + AA_MAY_CONNECT, skb->secmark, sk); 1416 + rcu_read_unlock(); 1417 + 1418 + return error; 1648 1419 } 1649 1420 #endif 1650 1421 ··· 1706 1467 LSM_HOOK_INIT(getprocattr, apparmor_getprocattr), 1707 1468 LSM_HOOK_INIT(setprocattr, apparmor_setprocattr), 1708 1469 1470 + LSM_HOOK_INIT(sk_alloc_security, apparmor_sk_alloc_security), 1709 1471 LSM_HOOK_INIT(sk_free_security, apparmor_sk_free_security), 1710 1472 LSM_HOOK_INIT(sk_clone_security, apparmor_sk_clone_security), 1711 1473 1474 + LSM_HOOK_INIT(unix_stream_connect, apparmor_unix_stream_connect), 1475 + LSM_HOOK_INIT(unix_may_send, apparmor_unix_may_send), 1476 + 1712 1477 LSM_HOOK_INIT(socket_create, apparmor_socket_create), 1713 1478 LSM_HOOK_INIT(socket_post_create, apparmor_socket_post_create), 1479 + LSM_HOOK_INIT(socket_socketpair, apparmor_socket_socketpair), 1714 1480 LSM_HOOK_INIT(socket_bind, apparmor_socket_bind), 1715 1481 LSM_HOOK_INIT(socket_connect, apparmor_socket_connect), 1716 1482 LSM_HOOK_INIT(socket_listen, apparmor_socket_listen), ··· 1815 1571 .get = param_get_aalockpolicy 1816 1572 }; 1817 1573 1574 + static int param_set_debug(const char *val, const struct kernel_param *kp); 1575 + static int param_get_debug(char *buffer, const struct kernel_param *kp); 1576 + 1818 1577 static int param_set_audit(const char *val, const struct kernel_param *kp); 1819 1578 static int param_get_audit(char *buffer, const struct kernel_param *kp); 1820 1579 ··· 1851 1604 aacompressionlevel, 0400); 1852 1605 1853 1606 /* Debug mode */ 1854 - bool aa_g_debug = IS_ENABLED(CONFIG_SECURITY_APPARMOR_DEBUG_MESSAGES); 1855 - module_param_named(debug, aa_g_debug, aabool, S_IRUSR | S_IWUSR); 1607 + int aa_g_debug; 1608 + module_param_call(debug, param_set_debug, param_get_debug, 1609 + &aa_g_debug, 0600); 1856 1610 1857 1611 /* Audit mode */ 1858 1612 enum audit_mode aa_g_audit; ··· 2044 1796 if (apparmor_initialized && !aa_current_policy_view_capable(NULL)) 2045 1797 return -EPERM; 2046 1798 return param_get_int(buffer, kp); 1799 + } 1800 + 1801 + static int param_get_debug(char *buffer, const struct kernel_param *kp) 1802 + { 1803 + if (!apparmor_enabled) 1804 + return -EINVAL; 1805 + if (apparmor_initialized && !aa_current_policy_view_capable(NULL)) 1806 + return -EPERM; 1807 + return aa_print_debug_params(buffer); 1808 + } 1809 + 1810 + static int param_set_debug(const char *val, const struct kernel_param *kp) 1811 + { 1812 + int i; 1813 + 1814 + if (!apparmor_enabled) 1815 + return -EINVAL; 1816 + if (!val) 1817 + return -EINVAL; 1818 + if (apparmor_initialized && !aa_current_policy_admin_capable(NULL)) 1819 + return -EPERM; 1820 + 1821 + i = aa_parse_debug_params(val); 1822 + if (i == DEBUG_PARSE_ERROR) 1823 + return -EINVAL; 1824 + 1825 + aa_g_debug = i; 1826 + return 0; 2047 1827 } 2048 1828 2049 1829 static int param_get_audit(char *buffer, const struct kernel_param *kp) ··· 2282 2006 * two should be enough, with more CPUs it is possible that more 2283 2007 * buffers will be used simultaneously. The preallocated pool may grow. 2284 2008 * This preallocation has also the side-effect that AppArmor will be 2285 - * disabled early at boot if aa_g_path_max is extremly high. 2009 + * disabled early at boot if aa_g_path_max is extremely high. 2286 2010 */ 2287 2011 if (num_online_cpus() > 1) 2288 2012 num = 4 + RESERVE_COUNT; ··· 2358 2082 { 2359 2083 struct aa_sk_ctx *ctx; 2360 2084 struct sock *sk; 2085 + int error; 2361 2086 2362 2087 if (!skb->secmark) 2363 2088 return NF_ACCEPT; ··· 2368 2091 return NF_ACCEPT; 2369 2092 2370 2093 ctx = aa_sock(sk); 2371 - if (!apparmor_secmark_check(ctx->label, OP_SENDMSG, AA_MAY_SEND, 2372 - skb->secmark, sk)) 2094 + rcu_read_lock(); 2095 + error = apparmor_secmark_check(rcu_dereference(ctx->label), OP_SENDMSG, 2096 + AA_MAY_SEND, skb->secmark, sk); 2097 + rcu_read_unlock(); 2098 + if (!error) 2373 2099 return NF_ACCEPT; 2374 2100 2375 2101 return NF_DROP_ERR(-ECONNREFUSED); ··· 2429 2149 __initcall(apparmor_nf_ip_init); 2430 2150 #endif 2431 2151 2432 - static char nulldfa_src[] = { 2152 + static char nulldfa_src[] __aligned(8) = { 2433 2153 #include "nulldfa.in" 2434 2154 }; 2435 2155 static struct aa_dfa *nulldfa; 2436 2156 2437 - static char stacksplitdfa_src[] = { 2157 + static char stacksplitdfa_src[] __aligned(8) = { 2438 2158 #include "stacksplitdfa.in" 2439 2159 }; 2440 2160 struct aa_dfa *stacksplitdfa;
+12 -11
security/apparmor/match.c
··· 679 679 return state; 680 680 } 681 681 682 - #define inc_wb_pos(wb) \ 683 - do { \ 682 + #define inc_wb_pos(wb) \ 683 + do { \ 684 + BUILD_BUG_ON_NOT_POWER_OF_2(WB_HISTORY_SIZE); \ 684 685 wb->pos = (wb->pos + 1) & (WB_HISTORY_SIZE - 1); \ 685 - wb->len = (wb->len + 1) & (WB_HISTORY_SIZE - 1); \ 686 + wb->len = (wb->len + 1) > WB_HISTORY_SIZE ? WB_HISTORY_SIZE : \ 687 + wb->len + 1; \ 686 688 } while (0) 687 689 688 690 /* For DFAs that don't support extended tagging of states */ 691 + /* adjust is only set if is_loop returns true */ 689 692 static bool is_loop(struct match_workbuf *wb, aa_state_t state, 690 693 unsigned int *adjust) 691 694 { 692 - aa_state_t pos = wb->pos; 693 - aa_state_t i; 695 + int pos = wb->pos; 696 + int i; 694 697 695 698 if (wb->history[pos] < state) 696 699 return false; 697 700 698 - for (i = 0; i <= wb->len; i++) { 701 + for (i = 0; i < wb->len; i++) { 699 702 if (wb->history[pos] == state) { 700 703 *adjust = i; 701 704 return true; 702 705 } 703 - if (pos == 0) 704 - pos = WB_HISTORY_SIZE; 705 - pos--; 706 + /* -1 wraps to WB_HISTORY_SIZE - 1 */ 707 + pos = (pos - 1) & (WB_HISTORY_SIZE - 1); 706 708 } 707 709 708 - *adjust = i; 709 - return true; 710 + return false; 710 711 } 711 712 712 713 static aa_state_t leftmatch_fb(struct aa_dfa *dfa, aa_state_t start,
+4 -8
security/apparmor/mount.c
··· 311 311 { 312 312 struct aa_perms perms = { }; 313 313 const char *mntpnt = NULL, *info = NULL; 314 - struct aa_ruleset *rules = list_first_entry(&profile->rules, 315 - typeof(*rules), list); 314 + struct aa_ruleset *rules = profile->label.rules[0]; 316 315 int pos, error; 317 316 318 317 AA_BUG(!profile); ··· 370 371 bool binary) 371 372 { 372 373 const char *devname = NULL, *info = NULL; 373 - struct aa_ruleset *rules = list_first_entry(&profile->rules, 374 - typeof(*rules), list); 374 + struct aa_ruleset *rules = profile->label.rules[0]; 375 375 int error = -EACCES; 376 376 377 377 AA_BUG(!profile); ··· 602 604 struct aa_profile *profile, const struct path *path, 603 605 char *buffer) 604 606 { 605 - struct aa_ruleset *rules = list_first_entry(&profile->rules, 606 - typeof(*rules), list); 607 + struct aa_ruleset *rules = profile->label.rules[0]; 607 608 struct aa_perms perms = { }; 608 609 const char *name = NULL, *info = NULL; 609 610 aa_state_t state; ··· 665 668 const struct path *old_path, 666 669 char *old_buffer) 667 670 { 668 - struct aa_ruleset *rules = list_first_entry(&profile->rules, 669 - typeof(*rules), list); 671 + struct aa_ruleset *rules = profile->label.rules[0]; 670 672 const char *old_name, *new_name = NULL, *info = NULL; 671 673 const char *trans_name = NULL; 672 674 struct aa_perms perms = { };
+163 -26
security/apparmor/net.c
··· 8 8 * Copyright 2009-2017 Canonical Ltd. 9 9 */ 10 10 11 + #include "include/af_unix.h" 11 12 #include "include/apparmor.h" 12 13 #include "include/audit.h" 13 14 #include "include/cred.h" ··· 22 21 23 22 struct aa_sfs_entry aa_sfs_entry_network[] = { 24 23 AA_SFS_FILE_STRING("af_mask", AA_SFS_AF_MASK), 24 + { } 25 + }; 26 + 27 + struct aa_sfs_entry aa_sfs_entry_networkv9[] = { 28 + AA_SFS_FILE_STRING("af_mask", AA_SFS_AF_MASK), 29 + AA_SFS_FILE_BOOLEAN("af_unix", 1), 25 30 { } 26 31 }; 27 32 ··· 73 66 "unknown", 74 67 }; 75 68 69 + static void audit_unix_addr(struct audit_buffer *ab, const char *str, 70 + struct sockaddr_un *addr, int addrlen) 71 + { 72 + int len = unix_addr_len(addrlen); 73 + 74 + if (!addr || len <= 0) { 75 + audit_log_format(ab, " %s=none", str); 76 + } else if (addr->sun_path[0]) { 77 + audit_log_format(ab, " %s=", str); 78 + audit_log_untrustedstring(ab, addr->sun_path); 79 + } else { 80 + audit_log_format(ab, " %s=\"@", str); 81 + if (audit_string_contains_control(&addr->sun_path[1], len - 1)) 82 + audit_log_n_hex(ab, &addr->sun_path[1], len - 1); 83 + else 84 + audit_log_format(ab, "%.*s", len - 1, 85 + &addr->sun_path[1]); 86 + audit_log_format(ab, "\""); 87 + } 88 + } 89 + 90 + static void audit_unix_sk_addr(struct audit_buffer *ab, const char *str, 91 + const struct sock *sk) 92 + { 93 + const struct unix_sock *u = unix_sk(sk); 94 + 95 + if (u && u->addr) { 96 + int addrlen; 97 + struct sockaddr_un *addr = aa_sunaddr(u, &addrlen); 98 + 99 + audit_unix_addr(ab, str, addr, addrlen); 100 + } else { 101 + audit_unix_addr(ab, str, NULL, 0); 102 + 103 + } 104 + } 76 105 77 106 /* audit callback for net specific fields */ 78 107 void audit_net_cb(struct audit_buffer *ab, void *va) ··· 116 73 struct common_audit_data *sa = va; 117 74 struct apparmor_audit_data *ad = aad(sa); 118 75 119 - if (address_family_names[sa->u.net->family]) 76 + if (address_family_names[ad->common.u.net->family]) 120 77 audit_log_format(ab, " family=\"%s\"", 121 - address_family_names[sa->u.net->family]); 78 + address_family_names[ad->common.u.net->family]); 122 79 else 123 80 audit_log_format(ab, " family=\"unknown(%d)\"", 124 - sa->u.net->family); 81 + ad->common.u.net->family); 125 82 if (sock_type_names[ad->net.type]) 126 83 audit_log_format(ab, " sock_type=\"%s\"", 127 84 sock_type_names[ad->net.type]); ··· 141 98 net_mask_names, NET_PERMS_MASK); 142 99 } 143 100 } 101 + if (ad->common.u.net->family == PF_UNIX) { 102 + if (ad->net.addr || !ad->common.u.net->sk) 103 + audit_unix_addr(ab, "addr", 104 + unix_addr(ad->net.addr), 105 + ad->net.addrlen); 106 + else 107 + audit_unix_sk_addr(ab, "addr", ad->common.u.net->sk); 108 + if (ad->request & NET_PEER_MASK) { 109 + audit_unix_addr(ab, "peer_addr", 110 + unix_addr(ad->net.peer.addr), 111 + ad->net.peer.addrlen); 112 + } 113 + } 144 114 if (ad->peer) { 145 115 audit_log_format(ab, " peer="); 146 116 aa_label_xaudit(ab, labels_ns(ad->subj_label), ad->peer, ··· 161 105 } 162 106 } 163 107 108 + /* standard permission lookup pattern - supports early bailout */ 109 + int aa_do_perms(struct aa_profile *profile, struct aa_policydb *policy, 110 + aa_state_t state, u32 request, 111 + struct aa_perms *p, struct apparmor_audit_data *ad) 112 + { 113 + struct aa_perms perms; 114 + 115 + AA_BUG(!profile); 116 + AA_BUG(!policy); 117 + 118 + 119 + if (state || !p) 120 + p = aa_lookup_perms(policy, state); 121 + perms = *p; 122 + aa_apply_modes_to_perms(profile, &perms); 123 + return aa_check_perms(profile, &perms, request, ad, 124 + audit_net_cb); 125 + } 126 + 127 + /* only continue match if 128 + * insufficient current perms at current state 129 + * indicates there are more perms in later state 130 + * Returns: perms struct if early match 131 + */ 132 + static struct aa_perms *early_match(struct aa_policydb *policy, 133 + aa_state_t state, u32 request) 134 + { 135 + struct aa_perms *p; 136 + 137 + p = aa_lookup_perms(policy, state); 138 + if (((p->allow & request) != request) && (p->allow & AA_CONT_MATCH)) 139 + return NULL; 140 + return p; 141 + } 142 + 143 + static aa_state_t aa_dfa_match_be16(struct aa_dfa *dfa, aa_state_t state, 144 + u16 data) 145 + { 146 + __be16 buffer = cpu_to_be16(data); 147 + 148 + return aa_dfa_match_len(dfa, state, (char *) &buffer, 2); 149 + } 150 + 151 + /** 152 + * aa_match_to_prot - match the af, type, protocol triplet 153 + * @policy: policy being matched 154 + * @state: state to start in 155 + * @request: permissions being requested, ignored if @p == NULL 156 + * @af: socket address family 157 + * @type: socket type 158 + * @protocol: socket protocol 159 + * @p: output - pointer to permission associated with match 160 + * @info: output - pointer to string describing failure 161 + * 162 + * RETURNS: state match stopped in. 163 + * 164 + * If @(p) is assigned a value the returned state will be the 165 + * corresponding state. Will not set @p on failure or if match completes 166 + * only if an early match occurs 167 + */ 168 + aa_state_t aa_match_to_prot(struct aa_policydb *policy, aa_state_t state, 169 + u32 request, u16 af, int type, int protocol, 170 + struct aa_perms **p, const char **info) 171 + { 172 + state = aa_dfa_match_be16(policy->dfa, state, (u16)af); 173 + if (!state) { 174 + *info = "failed af match"; 175 + return state; 176 + } 177 + state = aa_dfa_match_be16(policy->dfa, state, (u16)type); 178 + if (state) { 179 + if (p) 180 + *p = early_match(policy, state, request); 181 + if (!p || !*p) { 182 + state = aa_dfa_match_be16(policy->dfa, state, (u16)protocol); 183 + if (!state) 184 + *info = "failed protocol match"; 185 + } 186 + } else { 187 + *info = "failed type match"; 188 + } 189 + 190 + return state; 191 + } 192 + 164 193 /* Generic af perm */ 165 194 int aa_profile_af_perm(struct aa_profile *profile, 166 195 struct apparmor_audit_data *ad, u32 request, u16 family, 167 - int type) 196 + int type, int protocol) 168 197 { 169 - struct aa_ruleset *rules = list_first_entry(&profile->rules, 170 - typeof(*rules), list); 171 - struct aa_perms perms = { }; 198 + struct aa_ruleset *rules = profile->label.rules[0]; 199 + struct aa_perms *p = NULL; 172 200 aa_state_t state; 173 - __be16 buffer[2]; 174 201 175 202 AA_BUG(family >= AF_MAX); 176 203 AA_BUG(type < 0 || type >= SOCK_MAX); 204 + AA_BUG(profile_unconfined(profile)); 177 205 178 206 if (profile_unconfined(profile)) 179 207 return 0; 180 - state = RULE_MEDIATES(rules, AA_CLASS_NET); 208 + state = RULE_MEDIATES_NET(rules); 181 209 if (!state) 182 210 return 0; 183 - 184 - buffer[0] = cpu_to_be16(family); 185 - buffer[1] = cpu_to_be16((u16) type); 186 - state = aa_dfa_match_len(rules->policy->dfa, state, (char *) &buffer, 187 - 4); 188 - perms = *aa_lookup_perms(rules->policy, state); 189 - aa_apply_modes_to_perms(profile, &perms); 190 - 191 - return aa_check_perms(profile, &perms, request, ad, audit_net_cb); 211 + state = aa_match_to_prot(rules->policy, state, request, family, type, 212 + protocol, &p, &ad->info); 213 + return aa_do_perms(profile, rules->policy, state, request, p, ad); 192 214 } 193 215 194 216 int aa_af_perm(const struct cred *subj_cred, struct aa_label *label, 195 217 const char *op, u32 request, u16 family, int type, int protocol) 196 218 { 197 219 struct aa_profile *profile; 198 - DEFINE_AUDIT_NET(ad, op, NULL, family, type, protocol); 220 + DEFINE_AUDIT_NET(ad, op, subj_cred, NULL, family, type, protocol); 199 221 200 222 return fn_for_each_confined(label, profile, 201 223 aa_profile_af_perm(profile, &ad, request, family, 202 - type)); 224 + type, protocol)); 203 225 } 204 226 205 227 static int aa_label_sk_perm(const struct cred *subj_cred, ··· 291 157 AA_BUG(!label); 292 158 AA_BUG(!sk); 293 159 294 - if (ctx->label != kernel_t && !unconfined(label)) { 160 + if (rcu_access_pointer(ctx->label) != kernel_t && !unconfined(label)) { 295 161 struct aa_profile *profile; 296 - DEFINE_AUDIT_SK(ad, op, sk); 162 + DEFINE_AUDIT_SK(ad, op, subj_cred, sk); 297 163 298 164 ad.subj_cred = subj_cred; 299 165 error = fn_for_each_confined(label, profile, ··· 321 187 322 188 323 189 int aa_sock_file_perm(const struct cred *subj_cred, struct aa_label *label, 324 - const char *op, u32 request, struct socket *sock) 190 + const char *op, u32 request, struct file *file) 325 191 { 192 + struct socket *sock = (struct socket *) file->private_data; 193 + 326 194 AA_BUG(!label); 327 195 AA_BUG(!sock); 328 196 AA_BUG(!sock->sk); 329 197 198 + if (sock->sk->sk_family == PF_UNIX) 199 + return aa_unix_file_perm(subj_cred, label, op, request, file); 330 200 return aa_label_sk_perm(subj_cred, label, op, request, sock->sk); 331 201 } 332 202 ··· 361 223 { 362 224 int i, ret; 363 225 struct aa_perms perms = { }; 364 - struct aa_ruleset *rules = list_first_entry(&profile->rules, 365 - typeof(*rules), list); 226 + struct aa_ruleset *rules = profile->label.rules[0]; 366 227 367 228 if (rules->secmark_count == 0) 368 229 return 0; ··· 394 257 u32 secid, const struct sock *sk) 395 258 { 396 259 struct aa_profile *profile; 397 - DEFINE_AUDIT_SK(ad, op, sk); 260 + DEFINE_AUDIT_SK(ad, op, NULL, sk); 398 261 399 262 return fn_for_each_confined(label, profile, 400 263 aa_secmark_perm(profile, request, secid,
+65 -28
security/apparmor/policy.c
··· 243 243 { 244 244 int i; 245 245 246 + if (!rules) 247 + return; 248 + 246 249 aa_put_pdb(rules->file); 247 250 aa_put_pdb(rules->policy); 248 251 aa_free_cap_rules(&rules->caps); ··· 262 259 struct aa_ruleset *rules; 263 260 264 261 rules = kzalloc(sizeof(*rules), gfp); 265 - if (rules) 266 - INIT_LIST_HEAD(&rules->list); 267 262 268 263 return rules; 269 264 } ··· 278 277 */ 279 278 void aa_free_profile(struct aa_profile *profile) 280 279 { 281 - struct aa_ruleset *rule, *tmp; 282 280 struct rhashtable *rht; 283 281 284 - AA_DEBUG("%s(%p)\n", __func__, profile); 282 + AA_DEBUG(DEBUG_POLICY, "%s(%p)\n", __func__, profile); 285 283 286 284 if (!profile) 287 285 return; ··· 299 299 * at this point there are no tasks that can have a reference 300 300 * to rules 301 301 */ 302 - list_for_each_entry_safe(rule, tmp, &profile->rules, list) { 303 - list_del_init(&rule->list); 304 - free_ruleset(rule); 305 - } 302 + for (int i = 0; i < profile->n_rules; i++) 303 + free_ruleset(profile->label.rules[i]); 304 + 306 305 kfree_sensitive(profile->dirname); 307 306 308 307 if (profile->data) { ··· 330 331 gfp_t gfp) 331 332 { 332 333 struct aa_profile *profile; 333 - struct aa_ruleset *rules; 334 334 335 - /* freed by free_profile - usually through aa_put_profile */ 336 - profile = kzalloc(struct_size(profile, label.vec, 2), gfp); 335 + /* freed by free_profile - usually through aa_put_profile 336 + * this adds space for a single ruleset in the rules section of the 337 + * label 338 + */ 339 + profile = kzalloc(struct_size(profile, label.rules, 1), gfp); 337 340 if (!profile) 338 341 return NULL; 339 342 ··· 344 343 if (!aa_label_init(&profile->label, 1, gfp)) 345 344 goto fail; 346 345 347 - INIT_LIST_HEAD(&profile->rules); 348 - 349 346 /* allocate the first ruleset, but leave it empty */ 350 - rules = aa_alloc_ruleset(gfp); 351 - if (!rules) 347 + profile->label.rules[0] = aa_alloc_ruleset(gfp); 348 + if (!profile->label.rules[0]) 352 349 goto fail; 353 - list_add(&rules->list, &profile->rules); 350 + profile->n_rules = 1; 354 351 355 352 /* update being set needed by fs interface */ 356 353 if (!proxy) { ··· 363 364 profile->label.flags |= FLAG_PROFILE; 364 365 profile->label.vec[0] = profile; 365 366 367 + profile->signal = SIGKILL; 366 368 /* refcount released by caller */ 367 369 return profile; 368 370 ··· 371 371 aa_free_profile(profile); 372 372 373 373 return NULL; 374 + } 375 + 376 + static inline bool ANY_RULE_MEDIATES(struct aa_profile *profile, 377 + unsigned char class) 378 + { 379 + int i; 380 + 381 + for (i = 0; i < profile->n_rules; i++) { 382 + if (RULE_MEDIATES(profile->label.rules[i], class)) 383 + return true; 384 + } 385 + return false; 386 + } 387 + 388 + /* set of rules that are mediated by unconfined */ 389 + static int unconfined_mediates[] = { AA_CLASS_NS, AA_CLASS_IO_URING, 0 }; 390 + 391 + /* must be called after profile rulesets and start information is setup */ 392 + void aa_compute_profile_mediates(struct aa_profile *profile) 393 + { 394 + int c; 395 + 396 + if (profile_unconfined(profile)) { 397 + int *pos; 398 + 399 + for (pos = unconfined_mediates; *pos; pos++) { 400 + if (ANY_RULE_MEDIATES(profile, *pos)) 401 + profile->label.mediates |= ((u64) 1) << AA_CLASS_NS; 402 + } 403 + return; 404 + } 405 + for (c = 0; c <= AA_CLASS_LAST; c++) { 406 + if (ANY_RULE_MEDIATES(profile, c)) 407 + profile->label.mediates |= ((u64) 1) << c; 408 + } 374 409 } 375 410 376 411 /* TODO: profile accounting - setup in remove */ ··· 498 463 } 499 464 500 465 /** 501 - * __create_missing_ancestors - create place holders for missing ancestores 466 + * __create_missing_ancestors - create place holders for missing ancestors 502 467 * @ns: namespace to lookup profile in (NOT NULL) 503 468 * @hname: hierarchical profile name to find parent of (NOT NULL) 504 469 * @gfp: type of allocation. ··· 656 621 /* TODO: ideally we should inherit abi from parent */ 657 622 profile->label.flags |= FLAG_NULL; 658 623 profile->attach.xmatch = aa_get_pdb(nullpdb); 659 - rules = list_first_entry(&profile->rules, typeof(*rules), list); 624 + rules = profile->label.rules[0]; 660 625 rules->file = aa_get_pdb(nullpdb); 661 626 rules->policy = aa_get_pdb(nullpdb); 627 + aa_compute_profile_mediates(profile); 662 628 663 629 if (parent) { 664 630 profile->path_flags = parent->path_flags; 665 - 631 + /* override/inherit what is mediated from parent */ 632 + profile->label.mediates = parent->label.mediates; 666 633 /* released on free_profile */ 667 634 rcu_assign_pointer(profile->parent, aa_get_profile(parent)); 668 635 profile->ns = aa_get_ns(parent->ns); ··· 870 833 bool capable = policy_ns_capable(subj_cred, label, user_ns, 871 834 CAP_MAC_ADMIN) == 0; 872 835 873 - AA_DEBUG("cap_mac_admin? %d\n", capable); 874 - AA_DEBUG("policy locked? %d\n", aa_g_lock_policy); 836 + AA_DEBUG(DEBUG_POLICY, "cap_mac_admin? %d\n", capable); 837 + AA_DEBUG(DEBUG_POLICY, "policy locked? %d\n", aa_g_lock_policy); 875 838 876 839 return aa_policy_view_capable(subj_cred, label, ns) && capable && 877 840 !aa_g_lock_policy; ··· 880 843 bool aa_current_policy_view_capable(struct aa_ns *ns) 881 844 { 882 845 struct aa_label *label; 883 - bool res; 846 + bool needput, res; 884 847 885 - label = __begin_current_label_crit_section(); 848 + label = __begin_current_label_crit_section(&needput); 886 849 res = aa_policy_view_capable(current_cred(), label, ns); 887 - __end_current_label_crit_section(label); 850 + __end_current_label_crit_section(label, needput); 888 851 889 852 return res; 890 853 } ··· 892 855 bool aa_current_policy_admin_capable(struct aa_ns *ns) 893 856 { 894 857 struct aa_label *label; 895 - bool res; 858 + bool needput, res; 896 859 897 - label = __begin_current_label_crit_section(); 860 + label = __begin_current_label_crit_section(&needput); 898 861 res = aa_policy_admin_capable(current_cred(), label, ns); 899 - __end_current_label_crit_section(label); 862 + __end_current_label_crit_section(label, needput); 900 863 901 864 return res; 902 865 } ··· 1105 1068 goto out; 1106 1069 1107 1070 /* ensure that profiles are all for the same ns 1108 - * TODO: update locking to remove this constaint. All profiles in 1071 + * TODO: update locking to remove this constraint. All profiles in 1109 1072 * the load set must succeed as a set or the load will 1110 1073 * fail. Sort ent list and take ns locks in hierarchy order 1111 1074 */
+3 -3
security/apparmor/policy_compat.c
··· 286 286 287 287 AA_BUG(!dfa); 288 288 289 - for (state = 0; state < state_count; state++) 289 + for (state = 0; state < state_count; state++) { 290 290 ACCEPT_TABLE(dfa)[state] = state * factor; 291 - kvfree(dfa->tables[YYTD_ID_ACCEPT2]); 292 - dfa->tables[YYTD_ID_ACCEPT2] = NULL; 291 + ACCEPT_TABLE2(dfa)[state] = factor > 1 ? ACCEPT_FLAG_OWNER : 0; 292 + } 293 293 } 294 294 295 295 /* TODO: merge different dfa mappings into single map_policy fn */
+1 -1
security/apparmor/policy_ns.c
··· 107 107 struct aa_ns *ns; 108 108 109 109 ns = kzalloc(sizeof(*ns), GFP_KERNEL); 110 - AA_DEBUG("%s(%p)\n", __func__, ns); 110 + AA_DEBUG(DEBUG_POLICY, "%s(%p)\n", __func__, ns); 111 111 if (!ns) 112 112 return NULL; 113 113 if (!aa_policy_init(&ns->base, prefix, name, GFP_KERNEL))
+55 -12
security/apparmor/policy_unpack.c
··· 29 29 #include "include/policy.h" 30 30 #include "include/policy_unpack.h" 31 31 #include "include/policy_compat.h" 32 + #include "include/signal.h" 32 33 33 34 /* audit callback for unpack fields */ 34 35 static void audit_cb(struct audit_buffer *ab, void *va) ··· 599 598 fail: 600 599 if (rules->secmark) { 601 600 for (i = 0; i < size; i++) 602 - kfree(rules->secmark[i].label); 603 - kfree(rules->secmark); 601 + kfree_sensitive(rules->secmark[i].label); 602 + kfree_sensitive(rules->secmark); 604 603 rules->secmark_count = 0; 605 604 rules->secmark = NULL; 606 605 } ··· 717 716 void *pos = e->pos; 718 717 int i, flags, error = -EPROTO; 719 718 ssize_t size; 719 + u32 version = 0; 720 720 721 721 pdb = aa_alloc_pdb(GFP_KERNEL); 722 722 if (!pdb) ··· 735 733 if (pdb->perms) { 736 734 /* perms table present accept is index */ 737 735 flags = TO_ACCEPT1_FLAG(YYTD_DATA32); 736 + if (aa_unpack_u32(e, &version, "permsv") && version > 2) 737 + /* accept2 used for dfa flags */ 738 + flags |= TO_ACCEPT2_FLAG(YYTD_DATA32); 738 739 } else { 739 740 /* packed perms in accept1 and accept2 */ 740 741 flags = TO_ACCEPT1_FLAG(YYTD_DATA32) | ··· 775 770 } 776 771 } 777 772 773 + /* accept2 is in some cases being allocated, even with perms */ 774 + if (pdb->perms && !pdb->dfa->tables[YYTD_ID_ACCEPT2]) { 775 + /* add dfa flags table missing in v2 */ 776 + u32 noents = pdb->dfa->tables[YYTD_ID_ACCEPT]->td_lolen; 777 + u16 tdflags = pdb->dfa->tables[YYTD_ID_ACCEPT]->td_flags; 778 + size_t tsize = table_size(noents, tdflags); 779 + 780 + pdb->dfa->tables[YYTD_ID_ACCEPT2] = kvzalloc(tsize, GFP_KERNEL); 781 + if (!pdb->dfa->tables[YYTD_ID_ACCEPT2]) { 782 + *info = "failed to alloc dfa flags table"; 783 + goto out; 784 + } 785 + pdb->dfa->tables[YYTD_ID_ACCEPT2]->td_lolen = noents; 786 + pdb->dfa->tables[YYTD_ID_ACCEPT2]->td_flags = tdflags; 787 + } 778 788 /* 779 789 * Unfortunately due to a bug in earlier userspaces, a 780 790 * transition table may be present even when the dfa is ··· 803 783 if (!pdb->dfa && pdb->trans.table) 804 784 aa_free_str_table(&pdb->trans); 805 785 806 - /* TODO: move compat mapping here, requires dfa merging first */ 807 - /* TODO: move verify here, it has to be done after compat mappings */ 808 - 786 + /* TODO: 787 + * - move compat mapping here, requires dfa merging first 788 + * - move verify here, it has to be done after compat mappings 789 + * - move free of unneeded trans table here, has to be done 790 + * after perm mapping. 791 + */ 792 + out: 809 793 *policy = pdb; 810 794 return 0; 811 795 ··· 886 862 error = -ENOMEM; 887 863 goto fail; 888 864 } 889 - rules = list_first_entry(&profile->rules, typeof(*rules), list); 865 + rules = profile->label.rules[0]; 890 866 891 867 /* profile renaming is optional */ 892 868 (void) aa_unpack_str(e, &profile->rename, "rename"); ··· 922 898 (void) aa_unpack_strdup(e, &disconnected, "disconnected"); 923 899 profile->disconnected = disconnected; 924 900 901 + /* optional */ 902 + (void) aa_unpack_u32(e, &profile->signal, "kill"); 903 + if (profile->signal < 1 || profile->signal > MAXMAPPED_SIG) { 904 + info = "profile kill.signal invalid value"; 905 + goto fail; 906 + } 925 907 /* per profile debug flags (complain, audit) */ 926 908 if (!aa_unpack_nameX(e, AA_STRUCT, "flags")) { 927 909 info = "profile missing flags"; ··· 1131 1101 goto fail; 1132 1102 } 1133 1103 1104 + aa_compute_profile_mediates(profile); 1105 + 1134 1106 return profile; 1135 1107 1136 1108 fail: ··· 1247 1215 static bool verify_perms(struct aa_policydb *pdb) 1248 1216 { 1249 1217 int i; 1218 + int xidx, xmax = -1; 1250 1219 1251 1220 for (i = 0; i < pdb->size; i++) { 1252 1221 if (!verify_perm(&pdb->perms[i])) 1253 1222 return false; 1254 1223 /* verify indexes into str table */ 1255 - if ((pdb->perms[i].xindex & AA_X_TYPE_MASK) == AA_X_TABLE && 1256 - (pdb->perms[i].xindex & AA_X_INDEX_MASK) >= pdb->trans.size) 1257 - return false; 1224 + if ((pdb->perms[i].xindex & AA_X_TYPE_MASK) == AA_X_TABLE) { 1225 + xidx = pdb->perms[i].xindex & AA_X_INDEX_MASK; 1226 + if (xidx >= pdb->trans.size) 1227 + return false; 1228 + if (xmax < xidx) 1229 + xmax = xidx; 1230 + } 1258 1231 if (pdb->perms[i].tag && pdb->perms[i].tag >= pdb->trans.size) 1259 1232 return false; 1260 1233 if (pdb->perms[i].label && 1261 1234 pdb->perms[i].label >= pdb->trans.size) 1262 1235 return false; 1263 1236 } 1264 - 1237 + /* deal with incorrectly constructed string tables */ 1238 + if (xmax == -1) { 1239 + aa_free_str_table(&pdb->trans); 1240 + } else if (pdb->trans.size > xmax + 1) { 1241 + if (!aa_resize_str_table(&pdb->trans, xmax + 1, GFP_KERNEL)) 1242 + return false; 1243 + } 1265 1244 return true; 1266 1245 } 1267 1246 ··· 1286 1243 */ 1287 1244 static int verify_profile(struct aa_profile *profile) 1288 1245 { 1289 - struct aa_ruleset *rules = list_first_entry(&profile->rules, 1290 - typeof(*rules), list); 1246 + struct aa_ruleset *rules = profile->label.rules[0]; 1247 + 1291 1248 if (!rules) 1292 1249 return 0; 1293 1250
+4 -2
security/apparmor/policy_unpack_test.c
··· 9 9 #include "include/policy.h" 10 10 #include "include/policy_unpack.h" 11 11 12 + #include <linux/unaligned.h> 13 + 12 14 #define TEST_STRING_NAME "TEST_STRING" 13 15 #define TEST_STRING_DATA "testing" 14 16 #define TEST_STRING_BUF_OFFSET \ ··· 82 80 *(buf + 1) = strlen(TEST_U32_NAME) + 1; 83 81 strscpy(buf + 3, TEST_U32_NAME, e->end - (void *)(buf + 3)); 84 82 *(buf + 3 + strlen(TEST_U32_NAME) + 1) = AA_U32; 85 - *((__le32 *)(buf + 3 + strlen(TEST_U32_NAME) + 2)) = cpu_to_le32(TEST_U32_DATA); 83 + put_unaligned_le32(TEST_U32_DATA, buf + 3 + strlen(TEST_U32_NAME) + 2); 86 84 87 85 buf = e->start + TEST_NAMED_U64_BUF_OFFSET; 88 86 *buf = AA_NAME; ··· 105 103 *(buf + 1) = strlen(TEST_ARRAY_NAME) + 1; 106 104 strscpy(buf + 3, TEST_ARRAY_NAME, e->end - (void *)(buf + 3)); 107 105 *(buf + 3 + strlen(TEST_ARRAY_NAME) + 1) = AA_ARRAY; 108 - *((__le16 *)(buf + 3 + strlen(TEST_ARRAY_NAME) + 2)) = cpu_to_le16(TEST_ARRAY_SIZE); 106 + put_unaligned_le16(TEST_ARRAY_SIZE, buf + 3 + strlen(TEST_ARRAY_NAME) + 2); 109 107 110 108 return e; 111 109 }
+4 -2
security/apparmor/procattr.c
··· 125 125 for (count = 0; (hat < end) && count < 16; ++count) { 126 126 char *next = hat + strlen(hat) + 1; 127 127 hats[count] = hat; 128 - AA_DEBUG("%s: (pid %d) Magic 0x%llx count %d hat '%s'\n" 128 + AA_DEBUG(DEBUG_DOMAIN, 129 + "%s: (pid %d) Magic 0x%llx count %d hat '%s'\n" 129 130 , __func__, current->pid, token, count, hat); 130 131 hat = next; 131 132 } 132 133 } else 133 - AA_DEBUG("%s: (pid %d) Magic 0x%llx count %d Hat '%s'\n", 134 + AA_DEBUG(DEBUG_DOMAIN, 135 + "%s: (pid %d) Magic 0x%llx count %d Hat '%s'\n", 134 136 __func__, current->pid, token, count, "<NULL>"); 135 137 136 138 return aa_change_hat(hats, count, token, flags);
+3 -8
security/apparmor/resource.c
··· 89 89 struct aa_profile *profile, unsigned int resource, 90 90 struct rlimit *new_rlim) 91 91 { 92 - struct aa_ruleset *rules = list_first_entry(&profile->rules, 93 - typeof(*rules), list); 92 + struct aa_ruleset *rules = profile->label.rules[0]; 94 93 int e = 0; 95 94 96 95 if (rules->rlimits.mask & (1 << resource) && new_rlim->rlim_max > ··· 164 165 * to the lesser of the tasks hard limit and the init tasks soft limit 165 166 */ 166 167 label_for_each_confined(i, old_l, old) { 167 - struct aa_ruleset *rules = list_first_entry(&old->rules, 168 - typeof(*rules), 169 - list); 168 + struct aa_ruleset *rules = old->label.rules[0]; 170 169 if (rules->rlimits.mask) { 171 170 int j; 172 171 ··· 182 185 183 186 /* set any new hard limits as dictated by the new profile */ 184 187 label_for_each_confined(i, new_l, new) { 185 - struct aa_ruleset *rules = list_first_entry(&new->rules, 186 - typeof(*rules), 187 - list); 188 + struct aa_ruleset *rules = new->label.rules[0]; 188 189 int j; 189 190 190 191 if (!rules->rlimits.mask)
+4 -7
security/apparmor/task.c
··· 228 228 struct aa_label *peer, u32 request, 229 229 struct apparmor_audit_data *ad) 230 230 { 231 - struct aa_ruleset *rules = list_first_entry(&profile->rules, 232 - typeof(*rules), list); 231 + struct aa_ruleset *rules = profile->label.rules[0]; 233 232 struct aa_perms perms = { }; 234 233 235 234 ad->subj_cred = cred; ··· 245 246 struct apparmor_audit_data *ad) 246 247 { 247 248 if (profile_unconfined(tracee) || unconfined(tracer) || 248 - !ANY_RULE_MEDIATES(&tracee->rules, AA_CLASS_PTRACE)) 249 + !label_mediates(&tracee->label, AA_CLASS_PTRACE)) 249 250 return 0; 250 251 251 252 return profile_ptrace_perm(cred, tracee, tracer, request, ad); ··· 259 260 if (profile_unconfined(tracer)) 260 261 return 0; 261 262 262 - if (ANY_RULE_MEDIATES(&tracer->rules, AA_CLASS_PTRACE)) 263 + if (label_mediates(&tracer->label, AA_CLASS_PTRACE)) 263 264 return profile_ptrace_perm(cred, tracer, tracee, request, ad); 264 265 265 266 /* profile uses the old style capability check for ptrace */ ··· 323 324 ad->request = request; 324 325 325 326 if (!profile_unconfined(profile)) { 326 - struct aa_ruleset *rules = list_first_entry(&profile->rules, 327 - typeof(*rules), 328 - list); 327 + struct aa_ruleset *rules = profile->label.rules[0]; 329 328 aa_state_t state; 330 329 331 330 state = RULE_MEDIATES(rules, ad->class);