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

apparmor: provide finer control over policy management

Signed-off-by: John Johansen <john.johansen@canonical.com>

+35 -23
+7 -8
security/apparmor/apparmorfs.c
··· 400 400 return data; 401 401 } 402 402 403 - static ssize_t policy_update(int binop, const char __user *buf, size_t size, 403 + static ssize_t policy_update(u32 mask, const char __user *buf, size_t size, 404 404 loff_t *pos, struct aa_ns *ns) 405 405 { 406 406 ssize_t error; 407 407 struct aa_loaddata *data; 408 408 struct aa_profile *profile = aa_current_profile(); 409 - const char *op = binop == PROF_ADD ? OP_PROF_LOAD : OP_PROF_REPL; 410 409 /* high level check about policy management - fine grained in 411 410 * below after unpack 412 411 */ 413 - error = aa_may_manage_policy(profile, ns, op); 412 + error = aa_may_manage_policy(profile, ns, mask); 414 413 if (error) 415 414 return error; 416 415 ··· 417 418 error = PTR_ERR(data); 418 419 if (!IS_ERR(data)) { 419 420 error = aa_replace_profiles(ns ? ns : profile->ns, profile, 420 - binop, data); 421 + mask, data); 421 422 aa_put_loaddata(data); 422 423 } 423 424 ··· 429 430 loff_t *pos) 430 431 { 431 432 struct aa_ns *ns = aa_get_ns(f->f_inode->i_private); 432 - int error = policy_update(PROF_ADD, buf, size, pos, ns); 433 + int error = policy_update(AA_MAY_LOAD_POLICY, buf, size, pos, ns); 433 434 434 435 aa_put_ns(ns); 435 436 ··· 446 447 size_t size, loff_t *pos) 447 448 { 448 449 struct aa_ns *ns = aa_get_ns(f->f_inode->i_private); 449 - int error = policy_update(PROF_REPLACE, buf, size, pos, ns); 450 - 450 + int error = policy_update(AA_MAY_LOAD_POLICY | AA_MAY_REPLACE_POLICY, 451 + buf, size, pos, ns); 451 452 aa_put_ns(ns); 452 453 453 454 return error; ··· 471 472 /* high level check about policy management - fine grained in 472 473 * below after unpack 473 474 */ 474 - error = aa_may_manage_policy(profile, ns, OP_PROF_RM); 475 + error = aa_may_manage_policy(profile, ns, AA_MAY_REMOVE_POLICY); 475 476 if (error) 476 477 goto out; 477 478
+6 -2
security/apparmor/include/policy.h
··· 188 188 189 189 extern enum profile_mode aa_g_profile_mode; 190 190 191 + #define AA_MAY_LOAD_POLICY AA_MAY_APPEND 192 + #define AA_MAY_REPLACE_POLICY AA_MAY_WRITE 193 + #define AA_MAY_REMOVE_POLICY AA_MAY_DELETE 194 + 191 195 void __aa_update_proxy(struct aa_profile *orig, struct aa_profile *new); 192 196 193 197 void aa_add_profile(struct aa_policy *common, struct aa_profile *profile); ··· 212 208 struct aa_profile *aa_match_profile(struct aa_ns *ns, const char *name); 213 209 214 210 ssize_t aa_replace_profiles(struct aa_ns *view, struct aa_profile *profile, 215 - bool noreplace, struct aa_loaddata *udata); 211 + u32 mask, struct aa_loaddata *udata); 216 212 ssize_t aa_remove_profiles(struct aa_ns *view, struct aa_profile *profile, 217 213 char *name, size_t size); 218 214 void __aa_profile_list_release(struct list_head *head); ··· 327 323 bool policy_view_capable(struct aa_ns *ns); 328 324 bool policy_admin_capable(struct aa_ns *ns); 329 325 int aa_may_manage_policy(struct aa_profile *profile, struct aa_ns *ns, 330 - const char *op); 326 + u32 mask); 331 327 332 328 #endif /* __AA_POLICY_H */
+22 -13
security/apparmor/policy.c
··· 690 690 * 691 691 * Returns: 0 if the task is allowed to manipulate policy else error 692 692 */ 693 - int aa_may_manage_policy(struct aa_profile *profile, struct aa_ns *ns, 694 - const char *op) 693 + int aa_may_manage_policy(struct aa_profile *profile, struct aa_ns *ns, u32 mask) 695 694 { 695 + const char *op; 696 + 697 + if (mask & AA_MAY_REMOVE_POLICY) 698 + op = OP_PROF_RM; 699 + else if (mask & AA_MAY_REPLACE_POLICY) 700 + op = OP_PROF_REPL; 701 + else 702 + op = OP_PROF_LOAD; 703 + 696 704 /* check if loading policy is locked out */ 697 705 if (aa_g_lock_policy) 698 - return audit_policy(profile, op, NULL, NULL, 699 - "policy_locked", -EACCES); 706 + return audit_policy(profile, op, NULL, NULL, "policy_locked", 707 + -EACCES); 700 708 701 709 if (!policy_admin_capable(ns)) 702 - return audit_policy(profile, op, NULL, NULL, 703 - "not policy admin", -EACCES); 710 + return audit_policy(profile, op, NULL, NULL, "not policy admin", 711 + -EACCES); 704 712 705 713 /* TODO: add fine grained mediation of policy loads */ 706 714 return 0; ··· 833 825 * aa_replace_profiles - replace profile(s) on the profile list 834 826 * @view: namespace load is viewed from 835 827 * @label: label that is attempting to load/replace policy 836 - * @noreplace: true if only doing addition, no replacement allowed 828 + * @mask: permission mask 837 829 * @udata: serialized data stream (NOT NULL) 838 830 * 839 831 * unpack and replace a profile on the profile list and uses of that profile ··· 843 835 * Returns: size of data consumed else error code on failure. 844 836 */ 845 837 ssize_t aa_replace_profiles(struct aa_ns *view, struct aa_profile *profile, 846 - bool noreplace, struct aa_loaddata *udata) 838 + u32 mask, struct aa_loaddata *udata) 847 839 { 848 840 const char *ns_name, *info = NULL; 849 841 struct aa_ns *ns = NULL; 850 842 struct aa_load_ent *ent, *tmp; 851 843 struct aa_loaddata *rawdata_ent; 852 - const char *op = OP_PROF_REPL; 844 + const char *op; 853 845 ssize_t count, error; 854 - 855 846 LIST_HEAD(lh); 856 847 848 + op = mask & AA_MAY_REPLACE_POLICY ? OP_PROF_REPL : OP_PROF_LOAD; 857 849 aa_get_loaddata(udata); 858 850 /* released below */ 859 851 error = aa_unpack(udata, &lh, &ns_name); ··· 917 909 struct aa_policy *policy; 918 910 919 911 ent->new->rawdata = aa_get_loaddata(udata); 920 - error = __lookup_replace(ns, ent->new->base.hname, noreplace, 912 + error = __lookup_replace(ns, ent->new->base.hname, 913 + !(mask & AA_MAY_REPLACE_POLICY), 921 914 &ent->old, &info); 922 915 if (error) 923 916 goto fail_lock; 924 917 925 918 if (ent->new->rename) { 926 919 error = __lookup_replace(ns, ent->new->rename, 927 - noreplace, &ent->rename, 928 - &info); 920 + !(mask & AA_MAY_REPLACE_POLICY), 921 + &ent->rename, &info); 929 922 if (error) 930 923 goto fail_lock; 931 924 }