diff options
| author | John Johansen <john.johansen@canonical.com> | 2013-07-11 00:07:43 -0400 |
|---|---|---|
| committer | John Johansen <john.johansen@canonical.com> | 2013-08-14 14:42:06 -0400 |
| commit | 77b071b34045a0c65d0e1f85f3d47fd2b8b7a8a1 (patch) | |
| tree | b0b2c38b79969ac7b9439389888f6a1ac14a32a7 /security | |
| parent | 01e2b670aa898a39259bc85c78e3d74820f4d3b6 (diff) | |
apparmor: change how profile replacement update is done
remove the use of replaced by chaining and move to profile invalidation
and lookup to handle task replacement.
Replacement chaining can result in large chains of profiles being pinned
in memory when one profile in the chain is use. With implicit labeling
this will be even more of a problem, so move to a direct lookup method.
Signed-off-by: John Johansen <john.johansen@canonical.com>
Diffstat (limited to 'security')
| -rw-r--r-- | security/apparmor/context.c | 16 | ||||
| -rw-r--r-- | security/apparmor/domain.c | 4 | ||||
| -rw-r--r-- | security/apparmor/include/context.h | 15 | ||||
| -rw-r--r-- | security/apparmor/include/policy.h | 78 | ||||
| -rw-r--r-- | security/apparmor/lsm.c | 14 | ||||
| -rw-r--r-- | security/apparmor/policy.c | 85 |
6 files changed, 125 insertions, 87 deletions
diff --git a/security/apparmor/context.c b/security/apparmor/context.c index d5af1d15f26d..3064c6ced87c 100644 --- a/security/apparmor/context.c +++ b/security/apparmor/context.c | |||
| @@ -112,9 +112,9 @@ int aa_replace_current_profile(struct aa_profile *profile) | |||
| 112 | aa_clear_task_cxt_trans(cxt); | 112 | aa_clear_task_cxt_trans(cxt); |
| 113 | 113 | ||
| 114 | /* be careful switching cxt->profile, when racing replacement it | 114 | /* be careful switching cxt->profile, when racing replacement it |
| 115 | * is possible that cxt->profile->replacedby is the reference keeping | 115 | * is possible that cxt->profile->replacedby->profile is the reference |
| 116 | * @profile valid, so make sure to get its reference before dropping | 116 | * keeping @profile valid, so make sure to get its reference before |
| 117 | * the reference on cxt->profile */ | 117 | * dropping the reference on cxt->profile */ |
| 118 | aa_get_profile(profile); | 118 | aa_get_profile(profile); |
| 119 | aa_put_profile(cxt->profile); | 119 | aa_put_profile(cxt->profile); |
| 120 | cxt->profile = profile; | 120 | cxt->profile = profile; |
| @@ -175,7 +175,7 @@ int aa_set_current_hat(struct aa_profile *profile, u64 token) | |||
| 175 | abort_creds(new); | 175 | abort_creds(new); |
| 176 | return -EACCES; | 176 | return -EACCES; |
| 177 | } | 177 | } |
| 178 | cxt->profile = aa_get_profile(aa_newest_version(profile)); | 178 | cxt->profile = aa_get_newest_profile(profile); |
| 179 | /* clear exec on switching context */ | 179 | /* clear exec on switching context */ |
| 180 | aa_put_profile(cxt->onexec); | 180 | aa_put_profile(cxt->onexec); |
| 181 | cxt->onexec = NULL; | 181 | cxt->onexec = NULL; |
| @@ -212,14 +212,8 @@ int aa_restore_previous_profile(u64 token) | |||
| 212 | } | 212 | } |
| 213 | 213 | ||
| 214 | aa_put_profile(cxt->profile); | 214 | aa_put_profile(cxt->profile); |
| 215 | cxt->profile = aa_newest_version(cxt->previous); | 215 | cxt->profile = aa_get_newest_profile(cxt->previous); |
| 216 | BUG_ON(!cxt->profile); | 216 | BUG_ON(!cxt->profile); |
| 217 | if (unlikely(cxt->profile != cxt->previous)) { | ||
| 218 | aa_get_profile(cxt->profile); | ||
| 219 | aa_put_profile(cxt->previous); | ||
| 220 | } | ||
| 221 | /* ref has been transfered so avoid putting ref in clear_task_cxt */ | ||
| 222 | cxt->previous = NULL; | ||
| 223 | /* clear exec && prev information when restoring to previous context */ | 217 | /* clear exec && prev information when restoring to previous context */ |
| 224 | aa_clear_task_cxt_trans(cxt); | 218 | aa_clear_task_cxt_trans(cxt); |
| 225 | 219 | ||
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c index 454bcd7f3452..5488d095af6f 100644 --- a/security/apparmor/domain.c +++ b/security/apparmor/domain.c | |||
| @@ -359,7 +359,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) | |||
| 359 | cxt = cred_cxt(bprm->cred); | 359 | cxt = cred_cxt(bprm->cred); |
| 360 | BUG_ON(!cxt); | 360 | BUG_ON(!cxt); |
| 361 | 361 | ||
| 362 | profile = aa_get_profile(aa_newest_version(cxt->profile)); | 362 | profile = aa_get_newest_profile(cxt->profile); |
| 363 | /* | 363 | /* |
| 364 | * get the namespace from the replacement profile as replacement | 364 | * get the namespace from the replacement profile as replacement |
| 365 | * can change the namespace | 365 | * can change the namespace |
| @@ -417,7 +417,7 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) | |||
| 417 | 417 | ||
| 418 | if (!(cp.allow & AA_MAY_ONEXEC)) | 418 | if (!(cp.allow & AA_MAY_ONEXEC)) |
| 419 | goto audit; | 419 | goto audit; |
| 420 | new_profile = aa_get_profile(aa_newest_version(cxt->onexec)); | 420 | new_profile = aa_get_newest_profile(cxt->onexec); |
| 421 | goto apply; | 421 | goto apply; |
| 422 | } | 422 | } |
| 423 | 423 | ||
diff --git a/security/apparmor/include/context.h b/security/apparmor/include/context.h index d44ba5802e3d..6bf65798e5d1 100644 --- a/security/apparmor/include/context.h +++ b/security/apparmor/include/context.h | |||
| @@ -98,7 +98,7 @@ static inline struct aa_profile *aa_cred_profile(const struct cred *cred) | |||
| 98 | { | 98 | { |
| 99 | struct aa_task_cxt *cxt = cred_cxt(cred); | 99 | struct aa_task_cxt *cxt = cred_cxt(cred); |
| 100 | BUG_ON(!cxt || !cxt->profile); | 100 | BUG_ON(!cxt || !cxt->profile); |
| 101 | return aa_newest_version(cxt->profile); | 101 | return cxt->profile; |
| 102 | } | 102 | } |
| 103 | 103 | ||
| 104 | /** | 104 | /** |
| @@ -152,15 +152,14 @@ static inline struct aa_profile *aa_current_profile(void) | |||
| 152 | struct aa_profile *profile; | 152 | struct aa_profile *profile; |
| 153 | BUG_ON(!cxt || !cxt->profile); | 153 | BUG_ON(!cxt || !cxt->profile); |
| 154 | 154 | ||
| 155 | profile = aa_newest_version(cxt->profile); | 155 | if (PROFILE_INVALID(cxt->profile)) { |
| 156 | /* | 156 | profile = aa_get_newest_profile(cxt->profile); |
| 157 | * Whether or not replacement succeeds, use newest profile so | ||
| 158 | * there is no need to update it after replacement. | ||
| 159 | */ | ||
| 160 | if (unlikely((cxt->profile != profile))) | ||
| 161 | aa_replace_current_profile(profile); | 157 | aa_replace_current_profile(profile); |
| 158 | aa_put_profile(profile); | ||
| 159 | cxt = current_cxt(); | ||
| 160 | } | ||
| 162 | 161 | ||
| 163 | return profile; | 162 | return cxt->profile; |
| 164 | } | 163 | } |
| 165 | 164 | ||
| 166 | /** | 165 | /** |
diff --git a/security/apparmor/include/policy.h b/security/apparmor/include/policy.h index 82487a853353..e9f2baf4467e 100644 --- a/security/apparmor/include/policy.h +++ b/security/apparmor/include/policy.h | |||
| @@ -42,6 +42,8 @@ extern const char *const profile_mode_names[]; | |||
| 42 | 42 | ||
| 43 | #define PROFILE_IS_HAT(_profile) ((_profile)->flags & PFLAG_HAT) | 43 | #define PROFILE_IS_HAT(_profile) ((_profile)->flags & PFLAG_HAT) |
| 44 | 44 | ||
| 45 | #define PROFILE_INVALID(_profile) ((_profile)->flags & PFLAG_INVALID) | ||
| 46 | |||
| 45 | #define on_list_rcu(X) (!list_empty(X) && (X)->prev != LIST_POISON2) | 47 | #define on_list_rcu(X) (!list_empty(X) && (X)->prev != LIST_POISON2) |
| 46 | 48 | ||
| 47 | /* | 49 | /* |
| @@ -65,6 +67,7 @@ enum profile_flags { | |||
| 65 | PFLAG_USER_DEFINED = 0x20, /* user based profile - lower privs */ | 67 | PFLAG_USER_DEFINED = 0x20, /* user based profile - lower privs */ |
| 66 | PFLAG_NO_LIST_REF = 0x40, /* list doesn't keep profile ref */ | 68 | PFLAG_NO_LIST_REF = 0x40, /* list doesn't keep profile ref */ |
| 67 | PFLAG_OLD_NULL_TRANS = 0x100, /* use // as the null transition */ | 69 | PFLAG_OLD_NULL_TRANS = 0x100, /* use // as the null transition */ |
| 70 | PFLAG_INVALID = 0x200, /* profile replaced/removed */ | ||
| 68 | 71 | ||
| 69 | /* These flags must correspond with PATH_flags */ | 72 | /* These flags must correspond with PATH_flags */ |
| 70 | PFLAG_MEDIATE_DELETED = 0x10000, /* mediate instead delegate deleted */ | 73 | PFLAG_MEDIATE_DELETED = 0x10000, /* mediate instead delegate deleted */ |
| @@ -146,6 +149,12 @@ struct aa_policydb { | |||
| 146 | 149 | ||
| 147 | }; | 150 | }; |
| 148 | 151 | ||
| 152 | struct aa_replacedby { | ||
| 153 | struct kref count; | ||
| 154 | struct aa_profile __rcu *profile; | ||
| 155 | }; | ||
| 156 | |||
| 157 | |||
| 149 | /* struct aa_profile - basic confinement data | 158 | /* struct aa_profile - basic confinement data |
| 150 | * @base - base components of the profile (name, refcount, lists, lock ...) | 159 | * @base - base components of the profile (name, refcount, lists, lock ...) |
| 151 | * @parent: parent of profile | 160 | * @parent: parent of profile |
| @@ -169,8 +178,7 @@ struct aa_policydb { | |||
| 169 | * used to determine profile attachment against unconfined tasks. All other | 178 | * used to determine profile attachment against unconfined tasks. All other |
| 170 | * attachments are determined by profile X transition rules. | 179 | * attachments are determined by profile X transition rules. |
| 171 | * | 180 | * |
| 172 | * The @replacedby field is write protected by the profile lock. Reads | 181 | * The @replacedby struct is write protected by the profile lock. |
| 173 | * are assumed to be atomic. | ||
| 174 | * | 182 | * |
| 175 | * Profiles have a hierarchy where hats and children profiles keep | 183 | * Profiles have a hierarchy where hats and children profiles keep |
| 176 | * a reference to their parent. | 184 | * a reference to their parent. |
| @@ -184,14 +192,14 @@ struct aa_profile { | |||
| 184 | struct aa_profile __rcu *parent; | 192 | struct aa_profile __rcu *parent; |
| 185 | 193 | ||
| 186 | struct aa_namespace *ns; | 194 | struct aa_namespace *ns; |
| 187 | struct aa_profile *replacedby; | 195 | struct aa_replacedby *replacedby; |
| 188 | const char *rename; | 196 | const char *rename; |
| 189 | 197 | ||
| 190 | struct aa_dfa *xmatch; | 198 | struct aa_dfa *xmatch; |
| 191 | int xmatch_len; | 199 | int xmatch_len; |
| 192 | enum audit_mode audit; | 200 | enum audit_mode audit; |
| 193 | enum profile_mode mode; | ||
