diff options
Diffstat (limited to 'security/security.c')
-rw-r--r-- | security/security.c | 89 |
1 files changed, 87 insertions, 2 deletions
diff --git a/security/security.c b/security/security.c index 60b39db95c2f..09be8ce007a2 100644 --- a/security/security.c +++ b/security/security.c | |||
@@ -41,6 +41,8 @@ struct security_hook_heads security_hook_heads __lsm_ro_after_init; | |||
41 | static ATOMIC_NOTIFIER_HEAD(lsm_notifier_chain); | 41 | static ATOMIC_NOTIFIER_HEAD(lsm_notifier_chain); |
42 | 42 | ||
43 | char *lsm_names; | 43 | char *lsm_names; |
44 | static struct lsm_blob_sizes blob_sizes __lsm_ro_after_init; | ||
45 | |||
44 | /* Boot-time LSM user choice */ | 46 | /* Boot-time LSM user choice */ |
45 | static __initdata const char *chosen_lsm_order; | 47 | static __initdata const char *chosen_lsm_order; |
46 | static __initdata const char *chosen_major_lsm; | 48 | static __initdata const char *chosen_major_lsm; |
@@ -139,6 +141,25 @@ static bool __init lsm_allowed(struct lsm_info *lsm) | |||
139 | return true; | 141 | return true; |
140 | } | 142 | } |
141 | 143 | ||
144 | static void __init lsm_set_blob_size(int *need, int *lbs) | ||
145 | { | ||
146 | int offset; | ||
147 | |||
148 | if (*need > 0) { | ||
149 | offset = *lbs; | ||
150 | *lbs += *need; | ||
151 | *need = offset; | ||
152 | } | ||
153 | } | ||
154 | |||
155 | static void __init lsm_set_blob_sizes(struct lsm_blob_sizes *needed) | ||
156 | { | ||
157 | if (!needed) | ||
158 | return; | ||
159 | |||
160 | lsm_set_blob_size(&needed->lbs_cred, &blob_sizes.lbs_cred); | ||
161 | } | ||
162 | |||
142 | /* Prepare LSM for initialization. */ | 163 | /* Prepare LSM for initialization. */ |
143 | static void __init prepare_lsm(struct lsm_info *lsm) | 164 | static void __init prepare_lsm(struct lsm_info *lsm) |
144 | { | 165 | { |
@@ -153,6 +174,8 @@ static void __init prepare_lsm(struct lsm_info *lsm) | |||
153 | exclusive = lsm; | 174 | exclusive = lsm; |
154 | init_debug("exclusive chosen: %s\n", lsm->name); | 175 | init_debug("exclusive chosen: %s\n", lsm->name); |
155 | } | 176 | } |
177 | |||
178 | lsm_set_blob_sizes(lsm->blobs); | ||
156 | } | 179 | } |
157 | } | 180 | } |
158 | 181 | ||
@@ -255,6 +278,8 @@ static void __init ordered_lsm_init(void) | |||
255 | for (lsm = ordered_lsms; *lsm; lsm++) | 278 | for (lsm = ordered_lsms; *lsm; lsm++) |
256 | prepare_lsm(*lsm); | 279 | prepare_lsm(*lsm); |
257 | 280 | ||
281 | init_debug("cred blob size = %d\n", blob_sizes.lbs_cred); | ||
282 | |||
258 | for (lsm = ordered_lsms; *lsm; lsm++) | 283 | for (lsm = ordered_lsms; *lsm; lsm++) |
259 | initialize_lsm(*lsm); | 284 | initialize_lsm(*lsm); |
260 | 285 | ||
@@ -382,6 +407,47 @@ int unregister_lsm_notifier(struct notifier_block *nb) | |||
382 | } | 407 | } |
383 | EXPORT_SYMBOL(unregister_lsm_notifier); | 408 | EXPORT_SYMBOL(unregister_lsm_notifier); |
384 | 409 | ||
410 | /** | ||
411 | * lsm_cred_alloc - allocate a composite cred blob | ||
412 | * @cred: the cred that needs a blob | ||
413 | * @gfp: allocation type | ||
414 | * | ||
415 | * Allocate the cred blob for all the modules | ||
416 | * | ||
417 | * Returns 0, or -ENOMEM if memory can't be allocated. | ||
418 | */ | ||
419 | static int lsm_cred_alloc(struct cred *cred, gfp_t gfp) | ||
420 | { | ||
421 | if (blob_sizes.lbs_cred == 0) { | ||
422 | cred->security = NULL; | ||
423 | return 0; | ||
424 | } | ||
425 | |||
426 | cred->security = kzalloc(blob_sizes.lbs_cred, gfp); | ||
427 | if (cred->security == NULL) | ||
428 | return -ENOMEM; | ||
429 | return 0; | ||
430 | } | ||
431 | |||
432 | /** | ||
433 | * lsm_early_cred - during initialization allocate a composite cred blob | ||
434 | * @cred: the cred that needs a blob | ||
435 | * | ||
436 | * Allocate the cred blob for all the modules if it's not already there | ||
437 | */ | ||
438 | void __init lsm_early_cred(struct cred *cred) | ||
439 | { | ||
440 | int rc; | ||
441 | |||
442 | if (cred == NULL) | ||
443 | panic("%s: NULL cred.\n", __func__); | ||
444 | if (cred->security != NULL) | ||
445 | return; | ||
446 | rc = lsm_cred_alloc(cred, GFP_KERNEL); | ||
447 | if (rc) | ||
448 | panic("%s: Early cred alloc failed.\n", __func__); | ||
449 | } | ||
450 | |||
385 | /* | 451 | /* |
386 | * Hook list operation macros. | 452 | * Hook list operation macros. |
387 | * | 453 | * |
@@ -1195,17 +1261,36 @@ void security_task_free(struct task_struct *task) | |||
1195 | 1261 | ||
1196 | int security_cred_alloc_blank(struct cred *cred, gfp_t gfp) | 1262 | int security_cred_alloc_blank(struct cred *cred, gfp_t gfp) |
1197 | { | 1263 | { |
1198 | return call_int_hook(cred_alloc_blank, 0, cred, gfp); | 1264 | int rc = lsm_cred_alloc(cred, gfp); |
1265 | |||
1266 | if (rc) | ||
1267 | return rc; | ||
1268 | |||
1269 | rc = call_int_hook(cred_alloc_blank, 0, cred, gfp); | ||
1270 | if (rc) | ||
1271 | security_cred_free(cred); | ||
1272 | return rc; | ||
1199 | } | 1273 | } |
1200 | 1274 | ||
1201 | void security_cred_free(struct cred *cred) | 1275 | void security_cred_free(struct cred *cred) |
1202 | { | 1276 | { |
1203 | call_void_hook(cred_free, cred); | 1277 | call_void_hook(cred_free, cred); |
1278 | |||
1279 | kfree(cred->security); | ||
1280 | cred->security = NULL; | ||
1204 | } | 1281 | } |
1205 | 1282 | ||
1206 | int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp) | 1283 | int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp) |
1207 | { | 1284 | { |
1208 | return call_int_hook(cred_prepare, 0, new, old, gfp); | 1285 | int rc = lsm_cred_alloc(new, gfp); |
1286 | |||
1287 | if (rc) | ||
1288 | return rc; | ||
1289 | |||
1290 | rc = call_int_hook(cred_prepare, 0, new, old, gfp); | ||
1291 | if (rc) | ||
1292 | security_cred_free(new); | ||
1293 | return rc; | ||
1209 | } | 1294 | } |
1210 | 1295 | ||
1211 | void security_transfer_creds(struct cred *new, const struct cred *old) | 1296 | void security_transfer_creds(struct cred *new, const struct cred *old) |