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

Infrastructure management of the cred security blob

Move management of the cred security blob out of the
security modules and into the security infrastructre.
Instead of allocating and freeing space the security
modules tell the infrastructure how much space they
require.

Signed-off-by: Casey Schaufler <casey@schaufler-ca.com>
Reviewed-by: Kees Cook <keescook@chromium.org>
[kees: adjusted for ordered init series]
Signed-off-by: Kees Cook <keescook@chromium.org>

authored by

Casey Schaufler and committed by
Kees Cook
bbd3662a 43fc4609

+162 -102
+12
include/linux/lsm_hooks.h
··· 2028 2028 } __randomize_layout; 2029 2029 2030 2030 /* 2031 + * Security blob size or offset data. 2032 + */ 2033 + struct lsm_blob_sizes { 2034 + int lbs_cred; 2035 + }; 2036 + 2037 + /* 2031 2038 * Initializing a security_hook_list structure takes 2032 2039 * up a lot of space in a source file. This macro takes 2033 2040 * care of the common case and reduces the amount of ··· 2063 2056 unsigned long flags; /* Optional: flags describing LSM */ 2064 2057 int *enabled; /* Optional: controlled by CONFIG_LSM */ 2065 2058 int (*init)(void); /* Required. */ 2059 + struct lsm_blob_sizes *blobs; /* Optional: for blob sharing. */ 2066 2060 }; 2067 2061 2068 2062 extern struct lsm_info __start_lsm_info[], __end_lsm_info[]; ··· 2102 2094 #else 2103 2095 #define __lsm_ro_after_init __ro_after_init 2104 2096 #endif /* CONFIG_SECURITY_WRITABLE_HOOKS */ 2097 + 2098 + #ifdef CONFIG_SECURITY 2099 + void __init lsm_early_cred(struct cred *cred); 2100 + #endif 2105 2101 2106 2102 #endif /* ! __LINUX_LSM_HOOKS_H */
+2 -2
security/apparmor/include/cred.h
··· 25 25 26 26 static inline struct aa_label *cred_label(const struct cred *cred) 27 27 { 28 - struct aa_label **blob = cred->security; 28 + struct aa_label **blob = cred->security + apparmor_blob_sizes.lbs_cred; 29 29 30 30 AA_BUG(!blob); 31 31 return *blob; ··· 34 34 static inline void set_cred_label(const struct cred *cred, 35 35 struct aa_label *label) 36 36 { 37 - struct aa_label **blob = cred->security; 37 + struct aa_label **blob = cred->security + apparmor_blob_sizes.lbs_cred; 38 38 39 39 AA_BUG(!blob); 40 40 *blob = label;
+4
security/apparmor/include/lib.h
··· 16 16 17 17 #include <linux/slab.h> 18 18 #include <linux/fs.h> 19 + #include <linux/lsm_hooks.h> 19 20 20 21 #include "match.h" 21 22 ··· 55 54 const char *aa_splitn_fqname(const char *fqname, size_t n, const char **ns_name, 56 55 size_t *ns_len); 57 56 void aa_info_message(const char *str); 57 + 58 + /* Security blob offsets */ 59 + extern struct lsm_blob_sizes apparmor_blob_sizes; 58 60 59 61 /** 60 62 * aa_strneq - compare null terminated @str to a non null terminated substring
+9
security/apparmor/lsm.c
··· 1151 1151 } 1152 1152 #endif 1153 1153 1154 + /* 1155 + * The cred blob is a pointer to, not an instance of, an aa_task_ctx. 1156 + */ 1157 + struct lsm_blob_sizes apparmor_blob_sizes __lsm_ro_after_init = { 1158 + .lbs_cred = sizeof(struct aa_task_ctx *), 1159 + }; 1160 + 1154 1161 static struct security_hook_list apparmor_hooks[] __lsm_ro_after_init = { 1155 1162 LSM_HOOK_INIT(ptrace_access_check, apparmor_ptrace_access_check), 1156 1163 LSM_HOOK_INIT(ptrace_traceme, apparmor_ptrace_traceme), ··· 1492 1485 if (!ctx) 1493 1486 return -ENOMEM; 1494 1487 1488 + lsm_early_cred(cred); 1495 1489 set_cred_label(cred, aa_get_label(ns_unconfined(root_ns))); 1496 1490 task_ctx(current) = ctx; 1497 1491 ··· 1733 1725 .name = "apparmor", 1734 1726 .flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE, 1735 1727 .enabled = &apparmor_enabled, 1728 + .blobs = &apparmor_blob_sizes, 1736 1729 .init = apparmor_init, 1737 1730 };
+87 -2
security/security.c
··· 41 41 static ATOMIC_NOTIFIER_HEAD(lsm_notifier_chain); 42 42 43 43 char *lsm_names; 44 + static struct lsm_blob_sizes blob_sizes __lsm_ro_after_init; 45 + 44 46 /* Boot-time LSM user choice */ 45 47 static __initdata const char *chosen_lsm_order; 46 48 static __initdata const char *chosen_major_lsm; ··· 141 139 return true; 142 140 } 143 141 142 + static void __init lsm_set_blob_size(int *need, int *lbs) 143 + { 144 + int offset; 145 + 146 + if (*need > 0) { 147 + offset = *lbs; 148 + *lbs += *need; 149 + *need = offset; 150 + } 151 + } 152 + 153 + static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed) 154 + { 155 + if (!needed) 156 + return; 157 + 158 + lsm_set_blob_size(&needed->lbs_cred, &blob_sizes.lbs_cred); 159 + } 160 + 144 161 /* Prepare LSM for initialization. */ 145 162 static void __init prepare_lsm(struct lsm_info *lsm) 146 163 { ··· 174 153 exclusive = lsm; 175 154 init_debug("exclusive chosen: %s\n", lsm->name); 176 155 } 156 + 157 + lsm_set_blob_sizes(lsm->blobs); 177 158 } 178 159 } 179 160 ··· 277 254 278 255 for (lsm = ordered_lsms; *lsm; lsm++) 279 256 prepare_lsm(*lsm); 257 + 258 + init_debug("cred blob size = %d\n", blob_sizes.lbs_cred); 280 259 281 260 for (lsm = ordered_lsms; *lsm; lsm++) 282 261 initialize_lsm(*lsm); ··· 406 381 return atomic_notifier_chain_unregister(&lsm_notifier_chain, nb); 407 382 } 408 383 EXPORT_SYMBOL(unregister_lsm_notifier); 384 + 385 + /** 386 + * lsm_cred_alloc - allocate a composite cred blob 387 + * @cred: the cred that needs a blob 388 + * @gfp: allocation type 389 + * 390 + * Allocate the cred blob for all the modules 391 + * 392 + * Returns 0, or -ENOMEM if memory can't be allocated. 393 + */ 394 + static int lsm_cred_alloc(struct cred *cred, gfp_t gfp) 395 + { 396 + if (blob_sizes.lbs_cred == 0) { 397 + cred->security = NULL; 398 + return 0; 399 + } 400 + 401 + cred->security = kzalloc(blob_sizes.lbs_cred, gfp); 402 + if (cred->security == NULL) 403 + return -ENOMEM; 404 + return 0; 405 + } 406 + 407 + /** 408 + * lsm_early_cred - during initialization allocate a composite cred blob 409 + * @cred: the cred that needs a blob 410 + * 411 + * Allocate the cred blob for all the modules if it's not already there 412 + */ 413 + void __init lsm_early_cred(struct cred *cred) 414 + { 415 + int rc; 416 + 417 + if (cred == NULL) 418 + panic("%s: NULL cred.\n", __func__); 419 + if (cred->security != NULL) 420 + return; 421 + rc = lsm_cred_alloc(cred, GFP_KERNEL); 422 + if (rc) 423 + panic("%s: Early cred alloc failed.\n", __func__); 424 + } 409 425 410 426 /* 411 427 * Hook list operation macros. ··· 1261 1195 1262 1196 int security_cred_alloc_blank(struct cred *cred, gfp_t gfp) 1263 1197 { 1264 - return call_int_hook(cred_alloc_blank, 0, cred, gfp); 1198 + int rc = lsm_cred_alloc(cred, gfp); 1199 + 1200 + if (rc) 1201 + return rc; 1202 + 1203 + rc = call_int_hook(cred_alloc_blank, 0, cred, gfp); 1204 + if (rc) 1205 + security_cred_free(cred); 1206 + return rc; 1265 1207 } 1266 1208 1267 1209 void security_cred_free(struct cred *cred) 1268 1210 { 1269 1211 call_void_hook(cred_free, cred); 1212 + 1213 + kfree(cred->security); 1214 + cred->security = NULL; 1270 1215 } 1271 1216 1272 1217 int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp) 1273 1218 { 1274 - return call_int_hook(cred_prepare, 0, new, old, gfp); 1219 + int rc = lsm_cred_alloc(new, gfp); 1220 + 1221 + if (rc) 1222 + return rc; 1223 + 1224 + rc = call_int_hook(cred_prepare, 0, new, old, gfp); 1225 + if (rc) 1226 + security_cred_free(new); 1227 + return rc; 1275 1228 } 1276 1229 1277 1230 void security_transfer_creds(struct cred *new, const struct cred *old)
+10 -41
security/selinux/hooks.c
··· 210 210 struct cred *cred = (struct cred *) current->real_cred; 211 211 struct task_security_struct *tsec; 212 212 213 - tsec = kzalloc(sizeof(struct task_security_struct), GFP_KERNEL); 214 - if (!tsec) 215 - panic("SELinux: Failed to initialize initial task.\n"); 216 - 213 + lsm_early_cred(cred); 214 + tsec = selinux_cred(cred); 217 215 tsec->osid = tsec->sid = SECINITSID_KERNEL; 218 - cred->security = tsec; 219 216 } 220 217 221 218 /* ··· 3683 3686 } 3684 3687 3685 3688 /* 3686 - * allocate the SELinux part of blank credentials 3687 - */ 3688 - static int selinux_cred_alloc_blank(struct cred *cred, gfp_t gfp) 3689 - { 3690 - struct task_security_struct *tsec; 3691 - 3692 - tsec = kzalloc(sizeof(struct task_security_struct), gfp); 3693 - if (!tsec) 3694 - return -ENOMEM; 3695 - 3696 - cred->security = tsec; 3697 - return 0; 3698 - } 3699 - 3700 - /* 3701 - * detach and free the LSM part of a set of credentials 3702 - */ 3703 - static void selinux_cred_free(struct cred *cred) 3704 - { 3705 - struct task_security_struct *tsec = selinux_cred(cred); 3706 - 3707 - kfree(tsec); 3708 - } 3709 - 3710 - /* 3711 3689 * prepare a new set of credentials for modification 3712 3690 */ 3713 3691 static int selinux_cred_prepare(struct cred *new, const struct cred *old, 3714 3692 gfp_t gfp) 3715 3693 { 3716 - const struct task_security_struct *old_tsec; 3717 - struct task_security_struct *tsec; 3694 + const struct task_security_struct *old_tsec = selinux_cred(old); 3695 + struct task_security_struct *tsec = selinux_cred(new); 3718 3696 3719 - old_tsec = selinux_cred(old); 3720 - 3721 - tsec = kmemdup(old_tsec, sizeof(struct task_security_struct), gfp); 3722 - if (!tsec) 3723 - return -ENOMEM; 3724 - 3725 - new->security = tsec; 3697 + *tsec = *old_tsec; 3726 3698 return 0; 3727 3699 } 3728 3700 ··· 6644 6678 } 6645 6679 #endif 6646 6680 6681 + struct lsm_blob_sizes selinux_blob_sizes __lsm_ro_after_init = { 6682 + .lbs_cred = sizeof(struct task_security_struct), 6683 + }; 6684 + 6647 6685 static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { 6648 6686 LSM_HOOK_INIT(binder_set_context_mgr, selinux_binder_set_context_mgr), 6649 6687 LSM_HOOK_INIT(binder_transaction, selinux_binder_transaction), ··· 6731 6761 LSM_HOOK_INIT(file_open, selinux_file_open), 6732 6762 6733 6763 LSM_HOOK_INIT(task_alloc, selinux_task_alloc), 6734 - LSM_HOOK_INIT(cred_alloc_blank, selinux_cred_alloc_blank), 6735 - LSM_HOOK_INIT(cred_free, selinux_cred_free), 6736 6764 LSM_HOOK_INIT(cred_prepare, selinux_cred_prepare), 6737 6765 LSM_HOOK_INIT(cred_transfer, selinux_cred_transfer), 6738 6766 LSM_HOOK_INIT(cred_getsecid, selinux_cred_getsecid), ··· 6949 6981 .name = "selinux", 6950 6982 .flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE, 6951 6983 .enabled = &selinux_enabled, 6984 + .blobs = &selinux_blob_sizes, 6952 6985 .init = selinux_init, 6953 6986 }; 6954 6987
+3 -1
security/selinux/include/objsec.h
··· 25 25 #include <linux/binfmts.h> 26 26 #include <linux/in.h> 27 27 #include <linux/spinlock.h> 28 + #include <linux/lsm_hooks.h> 28 29 #include <net/net_namespace.h> 29 30 #include "flask.h" 30 31 #include "avc.h" ··· 159 158 u32 sid; /*SID of bpf obj creater*/ 160 159 }; 161 160 161 + extern struct lsm_blob_sizes selinux_blob_sizes; 162 162 static inline struct task_security_struct *selinux_cred(const struct cred *cred) 163 163 { 164 - return cred->security; 164 + return cred->security + selinux_blob_sizes.lbs_cred; 165 165 } 166 166 167 167 #endif /* _SELINUX_OBJSEC_H_ */
+2 -1
security/smack/smack.h
··· 336 336 extern struct smack_known *smack_unconfined; 337 337 #endif 338 338 extern int smack_ptrace_rule; 339 + extern struct lsm_blob_sizes smack_blob_sizes; 339 340 340 341 extern struct smack_known smack_known_floor; 341 342 extern struct smack_known smack_known_hat; ··· 359 358 360 359 static inline struct task_smack *smack_cred(const struct cred *cred) 361 360 { 362 - return cred->security; 361 + return cred->security + smack_blob_sizes.lbs_cred; 363 362 } 364 363 365 364 /*
+25 -54
security/smack/smack_lsm.c
··· 326 326 } 327 327 328 328 /** 329 - * new_task_smack - allocate a task security blob 329 + * init_task_smack - initialize a task security blob 330 + * @tsp: blob to initialize 330 331 * @task: a pointer to the Smack label for the running task 331 332 * @forked: a pointer to the Smack label for the forked task 332 - * @gfp: type of the memory for the allocation 333 333 * 334 - * Returns the new blob or NULL if there's no memory available 335 334 */ 336 - static struct task_smack *new_task_smack(struct smack_known *task, 337 - struct smack_known *forked, gfp_t gfp) 335 + static void init_task_smack(struct task_smack *tsp, struct smack_known *task, 336 + struct smack_known *forked) 338 337 { 339 - struct task_smack *tsp; 340 - 341 - tsp = kzalloc(sizeof(struct task_smack), gfp); 342 - if (tsp == NULL) 343 - return NULL; 344 - 345 338 tsp->smk_task = task; 346 339 tsp->smk_forked = forked; 347 340 INIT_LIST_HEAD(&tsp->smk_rules); 348 341 INIT_LIST_HEAD(&tsp->smk_relabel); 349 342 mutex_init(&tsp->smk_rules_lock); 350 - 351 - return tsp; 352 343 } 353 344 354 345 /** ··· 1872 1881 */ 1873 1882 static int smack_cred_alloc_blank(struct cred *cred, gfp_t gfp) 1874 1883 { 1875 - struct task_smack *tsp; 1876 - 1877 - tsp = new_task_smack(NULL, NULL, gfp); 1878 - if (tsp == NULL) 1879 - return -ENOMEM; 1880 - 1881 - cred->security = tsp; 1882 - 1884 + init_task_smack(smack_cred(cred), NULL, NULL); 1883 1885 return 0; 1884 1886 } 1885 1887 ··· 1889 1905 struct list_head *l; 1890 1906 struct list_head *n; 1891 1907 1892 - if (tsp == NULL) 1893 - return; 1894 - cred->security = NULL; 1895 - 1896 1908 smk_destroy_label_list(&tsp->smk_relabel); 1897 1909 1898 1910 list_for_each_safe(l, n, &tsp->smk_rules) { ··· 1896 1916 list_del(&rp->list); 1897 1917 kfree(rp); 1898 1918 } 1899 - kfree(tsp); 1900 1919 } 1901 1920 1902 1921 /** ··· 1910 1931 gfp_t gfp) 1911 1932 { 1912 1933 struct task_smack *old_tsp = smack_cred(old); 1913 - struct task_smack *new_tsp; 1934 + struct task_smack *new_tsp = smack_cred(new); 1914 1935 int rc; 1915 1936 1916 - new_tsp = new_task_smack(old_tsp->smk_task, old_tsp->smk_task, gfp); 1917 - if (new_tsp == NULL) 1918 - return -ENOMEM; 1919 - 1920 - new->security = new_tsp; 1937 + init_task_smack(new_tsp, old_tsp->smk_task, old_tsp->smk_task); 1921 1938 1922 1939 rc = smk_copy_rules(&new_tsp->smk_rules, &old_tsp->smk_rules, gfp); 1923 1940 if (rc != 0) ··· 1921 1946 1922 1947 rc = smk_copy_relabel(&new_tsp->smk_relabel, &old_tsp->smk_relabel, 1923 1948 gfp); 1924 - if (rc != 0) 1925 - return rc; 1926 - 1927 - return 0; 1949 + return rc; 1928 1950 } 1929 1951 1930 1952 /** ··· 4553 4581 return 0; 4554 4582 } 4555 4583 4584 + struct lsm_blob_sizes smack_blob_sizes __lsm_ro_after_init = { 4585 + .lbs_cred = sizeof(struct task_smack), 4586 + }; 4587 + 4556 4588 static struct security_hook_list smack_hooks[] __lsm_ro_after_init = { 4557 4589 LSM_HOOK_INIT(ptrace_access_check, smack_ptrace_access_check), 4558 4590 LSM_HOOK_INIT(ptrace_traceme, smack_ptrace_traceme), ··· 4734 4758 */ 4735 4759 static __init int smack_init(void) 4736 4760 { 4737 - struct cred *cred; 4761 + struct cred *cred = (struct cred *) current->cred; 4738 4762 struct task_smack *tsp; 4739 4763 4740 4764 smack_inode_cache = KMEM_CACHE(inode_smack, 0); 4741 4765 if (!smack_inode_cache) 4742 4766 return -ENOMEM; 4743 4767 4744 - tsp = new_task_smack(&smack_known_floor, &smack_known_floor, 4745 - GFP_KERNEL); 4746 - if (tsp == NULL) { 4747 - kmem_cache_destroy(smack_inode_cache); 4748 - return -ENOMEM; 4749 - } 4768 + lsm_early_cred(cred); 4750 4769 4770 + /* 4771 + * Set the security state for the initial task. 4772 + */ 4773 + tsp = smack_cred(cred); 4774 + init_task_smack(tsp, &smack_known_floor, &smack_known_floor); 4775 + 4776 + /* 4777 + * Register with LSM 4778 + */ 4779 + security_add_hooks(smack_hooks, ARRAY_SIZE(smack_hooks), "smack"); 4751 4780 smack_enabled = 1; 4752 4781 4753 4782 pr_info("Smack: Initializing.\n"); ··· 4766 4785 pr_info("Smack: IPv6 Netfilter enabled.\n"); 4767 4786 #endif 4768 4787 4769 - /* 4770 - * Set the security state for the initial task. 4771 - */ 4772 - cred = (struct cred *) current->cred; 4773 - cred->security = tsp; 4774 - 4775 4788 /* initialize the smack_known_list */ 4776 4789 init_smack_known_list(); 4777 - 4778 - /* 4779 - * Register with LSM 4780 - */ 4781 - security_add_hooks(smack_hooks, ARRAY_SIZE(smack_hooks), "smack"); 4782 4790 4783 4791 return 0; 4784 4792 } ··· 4779 4809 DEFINE_LSM(smack) = { 4780 4810 .name = "smack", 4781 4811 .flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE, 4812 + .blobs = &smack_blob_sizes, 4782 4813 .init = smack_init, 4783 4814 };
+2 -1
security/tomoyo/common.h
··· 1087 1087 extern struct tomoyo_policy_namespace tomoyo_kernel_namespace; 1088 1088 extern unsigned int tomoyo_memory_quota[TOMOYO_MAX_MEMORY_STAT]; 1089 1089 extern unsigned int tomoyo_memory_used[TOMOYO_MAX_MEMORY_STAT]; 1090 + extern struct lsm_blob_sizes tomoyo_blob_sizes; 1090 1091 1091 1092 /********** Inlined functions. **********/ 1092 1093 ··· 1207 1206 */ 1208 1207 static inline struct tomoyo_domain_info **tomoyo_cred(const struct cred *cred) 1209 1208 { 1210 - return (struct tomoyo_domain_info **)&cred->security; 1209 + return cred->security + tomoyo_blob_sizes.lbs_cred; 1211 1210 } 1212 1211 1213 1212 /**
+6
security/tomoyo/tomoyo.c
··· 509 509 return tomoyo_socket_sendmsg_permission(sock, msg, size); 510 510 } 511 511 512 + struct lsm_blob_sizes tomoyo_blob_sizes __lsm_ro_after_init = { 513 + .lbs_cred = sizeof(struct tomoyo_domain_info *), 514 + }; 515 + 512 516 /* 513 517 * tomoyo_security_ops is a "struct security_operations" which is used for 514 518 * registering TOMOYO. ··· 566 562 /* register ourselves with the security framework */ 567 563 security_add_hooks(tomoyo_hooks, ARRAY_SIZE(tomoyo_hooks), "tomoyo"); 568 564 printk(KERN_INFO "TOMOYO Linux initialized\n"); 565 + lsm_early_cred(cred); 569 566 blob = tomoyo_cred(cred); 570 567 *blob = &tomoyo_kernel_domain; 571 568 tomoyo_mm_init(); ··· 578 573 .name = "tomoyo", 579 574 .enabled = &tomoyo_enabled, 580 575 .flags = LSM_FLAG_LEGACY_MAJOR | LSM_FLAG_EXCLUSIVE, 576 + .blobs = &tomoyo_blob_sizes, 581 577 .init = tomoyo_init, 582 578 };