diff options
Diffstat (limited to 'security')
52 files changed, 882 insertions, 571 deletions
diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c index caaf51dda648..d4fa04d91439 100644 --- a/security/apparmor/apparmorfs.c +++ b/security/apparmor/apparmorfs.c | |||
@@ -533,7 +533,7 @@ static ssize_t ns_revision_read(struct file *file, char __user *buf, | |||
533 | long last_read; | 533 | long last_read; |
534 | int avail; | 534 | int avail; |
535 | 535 | ||
536 | mutex_lock(&rev->ns->lock); | 536 | mutex_lock_nested(&rev->ns->lock, rev->ns->level); |
537 | last_read = rev->last_read; | 537 | last_read = rev->last_read; |
538 | if (last_read == rev->ns->revision) { | 538 | if (last_read == rev->ns->revision) { |
539 | mutex_unlock(&rev->ns->lock); | 539 | mutex_unlock(&rev->ns->lock); |
@@ -543,7 +543,7 @@ static ssize_t ns_revision_read(struct file *file, char __user *buf, | |||
543 | last_read != | 543 | last_read != |
544 | READ_ONCE(rev->ns->revision))) | 544 | READ_ONCE(rev->ns->revision))) |
545 | return -ERESTARTSYS; | 545 | return -ERESTARTSYS; |
546 | mutex_lock(&rev->ns->lock); | 546 | mutex_lock_nested(&rev->ns->lock, rev->ns->level); |
547 | } | 547 | } |
548 | 548 | ||
549 | avail = sprintf(buffer, "%ld\n", rev->ns->revision); | 549 | avail = sprintf(buffer, "%ld\n", rev->ns->revision); |
@@ -577,7 +577,7 @@ static unsigned int ns_revision_poll(struct file *file, poll_table *pt) | |||
577 | unsigned int mask = 0; | 577 | unsigned int mask = 0; |
578 | 578 | ||
579 | if (rev) { | 579 | if (rev) { |
580 | mutex_lock(&rev->ns->lock); | 580 | mutex_lock_nested(&rev->ns->lock, rev->ns->level); |
581 | poll_wait(file, &rev->ns->wait, pt); | 581 | poll_wait(file, &rev->ns->wait, pt); |
582 | if (rev->last_read < rev->ns->revision) | 582 | if (rev->last_read < rev->ns->revision) |
583 | mask |= POLLIN | POLLRDNORM; | 583 | mask |= POLLIN | POLLRDNORM; |
@@ -1643,7 +1643,7 @@ static int ns_mkdir_op(struct inode *dir, struct dentry *dentry, umode_t mode) | |||
1643 | */ | 1643 | */ |
1644 | inode_unlock(dir); | 1644 | inode_unlock(dir); |
1645 | error = simple_pin_fs(&aafs_ops, &aafs_mnt, &aafs_count); | 1645 | error = simple_pin_fs(&aafs_ops, &aafs_mnt, &aafs_count); |
1646 | mutex_lock(&parent->lock); | 1646 | mutex_lock_nested(&parent->lock, parent->level); |
1647 | inode_lock_nested(dir, I_MUTEX_PARENT); | 1647 | inode_lock_nested(dir, I_MUTEX_PARENT); |
1648 | if (error) | 1648 | if (error) |
1649 | goto out; | 1649 | goto out; |
@@ -1692,7 +1692,7 @@ static int ns_rmdir_op(struct inode *dir, struct dentry *dentry) | |||
1692 | inode_unlock(dir); | 1692 | inode_unlock(dir); |
1693 | inode_unlock(dentry->d_inode); | 1693 | inode_unlock(dentry->d_inode); |
1694 | 1694 | ||
1695 | mutex_lock(&parent->lock); | 1695 | mutex_lock_nested(&parent->lock, parent->level); |
1696 | ns = aa_get_ns(__aa_findn_ns(&parent->sub_ns, dentry->d_name.name, | 1696 | ns = aa_get_ns(__aa_findn_ns(&parent->sub_ns, dentry->d_name.name, |
1697 | dentry->d_name.len)); | 1697 | dentry->d_name.len)); |
1698 | if (!ns) { | 1698 | if (!ns) { |
@@ -1747,7 +1747,7 @@ void __aafs_ns_rmdir(struct aa_ns *ns) | |||
1747 | __aafs_profile_rmdir(child); | 1747 | __aafs_profile_rmdir(child); |
1748 | 1748 | ||
1749 | list_for_each_entry(sub, &ns->sub_ns, base.list) { | 1749 | list_for_each_entry(sub, &ns->sub_ns, base.list) { |
1750 | mutex_lock(&sub->lock); | 1750 | mutex_lock_nested(&sub->lock, sub->level); |
1751 | __aafs_ns_rmdir(sub); | 1751 | __aafs_ns_rmdir(sub); |
1752 | mutex_unlock(&sub->lock); | 1752 | mutex_unlock(&sub->lock); |
1753 | } | 1753 | } |
@@ -1877,7 +1877,7 @@ int __aafs_ns_mkdir(struct aa_ns *ns, struct dentry *parent, const char *name, | |||
1877 | 1877 | ||
1878 | /* subnamespaces */ | 1878 | /* subnamespaces */ |
1879 | list_for_each_entry(sub, &ns->sub_ns, base.list) { | 1879 | list_for_each_entry(sub, &ns->sub_ns, base.list) { |
1880 | mutex_lock(&sub->lock); | 1880 | mutex_lock_nested(&sub->lock, sub->level); |
1881 | error = __aafs_ns_mkdir(sub, ns_subns_dir(ns), NULL, NULL); | 1881 | error = __aafs_ns_mkdir(sub, ns_subns_dir(ns), NULL, NULL); |
1882 | mutex_unlock(&sub->lock); | 1882 | mutex_unlock(&sub->lock); |
1883 | if (error) | 1883 | if (error) |
@@ -1921,7 +1921,7 @@ static struct aa_ns *__next_ns(struct aa_ns *root, struct aa_ns *ns) | |||
1921 | /* is next namespace a child */ | 1921 | /* is next namespace a child */ |
1922 | if (!list_empty(&ns->sub_ns)) { | 1922 | if (!list_empty(&ns->sub_ns)) { |
1923 | next = list_first_entry(&ns->sub_ns, typeof(*ns), base.list); | 1923 | next = list_first_entry(&ns->sub_ns, typeof(*ns), base.list); |
1924 | mutex_lock(&next->lock); | 1924 | mutex_lock_nested(&next->lock, next->level); |
1925 | return next; | 1925 | return next; |
1926 | } | 1926 | } |
1927 | 1927 | ||
@@ -1931,7 +1931,7 @@ static struct aa_ns *__next_ns(struct aa_ns *root, struct aa_ns *ns) | |||
1931 | mutex_unlock(&ns->lock); | 1931 | mutex_unlock(&ns->lock); |
1932 | next = list_next_entry(ns, base.list); | 1932 | next = list_next_entry(ns, base.list); |
1933 | if (!list_entry_is_head(next, &parent->sub_ns, base.list)) { | 1933 | if (!list_entry_is_head(next, &parent->sub_ns, base.list)) { |
1934 | mutex_lock(&next->lock); | 1934 | mutex_lock_nested(&next->lock, next->level); |
1935 | return next; | 1935 | return next; |
1936 | } | 1936 | } |
1937 | ns = parent; | 1937 | ns = parent; |
@@ -2039,7 +2039,7 @@ static void *p_start(struct seq_file *f, loff_t *pos) | |||
2039 | f->private = root; | 2039 | f->private = root; |
2040 | 2040 | ||
2041 | /* find the first profile */ | 2041 | /* find the first profile */ |
2042 | mutex_lock(&root->lock); | 2042 | mutex_lock_nested(&root->lock, root->level); |
2043 | profile = __first_profile(root, root); | 2043 | profile = __first_profile(root, root); |
2044 | 2044 | ||
2045 | /* skip to position */ | 2045 | /* skip to position */ |
@@ -2451,7 +2451,7 @@ static int __init aa_create_aafs(void) | |||
2451 | aafs_mnt = kern_mount(&aafs_ops); | 2451 | aafs_mnt = kern_mount(&aafs_ops); |
2452 | if (IS_ERR(aafs_mnt)) | 2452 | if (IS_ERR(aafs_mnt)) |
2453 | panic("can't set apparmorfs up\n"); | 2453 | panic("can't set apparmorfs up\n"); |
2454 | aafs_mnt->mnt_sb->s_flags &= ~MS_NOUSER; | 2454 | aafs_mnt->mnt_sb->s_flags &= ~SB_NOUSER; |
2455 | 2455 | ||
2456 | /* Populate fs tree. */ | 2456 | /* Populate fs tree. */ |
2457 | error = entry_create_dir(&aa_sfs_entry, NULL); | 2457 | error = entry_create_dir(&aa_sfs_entry, NULL); |
@@ -2491,7 +2491,7 @@ static int __init aa_create_aafs(void) | |||
2491 | ns_subrevision(root_ns) = dent; | 2491 | ns_subrevision(root_ns) = dent; |
2492 | 2492 | ||
2493 | /* policy tree referenced by magic policy symlink */ | 2493 | /* policy tree referenced by magic policy symlink */ |
2494 | mutex_lock(&root_ns->lock); | 2494 | mutex_lock_nested(&root_ns->lock, root_ns->level); |
2495 | error = __aafs_ns_mkdir(root_ns, aafs_mnt->mnt_root, ".policy", | 2495 | error = __aafs_ns_mkdir(root_ns, aafs_mnt->mnt_root, ".policy", |
2496 | aafs_mnt->mnt_root); | 2496 | aafs_mnt->mnt_root); |
2497 | mutex_unlock(&root_ns->lock); | 2497 | mutex_unlock(&root_ns->lock); |
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c index dd754b7850a8..6a54d2ffa840 100644 --- a/security/apparmor/domain.c +++ b/security/apparmor/domain.c | |||
@@ -305,6 +305,7 @@ static int change_profile_perms(struct aa_profile *profile, | |||
305 | * __attach_match_ - find an attachment match | 305 | * __attach_match_ - find an attachment match |
306 | * @name - to match against (NOT NULL) | 306 | * @name - to match against (NOT NULL) |
307 | * @head - profile list to walk (NOT NULL) | 307 | * @head - profile list to walk (NOT NULL) |
308 | * @info - info message if there was an error (NOT NULL) | ||
308 | * | 309 | * |
309 | * Do a linear search on the profiles in the list. There is a matching | 310 | * Do a linear search on the profiles in the list. There is a matching |
310 | * preference where an exact match is preferred over a name which uses | 311 | * preference where an exact match is preferred over a name which uses |
@@ -316,28 +317,47 @@ static int change_profile_perms(struct aa_profile *profile, | |||
316 | * Returns: profile or NULL if no match found | 317 | * Returns: profile or NULL if no match found |
317 | */ | 318 | */ |
318 | static struct aa_profile *__attach_match(const char *name, | 319 | static struct aa_profile *__attach_match(const char *name, |
319 | struct list_head *head) | 320 | struct list_head *head, |
321 | const char **info) | ||
320 | { | 322 | { |
321 | int len = 0; | 323 | int len = 0; |
324 | bool conflict = false; | ||
322 | struct aa_profile *profile, *candidate = NULL; | 325 | struct aa_profile *profile, *candidate = NULL; |
323 | 326 | ||
324 | list_for_each_entry_rcu(profile, head, base.list) { | 327 | list_for_each_entry_rcu(profile, head, base.list) { |
325 | if (profile->label.flags & FLAG_NULL) | 328 | if (profile->label.flags & FLAG_NULL && |
329 | &profile->label == ns_unconfined(profile->ns)) | ||
326 | continue; | 330 | continue; |
327 | if (profile->xmatch && profile->xmatch_len > len) { | 331 | |
328 | unsigned int state = aa_dfa_match(profile->xmatch, | 332 | if (profile->xmatch) { |
329 | DFA_START, name); | 333 | if (profile->xmatch_len >= len) { |
330 | u32 perm = dfa_user_allow(profile->xmatch, state); | 334 | unsigned int state; |
331 | /* any accepting state means a valid match. */ | 335 | u32 perm; |
332 | if (perm & MAY_EXEC) { | 336 | |
333 | candidate = profile; | 337 | state = aa_dfa_match(profile->xmatch, |
334 | len = profile->xmatch_len; | 338 | DFA_START, name); |
339 | perm = dfa_user_allow(profile->xmatch, state); | ||
340 | /* any accepting state means a valid match. */ | ||
341 | if (perm & MAY_EXEC) { | ||
342 | if (profile->xmatch_len == len) { | ||
343 | conflict = true; | ||
344 | continue; | ||
345 | } | ||
346 | candidate = profile; | ||
347 | len = profile->xmatch_len; | ||
348 | conflict = false; | ||
349 | } | ||
335 | } | 350 | } |
336 | } else if (!strcmp(profile->base.name, name)) | 351 | } else if (!strcmp(profile->base.name, name)) |
337 | /* exact non-re match, no more searching required */ | 352 | /* exact non-re match, no more searching required */ |
338 | return profile; | 353 | return profile; |
339 | } | 354 | } |
340 | 355 | ||
356 | if (conflict) { | ||
357 | *info = "conflicting profile attachments"; | ||
358 | return NULL; | ||
359 | } | ||
360 | |||
341 | return candidate; | 361 | return candidate; |
342 | } | 362 | } |
343 | 363 | ||
@@ -346,16 +366,17 @@ static struct aa_profile *__attach_match(const char *name, | |||
346 | * @ns: the current namespace (NOT NULL) | 366 | * @ns: the current namespace (NOT NULL) |
347 | * @list: list to search (NOT NULL) | 367 | * @list: list to search (NOT NULL) |
348 | * @name: the executable name to match against (NOT NULL) | 368 | * @name: the executable name to match against (NOT NULL) |
369 | * @info: info message if there was an error | ||
349 | * | 370 | * |
350 | * Returns: label or NULL if no match found | 371 | * Returns: label or NULL if no match found |
351 | */ | 372 | */ |
352 | static struct aa_label *find_attach(struct aa_ns *ns, struct list_head *list, | 373 | static struct aa_label *find_attach(struct aa_ns *ns, struct list_head *list, |
353 | const char *name) | 374 | const char *name, const char **info) |
354 | { | 375 | { |
355 | struct aa_profile *profile; | 376 | struct aa_profile *profile; |
356 | 377 | ||
357 | rcu_read_lock(); | 378 | rcu_read_lock(); |
358 | profile = aa_get_profile(__attach_match(name, list)); | 379 | profile = aa_get_profile(__attach_match(name, list, info)); |
359 | rcu_read_unlock(); | 380 | rcu_read_unlock(); |
360 | 381 | ||
361 | return profile ? &profile->label : NULL; | 382 | return profile ? &profile->label : NULL; |
@@ -448,11 +469,11 @@ static struct aa_label *x_to_label(struct aa_profile *profile, | |||
448 | if (xindex & AA_X_CHILD) | 469 | if (xindex & AA_X_CHILD) |
449 | /* released by caller */ | 470 | /* released by caller */ |
450 | new = find_attach(ns, &profile->base.profiles, | 471 | new = find_attach(ns, &profile->base.profiles, |
451 | name); | 472 | name, info); |
452 | else | 473 | else |
453 | /* released by caller */ | 474 | /* released by caller */ |
454 | new = find_attach(ns, &ns->base.profiles, | 475 | new = find_attach(ns, &ns->base.profiles, |
455 | name); | 476 | name, info); |
456 | *lookupname = name; | 477 | *lookupname = name; |
457 | break; | 478 | break; |
458 | } | 479 | } |
@@ -516,7 +537,7 @@ static struct aa_label *profile_transition(struct aa_profile *profile, | |||
516 | 537 | ||
517 | if (profile_unconfined(profile)) { | 538 | if (profile_unconfined(profile)) { |
518 | new = find_attach(profile->ns, &profile->ns->base.profiles, | 539 | new = find_attach(profile->ns, &profile->ns->base.profiles, |
519 | name); | 540 | name, &info); |
520 | if (new) { | 541 | if (new) { |
521 | AA_DEBUG("unconfined attached to new label"); | 542 | AA_DEBUG("unconfined attached to new label"); |
522 | return new; | 543 | return new; |
@@ -541,9 +562,21 @@ static struct aa_label *profile_transition(struct aa_profile *profile, | |||
541 | } | 562 | } |
542 | } else if (COMPLAIN_MODE(profile)) { | 563 | } else if (COMPLAIN_MODE(profile)) { |
543 | /* no exec permission - learning mode */ | 564 | /* no exec permission - learning mode */ |
544 | struct aa_profile *new_profile = aa_new_null_profile(profile, | 565 | struct aa_profile *new_profile = NULL; |
545 | false, name, | 566 | char *n = kstrdup(name, GFP_ATOMIC); |
546 | GFP_ATOMIC); | 567 | |
568 | if (n) { | ||
569 | /* name is ptr into buffer */ | ||
570 | long pos = name - buffer; | ||
571 | /* break per cpu buffer hold */ | ||
572 | put_buffers(buffer); | ||
573 | new_profile = aa_new_null_profile(profile, false, n, | ||
574 | GFP_KERNEL); | ||
575 | get_buffers(buffer); | ||
576 | name = buffer + pos; | ||
577 | strcpy((char *)name, n); | ||
578 | kfree(n); | ||
579 | } | ||
547 | if (!new_profile) { | 580 | if (!new_profile) { |
548 | error = -ENOMEM; | 581 | error = -ENOMEM; |
549 | info = "could not create null profile"; | 582 | info = "could not create null profile"; |
diff --git a/security/apparmor/file.c b/security/apparmor/file.c index 3382518b87fa..e79bf44396a3 100644 --- a/security/apparmor/file.c +++ b/security/apparmor/file.c | |||
@@ -226,18 +226,12 @@ static u32 map_old_perms(u32 old) | |||
226 | struct aa_perms aa_compute_fperms(struct aa_dfa *dfa, unsigned int state, | 226 | struct aa_perms aa_compute_fperms(struct aa_dfa *dfa, unsigned int state, |
227 | struct path_cond *cond) | 227 | struct path_cond *cond) |
228 | { | 228 | { |
229 | struct aa_perms perms; | ||
230 | |||
231 | /* FIXME: change over to new dfa format | 229 | /* FIXME: change over to new dfa format |
232 | * currently file perms are encoded in the dfa, new format | 230 | * currently file perms are encoded in the dfa, new format |
233 | * splits the permissions from the dfa. This mapping can be | 231 | * splits the permissions from the dfa. This mapping can be |
234 | * done at profile load | 232 | * done at profile load |
235 | */ | 233 | */ |
236 | perms.deny = 0; | 234 | struct aa_perms perms = { }; |
237 | perms.kill = perms.stop = 0; | ||
238 | perms.complain = perms.cond = 0; | ||
239 | perms.hide = 0; | ||
240 | perms.prompt = 0; | ||
241 | 235 | ||
242 | if (uid_eq(current_fsuid(), cond->uid)) { | 236 | if (uid_eq(current_fsuid(), cond->uid)) { |
243 | perms.allow = map_old_perms(dfa_user_allow(dfa, state)); | 237 | perms.allow = map_old_perms(dfa_user_allow(dfa, state)); |
diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h index 620e81169659..4ac095118717 100644 --- a/security/apparmor/include/audit.h +++ b/security/apparmor/include/audit.h | |||
@@ -121,17 +121,19 @@ struct apparmor_audit_data { | |||
121 | /* these entries require a custom callback fn */ | 121 | /* these entries require a custom callback fn */ |
122 | struct { | 122 | struct { |
123 | struct aa_label *peer; | 123 | struct aa_label *peer; |
124 | struct { | 124 | union { |
125 | const char *target; | 125 | struct { |
126 | kuid_t ouid; | 126 | const char *target; |
127 | } fs; | 127 | kuid_t ouid; |
128 | } fs; | ||
129 | int signal; | ||
130 | }; | ||
128 | }; | 131 | }; |
129 | struct { | 132 | struct { |
130 | struct aa_profile *profile; | 133 | struct aa_profile *profile; |
131 | const char *ns; | 134 | const char *ns; |
132 | long pos; | 135 | long pos; |
133 | } iface; | 136 | } iface; |
134 | int signal; | ||
135 | struct { | 137 | struct { |
136 | int rlim; | 138 | int rlim; |
137 | unsigned long max; | 139 | unsigned long max; |
diff --git a/security/apparmor/include/lib.h b/security/apparmor/include/lib.h index 436b3a722357..6505e1ad9e23 100644 --- a/security/apparmor/include/lib.h +++ b/security/apparmor/include/lib.h | |||
@@ -19,17 +19,6 @@ | |||
19 | 19 | ||
20 | #include "match.h" | 20 | #include "match.h" |
21 | 21 | ||
22 | /* Provide our own test for whether a write lock is held for asserts | ||
23 | * this is because on none SMP systems write_can_lock will always | ||
24 | * resolve to true, which is what you want for code making decisions | ||
25 | * based on it, but wrong for asserts checking that the lock is held | ||
26 | */ | ||
27 | #ifdef CONFIG_SMP | ||
28 | #define write_is_locked(X) !write_can_lock(X) | ||
29 | #else | ||
30 | #define write_is_locked(X) (1) | ||
31 | #endif /* CONFIG_SMP */ | ||
32 | |||
33 | /* | 22 | /* |
34 | * DEBUG remains global (no per profile flag) since it is mostly used in sysctl | 23 | * DEBUG remains global (no per profile flag) since it is mostly used in sysctl |
35 | * which is not related to profile accesses. | 24 | * which is not related to profile accesses. |
@@ -97,7 +86,7 @@ static inline unsigned int aa_dfa_null_transition(struct aa_dfa *dfa, | |||
97 | 86 | ||
98 | static inline bool path_mediated_fs(struct dentry *dentry) | 87 | static inline bool path_mediated_fs(struct dentry *dentry) |
99 | { | 88 | { |
100 | return !(dentry->d_sb->s_flags & MS_NOUSER); | 89 | return !(dentry->d_sb->s_flags & SB_NOUSER); |
101 | } | 90 | } |
102 | 91 | ||
103 | 92 | ||
diff --git a/security/apparmor/include/perms.h b/security/apparmor/include/perms.h index 2b27bb79aec4..d7b7e7115160 100644 --- a/security/apparmor/include/perms.h +++ b/security/apparmor/include/perms.h | |||
@@ -133,6 +133,9 @@ extern struct aa_perms allperms; | |||
133 | #define xcheck_labels_profiles(L1, L2, FN, args...) \ | 133 | #define xcheck_labels_profiles(L1, L2, FN, args...) \ |
134 | xcheck_ns_labels((L1), (L2), xcheck_ns_profile_label, (FN), args) | 134 | xcheck_ns_labels((L1), (L2), xcheck_ns_profile_label, (FN), args) |
135 | 135 | ||
136 | #define xcheck_labels(L1, L2, P, FN1, FN2) \ | ||
137 | xcheck(fn_for_each((L1), (P), (FN1)), fn_for_each((L2), (P), (FN2))) | ||
138 | |||
136 | 139 | ||
137 | void aa_perm_mask_to_str(char *str, const char *chrs, u32 mask); | 140 | void aa_perm_mask_to_str(char *str, const char *chrs, u32 mask); |
138 | void aa_audit_perm_names(struct audit_buffer *ab, const char **names, u32 mask); | 141 | void aa_audit_perm_names(struct audit_buffer *ab, const char **names, u32 mask); |
diff --git a/security/apparmor/ipc.c b/security/apparmor/ipc.c index 7ca0032e7ba9..b40678f3c1d5 100644 --- a/security/apparmor/ipc.c +++ b/security/apparmor/ipc.c | |||
@@ -64,40 +64,48 @@ static void audit_ptrace_cb(struct audit_buffer *ab, void *va) | |||
64 | FLAGS_NONE, GFP_ATOMIC); | 64 | FLAGS_NONE, GFP_ATOMIC); |
65 | } | 65 | } |
66 | 66 | ||
67 | /* assumes check for PROFILE_MEDIATES is already done */ | ||
67 | /* TODO: conditionals */ | 68 | /* TODO: conditionals */ |
68 | static int profile_ptrace_perm(struct aa_profile *profile, | 69 | static int profile_ptrace_perm(struct aa_profile *profile, |
69 | struct aa_profile *peer, u32 request, | 70 | struct aa_label *peer, u32 request, |
70 | struct common_audit_data *sa) | 71 | struct common_audit_data *sa) |
71 | { | 72 | { |
72 | struct aa_perms perms = { }; | 73 | struct aa_perms perms = { }; |
73 | 74 | ||
74 | /* need because of peer in cross check */ | 75 | aad(sa)->peer = peer; |
75 | if (profile_unconfined(profile) || | 76 | aa_profile_match_label(profile, peer, AA_CLASS_PTRACE, request, |
76 | !PROFILE_MEDIATES(profile, AA_CLASS_PTRACE)) | ||
77 | return 0; | ||
78 | |||
79 | aad(sa)->peer = &peer->label; | ||
80 | aa_profile_match_label(profile, &peer->label, AA_CLASS_PTRACE, request, | ||
81 | &perms); | 77 | &perms); |
82 | aa_apply_modes_to_perms(profile, &perms); | 78 | aa_apply_modes_to_perms(profile, &perms); |
83 | return aa_check_perms(profile, &perms, request, sa, audit_ptrace_cb); | 79 | return aa_check_perms(profile, &perms, request, sa, audit_ptrace_cb); |
84 | } | 80 | } |
85 | 81 | ||
86 | static int cross_ptrace_perm(struct aa_profile *tracer, | 82 | static int profile_tracee_perm(struct aa_profile *tracee, |
87 | struct aa_profile *tracee, u32 request, | 83 | struct aa_label *tracer, u32 request, |
88 | struct common_audit_data *sa) | 84 | struct common_audit_data *sa) |
89 | { | 85 | { |
86 | if (profile_unconfined(tracee) || unconfined(tracer) || | ||
87 | !PROFILE_MEDIATES(tracee, AA_CLASS_PTRACE)) | ||
88 | return 0; | ||
89 | |||
90 | return profile_ptrace_perm(tracee, tracer, request, sa); | ||
91 | } | ||
92 | |||
93 | static int profile_tracer_perm(struct aa_profile *tracer, | ||
94 | struct aa_label *tracee, u32 request, | ||
95 | struct common_audit_data *sa) | ||
96 | { | ||
97 | if (profile_unconfined(tracer)) | ||
98 | return 0; | ||
99 | |||
90 | if (PROFILE_MEDIATES(tracer, AA_CLASS_PTRACE)) | 100 | if (PROFILE_MEDIATES(tracer, AA_CLASS_PTRACE)) |
91 | return xcheck(profile_ptrace_perm(tracer, tracee, request, sa), | 101 | return profile_ptrace_perm(tracer, tracee, request, sa); |
92 | profile_ptrace_perm(tracee, tracer, | 102 | |
93 | request << PTRACE_PERM_SHIFT, | 103 | /* profile uses the old style capability check for ptrace */ |
94 | sa)); | 104 | if (&tracer->label == tracee) |
95 | /* policy uses the old style capability check for ptrace */ | ||
96 | if (profile_unconfined(tracer) || tracer == tracee) | ||
97 | return 0; | 105 | return 0; |
98 | 106 | ||
99 | aad(sa)->label = &tracer->label; | 107 | aad(sa)->label = &tracer->label; |
100 | aad(sa)->peer = &tracee->label; | 108 | aad(sa)->peer = tracee; |
101 | aad(sa)->request = 0; | 109 | aad(sa)->request = 0; |
102 | aad(sa)->error = aa_capable(&tracer->label, CAP_SYS_PTRACE, 1); | 110 | aad(sa)->error = aa_capable(&tracer->label, CAP_SYS_PTRACE, 1); |
103 | 111 | ||
@@ -115,10 +123,13 @@ static int cross_ptrace_perm(struct aa_profile *tracer, | |||
115 | int aa_may_ptrace(struct aa_label *tracer, struct aa_label *tracee, | 123 | int aa_may_ptrace(struct aa_label *tracer, struct aa_label *tracee, |
116 | u32 request) | 124 | u32 request) |
117 | { | 125 | { |
126 | struct aa_profile *profile; | ||
127 | u32 xrequest = request << PTRACE_PERM_SHIFT; | ||
118 | DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, OP_PTRACE); | 128 | DEFINE_AUDIT_DATA(sa, LSM_AUDIT_DATA_NONE, OP_PTRACE); |
119 | 129 | ||
120 | return xcheck_labels_profiles(tracer, tracee, cross_ptrace_perm, | 130 | return xcheck_labels(tracer, tracee, profile, |
121 | request, &sa); | 131 | profile_tracer_perm(profile, tracee, request, &sa), |
132 | profile_tracee_perm(profile, tracer, xrequest, &sa)); | ||
122 | } | 133 | } |
123 | 134 | ||
124 | 135 | ||
diff --git a/security/apparmor/label.c b/security/apparmor/label.c index c5b99b954580..324fe5c60f87 100644 --- a/security/apparmor/label.c +++ b/security/apparmor/label.c | |||
@@ -80,7 +80,7 @@ void __aa_proxy_redirect(struct aa_label *orig, struct aa_label *new) | |||
80 | 80 | ||
81 | AA_BUG(!orig); | 81 | AA_BUG(!orig); |
82 | AA_BUG(!new); | 82 | AA_BUG(!new); |
83 | AA_BUG(!write_is_locked(&labels_set(orig)->lock)); | 83 | lockdep_assert_held_exclusive(&labels_set(orig)->lock); |
84 | 84 | ||
85 | tmp = rcu_dereference_protected(orig->proxy->label, | 85 | tmp = rcu_dereference_protected(orig->proxy->label, |
86 | &labels_ns(orig)->lock); | 86 | &labels_ns(orig)->lock); |
@@ -571,7 +571,7 @@ static bool __label_remove(struct aa_label *label, struct aa_label *new) | |||
571 | 571 | ||
572 | AA_BUG(!ls); | 572 | AA_BUG(!ls); |
573 | AA_BUG(!label); | 573 | AA_BUG(!label); |
574 | AA_BUG(!write_is_locked(&ls->lock)); | 574 | lockdep_assert_held_exclusive(&ls->lock); |
575 | 575 | ||
576 | if (new) | 576 | if (new) |
577 | __aa_proxy_redirect(label, new); | 577 | __aa_proxy_redirect(label, new); |
@@ -608,7 +608,7 @@ static bool __label_replace(struct aa_label *old, struct aa_label *new) | |||
608 | AA_BUG(!ls); | 608 | AA_BUG(!ls); |
609 | AA_BUG(!old); | 609 | AA_BUG(!old); |
610 | AA_BUG(!new); | 610 | AA_BUG(!new); |
611 | AA_BUG(!write_is_locked(&ls->lock)); | 611 | lockdep_assert_held_exclusive(&ls->lock); |
612 | AA_BUG(new->flags & FLAG_IN_TREE); | 612 | AA_BUG(new->flags & FLAG_IN_TREE); |
613 | 613 | ||
614 | if (!label_is_stale(old)) | 614 | if (!label_is_stale(old)) |
@@ -645,7 +645,7 @@ static struct aa_label *__label_insert(struct aa_labelset *ls, | |||
645 | AA_BUG(!ls); | 645 | AA_BUG(!ls); |
646 | AA_BUG(!label); | 646 | AA_BUG(!label); |
647 | AA_BUG(labels_set(label) != ls); | 647 | AA_BUG(labels_set(label) != ls); |
648 | AA_BUG(!write_is_locked(&ls->lock)); | 648 | lockdep_assert_held_exclusive(&ls->lock); |
649 | AA_BUG(label->flags & FLAG_IN_TREE); | 649 | AA_BUG(label->flags & FLAG_IN_TREE); |
650 | 650 | ||
651 | /* Figure out where to put new node */ | 651 | /* Figure out where to put new node */ |
@@ -2115,7 +2115,7 @@ void __aa_labelset_update_subtree(struct aa_ns *ns) | |||
2115 | __labelset_update(ns); | 2115 | __labelset_update(ns); |
2116 | 2116 | ||
2117 | list_for_each_entry(child, &ns->sub_ns, base.list) { | 2117 | list_for_each_entry(child, &ns->sub_ns, base.list) { |
2118 | mutex_lock(&child->lock); | 2118 | mutex_lock_nested(&child->lock, child->level); |
2119 | __aa_labelset_update_subtree(child); | 2119 | __aa_labelset_update_subtree(child); |
2120 | mutex_unlock(&child->lock); | 2120 | mutex_unlock(&child->lock); |
2121 | } | 2121 | } |
diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c index 08ca26bcca77..4d5e98e49d5e 100644 --- a/security/apparmor/lib.c +++ b/security/apparmor/lib.c | |||
@@ -317,14 +317,11 @@ static u32 map_other(u32 x) | |||
317 | void aa_compute_perms(struct aa_dfa *dfa, unsigned int state, | 317 | void aa_compute_perms(struct aa_dfa *dfa, unsigned int state, |
318 | struct aa_perms *perms) | 318 | struct aa_perms *perms) |
319 | { | 319 | { |
320 | perms->deny = 0; | 320 | *perms = (struct aa_perms) { |
321 | perms->kill = perms->stop = 0; | 321 | .allow = dfa_user_allow(dfa, state), |
322 | perms->complain = perms->cond = 0; | 322 | .audit = dfa_user_audit(dfa, state), |
323 | perms->hide = 0; | 323 | .quiet = dfa_user_quiet(dfa, state), |
324 | perms->prompt = 0; | 324 | }; |
325 | perms->allow = dfa_user_allow(dfa, state); | ||
326 | perms->audit = dfa_user_audit(dfa, state); | ||
327 | perms->quiet = dfa_user_quiet(dfa, state); | ||
328 | 325 | ||
329 | /* for v5 perm mapping in the policydb, the other set is used | 326 | /* for v5 perm mapping in the policydb, the other set is used |
330 | * to extend the general perm set | 327 | * to extend the general perm set |
@@ -426,7 +423,6 @@ int aa_check_perms(struct aa_profile *profile, struct aa_perms *perms, | |||
426 | void (*cb)(struct audit_buffer *, void *)) | 423 | void (*cb)(struct audit_buffer *, void *)) |
427 | { | 424 | { |
428 | int type, error; | 425 | int type, error; |
429 | bool stop = false; | ||
430 | u32 denied = request & (~perms->allow | perms->deny); | 426 | u32 denied = request & (~perms->allow | perms->deny); |
431 | 427 | ||
432 | if (likely(!denied)) { | 428 | if (likely(!denied)) { |
@@ -447,8 +443,6 @@ int aa_check_perms(struct aa_profile *profile, struct aa_perms *perms, | |||
447 | else | 443 | else |
448 | type = AUDIT_APPARMOR_DENIED; | 444 | type = AUDIT_APPARMOR_DENIED; |
449 | 445 | ||
450 | if (denied & perms->stop) | ||
451 | stop = true; | ||
452 | if (denied == (denied & perms->hide)) | 446 | if (denied == (denied & perms->hide)) |
453 | error = -ENOENT; | 447 | error = -ENOENT; |
454 | 448 | ||
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index 1346ee5be04f..9a65eeaf7dfa 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c | |||
@@ -813,11 +813,11 @@ static const struct kernel_param_ops param_ops_aalockpolicy = { | |||
813 | .get = param_get_aalockpolicy | 813 | .get = param_get_aalockpolicy |
814 | }; | 814 | }; |
815 | 815 | ||
816 | static int param_set_audit(const char *val, struct kernel_param *kp); | 816 | static int param_set_audit(const char *val, const struct kernel_param *kp); |
817 | static int param_get_audit(char *buffer, struct kernel_param *kp); | 817 | static int param_get_audit(char *buffer, const struct kernel_param *kp); |
818 | 818 | ||
819 | static int param_set_mode(const char *val, struct kernel_param *kp); | 819 | static int param_set_mode(const char *val, const struct kernel_param *kp); |
820 | static int param_get_mode(char *buffer, struct kernel_param *kp); | 820 | static int param_get_mode(char *buffer, const struct kernel_param *kp); |
821 | 821 | ||
822 | /* Flag values, also controllable via /sys/module/apparmor/parameters | 822 | /* Flag values, also controllable via /sys/module/apparmor/parameters |
823 | * We define special types as we want to do additional mediation. | 823 | * We define special types as we want to do additional mediation. |
@@ -846,7 +846,7 @@ module_param_call(audit, param_set_audit, param_get_audit, | |||
846 | /* Determines if audit header is included in audited messages. This | 846 | /* Determines if audit header is included in audited messages. This |
847 | * provides more context if the audit daemon is not running | 847 | * provides more context if the audit daemon is not running |
848 | */ | 848 | */ |
849 | bool aa_g_audit_header = 1; | 849 | bool aa_g_audit_header = true; |
850 | module_param_named(audit_header, aa_g_audit_header, aabool, | 850 | module_param_named(audit_header, aa_g_audit_header, aabool, |
851 | S_IRUSR | S_IWUSR); | 851 | S_IRUSR | S_IWUSR); |
852 | 852 | ||
@@ -871,7 +871,7 @@ module_param_named(path_max, aa_g_path_max, aauint, S_IRUSR); | |||
871 | * DEPRECATED: read only as strict checking of load is always done now | 871 | * DEPRECATED: read only as strict checking of load is always done now |
872 | * that none root users (user namespaces) can load policy. | 872 | * that none root users (user namespaces) can load policy. |
873 | */ | 873 | */ |
874 | bool aa_g_paranoid_load = 1; | 874 | bool aa_g_paranoid_load = true; |
875 | module_param_named(paranoid_load, aa_g_paranoid_load, aabool, S_IRUGO); | 875 | module_param_named(paranoid_load, aa_g_paranoid_load, aabool, S_IRUGO); |
876 | 876 | ||
877 | /* Boot time disable flag */ | 877 | /* Boot time disable flag */ |
@@ -951,7 +951,7 @@ static int param_get_aauint(char *buffer, const struct kernel_param *kp) | |||
951 | return param_get_uint(buffer, kp); | 951 | return param_get_uint(buffer, kp); |
952 | } | 952 | } |
953 | 953 | ||
954 | static int param_get_audit(char *buffer, struct kernel_param *kp) | 954 | static int param_get_audit(char *buffer, const struct kernel_param *kp) |
955 | { | 955 | { |
956 | if (!apparmor_enabled) | 956 | if (!apparmor_enabled) |
957 | return -EINVAL; | 957 | return -EINVAL; |
@@ -960,7 +960,7 @@ static int param_get_audit(char *buffer, struct kernel_param *kp) | |||
960 | return sprintf(buffer, "%s", audit_mode_names[aa_g_audit]); | 960 | return sprintf(buffer, "%s", audit_mode_names[aa_g_audit]); |
961 | } | 961 | } |
962 | 962 | ||
963 | static int param_set_audit(const char *val, struct kernel_param *kp) | 963 | static int param_set_audit(const char *val, const struct kernel_param *kp) |
964 | { | 964 | { |
965 | int i; | 965 | int i; |
966 | 966 | ||
@@ -981,7 +981,7 @@ static int param_set_audit(const char *val, struct kernel_param *kp) | |||
981 | return -EINVAL; | 981 | return -EINVAL; |
982 | } | 982 | } |
983 | 983 | ||
984 | static int param_get_mode(char *buffer, struct kernel_param *kp) | 984 | static int param_get_mode(char *buffer, const struct kernel_param *kp) |
985 | { | 985 | { |
986 | if (!apparmor_enabled) | 986 | if (!apparmor_enabled) |
987 | return -EINVAL; | 987 | return -EINVAL; |
@@ -991,7 +991,7 @@ static int param_get_mode(char *buffer, struct kernel_param *kp) | |||
991 | return sprintf(buffer, "%s", aa_profile_mode_names[aa_g_profile_mode]); | 991 | return sprintf(buffer, "%s", aa_profile_mode_names[aa_g_profile_mode]); |
992 | } | 992 | } |
993 | 993 | ||
994 | static int param_set_mode(const char *val, struct kernel_param *kp) | 994 | static int param_set_mode(const char *val, const struct kernel_param *kp) |
995 | { | 995 | { |
996 | int i; | 996 | int i; |
997 | 997 | ||
@@ -1119,7 +1119,7 @@ static int __init apparmor_init(void) | |||
1119 | 1119 | ||
1120 | if (!apparmor_enabled || !security_module_enable("apparmor")) { | 1120 | if (!apparmor_enabled || !security_module_enable("apparmor")) { |
1121 | aa_info_message("AppArmor disabled by boot time parameter"); | 1121 | aa_info_message("AppArmor disabled by boot time parameter"); |
1122 | apparmor_enabled = 0; | 1122 | apparmor_enabled = false; |
1123 | return 0; | 1123 | return 0; |
1124 | } | 1124 | } |
1125 | 1125 | ||
@@ -1175,7 +1175,7 @@ alloc_out: | |||
1175 | aa_destroy_aafs(); | 1175 | aa_destroy_aafs(); |
1176 | aa_teardown_dfa_engine(); | 1176 | aa_teardown_dfa_engine(); |
1177 | 1177 | ||
1178 | apparmor_enabled = 0; | 1178 | apparmor_enabled = false; |
1179 | return error; | 1179 | return error; |
1180 | } | 1180 | } |
1181 | 1181 | ||
diff --git a/security/apparmor/mount.c b/security/apparmor/mount.c index 82a64b58041d..8c558cbce930 100644 --- a/security/apparmor/mount.c +++ b/security/apparmor/mount.c | |||
@@ -216,13 +216,12 @@ static unsigned int match_mnt_flags(struct aa_dfa *dfa, unsigned int state, | |||
216 | static struct aa_perms compute_mnt_perms(struct aa_dfa *dfa, | 216 | static struct aa_perms compute_mnt_perms(struct aa_dfa *dfa, |
217 | unsigned int state) | 217 | unsigned int state) |
218 | { | 218 | { |
219 | struct aa_perms perms; | 219 | struct aa_perms perms = { |
220 | 220 | .allow = dfa_user_allow(dfa, state), | |
221 | perms.kill = 0; | 221 | .audit = dfa_user_audit(dfa, state), |
222 | perms.allow = dfa_user_allow(dfa, state); | 222 | .quiet = dfa_user_quiet(dfa, state), |
223 | perms.audit = dfa_user_audit(dfa, state); | 223 | .xindex = dfa_user_xindex(dfa, state), |
224 | perms.quiet = dfa_user_quiet(dfa, state); | 224 | }; |
225 | perms.xindex = dfa_user_xindex(dfa, state); | ||
226 | 225 | ||
227 | return perms; | 226 | return perms; |
228 | } | 227 | } |
@@ -330,6 +329,9 @@ static int match_mnt_path_str(struct aa_profile *profile, | |||
330 | AA_BUG(!mntpath); | 329 | AA_BUG(!mntpath); |
331 | AA_BUG(!buffer); | 330 | AA_BUG(!buffer); |
332 | 331 | ||
332 | if (!PROFILE_MEDIATES(profile, AA_CLASS_MOUNT)) | ||
333 | return 0; | ||
334 | |||
333 | error = aa_path_name(mntpath, path_flags(profile, mntpath), buffer, | 335 | error = aa_path_name(mntpath, path_flags(profile, mntpath), buffer, |
334 | &mntpnt, &info, profile->disconnected); | 336 | &mntpnt, &info, profile->disconnected); |
335 | if (error) | 337 | if (error) |
@@ -381,6 +383,9 @@ static int match_mnt(struct aa_profile *profile, const struct path *path, | |||
381 | AA_BUG(!profile); | 383 | AA_BUG(!profile); |
382 | AA_BUG(devpath && !devbuffer); | 384 | AA_BUG(devpath && !devbuffer); |
383 | 385 | ||
386 | if (!PROFILE_MEDIATES(profile, AA_CLASS_MOUNT)) | ||
387 | return 0; | ||
388 | |||
384 | if (devpath) { | 389 | if (devpath) { |
385 | error = aa_path_name(devpath, path_flags(profile, devpath), | 390 | error = aa_path_name(devpath, path_flags(profile, devpath), |
386 | devbuffer, &devname, &info, | 391 | devbuffer, &devname, &info, |
@@ -559,6 +564,9 @@ static int profile_umount(struct aa_profile *profile, struct path *path, | |||
559 | AA_BUG(!profile); | 564 | AA_BUG(!profile); |
560 | AA_BUG(!path); | 565 | AA_BUG(!path); |
561 | 566 | ||
567 | if (!PROFILE_MEDIATES(profile, AA_CLASS_MOUNT)) | ||
568 | return 0; | ||
569 | |||
562 | error = aa_path_name(path, path_flags(profile, path), buffer, &name, | 570 | error = aa_path_name(path, path_flags(profile, path), buffer, &name, |
563 | &info, profile->disconnected); | 571 | &info, profile->disconnected); |
564 | if (error) | 572 | if (error) |
@@ -614,7 +622,8 @@ static struct aa_label *build_pivotroot(struct aa_profile *profile, | |||
614 | AA_BUG(!new_path); | 622 | AA_BUG(!new_path); |
615 | AA_BUG(!old_path); | 623 | AA_BUG(!old_path); |
616 | 624 | ||
617 | if (profile_unconfined(profile)) | 625 | if (profile_unconfined(profile) || |
626 | !PROFILE_MEDIATES(profile, AA_CLASS_MOUNT)) | ||
618 | return aa_get_newest_label(&profile->label); | 627 | return aa_get_newest_label(&profile->label); |
619 | 628 | ||
620 | error = aa_path_name(old_path, path_flags(profile, old_path), | 629 | error = aa_path_name(old_path, path_flags(profile, old_path), |
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index 4243b0c3f0e4..b0b58848c248 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c | |||
@@ -502,7 +502,7 @@ struct aa_profile *aa_new_null_profile(struct aa_profile *parent, bool hat, | |||
502 | { | 502 | { |
503 | struct aa_profile *p, *profile; | 503 | struct aa_profile *p, *profile; |
504 | const char *bname; | 504 | const char *bname; |
505 | char *name; | 505 | char *name = NULL; |
506 | 506 | ||
507 | AA_BUG(!parent); | 507 | AA_BUG(!parent); |
508 | 508 | ||
@@ -545,7 +545,7 @@ name: | |||
545 | profile->file.dfa = aa_get_dfa(nulldfa); | 545 | profile->file.dfa = aa_get_dfa(nulldfa); |
546 | profile->policy.dfa = aa_get_dfa(nulldfa); | 546 | profile->policy.dfa = aa_get_dfa(nulldfa); |
547 | 547 | ||
548 | mutex_lock(&profile->ns->lock); | 548 | mutex_lock_nested(&profile->ns->lock, profile->ns->level); |
549 | p = __find_child(&parent->base.profiles, bname); | 549 | p = __find_child(&parent->base.profiles, bname); |
550 | if (p) { | 550 | if (p) { |
551 | aa_free_profile(profile); | 551 | aa_free_profile(profile); |
@@ -562,6 +562,7 @@ out: | |||
562 | return profile; | 562 | return profile; |
563 | 563 | ||
564 | fail: | 564 | fail: |
565 | kfree(name); | ||
565 | aa_free_profile(profile); | 566 | aa_free_profile(profile); |
566 | return NULL; | 567 | return NULL; |
567 | } | 568 | } |
@@ -905,7 +906,7 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label, | |||
905 | } else | 906 | } else |
906 | ns = aa_get_ns(policy_ns ? policy_ns : labels_ns(label)); | 907 | ns = aa_get_ns(policy_ns ? policy_ns : labels_ns(label)); |
907 | 908 | ||
908 | mutex_lock(&ns->lock); | 909 | mutex_lock_nested(&ns->lock, ns->level); |
909 | /* check for duplicate rawdata blobs: space and file dedup */ | 910 | /* check for duplicate rawdata blobs: space and file dedup */ |
910 | list_for_each_entry(rawdata_ent, &ns->rawdata_list, list) { | 911 | list_for_each_entry(rawdata_ent, &ns->rawdata_list, list) { |
911 | if (aa_rawdata_eq(rawdata_ent, udata)) { | 912 | if (aa_rawdata_eq(rawdata_ent, udata)) { |
@@ -1116,13 +1117,13 @@ ssize_t aa_remove_profiles(struct aa_ns *policy_ns, struct aa_label *subj, | |||
1116 | 1117 | ||
1117 | if (!name) { | 1118 | if (!name) { |
1118 | /* remove namespace - can only happen if fqname[0] == ':' */ | 1119 | /* remove namespace - can only happen if fqname[0] == ':' */ |
1119 | mutex_lock(&ns->parent->lock); | 1120 | mutex_lock_nested(&ns->parent->lock, ns->level); |
1120 | __aa_remove_ns(ns); | 1121 | __aa_remove_ns(ns); |
1121 | __aa_bump_ns_revision(ns); | 1122 | __aa_bump_ns_revision(ns); |
1122 | mutex_unlock(&ns->parent->lock); | 1123 | mutex_unlock(&ns->parent->lock); |
1123 | } else { | 1124 | } else { |
1124 | /* remove profile */ | 1125 | /* remove profile */ |
1125 | mutex_lock(&ns->lock); | 1126 | mutex_lock_nested(&ns->lock, ns->level); |
1126 | profile = aa_get_profile(__lookup_profile(&ns->base, name)); | 1127 | profile = aa_get_profile(__lookup_profile(&ns->base, name)); |
1127 | if (!profile) { | 1128 | if (!profile) { |
1128 | error = -ENOENT; | 1129 | error = -ENOENT; |
diff --git a/security/apparmor/policy_ns.c b/security/apparmor/policy_ns.c index 62a3589c62ab..b1e629cba70b 100644 --- a/security/apparmor/policy_ns.c +++ b/security/apparmor/policy_ns.c | |||
@@ -256,7 +256,8 @@ static struct aa_ns *__aa_create_ns(struct aa_ns *parent, const char *name, | |||
256 | ns = alloc_ns(parent->base.hname, name); | 256 | ns = alloc_ns(parent->base.hname, name); |
257 | if (!ns) | 257 | if (!ns) |
258 | return NULL; | 258 | return NULL; |
259 | mutex_lock(&ns->lock); | 259 | ns->level = parent->level + 1; |
260 | mutex_lock_nested(&ns->lock, ns->level); | ||
260 | error = __aafs_ns_mkdir(ns, ns_subns_dir(parent), name, dir); | 261 | error = __aafs_ns_mkdir(ns, ns_subns_dir(parent), name, dir); |
261 | if (error) { | 262 | if (error) { |
262 | AA_ERROR("Failed to create interface for ns %s\n", | 263 | AA_ERROR("Failed to create interface for ns %s\n", |
@@ -266,7 +267,6 @@ static struct aa_ns *__aa_create_ns(struct aa_ns *parent, const char *name, | |||
266 | return ERR_PTR(error); | 267 | return ERR_PTR(error); |
267 | } | 268 | } |
268 | ns->parent = aa_get_ns(parent); | 269 | ns->parent = aa_get_ns(parent); |
269 | ns->level = parent->level + 1; | ||
270 | list_add_rcu(&ns->base.list, &parent->sub_ns); | 270 | list_add_rcu(&ns->base.list, &parent->sub_ns); |
271 | /* add list ref */ | 271 | /* add list ref */ |
272 | aa_get_ns(ns); | 272 | aa_get_ns(ns); |
@@ -313,7 +313,7 @@ struct aa_ns *aa_prepare_ns(struct aa_ns *parent, const char *name) | |||
313 | { | 313 | { |
314 | struct aa_ns *ns; | 314 | struct aa_ns *ns; |
315 | 315 | ||
316 | mutex_lock(&parent->lock); | 316 | mutex_lock_nested(&parent->lock, parent->level); |
317 | /* try and find the specified ns and if it doesn't exist create it */ | 317 | /* try and find the specified ns and if it doesn't exist create it */ |
318 | /* released by caller */ | 318 | /* released by caller */ |
319 | ns = aa_get_ns(__aa_find_ns(&parent->sub_ns, name)); | 319 | ns = aa_get_ns(__aa_find_ns(&parent->sub_ns, name)); |
@@ -336,7 +336,7 @@ static void destroy_ns(struct aa_ns *ns) | |||
336 | if (!ns) | 336 | if (!ns) |
337 | return; | 337 | return; |
338 | 338 | ||
339 | mutex_lock(&ns->lock); | 339 | mutex_lock_nested(&ns->lock, ns->level); |
340 | /* release all profiles in this namespace */ | 340 | /* release all profiles in this namespace */ |
341 | __aa_profile_list_release(&ns->base.profiles); | 341 | __aa_profile_list_release(&ns->base.profiles); |
342 | 342 | ||
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c index 4ede87c30f8b..59a1a25b7d43 100644 --- a/security/apparmor/policy_unpack.c +++ b/security/apparmor/policy_unpack.c | |||
@@ -157,7 +157,7 @@ static void do_loaddata_free(struct work_struct *work) | |||
157 | struct aa_ns *ns = aa_get_ns(d->ns); | 157 | struct aa_ns *ns = aa_get_ns(d->ns); |
158 | 158 | ||
159 | if (ns) { | 159 | if (ns) { |
160 | mutex_lock(&ns->lock); | 160 | mutex_lock_nested(&ns->lock, ns->level); |
161 | __aa_fs_remove_rawdata(d); | 161 | __aa_fs_remove_rawdata(d); |
162 | mutex_unlock(&ns->lock); | 162 | mutex_unlock(&ns->lock); |
163 | aa_put_ns(ns); | 163 | aa_put_ns(ns); |
diff --git a/security/apparmor/resource.c b/security/apparmor/resource.c index d8bc842594ed..cf4d234febe9 100644 --- a/security/apparmor/resource.c +++ b/security/apparmor/resource.c | |||
@@ -47,7 +47,7 @@ static void audit_cb(struct audit_buffer *ab, void *va) | |||
47 | /** | 47 | /** |
48 | * audit_resource - audit setting resource limit | 48 | * audit_resource - audit setting resource limit |
49 | * @profile: profile being enforced (NOT NULL) | 49 | * @profile: profile being enforced (NOT NULL) |
50 | * @resoure: rlimit being auditing | 50 | * @resource: rlimit being auditing |
51 | * @value: value being set | 51 | * @value: value being set |
52 | * @error: error value | 52 | * @error: error value |
53 | * | 53 | * |
@@ -128,7 +128,7 @@ int aa_task_setrlimit(struct aa_label *label, struct task_struct *task, | |||
128 | error = fn_for_each(label, profile, | 128 | error = fn_for_each(label, profile, |
129 | audit_resource(profile, resource, | 129 | audit_resource(profile, resource, |
130 | new_rlim->rlim_max, peer, | 130 | new_rlim->rlim_max, peer, |
131 | "cap_sys_resoure", -EACCES)); | 131 | "cap_sys_resource", -EACCES)); |
132 | else | 132 | else |
133 | error = fn_for_each_confined(label, profile, | 133 | error = fn_for_each_confined(label, profile, |
134 | profile_setrlimit(profile, resource, new_rlim)); | 134 | profile_setrlimit(profile, resource, new_rlim)); |
diff --git a/security/commoncap.c b/security/commoncap.c index fc46f5b85251..48620c93d697 100644 --- a/security/commoncap.c +++ b/security/commoncap.c | |||
@@ -348,21 +348,18 @@ static __u32 sansflags(__u32 m) | |||
348 | return m & ~VFS_CAP_FLAGS_EFFECTIVE; | 348 | return m & ~VFS_CAP_FLAGS_EFFECTIVE; |
349 | } | 349 | } |
350 | 350 | ||
351 | static bool is_v2header(size_t size, __le32 magic) | 351 | static bool is_v2header(size_t size, const struct vfs_cap_data *cap) |
352 | { | 352 | { |
353 | __u32 m = le32_to_cpu(magic); | ||
354 | if (size != XATTR_CAPS_SZ_2) | 353 | if (size != XATTR_CAPS_SZ_2) |
355 | return false; | 354 | return false; |
356 | return sansflags(m) == VFS_CAP_REVISION_2; | 355 | return sansflags(le32_to_cpu(cap->magic_etc)) == VFS_CAP_REVISION_2; |
357 | } | 356 | } |
358 | 357 | ||
359 | static bool is_v3header(size_t size, __le32 magic) | 358 | static bool is_v3header(size_t size, const struct vfs_cap_data *cap) |
360 | { | 359 | { |
361 | __u32 m = le32_to_cpu(magic); | ||
362 | |||
363 | if (size != XATTR_CAPS_SZ_3) | 360 | if (size != XATTR_CAPS_SZ_3) |
364 | return false; | 361 | return false; |
365 | return sansflags(m) == VFS_CAP_REVISION_3; | 362 | return sansflags(le32_to_cpu(cap->magic_etc)) == VFS_CAP_REVISION_3; |
366 | } | 363 | } |
367 | 364 | ||
368 | /* | 365 | /* |
@@ -405,7 +402,7 @@ int cap_inode_getsecurity(struct inode *inode, const char *name, void **buffer, | |||
405 | 402 | ||
406 | fs_ns = inode->i_sb->s_user_ns; | 403 | fs_ns = inode->i_sb->s_user_ns; |
407 | cap = (struct vfs_cap_data *) tmpbuf; | 404 | cap = (struct vfs_cap_data *) tmpbuf; |
408 | if (is_v2header((size_t) ret, cap->magic_etc)) { | 405 | if (is_v2header((size_t) ret, cap)) { |
409 | /* If this is sizeof(vfs_cap_data) then we're ok with the | 406 | /* If this is sizeof(vfs_cap_data) then we're ok with the |
410 | * on-disk value, so return that. */ | 407 | * on-disk value, so return that. */ |
411 | if (alloc) | 408 | if (alloc) |
@@ -413,7 +410,7 @@ int cap_inode_getsecurity(struct inode *inode, const char *name, void **buffer, | |||
413 | else | 410 | else |
414 | kfree(tmpbuf); | 411 | kfree(tmpbuf); |
415 | return ret; | 412 | return ret; |
416 | } else if (!is_v3header((size_t) ret, cap->magic_etc)) { | 413 | } else if (!is_v3header((size_t) ret, cap)) { |
417 | kfree(tmpbuf); | 414 | kfree(tmpbuf); |
418 | return -EINVAL; | 415 | return -EINVAL; |
419 | } | 416 | } |
@@ -470,9 +467,9 @@ static kuid_t rootid_from_xattr(const void *value, size_t size, | |||
470 | return make_kuid(task_ns, rootid); | 467 | return make_kuid(task_ns, rootid); |
471 | } | 468 | } |
472 | 469 | ||
473 | static bool validheader(size_t size, __le32 magic) | 470 | static bool validheader(size_t size, const struct vfs_cap_data *cap) |
474 | { | 471 | { |
475 | return is_v2header(size, magic) || is_v3header(size, magic); | 472 | return is_v2header(size, cap) || is_v3header(size, cap); |
476 | } | 473 | } |
477 | 474 | ||
478 | /* | 475 | /* |
@@ -495,7 +492,7 @@ int cap_convert_nscap(struct dentry *dentry, void **ivalue, size_t size) | |||
495 | 492 | ||
496 | if (!*ivalue) | 493 | if (!*ivalue) |
497 | return -EINVAL; | 494 | return -EINVAL; |
498 | if (!validheader(size, cap->magic_etc)) | 495 | if (!validheader(size, cap)) |
499 | return -EINVAL; | 496 | return -EINVAL; |
500 | if (!capable_wrt_inode_uidgid(inode, CAP_SETFCAP)) | 497 | if (!capable_wrt_inode_uidgid(inode, CAP_SETFCAP)) |
501 | return -EPERM; | 498 | return -EPERM; |
@@ -536,7 +533,7 @@ int cap_convert_nscap(struct dentry *dentry, void **ivalue, size_t size) | |||
536 | static inline int bprm_caps_from_vfs_caps(struct cpu_vfs_cap_data *caps, | 533 | static inline int bprm_caps_from_vfs_caps(struct cpu_vfs_cap_data *caps, |
537 | struct linux_binprm *bprm, | 534 | struct linux_binprm *bprm, |
538 | bool *effective, | 535 | bool *effective, |
539 | bool *has_cap) | 536 | bool *has_fcap) |
540 | { | 537 | { |
541 | struct cred *new = bprm->cred; | 538 | struct cred *new = bprm->cred; |
542 | unsigned i; | 539 | unsigned i; |
@@ -546,7 +543,7 @@ static inline int bprm_caps_from_vfs_caps(struct cpu_vfs_cap_data *caps, | |||
546 | *effective = true; | 543 | *effective = true; |
547 | 544 | ||
548 | if (caps->magic_etc & VFS_CAP_REVISION_MASK) | 545 | if (caps->magic_etc & VFS_CAP_REVISION_MASK) |
549 | *has_cap = true; | 546 | *has_fcap = true; |
550 | 547 | ||
551 | CAP_FOR_EACH_U32(i) { | 548 | CAP_FOR_EACH_U32(i) { |
552 | __u32 permitted = caps->permitted.cap[i]; | 549 | __u32 permitted = caps->permitted.cap[i]; |
@@ -653,7 +650,7 @@ int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data | |||
653 | * its xattrs and, if present, apply them to the proposed credentials being | 650 | * its xattrs and, if present, apply them to the proposed credentials being |
654 | * constructed by execve(). | 651 | * constructed by execve(). |
655 | */ | 652 | */ |
656 | static int get_file_caps(struct linux_binprm *bprm, bool *effective, bool *has_cap) | 653 | static int get_file_caps(struct linux_binprm *bprm, bool *effective, bool *has_fcap) |
657 | { | 654 | { |
658 | int rc = 0; | 655 | int rc = 0; |
659 | struct cpu_vfs_cap_data vcaps; | 656 | struct cpu_vfs_cap_data vcaps; |
@@ -684,7 +681,7 @@ static int get_file_caps(struct linux_binprm *bprm, bool *effective, bool *has_c | |||
684 | goto out; | 681 | goto out; |
685 | } | 682 | } |
686 | 683 | ||
687 | rc = bprm_caps_from_vfs_caps(&vcaps, bprm, effective, has_cap); | 684 | rc = bprm_caps_from_vfs_caps(&vcaps, bprm, effective, has_fcap); |
688 | if (rc == -EINVAL) | 685 | if (rc == -EINVAL) |
689 | printk(KERN_NOTICE "%s: cap_from_disk returned %d for %s\n", | 686 | printk(KERN_NOTICE "%s: cap_from_disk returned %d for %s\n", |
690 | __func__, rc, bprm->filename); | 687 | __func__, rc, bprm->filename); |
@@ -696,6 +693,115 @@ out: | |||
696 | return rc; | 693 | return rc; |
697 | } | 694 | } |
698 | 695 | ||
696 | static inline bool root_privileged(void) { return !issecure(SECURE_NOROOT); } | ||
697 | |||
698 | static inline bool __is_real(kuid_t uid, struct cred *cred) | ||
699 | { return uid_eq(cred->uid, uid); } | ||
700 | |||
701 | static inline bool __is_eff(kuid_t uid, struct cred *cred) | ||
702 | { return uid_eq(cred->euid, uid); } | ||
703 | |||
704 | static inline bool __is_suid(kuid_t uid, struct cred *cred) | ||
705 | { return !__is_real(uid, cred) && __is_eff(uid, cred); } | ||
706 | |||
707 | /* | ||
708 | * handle_privileged_root - Handle case of privileged root | ||
709 | * @bprm: The execution parameters, including the proposed creds | ||
710 | * @has_fcap: Are any file capabilities set? | ||
711 | * @effective: Do we have effective root privilege? | ||
712 | * @root_uid: This namespace' root UID WRT initial USER namespace | ||
713 | * | ||
714 | * Handle the case where root is privileged and hasn't been neutered by | ||
715 | * SECURE_NOROOT. If file capabilities are set, they won't be combined with | ||
716 | * set UID root and nothing is changed. If we are root, cap_permitted is | ||
717 | * updated. If we have become set UID root, the effective bit is set. | ||
718 | */ | ||
719 | static void handle_privileged_root(struct linux_binprm *bprm, bool has_fcap, | ||
720 | bool *effective, kuid_t root_uid) | ||
721 | { | ||
722 | const struct cred *old = current_cred(); | ||
723 | struct cred *new = bprm->cred; | ||
724 | |||
725 | if (!root_privileged()) | ||
726 | return; | ||
727 | /* | ||
728 | * If the legacy file capability is set, then don't set privs | ||
729 | * for a setuid root binary run by a non-root user. Do set it | ||
730 | * for a root user just to cause least surprise to an admin. | ||
731 | */ | ||
732 | if (has_fcap && __is_suid(root_uid, new)) { | ||
733 | warn_setuid_and_fcaps_mixed(bprm->filename); | ||
734 | return; | ||
735 | } | ||
736 | /* | ||
737 | * To support inheritance of root-permissions and suid-root | ||
738 | * executables under compatibility mode, we override the | ||
739 | * capability sets for the file. | ||
740 | */ | ||
741 | if (__is_eff(root_uid, new) || __is_real(root_uid, new)) { | ||
742 | /* pP' = (cap_bset & ~0) | (pI & ~0) */ | ||
743 | new->cap_permitted = cap_combine(old->cap_bset, | ||
744 | old->cap_inheritable); | ||
745 | } | ||
746 | /* | ||
747 | * If only the real uid is 0, we do not set the effective bit. | ||
748 | */ | ||
749 | if (__is_eff(root_uid, new)) | ||
750 | *effective = true; | ||
751 | } | ||
752 | |||
753 | #define __cap_gained(field, target, source) \ | ||
754 | !cap_issubset(target->cap_##field, source->cap_##field) | ||
755 | #define __cap_grew(target, source, cred) \ | ||
756 | !cap_issubset(cred->cap_##target, cred->cap_##source) | ||
757 | #define __cap_full(field, cred) \ | ||
758 | cap_issubset(CAP_FULL_SET, cred->cap_##field) | ||
759 | |||
760 | static inline bool __is_setuid(struct cred *new, const struct cred *old) | ||
761 | { return !uid_eq(new->euid, old->uid); } | ||
762 | |||
763 | static inline bool __is_setgid(struct cred *new, const struct cred *old) | ||
764 | { return !gid_eq(new->egid, old->gid); } | ||
765 | |||
766 | /* | ||
767 | * 1) Audit candidate if current->cap_effective is set | ||
768 | * | ||
769 | * We do not bother to audit if 3 things are true: | ||
770 | * 1) cap_effective has all caps | ||
771 | * 2) we became root *OR* are were already root | ||
772 | * 3) root is supposed to have all caps (SECURE_NOROOT) | ||
773 | * Since this is just a normal root execing a process. | ||
774 | * | ||
775 | * Number 1 above might fail if you don't have a full bset, but I think | ||
776 | * that is interesting information to audit. | ||
777 | * | ||
778 | * A number of other conditions require logging: | ||
779 | * 2) something prevented setuid root getting all caps | ||
780 | * 3) non-setuid root gets fcaps | ||
781 | * 4) non-setuid root gets ambient | ||
782 | */ | ||
783 | static inline bool nonroot_raised_pE(struct cred *new, const struct cred *old, | ||
784 | kuid_t root, bool has_fcap) | ||
785 | { | ||
786 | bool ret = false; | ||
787 | |||
788 | if ((__cap_grew(effective, ambient, new) && | ||
789 | !(__cap_full(effective, new) && | ||
790 | (__is_eff(root, new) || __is_real(root, new)) && | ||
791 | root_privileged())) || | ||
792 | (root_privileged() && | ||
793 | __is_suid(root, new) && | ||
794 | !__cap_full(effective, new)) || | ||
795 | (!__is_setuid(new, old) && | ||
796 | ((has_fcap && | ||
797 | __cap_gained(permitted, new, old)) || | ||
798 | __cap_gained(ambient, new, old)))) | ||
799 | |||
800 | ret = true; | ||
801 | |||
802 | return ret; | ||
803 | } | ||
804 | |||
699 | /** | 805 | /** |
700 | * cap_bprm_set_creds - Set up the proposed credentials for execve(). | 806 | * cap_bprm_set_creds - Set up the proposed credentials for execve(). |
701 | * @bprm: The execution parameters, including the proposed creds | 807 | * @bprm: The execution parameters, including the proposed creds |
@@ -708,61 +814,33 @@ int cap_bprm_set_creds(struct linux_binprm *bprm) | |||
708 | { | 814 | { |
709 | const struct cred *old = current_cred(); | 815 | const struct cred *old = current_cred(); |
710 | struct cred *new = bprm->cred; | 816 | struct cred *new = bprm->cred; |
711 | bool effective, has_cap = false, is_setid; | 817 | bool effective = false, has_fcap = false, is_setid; |
712 | int ret; | 818 | int ret; |
713 | kuid_t root_uid; | 819 | kuid_t root_uid; |
714 | 820 | ||
715 | if (WARN_ON(!cap_ambient_invariant_ok(old))) | 821 | if (WARN_ON(!cap_ambient_invariant_ok(old))) |
716 | return -EPERM; | 822 | return -EPERM; |
717 | 823 | ||
718 | effective = false; | 824 | ret = get_file_caps(bprm, &effective, &has_fcap); |
719 | ret = get_file_caps(bprm, &effective, &has_cap); | ||
720 | if (ret < 0) | 825 | if (ret < 0) |
721 | return ret; | 826 | return ret; |
722 | 827 | ||
723 | root_uid = make_kuid(new->user_ns, 0); | 828 | root_uid = make_kuid(new->user_ns, 0); |
724 | 829 | ||
725 | if (!issecure(SECURE_NOROOT)) { | 830 | handle_privileged_root(bprm, has_fcap, &effective, root_uid); |
726 | /* | ||
727 | * If the legacy file capability is set, then don't set privs | ||
728 | * for a setuid root binary run by a non-root user. Do set it | ||
729 | * for a root user just to cause least surprise to an admin. | ||
730 | */ | ||
731 | if (has_cap && !uid_eq(new->uid, root_uid) && uid_eq(new->euid, root_uid)) { | ||
732 | warn_setuid_and_fcaps_mixed(bprm->filename); | ||
733 | goto skip; | ||
734 | } | ||
735 | /* | ||
736 | * To support inheritance of root-permissions and suid-root | ||
737 | * executables under compatibility mode, we override the | ||
738 | * capability sets for the file. | ||
739 | * | ||
740 | * If only the real uid is 0, we do not set the effective bit. | ||
741 | */ | ||
742 | if (uid_eq(new->euid, root_uid) || uid_eq(new->uid, root_uid)) { | ||
743 | /* pP' = (cap_bset & ~0) | (pI & ~0) */ | ||
744 | new->cap_permitted = cap_combine(old->cap_bset, | ||
745 | old->cap_inheritable); | ||
746 | } | ||
747 | if (uid_eq(new->euid, root_uid)) | ||
748 | effective = true; | ||
749 | } | ||
750 | skip: | ||
751 | 831 | ||
752 | /* if we have fs caps, clear dangerous personality flags */ | 832 | /* if we have fs caps, clear dangerous personality flags */ |
753 | if (!cap_issubset(new->cap_permitted, old->cap_permitted)) | 833 | if (__cap_gained(permitted, new, old)) |
754 | bprm->per_clear |= PER_CLEAR_ON_SETID; | 834 | bprm->per_clear |= PER_CLEAR_ON_SETID; |
755 | 835 | ||
756 | |||
757 | /* Don't let someone trace a set[ug]id/setpcap binary with the revised | 836 | /* Don't let someone trace a set[ug]id/setpcap binary with the revised |
758 | * credentials unless they have the appropriate permit. | 837 | * credentials unless they have the appropriate permit. |
759 | * | 838 | * |
760 | * In addition, if NO_NEW_PRIVS, then ensure we get no new privs. | 839 | * In addition, if NO_NEW_PRIVS, then ensure we get no new privs. |
761 | */ | 840 | */ |
762 | is_setid = !uid_eq(new->euid, old->uid) || !gid_eq(new->egid, old->gid); | 841 | is_setid = __is_setuid(new, old) || __is_setgid(new, old); |
763 | 842 | ||
764 | if ((is_setid || | 843 | if ((is_setid || __cap_gained(permitted, new, old)) && |
765 | !cap_issubset(new->cap_permitted, old->cap_permitted)) && | ||
766 | ((bprm->unsafe & ~LSM_UNSAFE_PTRACE) || | 844 | ((bprm->unsafe & ~LSM_UNSAFE_PTRACE) || |
767 | !ptracer_capable(current, new->user_ns))) { | 845 | !ptracer_capable(current, new->user_ns))) { |
768 | /* downgrade; they get no more than they had, and maybe less */ | 846 | /* downgrade; they get no more than they had, and maybe less */ |
@@ -779,7 +857,7 @@ skip: | |||
779 | new->sgid = new->fsgid = new->egid; | 857 | new->sgid = new->fsgid = new->egid; |
780 | 858 | ||
781 | /* File caps or setid cancels ambient. */ | 859 | /* File caps or setid cancels ambient. */ |
782 | if (has_cap || is_setid) | 860 | if (has_fcap || is_setid) |
783 | cap_clear(new->cap_ambient); | 861 | cap_clear(new->cap_ambient); |
784 | 862 | ||
785 | /* | 863 | /* |
@@ -800,26 +878,10 @@ skip: | |||
800 | if (WARN_ON(!cap_ambient_invariant_ok(new))) | 878 | if (WARN_ON(!cap_ambient_invariant_ok(new))) |
801 | return -EPERM; | 879 | return -EPERM; |
802 | 880 | ||
803 | /* | 881 | if (nonroot_raised_pE(new, old, root_uid, has_fcap)) { |
804 | * Audit candidate if current->cap_effective is set | 882 | ret = audit_log_bprm_fcaps(bprm, new, old); |
805 | * | 883 | if (ret < 0) |
806 | * We do not bother to audit if 3 things are true: | 884 | return ret; |
807 | * 1) cap_effective has all caps | ||
808 | * 2) we are root | ||
809 | * 3) root is supposed to have all caps (SECURE_NOROOT) | ||
810 | * Since this is just a normal root execing a process. | ||
811 | * | ||
812 | * Number 1 above might fail if you don't have a full bset, but I think | ||
813 | * that is interesting information to audit. | ||
814 | */ | ||
815 | if (!cap_issubset(new->cap_effective, new->cap_ambient)) { | ||
816 | if (!cap_issubset(CAP_FULL_SET, new->cap_effective) || | ||
817 | !uid_eq(new->euid, root_uid) || !uid_eq(new->uid, root_uid) || | ||
818 | issecure(SECURE_NOROOT)) { | ||
819 | ret = audit_log_bprm_fcaps(bprm, new, old); | ||
820 | if (ret < 0) | ||
821 | return ret; | ||
822 | } | ||
823 | } | 885 | } |
824 | 886 | ||
825 | new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS); | 887 | new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS); |
@@ -829,13 +891,11 @@ skip: | |||
829 | 891 | ||
830 | /* Check for privilege-elevated exec. */ | 892 | /* Check for privilege-elevated exec. */ |
831 | bprm->cap_elevated = 0; | 893 | bprm->cap_elevated = 0; |
832 | if (is_setid) { | 894 | if (is_setid || |
895 | (!__is_real(root_uid, new) && | ||
896 | (effective || | ||
897 | __cap_grew(permitted, ambient, new)))) | ||
833 | bprm->cap_elevated = 1; | 898 | bprm->cap_elevated = 1; |
834 | } else if (!uid_eq(new->uid, root_uid)) { | ||
835 | if (effective || | ||
836 | !cap_issubset(new->cap_permitted, new->cap_ambient)) | ||
837 | bprm->cap_elevated = 1; | ||
838 | } | ||
839 | 899 | ||
840 | return 0; | 900 | return 0; |
841 | } | 901 | } |
diff --git a/security/device_cgroup.c b/security/device_cgroup.c index 5ef7e5240563..c65b39bafdfe 100644 --- a/security/device_cgroup.c +++ b/security/device_cgroup.c | |||
@@ -15,15 +15,6 @@ | |||
15 | #include <linux/rcupdate.h> | 15 | #include <linux/rcupdate.h> |
16 | #include <linux/mutex.h> | 16 | #include <linux/mutex.h> |
17 | 17 | ||
18 | #define ACC_MKNOD 1 | ||
19 | #define ACC_READ 2 | ||
20 | #define ACC_WRITE 4 | ||
21 | #define ACC_MASK (ACC_MKNOD | ACC_READ | ACC_WRITE) | ||
22 | |||
23 | #define DEV_BLOCK 1 | ||
24 | #define DEV_CHAR 2 | ||
25 | #define DEV_ALL 4 /* this represents all devices */ | ||
26 | |||
27 | static DEFINE_MUTEX(devcgroup_mutex); | 18 | static DEFINE_MUTEX(devcgroup_mutex); |
28 | 19 | ||
29 | enum devcg_behavior { | 20 | enum devcg_behavior { |
@@ -246,21 +237,21 @@ static void set_access(char *acc, short access) | |||
246 | { | 237 | { |
247 | int idx = 0; | 238 | int idx = 0; |
248 | memset(acc, 0, ACCLEN); | 239 | memset(acc, 0, ACCLEN); |
249 | if (access & ACC_READ) | 240 | if (access & DEVCG_ACC_READ) |
250 | acc[idx++] = 'r'; | 241 | acc[idx++] = 'r'; |
251 | if (access & ACC_WRITE) | 242 | if (access & DEVCG_ACC_WRITE) |
252 | acc[idx++] = 'w'; | 243 | acc[idx++] = 'w'; |
253 | if (access & ACC_MKNOD) | 244 | if (access & DEVCG_ACC_MKNOD) |
254 | acc[idx++] = 'm'; | 245 | acc[idx++] = 'm'; |
255 | } | 246 | } |
256 | 247 | ||
257 | static char type_to_char(short type) | 248 | static char type_to_char(short type) |
258 | { | 249 | { |
259 | if (type == DEV_ALL) | 250 | if (type == DEVCG_DEV_ALL) |
260 | return 'a'; | 251 | return 'a'; |
261 | if (type == DEV_CHAR) | 252 | if (type == DEVCG_DEV_CHAR) |
262 | return 'c'; | 253 | return 'c'; |
263 | if (type == DEV_BLOCK) | 254 | if (type == DEVCG_DEV_BLOCK) |
264 | return 'b'; | 255 | return 'b'; |
265 | return 'X'; | 256 | return 'X'; |
266 | } | 257 | } |
@@ -287,10 +278,10 @@ static int devcgroup_seq_show(struct seq_file *m, void *v) | |||
287 | * This way, the file remains as a "whitelist of devices" | 278 | * This way, the file remains as a "whitelist of devices" |
288 | */ | 279 | */ |
289 | if (devcgroup->behavior == DEVCG_DEFAULT_ALLOW) { | 280 | if (devcgroup->behavior == DEVCG_DEFAULT_ALLOW) { |
290 | set_access(acc, ACC_MASK); | 281 | set_access(acc, DEVCG_ACC_MASK); |
291 | set_majmin(maj, ~0); | 282 | set_majmin(maj, ~0); |
292 | set_majmin(min, ~0); | 283 | set_majmin(min, ~0); |
293 | seq_printf(m, "%c %s:%s %s\n", type_to_char(DEV_ALL), | 284 | seq_printf(m, "%c %s:%s %s\n", type_to_char(DEVCG_DEV_ALL), |
294 | maj, min, acc); | 285 | maj, min, acc); |
295 | } else { | 286 | } else { |
296 | list_for_each_entry_rcu(ex, &devcgroup->exceptions, list) { | 287 | list_for_each_entry_rcu(ex, &devcgroup->exceptions, list) { |
@@ -309,10 +300,10 @@ static int devcgroup_seq_show(struct seq_file *m, void *v) | |||
309 | /** | 300 | /** |
310 | * match_exception - iterates the exception list trying to find a complete match | 301 | * match_exception - iterates the exception list trying to find a complete match |
311 | * @exceptions: list of exceptions | 302 | * @exceptions: list of exceptions |
312 | * @type: device type (DEV_BLOCK or DEV_CHAR) | 303 | * @type: device type (DEVCG_DEV_BLOCK or DEVCG_DEV_CHAR) |
313 | * @major: device file major number, ~0 to match all | 304 | * @major: device file major number, ~0 to match all |
314 | * @minor: device file minor number, ~0 to match all | 305 | * @minor: device file minor number, ~0 to match all |
315 | * @access: permission mask (ACC_READ, ACC_WRITE, ACC_MKNOD) | 306 | * @access: permission mask (DEVCG_ACC_READ, DEVCG_ACC_WRITE, DEVCG_ACC_MKNOD) |
316 | * | 307 | * |
317 | * It is considered a complete match if an exception is found that will | 308 | * It is considered a complete match if an exception is found that will |
318 | * contain the entire range of provided parameters. | 309 | * contain the entire range of provided parameters. |
@@ -325,9 +316,9 @@ static bool match_exception(struct list_head *exceptions, short type, | |||
325 | struct dev_exception_item *ex; | 316 | struct dev_exception_item *ex; |
326 | 317 | ||
327 | list_for_each_entry_rcu(ex, exceptions, list) { | 318 | list_for_each_entry_rcu(ex, exceptions, list) { |
328 | if ((type & DEV_BLOCK) && !(ex->type & DEV_BLOCK)) | 319 | if ((type & DEVCG_DEV_BLOCK) && !(ex->type & DEVCG_DEV_BLOCK)) |
329 | continue; | 320 | continue; |
330 | if ((type & DEV_CHAR) && !(ex->type & DEV_CHAR)) | 321 | if ((type & DEVCG_DEV_CHAR) && !(ex->type & DEVCG_DEV_CHAR)) |
331 | continue; | 322 | continue; |
332 | if (ex->major != ~0 && ex->major != major) | 323 | if (ex->major != ~0 && ex->major != major) |
333 | continue; | 324 | continue; |
@@ -344,10 +335,10 @@ static bool match_exception(struct list_head *exceptions, short type, | |||
344 | /** | 335 | /** |
345 | * match_exception_partial - iterates the exception list trying to find a partial match | 336 | * match_exception_partial - iterates the exception list trying to find a partial match |
346 | * @exceptions: list of exceptions | 337 | * @exceptions: list of exceptions |
347 | * @type: device type (DEV_BLOCK or DEV_CHAR) | 338 | * @type: device type (DEVCG_DEV_BLOCK or DEVCG_DEV_CHAR) |
348 | * @major: device file major number, ~0 to match all | 339 | * @major: device file major number, ~0 to match all |
349 | * @minor: device file minor number, ~0 to match all | 340 | * @minor: device file minor number, ~0 to match all |
350 | * @access: permission mask (ACC_READ, ACC_WRITE, ACC_MKNOD) | 341 | * @access: permission mask (DEVCG_ACC_READ, DEVCG_ACC_WRITE, DEVCG_ACC_MKNOD) |
351 | * | 342 | * |
352 | * It is considered a partial match if an exception's range is found to | 343 | * It is considered a partial match if an exception's range is found to |
353 | * contain *any* of the devices specified by provided parameters. This is | 344 | * contain *any* of the devices specified by provided parameters. This is |
@@ -362,9 +353,9 @@ static bool match_exception_partial(struct list_head *exceptions, short type, | |||
362 | struct dev_exception_item *ex; | 353 | struct dev_exception_item *ex; |
363 | 354 | ||
364 | list_for_each_entry_rcu(ex, exceptions, list) { | 355 | list_for_each_entry_rcu(ex, exceptions, list) { |
365 | if ((type & DEV_BLOCK) && !(ex->type & DEV_BLOCK)) | 356 | if ((type & DEVCG_DEV_BLOCK) && !(ex->type & DEVCG_DEV_BLOCK)) |
366 | continue; | 357 | continue; |
367 | if ((type & DEV_CHAR) && !(ex->type & DEV_CHAR)) | 358 | if ((type & DEVCG_DEV_CHAR) && !(ex->type & DEVCG_DEV_CHAR)) |
368 | continue; | 359 | continue; |
369 | /* | 360 | /* |
370 | * We must be sure that both the exception and the provided | 361 | * We must be sure that both the exception and the provided |
@@ -647,10 +638,10 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup, | |||
647 | } | 638 | } |
648 | return 0; | 639 | return 0; |
649 | case 'b': | 640 | case 'b': |
650 | ex.type = DEV_BLOCK; | 641 | ex.type = DEVCG_DEV_BLOCK; |
651 | break; | 642 | break; |
652 | case 'c': | 643 | case 'c': |
653 | ex.type = DEV_CHAR; | 644 | ex.type = DEVCG_DEV_CHAR; |
654 | break; | 645 | break; |
655 | default: | 646 | default: |
656 | return -EINVAL; | 647 | return -EINVAL; |
@@ -703,13 +694,13 @@ static int devcgroup_update_access(struct dev_cgroup *devcgroup, | |||
703 | for (b++, count = 0; count < 3; count++, b++) { | 694 | for (b++, count = 0; count < 3; count++, b++) { |
704 | switch (*b) { | 695 | switch (*b) { |
705 | case 'r': | 696 | case 'r': |
706 | ex.access |= ACC_READ; | 697 | ex.access |= DEVCG_ACC_READ; |
707 | break; | 698 | break; |
708 | case 'w': | 699 | case 'w': |
709 | ex.access |= ACC_WRITE; | 700 | ex.access |= DEVCG_ACC_WRITE; |
710 | break; | 701 | break; |
711 | case 'm': | 702 | case 'm': |
712 | ex.access |= ACC_MKNOD; | 703 | ex.access |= DEVCG_ACC_MKNOD; |
713 | break; | 704 | break; |
714 | case '\n': | 705 | case '\n': |
715 | case '\0': | 706 | case '\0': |
@@ -806,12 +797,12 @@ struct cgroup_subsys devices_cgrp_subsys = { | |||
806 | * @type: device type | 797 | * @type: device type |
807 | * @major: device major number | 798 | * @major: device major number |
808 | * @minor: device minor number | 799 | * @minor: device minor number |
809 | * @access: combination of ACC_WRITE, ACC_READ and ACC_MKNOD | 800 | * @access: combination of DEVCG_ACC_WRITE, DEVCG_ACC_READ and DEVCG_ACC_MKNOD |
810 | * | 801 | * |
811 | * returns 0 on success, -EPERM case the operation is not permitted | 802 | * returns 0 on success, -EPERM case the operation is not permitted |
812 | */ | 803 | */ |
813 | static int __devcgroup_check_permission(short type, u32 major, u32 minor, | 804 | int __devcgroup_check_permission(short type, u32 major, u32 minor, |
814 | short access) | 805 | short access) |
815 | { | 806 | { |
816 | struct dev_cgroup *dev_cgroup; | 807 | struct dev_cgroup *dev_cgroup; |
817 | bool rc; | 808 | bool rc; |
@@ -833,37 +824,3 @@ static int __devcgroup_check_permission(short type, u32 major, u32 minor, | |||
833 | 824 | ||
834 | return 0; | 825 | return 0; |
835 | } | 826 | } |
836 | |||
837 | int __devcgroup_inode_permission(struct inode *inode, int mask) | ||
838 | { | ||
839 | short type, access = 0; | ||
840 | |||
841 | if (S_ISBLK(inode->i_mode)) | ||
842 | type = DEV_BLOCK; | ||
843 | if (S_ISCHR(inode->i_mode)) | ||
844 | type = DEV_CHAR; | ||
845 | if (mask & MAY_WRITE) | ||
846 | access |= ACC_WRITE; | ||
847 | if (mask & MAY_READ) | ||
848 | access |= ACC_READ; | ||
849 | |||
850 | return __devcgroup_check_permission(type, imajor(inode), iminor(inode), | ||
851 | access); | ||
852 | } | ||
853 | |||
854 | int devcgroup_inode_mknod(int mode, dev_t dev) | ||
855 | { | ||
856 | short type; | ||
857 | |||
858 | if (!S_ISBLK(mode) && !S_ISCHR(mode)) | ||
859 | return 0; | ||
860 | |||
861 | if (S_ISBLK(mode)) | ||
862 | type = DEV_BLOCK; | ||
863 | else | ||
864 | type = DEV_CHAR; | ||
865 | |||
866 | return __devcgroup_check_permission(type, MAJOR(dev), MINOR(dev), | ||
867 | ACC_MKNOD); | ||
868 | |||
869 | } | ||
diff --git a/security/integrity/digsig.c b/security/integrity/digsig.c index 06554c448dce..6f9e4ce568cd 100644 --- a/security/integrity/digsig.c +++ b/security/integrity/digsig.c | |||
@@ -112,21 +112,25 @@ int __init integrity_init_keyring(const unsigned int id) | |||
112 | int __init integrity_load_x509(const unsigned int id, const char *path) | 112 | int __init integrity_load_x509(const unsigned int id, const char *path) |
113 | { | 113 | { |
114 | key_ref_t key; | 114 | key_ref_t key; |
115 | char *data; | 115 | void *data; |
116 | loff_t size; | ||
116 | int rc; | 117 | int rc; |
117 | 118 | ||
118 | if (!keyring[id]) | 119 | if (!keyring[id]) |
119 | return -EINVAL; | 120 | return -EINVAL; |
120 | 121 | ||
121 | rc = integrity_read_file(path, &data); | 122 | rc = kernel_read_file_from_path(path, &data, &size, 0, |
122 | if (rc < 0) | 123 | READING_X509_CERTIFICATE); |
124 | if (rc < 0) { | ||
125 | pr_err("Unable to open file: %s (%d)", path, rc); | ||
123 | return rc; | 126 | return rc; |
127 | } | ||
124 | 128 | ||
125 | key = key_create_or_update(make_key_ref(keyring[id], 1), | 129 | key = key_create_or_update(make_key_ref(keyring[id], 1), |
126 | "asymmetric", | 130 | "asymmetric", |
127 | NULL, | 131 | NULL, |
128 | data, | 132 | data, |
129 | rc, | 133 | size, |
130 | ((KEY_POS_ALL & ~KEY_POS_SETATTR) | | 134 | ((KEY_POS_ALL & ~KEY_POS_SETATTR) | |
131 | KEY_USR_VIEW | KEY_USR_READ), | 135 | KEY_USR_VIEW | KEY_USR_READ), |
132 | KEY_ALLOC_NOT_IN_QUOTA); | 136 | KEY_ALLOC_NOT_IN_QUOTA); |
@@ -139,6 +143,6 @@ int __init integrity_load_x509(const unsigned int id, const char *path) | |||
139 | key_ref_to_ptr(key)->description, path); | 143 | key_ref_to_ptr(key)->description, path); |
140 | key_ref_put(key); | 144 | key_ref_put(key); |
141 | } | 145 | } |
142 | kfree(data); | 146 | vfree(data); |
143 | return 0; | 147 | return 0; |
144 | } | 148 | } |
diff --git a/security/integrity/evm/evm.h b/security/integrity/evm/evm.h index f5f12727771a..241aca315b0c 100644 --- a/security/integrity/evm/evm.h +++ b/security/integrity/evm/evm.h | |||
@@ -23,6 +23,9 @@ | |||
23 | 23 | ||
24 | #define EVM_INIT_HMAC 0x0001 | 24 | #define EVM_INIT_HMAC 0x0001 |
25 | #define EVM_INIT_X509 0x0002 | 25 | #define EVM_INIT_X509 0x0002 |
26 | #define EVM_SETUP 0x80000000 /* userland has signaled key load */ | ||
27 | |||
28 | #define EVM_INIT_MASK (EVM_INIT_HMAC | EVM_INIT_X509 | EVM_SETUP) | ||
26 | 29 | ||
27 | extern int evm_initialized; | 30 | extern int evm_initialized; |
28 | extern char *evm_hmac; | 31 | extern char *evm_hmac; |
diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c index 1d32cd20009a..bcd64baf8788 100644 --- a/security/integrity/evm/evm_crypto.c +++ b/security/integrity/evm/evm_crypto.c | |||
@@ -80,7 +80,7 @@ static struct shash_desc *init_desc(char type) | |||
80 | 80 | ||
81 | if (type == EVM_XATTR_HMAC) { | 81 | if (type == EVM_XATTR_HMAC) { |
82 | if (!(evm_initialized & EVM_INIT_HMAC)) { | 82 | if (!(evm_initialized & EVM_INIT_HMAC)) { |
83 | pr_err("HMAC key is not set\n"); | 83 | pr_err_once("HMAC key is not set\n"); |
84 | return ERR_PTR(-ENOKEY); | 84 | return ERR_PTR(-ENOKEY); |
85 | } | 85 | } |
86 | tfm = &hmac_tfm; | 86 | tfm = &hmac_tfm; |
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c index 063d38aef64e..9826c02e2db8 100644 --- a/security/integrity/evm/evm_main.c +++ b/security/integrity/evm/evm_main.c | |||
@@ -49,6 +49,9 @@ char *evm_config_xattrnames[] = { | |||
49 | XATTR_NAME_SMACKMMAP, | 49 | XATTR_NAME_SMACKMMAP, |
50 | #endif | 50 | #endif |
51 | #endif | 51 | #endif |
52 | #ifdef CONFIG_SECURITY_APPARMOR | ||
53 | XATTR_NAME_APPARMOR, | ||
54 | #endif | ||
52 | #ifdef CONFIG_IMA_APPRAISE | 55 | #ifdef CONFIG_IMA_APPRAISE |
53 | XATTR_NAME_IMA, | 56 | XATTR_NAME_IMA, |
54 | #endif | 57 | #endif |
diff --git a/security/integrity/evm/evm_secfs.c b/security/integrity/evm/evm_secfs.c index c8dccd54d501..319cf16d6603 100644 --- a/security/integrity/evm/evm_secfs.c +++ b/security/integrity/evm/evm_secfs.c | |||
@@ -40,7 +40,7 @@ static ssize_t evm_read_key(struct file *filp, char __user *buf, | |||
40 | if (*ppos != 0) | 40 | if (*ppos != 0) |
41 | return 0; | 41 | return 0; |
42 | 42 | ||
43 | sprintf(temp, "%d", evm_initialized); | 43 | sprintf(temp, "%d", (evm_initialized & ~EVM_SETUP)); |
44 | rc = simple_read_from_buffer(buf, count, ppos, temp, strlen(temp)); | 44 | rc = simple_read_from_buffer(buf, count, ppos, temp, strlen(temp)); |
45 | 45 | ||
46 | return rc; | 46 | return rc; |
@@ -61,24 +61,29 @@ static ssize_t evm_read_key(struct file *filp, char __user *buf, | |||
61 | static ssize_t evm_write_key(struct file *file, const char __user *buf, | 61 | static ssize_t evm_write_key(struct file *file, const char __user *buf, |
62 | size_t count, loff_t *ppos) | 62 | size_t count, loff_t *ppos) |
63 | { | 63 | { |
64 | char temp[80]; | 64 | int i, ret; |
65 | int i; | ||
66 | 65 | ||
67 | if (!capable(CAP_SYS_ADMIN) || (evm_initialized & EVM_INIT_HMAC)) | 66 | if (!capable(CAP_SYS_ADMIN) || (evm_initialized & EVM_SETUP)) |
68 | return -EPERM; | 67 | return -EPERM; |
69 | 68 | ||
70 | if (count >= sizeof(temp) || count == 0) | 69 | ret = kstrtoint_from_user(buf, count, 0, &i); |
71 | return -EINVAL; | ||
72 | |||
73 | if (copy_from_user(temp, buf, count) != 0) | ||
74 | return -EFAULT; | ||
75 | 70 | ||
76 | temp[count] = '\0'; | 71 | if (ret) |
72 | return ret; | ||
77 | 73 | ||
78 | if ((sscanf(temp, "%d", &i) != 1) || (i != 1)) | 74 | /* Reject invalid values */ |
75 | if (!i || (i & ~EVM_INIT_MASK) != 0) | ||
79 | return -EINVAL; | 76 | return -EINVAL; |
80 | 77 | ||
81 | evm_init_key(); | 78 | if (i & EVM_INIT_HMAC) { |
79 | ret = evm_init_key(); | ||
80 | if (ret != 0) | ||
81 | return ret; | ||
82 | /* Forbid further writes after the symmetric key is loaded */ | ||
83 | i |= EVM_SETUP; | ||
84 | } | ||
85 | |||
86 | evm_initialized |= i; | ||
82 | 87 | ||
83 | return count; | 88 | return count; |
84 | } | 89 | } |
diff --git a/security/integrity/iint.c b/security/integrity/iint.c index 6fc888ca468e..c84e05866052 100644 --- a/security/integrity/iint.c +++ b/security/integrity/iint.c | |||
@@ -200,55 +200,6 @@ int integrity_kernel_read(struct file *file, loff_t offset, | |||
200 | } | 200 | } |
201 | 201 | ||
202 | /* | 202 | /* |
203 | * integrity_read_file - read entire file content into the buffer | ||
204 | * | ||
205 | * This is function opens a file, allocates the buffer of required | ||
206 | * size, read entire file content to the buffer and closes the file | ||
207 | * | ||
208 | * It is used only by init code. | ||
209 | * | ||
210 | */ | ||
211 | int __init integrity_read_file(const char *path, char **data) | ||
212 | { | ||
213 | struct file *file; | ||
214 | loff_t size; | ||
215 | char *buf; | ||
216 | int rc = -EINVAL; | ||
217 | |||
218 | if (!path || !*path) | ||
219 | return -EINVAL; | ||
220 | |||
221 | file = filp_open(path, O_RDONLY, 0); | ||
222 | if (IS_ERR(file)) { | ||
223 | rc = PTR_ERR(file); | ||
224 | pr_err("Unable to open file: %s (%d)", path, rc); | ||
225 | return rc; | ||
226 | } | ||
227 | |||
228 | size = i_size_read(file_inode(file)); | ||
229 | if (size <= 0) | ||
230 | goto out; | ||
231 | |||
232 | buf = kmalloc(size, GFP_KERNEL); | ||
233 | if (!buf) { | ||
234 | rc = -ENOMEM; | ||
235 | goto out; | ||
236 | } | ||
237 | |||
238 | rc = integrity_kernel_read(file, 0, buf, size); | ||
239 | if (rc == size) { | ||
240 | *data = buf; | ||
241 | } else { | ||
242 | kfree(buf); | ||
243 | if (rc >= 0) | ||
244 | rc = -EIO; | ||
245 | } | ||
246 | out: | ||
247 | fput(file); | ||
248 | return rc; | ||
249 | } | ||
250 | |||
251 | /* | ||
252 | * integrity_load_keys - load integrity keys hook | 203 | * integrity_load_keys - load integrity keys hook |
253 | * | 204 | * |
254 | * Hooks is called from init/main.c:kernel_init_freeable() | 205 | * Hooks is called from init/main.c:kernel_init_freeable() |
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index c2edba8de35e..c7e8db0ea4c0 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c | |||
@@ -199,42 +199,59 @@ int ima_collect_measurement(struct integrity_iint_cache *iint, | |||
199 | struct inode *inode = file_inode(file); | 199 | struct inode *inode = file_inode(file); |
200 | const char *filename = file->f_path.dentry->d_name.name; | 200 | const char *filename = file->f_path.dentry->d_name.name; |
201 | int result = 0; | 201 | int result = 0; |
202 | int length; | ||
203 | void *tmpbuf; | ||
204 | u64 i_version; | ||
202 | struct { | 205 | struct { |
203 | struct ima_digest_data hdr; | 206 | struct ima_digest_data hdr; |
204 | char digest[IMA_MAX_DIGEST_SIZE]; | 207 | char digest[IMA_MAX_DIGEST_SIZE]; |
205 | } hash; | 208 | } hash; |
206 | 209 | ||
207 | if (!(iint->flags & IMA_COLLECTED)) { | 210 | if (iint->flags & IMA_COLLECTED) |
208 | u64 i_version = file_inode(file)->i_version; | 211 | goto out; |
209 | 212 | ||
210 | if (file->f_flags & O_DIRECT) { | 213 | /* |
211 | audit_cause = "failed(directio)"; | 214 | * Dectecting file change is based on i_version. On filesystems |
212 | result = -EACCES; | 215 | * which do not support i_version, support is limited to an initial |
213 | goto out; | 216 | * measurement/appraisal/audit. |
214 | } | 217 | */ |
218 | i_version = file_inode(file)->i_version; | ||
219 | hash.hdr.algo = algo; | ||
215 | 220 | ||
216 | hash.hdr.algo = algo; | 221 | /* Initialize hash digest to 0's in case of failure */ |
217 | 222 | memset(&hash.digest, 0, sizeof(hash.digest)); | |
218 | result = (!buf) ? ima_calc_file_hash(file, &hash.hdr) : | 223 | |
219 | ima_calc_buffer_hash(buf, size, &hash.hdr); | 224 | if (buf) |
220 | if (!result) { | 225 | result = ima_calc_buffer_hash(buf, size, &hash.hdr); |
221 | int length = sizeof(hash.hdr) + hash.hdr.length; | 226 | else |
222 | void *tmpbuf = krealloc(iint->ima_hash, length, | 227 | result = ima_calc_file_hash(file, &hash.hdr); |
223 | GFP_NOFS); | 228 | |
224 | if (tmpbuf) { | 229 | if (result && result != -EBADF && result != -EINVAL) |
225 | iint->ima_hash = tmpbuf; | 230 | goto out; |
226 | memcpy(iint->ima_hash, &hash, length); | 231 | |
227 | iint->version = i_version; | 232 | length = sizeof(hash.hdr) + hash.hdr.length; |
228 | iint->flags |= IMA_COLLECTED; | 233 | tmpbuf = krealloc(iint->ima_hash, length, GFP_NOFS); |
229 | } else | 234 | if (!tmpbuf) { |
230 | result = -ENOMEM; | 235 | result = -ENOMEM; |
231 | } | 236 | goto out; |
232 | } | 237 | } |
238 | |||
239 | iint->ima_hash = tmpbuf; | ||
240 | memcpy(iint->ima_hash, &hash, length); | ||
241 | iint->version = i_version; | ||
242 | |||
243 | /* Possibly temporary failure due to type of read (eg. O_DIRECT) */ | ||
244 | if (!result) | ||
245 | iint->flags |= IMA_COLLECTED; | ||
233 | out: | 246 | out: |
234 | if (result) | 247 | if (result) { |
248 | if (file->f_flags & O_DIRECT) | ||
249 | audit_cause = "failed(directio)"; | ||
250 | |||
235 | integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, | 251 | integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, |
236 | filename, "collect_data", audit_cause, | 252 | filename, "collect_data", audit_cause, |
237 | result, 0); | 253 | result, 0); |
254 | } | ||
238 | return result; | 255 | return result; |
239 | } | 256 | } |
240 | 257 | ||
@@ -278,7 +295,7 @@ void ima_store_measurement(struct integrity_iint_cache *iint, | |||
278 | } | 295 | } |
279 | 296 | ||
280 | result = ima_store_template(entry, violation, inode, filename, pcr); | 297 | result = ima_store_template(entry, violation, inode, filename, pcr); |
281 | if (!result || result == -EEXIST) { | 298 | if ((!result || result == -EEXIST) && !(file->f_flags & O_DIRECT)) { |
282 | iint->flags |= IMA_MEASURED; | 299 | iint->flags |= IMA_MEASURED; |
283 | iint->measured_pcrs |= (0x1 << pcr); | 300 | iint->measured_pcrs |= (0x1 << pcr); |
284 | } | 301 | } |
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c index 809ba70fbbbf..65fbcf3c32c7 100644 --- a/security/integrity/ima/ima_appraise.c +++ b/security/integrity/ima/ima_appraise.c | |||
@@ -40,7 +40,7 @@ __setup("ima_appraise=", default_appraise_setup); | |||
40 | */ | 40 | */ |
41 | bool is_ima_appraise_enabled(void) | 41 | bool is_ima_appraise_enabled(void) |
42 | { | 42 | { |
43 | return (ima_appraise & IMA_APPRAISE_ENFORCE) ? 1 : 0; | 43 | return ima_appraise & IMA_APPRAISE_ENFORCE; |
44 | } | 44 | } |
45 | 45 | ||
46 | /* | 46 | /* |
@@ -320,6 +320,9 @@ void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file) | |||
320 | if (iint->flags & IMA_DIGSIG) | 320 | if (iint->flags & IMA_DIGSIG) |
321 | return; | 321 | return; |
322 | 322 | ||
323 | if (iint->ima_file_status != INTEGRITY_PASS) | ||
324 | return; | ||
325 | |||
323 | rc = ima_collect_measurement(iint, file, NULL, 0, ima_hash_algo); | 326 | rc = ima_collect_measurement(iint, file, NULL, 0, ima_hash_algo); |
324 | if (rc < 0) | 327 | if (rc < 0) |
325 | return; | 328 | return; |
@@ -405,7 +408,7 @@ int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name, | |||
405 | if (!xattr_value_len || (xvalue->type >= IMA_XATTR_LAST)) | 408 | if (!xattr_value_len || (xvalue->type >= IMA_XATTR_LAST)) |
406 | return -EINVAL; | 409 | return -EINVAL; |
407 | ima_reset_appraise_flags(d_backing_inode(dentry), | 410 | ima_reset_appraise_flags(d_backing_inode(dentry), |
408 | (xvalue->type == EVM_IMA_XATTR_DIGSIG) ? 1 : 0); | 411 | xvalue->type == EVM_IMA_XATTR_DIGSIG); |
409 | result = 0; | 412 | result = 0; |
410 | } | 413 | } |
411 | return result; | 414 | return result; |
diff --git a/security/integrity/ima/ima_crypto.c b/security/integrity/ima/ima_crypto.c index 802d5d20f36f..9057b163c378 100644 --- a/security/integrity/ima/ima_crypto.c +++ b/security/integrity/ima/ima_crypto.c | |||
@@ -27,11 +27,6 @@ | |||
27 | 27 | ||
28 | #include "ima.h" | 28 | #include "ima.h" |
29 | 29 | ||
30 | struct ahash_completion { | ||
31 | struct completion completion; | ||
32 | int err; | ||
33 | }; | ||
34 | |||
35 | /* minimum file size for ahash use */ | 30 | /* minimum file size for ahash use */ |
36 | static unsigned long ima_ahash_minsize; | 31 | static unsigned long ima_ahash_minsize; |
37 | module_param_named(ahash_minsize, ima_ahash_minsize, ulong, 0644); | 32 | module_param_named(ahash_minsize, ima_ahash_minsize, ulong, 0644); |
@@ -196,30 +191,13 @@ static void ima_free_atfm(struct crypto_ahash *tfm) | |||
196 | crypto_free_ahash(tfm); | 191 | crypto_free_ahash(tfm); |
197 | } | 192 | } |
198 | 193 | ||
199 | static void ahash_complete(struct crypto_async_request *req, int err) | 194 | static inline int ahash_wait(int err, struct crypto_wait *wait) |
200 | { | 195 | { |
201 | struct ahash_completion *res = req->data; | ||
202 | 196 | ||
203 | if (err == -EINPROGRESS) | 197 | err = crypto_wait_req(err, wait); |
204 | return; | ||
205 | res->err = err; | ||
206 | complete(&res->completion); | ||
207 | } | ||
208 | 198 | ||
209 | static int ahash_wait(int err, struct ahash_completion *res) | 199 | if (err) |
210 | { | ||
211 | switch (err) { | ||
212 | case 0: | ||
213 | break; | ||
214 | case -EINPROGRESS: | ||
215 | case -EBUSY: | ||
216 | wait_for_completion(&res->completion); | ||
217 | reinit_completion(&res->completion); | ||
218 | err = res->err; | ||
219 | /* fall through */ | ||
220 | default: | ||
221 | pr_crit_ratelimited("ahash calculation failed: err: %d\n", err); | 200 | pr_crit_ratelimited("ahash calculation failed: err: %d\n", err); |
222 | } | ||
223 | 201 | ||
224 | return err; | 202 | return err; |
225 | } | 203 | } |
@@ -233,7 +211,7 @@ static int ima_calc_file_hash_atfm(struct file *file, | |||
233 | int rc, read = 0, rbuf_len, active = 0, ahash_rc = 0; | 211 | int rc, read = 0, rbuf_len, active = 0, ahash_rc = 0; |
234 | struct ahash_request *req; | 212 | struct ahash_request *req; |
235 | struct scatterlist sg[1]; | 213 | struct scatterlist sg[1]; |
236 | struct ahash_completion res; | 214 | struct crypto_wait wait; |
237 | size_t rbuf_size[2]; | 215 | size_t rbuf_size[2]; |
238 | 216 | ||
239 | hash->length = crypto_ahash_digestsize(tfm); | 217 | hash->length = crypto_ahash_digestsize(tfm); |
@@ -242,12 +220,12 @@ static int ima_calc_file_hash_atfm(struct file *file, | |||
242 | if (!req) | 220 | if (!req) |
243 | return -ENOMEM; | 221 | return -ENOMEM; |
244 | 222 | ||
245 | init_completion(&res.completion); | 223 | crypto_init_wait(&wait); |
246 | ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | | 224 | ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | |
247 | CRYPTO_TFM_REQ_MAY_SLEEP, | 225 | CRYPTO_TFM_REQ_MAY_SLEEP, |
248 | ahash_complete, &res); | 226 | crypto_req_done, &wait); |
249 | 227 | ||
250 | rc = ahash_wait(crypto_ahash_init(req), &res); | 228 | rc = ahash_wait(crypto_ahash_init(req), &wait); |
251 | if (rc) | 229 | if (rc) |
252 | goto out1; | 230 | goto out1; |
253 | 231 | ||
@@ -288,7 +266,7 @@ static int ima_calc_file_hash_atfm(struct file *file, | |||
288 | * read/request, wait for the completion of the | 266 | * read/request, wait for the completion of the |
289 | * previous ahash_update() request. | 267 | * previous ahash_update() request. |
290 | */ | 268 | */ |
291 | rc = ahash_wait(ahash_rc, &res); | 269 | rc = ahash_wait(ahash_rc, &wait); |
292 | if (rc) | 270 | if (rc) |
293 | goto out3; | 271 | goto out3; |
294 | } | 272 | } |
@@ -304,7 +282,7 @@ static int ima_calc_file_hash_atfm(struct file *file, | |||
304 | * read/request, wait for the completion of the | 282 | * read/request, wait for the completion of the |
305 | * previous ahash_update() request. | 283 | * previous ahash_update() request. |
306 | */ | 284 | */ |
307 | rc = ahash_wait(ahash_rc, &res); | 285 | rc = ahash_wait(ahash_rc, &wait); |
308 | if (rc) | 286 | if (rc) |
309 | goto out3; | 287 | goto out3; |
310 | } | 288 | } |
@@ -318,7 +296,7 @@ static int ima_calc_file_hash_atfm(struct file *file, | |||
318 | active = !active; /* swap buffers, if we use two */ | 296 | active = !active; /* swap buffers, if we use two */ |
319 | } | 297 | } |
320 | /* wait for the last update request to complete */ | 298 | /* wait for the last update request to complete */ |
321 | rc = ahash_wait(ahash_rc, &res); | 299 | rc = ahash_wait(ahash_rc, &wait); |
322 | out3: | 300 | out3: |
323 | if (read) | 301 | if (read) |
324 | file->f_mode &= ~FMODE_READ; | 302 | file->f_mode &= ~FMODE_READ; |
@@ -327,7 +305,7 @@ out3: | |||
327 | out2: | 305 | out2: |
328 | if (!rc) { | 306 | if (!rc) { |
329 | ahash_request_set_crypt(req, NULL, hash->digest, 0); | 307 | ahash_request_set_crypt(req, NULL, hash->digest, 0); |
330 | rc = ahash_wait(crypto_ahash_final(req), &res); | 308 | rc = ahash_wait(crypto_ahash_final(req), &wait); |
331 | } | 309 | } |
332 | out1: | 310 | out1: |
333 | ahash_request_free(req); | 311 | ahash_request_free(req); |
@@ -441,6 +419,16 @@ int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash) | |||
441 | loff_t i_size; | 419 | loff_t i_size; |
442 | int rc; | 420 | int rc; |
443 | 421 | ||
422 | /* | ||
423 | * For consistency, fail file's opened with the O_DIRECT flag on | ||
424 | * filesystems mounted with/without DAX option. | ||
425 | */ | ||
426 | if (file->f_flags & O_DIRECT) { | ||
427 | hash->length = hash_digest_size[ima_hash_algo]; | ||
428 | hash->algo = ima_hash_algo; | ||
429 | return -EINVAL; | ||
430 | } | ||
431 | |||
444 | i_size = i_size_read(file_inode(file)); | 432 | i_size = i_size_read(file_inode(file)); |
445 | 433 | ||
446 | if (ima_ahash_minsize && i_size >= ima_ahash_minsize) { | 434 | if (ima_ahash_minsize && i_size >= ima_ahash_minsize) { |
@@ -527,7 +515,7 @@ static int calc_buffer_ahash_atfm(const void *buf, loff_t len, | |||
527 | { | 515 | { |
528 | struct ahash_request *req; | 516 | struct ahash_request *req; |
529 | struct scatterlist sg; | 517 | struct scatterlist sg; |
530 | struct ahash_completion res; | 518 | struct crypto_wait wait; |
531 | int rc, ahash_rc = 0; | 519 | int rc, ahash_rc = 0; |
532 | 520 | ||
533 | hash->length = crypto_ahash_digestsize(tfm); | 521 | hash->length = crypto_ahash_digestsize(tfm); |
@@ -536,12 +524,12 @@ static int calc_buffer_ahash_atfm(const void *buf, loff_t len, | |||
536 | if (!req) | 524 | if (!req) |
537 | return -ENOMEM; | 525 | return -ENOMEM; |
538 | 526 | ||
539 | init_completion(&res.completion); | 527 | crypto_init_wait(&wait); |
540 | ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | | 528 | ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG | |
541 | CRYPTO_TFM_REQ_MAY_SLEEP, | 529 | CRYPTO_TFM_REQ_MAY_SLEEP, |
542 | ahash_complete, &res); | 530 | crypto_req_done, &wait); |
543 | 531 | ||
544 | rc = ahash_wait(crypto_ahash_init(req), &res); | 532 | rc = ahash_wait(crypto_ahash_init(req), &wait); |
545 | if (rc) | 533 | if (rc) |
546 | goto out; | 534 | goto out; |
547 | 535 | ||
@@ -551,10 +539,10 @@ static int calc_buffer_ahash_atfm(const void *buf, loff_t len, | |||
551 | ahash_rc = crypto_ahash_update(req); | 539 | ahash_rc = crypto_ahash_update(req); |
552 | 540 | ||
553 | /* wait for the update request to complete */ | 541 | /* wait for the update request to complete */ |
554 | rc = ahash_wait(ahash_rc, &res); | 542 | rc = ahash_wait(ahash_rc, &wait); |
555 | if (!rc) { | 543 | if (!rc) { |
556 | ahash_request_set_crypt(req, NULL, hash->digest, 0); | 544 | ahash_request_set_crypt(req, NULL, hash->digest, 0); |
557 | rc = ahash_wait(crypto_ahash_final(req), &res); | 545 | rc = ahash_wait(crypto_ahash_final(req), &wait); |
558 | } | 546 | } |
559 | out: | 547 | out: |
560 | ahash_request_free(req); | 548 | ahash_request_free(req); |
diff --git a/security/integrity/ima/ima_fs.c b/security/integrity/ima/ima_fs.c index ad491c51e833..fa540c0469da 100644 --- a/security/integrity/ima/ima_fs.c +++ b/security/integrity/ima/ima_fs.c | |||
@@ -32,7 +32,7 @@ bool ima_canonical_fmt; | |||
32 | static int __init default_canonical_fmt_setup(char *str) | 32 | static int __init default_canonical_fmt_setup(char *str) |
33 | { | 33 | { |
34 | #ifdef __BIG_ENDIAN | 34 | #ifdef __BIG_ENDIAN |
35 | ima_canonical_fmt = 1; | 35 | ima_canonical_fmt = true; |
36 | #endif | 36 | #endif |
37 | return 1; | 37 | return 1; |
38 | } | 38 | } |
@@ -429,10 +429,10 @@ static int ima_release_policy(struct inode *inode, struct file *file) | |||
429 | } | 429 | } |
430 | 430 | ||
431 | ima_update_policy(); | 431 | ima_update_policy(); |
432 | #ifndef CONFIG_IMA_WRITE_POLICY | 432 | #if !defined(CONFIG_IMA_WRITE_POLICY) && !defined(CONFIG_IMA_READ_POLICY) |
433 | securityfs_remove(ima_policy); | 433 | securityfs_remove(ima_policy); |
434 | ima_policy = NULL; | 434 | ima_policy = NULL; |
435 | #else | 435 | #elif defined(CONFIG_IMA_WRITE_POLICY) |
436 | clear_bit(IMA_FS_BUSY, &ima_fs_flags); | 436 | clear_bit(IMA_FS_BUSY, &ima_fs_flags); |
437 | #endif | 437 | #endif |
438 | return 0; | 438 | return 0; |
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 2aebb7984437..770654694efc 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c | |||
@@ -51,6 +51,8 @@ static int __init hash_setup(char *str) | |||
51 | ima_hash_algo = HASH_ALGO_SHA1; | 51 | ima_hash_algo = HASH_ALGO_SHA1; |
52 | else if (strncmp(str, "md5", 3) == 0) | 52 | else if (strncmp(str, "md5", 3) == 0) |
53 | ima_hash_algo = HASH_ALGO_MD5; | 53 | ima_hash_algo = HASH_ALGO_MD5; |
54 | else | ||
55 | return 1; | ||
54 | goto out; | 56 | goto out; |
55 | } | 57 | } |
56 | 58 | ||
@@ -60,6 +62,8 @@ static int __init hash_setup(char *str) | |||
60 | break; | 62 | break; |
61 | } | 63 | } |
62 | } | 64 | } |
65 | if (i == HASH_ALGO__LAST) | ||
66 | return 1; | ||
63 | out: | 67 | out: |
64 | hash_setup_done = 1; | 68 | hash_setup_done = 1; |
65 | return 1; | 69 | return 1; |
@@ -235,11 +239,8 @@ static int process_measurement(struct file *file, char *buf, loff_t size, | |||
235 | hash_algo = ima_get_hash_algo(xattr_value, xattr_len); | 239 | hash_algo = ima_get_hash_algo(xattr_value, xattr_len); |
236 | 240 | ||
237 | rc = ima_collect_measurement(iint, file, buf, size, hash_algo); | 241 | rc = ima_collect_measurement(iint, file, buf, size, hash_algo); |
238 | if (rc != 0) { | 242 | if (rc != 0 && rc != -EBADF && rc != -EINVAL) |
239 | if (file->f_flags & O_DIRECT) | ||
240 | rc = (iint->flags & IMA_PERMIT_DIRECTIO) ? 0 : -EACCES; | ||
241 | goto out_digsig; | 243 | goto out_digsig; |
242 | } | ||
243 | 244 | ||
244 | if (!pathbuf) /* ima_rdwr_violation possibly pre-fetched */ | 245 | if (!pathbuf) /* ima_rdwr_violation possibly pre-fetched */ |
245 | pathname = ima_d_path(&file->f_path, &pathbuf, filename); | 246 | pathname = ima_d_path(&file->f_path, &pathbuf, filename); |
@@ -247,12 +248,14 @@ static int process_measurement(struct file *file, char *buf, loff_t size, | |||
247 | if (action & IMA_MEASURE) | 248 | if (action & IMA_MEASURE) |
248 | ima_store_measurement(iint, file, pathname, | 249 | ima_store_measurement(iint, file, pathname, |
249 | xattr_value, xattr_len, pcr); | 250 | xattr_value, xattr_len, pcr); |
250 | if (action & IMA_APPRAISE_SUBMASK) | 251 | if (rc == 0 && (action & IMA_APPRAISE_SUBMASK)) |
251 | rc = ima_appraise_measurement(func, iint, file, pathname, | 252 | rc = ima_appraise_measurement(func, iint, file, pathname, |
252 | xattr_value, xattr_len, opened); | 253 | xattr_value, xattr_len, opened); |
253 | if (action & IMA_AUDIT) | 254 | if (action & IMA_AUDIT) |
254 | ima_audit_measurement(iint, pathname); | 255 | ima_audit_measurement(iint, pathname); |
255 | 256 | ||
257 | if ((file->f_flags & O_DIRECT) && (iint->flags & IMA_PERMIT_DIRECTIO)) | ||
258 | rc = 0; | ||
256 | out_digsig: | 259 | out_digsig: |
257 | if ((mask & MAY_WRITE) && (iint->flags & IMA_DIGSIG) && | 260 | if ((mask & MAY_WRITE) && (iint->flags & IMA_DIGSIG) && |
258 | !(iint->flags & IMA_NEW_FILE)) | 261 | !(iint->flags & IMA_NEW_FILE)) |
@@ -359,12 +362,12 @@ void ima_post_path_mknod(struct dentry *dentry) | |||
359 | */ | 362 | */ |
360 | int ima_read_file(struct file *file, enum kernel_read_file_id read_id) | 363 | int ima_read_file(struct file *file, enum kernel_read_file_id read_id) |
361 | { | 364 | { |
365 | bool sig_enforce = is_module_sig_enforced(); | ||
366 | |||
362 | if (!file && read_id == READING_MODULE) { | 367 | if (!file && read_id == READING_MODULE) { |
363 | #ifndef CONFIG_MODULE_SIG_FORCE | 368 | if (!sig_enforce && (ima_appraise & IMA_APPRAISE_MODULES) && |
364 | if ((ima_appraise & IMA_APPRAISE_MODULES) && | ||
365 | (ima_appraise & IMA_APPRAISE_ENFORCE)) | 369 | (ima_appraise & IMA_APPRAISE_ENFORCE)) |
366 | return -EACCES; /* INTEGRITY_UNKNOWN */ | 370 | return -EACCES; /* INTEGRITY_UNKNOWN */ |
367 | #endif | ||
368 | return 0; /* We rely on module signature checking */ | 371 | return 0; /* We rely on module signature checking */ |
369 | } | 372 | } |
370 | return 0; | 373 | return 0; |
@@ -406,6 +409,10 @@ int ima_post_read_file(struct file *file, void *buf, loff_t size, | |||
406 | if (!file && read_id == READING_MODULE) /* MODULE_SIG_FORCE enabled */ | 409 | if (!file && read_id == READING_MODULE) /* MODULE_SIG_FORCE enabled */ |
407 | return 0; | 410 | return 0; |
408 | 411 | ||
412 | /* permit signed certs */ | ||
413 | if (!file && read_id == READING_X509_CERTIFICATE) | ||
414 | return 0; | ||
415 | |||
409 | if (!file || !buf || size == 0) { /* should never happen */ | 416 | if (!file || !buf || size == 0) { /* should never happen */ |
410 | if (ima_appraise & IMA_APPRAISE_ENFORCE) | 417 | if (ima_appraise & IMA_APPRAISE_ENFORCE) |
411 | return -EACCES; | 418 | return -EACCES; |
diff --git a/security/integrity/ima/ima_policy.c b/security/integrity/ima/ima_policy.c index 95209a5f8595..ee4613fa5840 100644 --- a/security/integrity/ima/ima_policy.c +++ b/security/integrity/ima/ima_policy.c | |||
@@ -196,9 +196,9 @@ static int __init policy_setup(char *str) | |||
196 | if ((strcmp(p, "tcb") == 0) && !ima_policy) | 196 | if ((strcmp(p, "tcb") == 0) && !ima_policy) |
197 | ima_policy = DEFAULT_TCB; | 197 | ima_policy = DEFAULT_TCB; |
198 | else if (strcmp(p, "appraise_tcb") == 0) | 198 | else if (strcmp(p, "appraise_tcb") == 0) |
199 | ima_use_appraise_tcb = 1; | 199 | ima_use_appraise_tcb = true; |
200 | else if (strcmp(p, "secure_boot") == 0) | 200 | else if (strcmp(p, "secure_boot") == 0) |
201 | ima_use_secure_boot = 1; | 201 | ima_use_secure_boot = true; |
202 | } | 202 | } |
203 | 203 | ||
204 | return 1; | 204 | return 1; |
@@ -207,7 +207,7 @@ __setup("ima_policy=", policy_setup); | |||
207 | 207 | ||
208 | static int __init default_appraise_policy_setup(char *str) | 208 | static int __init default_appraise_policy_setup(char *str) |
209 | { | 209 | { |
210 | ima_use_appraise_tcb = 1; | 210 | ima_use_appraise_tcb = true; |
211 | return 1; | 211 | return 1; |
212 | } | 212 | } |
213 | __setup("ima_appraise_tcb", default_appraise_policy_setup); | 213 | __setup("ima_appraise_tcb", default_appraise_policy_setup); |
diff --git a/security/integrity/integrity.h b/security/integrity/integrity.h index a53e7e4ab06c..e1bf040fb110 100644 --- a/security/integrity/integrity.h +++ b/security/integrity/integrity.h | |||
@@ -120,8 +120,6 @@ struct integrity_iint_cache *integrity_iint_find(struct inode *inode); | |||
120 | int integrity_kernel_read(struct file *file, loff_t offset, | 120 | int integrity_kernel_read(struct file *file, loff_t offset, |
121 | void *addr, unsigned long count); | 121 | void *addr, unsigned long count); |
122 | 122 | ||
123 | int __init integrity_read_file(const char *path, char **data); | ||
124 | |||
125 | #define INTEGRITY_KEYRING_EVM 0 | 123 | #define INTEGRITY_KEYRING_EVM 0 |
126 | #define INTEGRITY_KEYRING_IMA 1 | 124 | #define INTEGRITY_KEYRING_IMA 1 |
127 | #define INTEGRITY_KEYRING_MODULE 2 | 125 | #define INTEGRITY_KEYRING_MODULE 2 |
diff --git a/security/keys/gc.c b/security/keys/gc.c index f01d48cb3de1..7207e6094dc1 100644 --- a/security/keys/gc.c +++ b/security/keys/gc.c | |||
@@ -29,10 +29,10 @@ DECLARE_WORK(key_gc_work, key_garbage_collector); | |||
29 | /* | 29 | /* |
30 | * Reaper for links from keyrings to dead keys. | 30 | * Reaper for links from keyrings to dead keys. |
31 | */ | 31 | */ |
32 | static void key_gc_timer_func(unsigned long); | 32 | static void key_gc_timer_func(struct timer_list *); |
33 | static DEFINE_TIMER(key_gc_timer, key_gc_timer_func, 0, 0); | 33 | static DEFINE_TIMER(key_gc_timer, key_gc_timer_func); |
34 | 34 | ||
35 | static time_t key_gc_next_run = LONG_MAX; | 35 | static time64_t key_gc_next_run = TIME64_MAX; |
36 | static struct key_type *key_gc_dead_keytype; | 36 | static struct key_type *key_gc_dead_keytype; |
37 | 37 | ||
38 | static unsigned long key_gc_flags; | 38 | static unsigned long key_gc_flags; |
@@ -53,12 +53,12 @@ struct key_type key_type_dead = { | |||
53 | * Schedule a garbage collection run. | 53 | * Schedule a garbage collection run. |
54 | * - time precision isn't particularly important | 54 | * - time precision isn't particularly important |
55 | */ | 55 | */ |
56 | void key_schedule_gc(time_t gc_at) | 56 | void key_schedule_gc(time64_t gc_at) |
57 | { | 57 | { |
58 | unsigned long expires; | 58 | unsigned long expires; |
59 | time_t now = current_kernel_time().tv_sec; | 59 | time64_t now = ktime_get_real_seconds(); |
60 | 60 | ||
61 | kenter("%ld", gc_at - now); | 61 | kenter("%lld", gc_at - now); |
62 | 62 | ||
63 | if (gc_at <= now || test_bit(KEY_GC_REAP_KEYTYPE, &key_gc_flags)) { | 63 | if (gc_at <= now || test_bit(KEY_GC_REAP_KEYTYPE, &key_gc_flags)) { |
64 | kdebug("IMMEDIATE"); | 64 | kdebug("IMMEDIATE"); |
@@ -84,10 +84,10 @@ void key_schedule_gc_links(void) | |||
84 | * Some key's cleanup time was met after it expired, so we need to get the | 84 | * Some key's cleanup time was met after it expired, so we need to get the |
85 | * reaper to go through a cycle finding expired keys. | 85 | * reaper to go through a cycle finding expired keys. |
86 | */ | 86 | */ |
87 | static void key_gc_timer_func(unsigned long data) | 87 | static void key_gc_timer_func(struct timer_list *unused) |
88 | { | 88 | { |
89 | kenter(""); | 89 | kenter(""); |
90 | key_gc_next_run = LONG_MAX; | 90 | key_gc_next_run = TIME64_MAX; |
91 | key_schedule_gc_links(); | 91 | key_schedule_gc_links(); |
92 | } | 92 | } |
93 | 93 | ||
@@ -184,11 +184,11 @@ static void key_garbage_collector(struct work_struct *work) | |||
184 | 184 | ||
185 | struct rb_node *cursor; | 185 | struct rb_node *cursor; |
186 | struct key *key; | 186 | struct key *key; |
187 | time_t new_timer, limit; | 187 | time64_t new_timer, limit; |
188 | 188 | ||
189 | kenter("[%lx,%x]", key_gc_flags, gc_state); | 189 | kenter("[%lx,%x]", key_gc_flags, gc_state); |
190 | 190 | ||
191 | limit = current_kernel_time().tv_sec; | 191 | limit = ktime_get_real_seconds(); |
192 | if (limit > key_gc_delay) | 192 | if (limit > key_gc_delay) |
193 | limit -= key_gc_delay; | 193 | limit -= key_gc_delay; |
194 | else | 194 | else |
@@ -204,7 +204,7 @@ static void key_garbage_collector(struct work_struct *work) | |||
204 | gc_state |= KEY_GC_REAPING_DEAD_1; | 204 | gc_state |= KEY_GC_REAPING_DEAD_1; |
205 | kdebug("new pass %x", gc_state); | 205 | kdebug("new pass %x", gc_state); |
206 | 206 | ||
207 | new_timer = LONG_MAX; | 207 | new_timer = TIME64_MAX; |
208 | 208 | ||
209 | /* As only this function is permitted to remove things from the key | 209 | /* As only this function is permitted to remove things from the key |
210 | * serial tree, if cursor is non-NULL then it will always point to a | 210 | * serial tree, if cursor is non-NULL then it will always point to a |
@@ -235,7 +235,7 @@ continue_scanning: | |||
235 | 235 | ||
236 | if (gc_state & KEY_GC_SET_TIMER) { | 236 | if (gc_state & KEY_GC_SET_TIMER) { |
237 | if (key->expiry > limit && key->expiry < new_timer) { | 237 | if (key->expiry > limit && key->expiry < new_timer) { |
238 | kdebug("will expire %x in %ld", | 238 | kdebug("will expire %x in %lld", |
239 | key_serial(key), key->expiry - limit); | 239 | key_serial(key), key->expiry - limit); |
240 | new_timer = key->expiry; | 240 | new_timer = key->expiry; |
241 | } | 241 | } |
@@ -276,7 +276,7 @@ maybe_resched: | |||
276 | */ | 276 | */ |
277 | kdebug("pass complete"); | 277 | kdebug("pass complete"); |
278 | 278 | ||
279 | if (gc_state & KEY_GC_SET_TIMER && new_timer != (time_t)LONG_MAX) { | 279 | if (gc_state & KEY_GC_SET_TIMER && new_timer != (time64_t)TIME64_MAX) { |
280 | new_timer += key_gc_delay; | 280 | new_timer += key_gc_delay; |
281 | key_schedule_gc(new_timer); | 281 | key_schedule_gc(new_timer); |
282 | } | 282 | } |
diff --git a/security/keys/internal.h b/security/keys/internal.h index 503adbae7b0d..9f8208dc0e55 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h | |||
@@ -130,7 +130,7 @@ struct keyring_search_context { | |||
130 | int skipped_ret; | 130 | int skipped_ret; |
131 | bool possessed; | 131 | bool possessed; |
132 | key_ref_t result; | 132 | key_ref_t result; |
133 | struct timespec now; | 133 | time64_t now; |
134 | }; | 134 | }; |
135 | 135 | ||
136 | extern bool key_default_cmp(const struct key *key, | 136 | extern bool key_default_cmp(const struct key *key, |
@@ -169,10 +169,10 @@ extern void key_change_session_keyring(struct callback_head *twork); | |||
169 | 169 | ||
170 | extern struct work_struct key_gc_work; | 170 | extern struct work_struct key_gc_work; |
171 | extern unsigned key_gc_delay; | 171 | extern unsigned key_gc_delay; |
172 | extern void keyring_gc(struct key *keyring, time_t limit); | 172 | extern void keyring_gc(struct key *keyring, time64_t limit); |
173 | extern void keyring_restriction_gc(struct key *keyring, | 173 | extern void keyring_restriction_gc(struct key *keyring, |
174 | struct key_type *dead_type); | 174 | struct key_type *dead_type); |
175 | extern void key_schedule_gc(time_t gc_at); | 175 | extern void key_schedule_gc(time64_t gc_at); |
176 | extern void key_schedule_gc_links(void); | 176 | extern void key_schedule_gc_links(void); |
177 | extern void key_gc_keytype(struct key_type *ktype); | 177 | extern void key_gc_keytype(struct key_type *ktype); |
178 | 178 | ||
@@ -211,7 +211,7 @@ extern struct key *key_get_instantiation_authkey(key_serial_t target_id); | |||
211 | /* | 211 | /* |
212 | * Determine whether a key is dead. | 212 | * Determine whether a key is dead. |
213 | */ | 213 | */ |
214 | static inline bool key_is_dead(const struct key *key, time_t limit) | 214 | static inline bool key_is_dead(const struct key *key, time64_t limit) |
215 | { | 215 | { |
216 | return | 216 | return |
217 | key->flags & ((1 << KEY_FLAG_DEAD) | | 217 | key->flags & ((1 << KEY_FLAG_DEAD) | |
diff --git a/security/keys/key.c b/security/keys/key.c index 83bf4b4afd49..d97c9394b5dd 100644 --- a/security/keys/key.c +++ b/security/keys/key.c | |||
@@ -460,7 +460,7 @@ static int __key_instantiate_and_link(struct key *key, | |||
460 | if (authkey) | 460 | if (authkey) |
461 | key_revoke(authkey); | 461 | key_revoke(authkey); |
462 | 462 | ||
463 | if (prep->expiry != TIME_T_MAX) { | 463 | if (prep->expiry != TIME64_MAX) { |
464 | key->expiry = prep->expiry; | 464 | key->expiry = prep->expiry; |
465 | key_schedule_gc(prep->expiry + key_gc_delay); | 465 | key_schedule_gc(prep->expiry + key_gc_delay); |
466 | } | 466 | } |
@@ -506,7 +506,7 @@ int key_instantiate_and_link(struct key *key, | |||
506 | prep.data = data; | 506 | prep.data = data; |
507 | prep.datalen = datalen; | 507 | prep.datalen = datalen; |
508 | prep.quotalen = key->type->def_datalen; | 508 | prep.quotalen = key->type->def_datalen; |
509 | prep.expiry = TIME_T_MAX; | 509 | prep.expiry = TIME64_MAX; |
510 | if (key->type->preparse) { | 510 | if (key->type->preparse) { |
511 | ret = key->type->preparse(&prep); | 511 | ret = key->type->preparse(&prep); |
512 | if (ret < 0) | 512 | if (ret < 0) |
@@ -570,7 +570,6 @@ int key_reject_and_link(struct key *key, | |||
570 | struct key *authkey) | 570 | struct key *authkey) |
571 | { | 571 | { |
572 | struct assoc_array_edit *edit; | 572 | struct assoc_array_edit *edit; |
573 | struct timespec now; | ||
574 | int ret, awaken, link_ret = 0; | 573 | int ret, awaken, link_ret = 0; |
575 | 574 | ||
576 | key_check(key); | 575 | key_check(key); |
@@ -593,8 +592,7 @@ int key_reject_and_link(struct key *key, | |||
593 | /* mark the key as being negatively instantiated */ | 592 | /* mark the key as being negatively instantiated */ |
594 | atomic_inc(&key->user->nikeys); | 593 | atomic_inc(&key->user->nikeys); |
595 | mark_key_instantiated(key, -error); | 594 | mark_key_instantiated(key, -error); |
596 | now = current_kernel_time(); | 595 | key->expiry = ktime_get_real_seconds() + timeout; |
597 | key->expiry = now.tv_sec + timeout; | ||
598 | key_schedule_gc(key->expiry + key_gc_delay); | 596 | key_schedule_gc(key->expiry + key_gc_delay); |
599 | 597 | ||
600 | if (test_and_clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags)) | 598 | if (test_and_clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags)) |
@@ -710,16 +708,13 @@ found_kernel_type: | |||
710 | 708 | ||
711 | void key_set_timeout(struct key *key, unsigned timeout) | 709 | void key_set_timeout(struct key *key, unsigned timeout) |
712 | { | 710 | { |
713 | struct timespec now; | 711 | time64_t expiry = 0; |
714 | time_t expiry = 0; | ||
715 | 712 | ||
716 | /* make the changes with the locks held to prevent races */ | 713 | /* make the changes with the locks held to prevent races */ |
717 | down_write(&key->sem); | 714 | down_write(&key->sem); |
718 | 715 | ||
719 | if (timeout > 0) { | 716 | if (timeout > 0) |
720 | now = current_kernel_time(); | 717 | expiry = ktime_get_real_seconds() + timeout; |
721 | expiry = now.tv_sec + timeout; | ||
722 | } | ||
723 | 718 | ||
724 | key->expiry = expiry; | 719 | key->expiry = expiry; |
725 | key_schedule_gc(key->expiry + key_gc_delay); | 720 | key_schedule_gc(key->expiry + key_gc_delay); |
@@ -838,7 +833,6 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, | |||
838 | 833 | ||
839 | key_check(keyring); | 834 | key_check(keyring); |
840 | 835 | ||
841 | key_ref = ERR_PTR(-EPERM); | ||
842 | if (!(flags & KEY_ALLOC_BYPASS_RESTRICTION)) | 836 | if (!(flags & KEY_ALLOC_BYPASS_RESTRICTION)) |
843 | restrict_link = keyring->restrict_link; | 837 | restrict_link = keyring->restrict_link; |
844 | 838 | ||
@@ -850,7 +844,7 @@ key_ref_t key_create_or_update(key_ref_t keyring_ref, | |||
850 | prep.data = payload; | 844 | prep.data = payload; |
851 | prep.datalen = plen; | 845 | prep.datalen = plen; |
852 | prep.quotalen = index_key.type->def_datalen; | 846 | prep.quotalen = index_key.type->def_datalen; |
853 | prep.expiry = TIME_T_MAX; | 847 | prep.expiry = TIME64_MAX; |
854 | if (index_key.type->preparse) { | 848 | if (index_key.type->preparse) { |
855 | ret = index_key.type->preparse(&prep); | 849 | ret = index_key.type->preparse(&prep); |
856 | if (ret < 0) { | 850 | if (ret < 0) { |
@@ -994,7 +988,7 @@ int key_update(key_ref_t key_ref, const void *payload, size_t plen) | |||
994 | prep.data = payload; | 988 | prep.data = payload; |
995 | prep.datalen = plen; | 989 | prep.datalen = plen; |
996 | prep.quotalen = key->type->def_datalen; | 990 | prep.quotalen = key->type->def_datalen; |
997 | prep.expiry = TIME_T_MAX; | 991 | prep.expiry = TIME64_MAX; |
998 | if (key->type->preparse) { | 992 | if (key->type->preparse) { |
999 | ret = key->type->preparse(&prep); | 993 | ret = key->type->preparse(&prep); |
1000 | if (ret < 0) | 994 | if (ret < 0) |
@@ -1028,8 +1022,7 @@ EXPORT_SYMBOL(key_update); | |||
1028 | */ | 1022 | */ |
1029 | void key_revoke(struct key *key) | 1023 | void key_revoke(struct key *key) |
1030 | { | 1024 | { |
1031 | struct timespec now; | 1025 | time64_t time; |
1032 | time_t time; | ||
1033 | 1026 | ||
1034 | key_check(key); | 1027 | key_check(key); |
1035 | 1028 | ||
@@ -1044,8 +1037,7 @@ void key_revoke(struct key *key) | |||
1044 | key->type->revoke(key); | 1037 | key->type->revoke(key); |
1045 | 1038 | ||
1046 | /* set the death time to no more than the expiry time */ | 1039 | /* set the death time to no more than the expiry time */ |
1047 | now = current_kernel_time(); | 1040 | time = ktime_get_real_seconds(); |
1048 | time = now.tv_sec; | ||
1049 | if (key->revoked_at == 0 || key->revoked_at > time) { | 1041 | if (key->revoked_at == 0 || key->revoked_at > time) { |
1050 | key->revoked_at = time; | 1042 | key->revoked_at = time; |
1051 | key_schedule_gc(key->revoked_at + key_gc_delay); | 1043 | key_schedule_gc(key->revoked_at + key_gc_delay); |
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index 76d22f726ae4..1ffe60bb2845 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c | |||
@@ -1588,9 +1588,8 @@ error_keyring: | |||
1588 | * The caller must have Setattr permission to change keyring restrictions. | 1588 | * The caller must have Setattr permission to change keyring restrictions. |
1589 | * | 1589 | * |
1590 | * The requested type name may be a NULL pointer to reject all attempts | 1590 | * The requested type name may be a NULL pointer to reject all attempts |
1591 | * to link to the keyring. If _type is non-NULL, _restriction can be | 1591 | * to link to the keyring. In this case, _restriction must also be NULL. |
1592 | * NULL or a pointer to a string describing the restriction. If _type is | 1592 | * Otherwise, both _type and _restriction must be non-NULL. |
1593 | * NULL, _restriction must also be NULL. | ||
1594 | * | 1593 | * |
1595 | * Returns 0 if successful. | 1594 | * Returns 0 if successful. |
1596 | */ | 1595 | */ |
@@ -1598,7 +1597,6 @@ long keyctl_restrict_keyring(key_serial_t id, const char __user *_type, | |||
1598 | const char __user *_restriction) | 1597 | const char __user *_restriction) |
1599 | { | 1598 | { |
1600 | key_ref_t key_ref; | 1599 | key_ref_t key_ref; |
1601 | bool link_reject = !_type; | ||
1602 | char type[32]; | 1600 | char type[32]; |
1603 | char *restriction = NULL; | 1601 | char *restriction = NULL; |
1604 | long ret; | 1602 | long ret; |
@@ -1607,31 +1605,29 @@ long keyctl_restrict_keyring(key_serial_t id, const char __user *_type, | |||
1607 | if (IS_ERR(key_ref)) | 1605 | if (IS_ERR(key_ref)) |
1608 | return PTR_ERR(key_ref); | 1606 | return PTR_ERR(key_ref); |
1609 | 1607 | ||
1608 | ret = -EINVAL; | ||
1610 | if (_type) { | 1609 | if (_type) { |
1611 | ret = key_get_type_from_user(type, _type, sizeof(type)); | 1610 | if (!_restriction) |
1612 | if (ret < 0) | ||
1613 | goto error; | 1611 | goto error; |
1614 | } | ||
1615 | 1612 | ||
1616 | if (_restriction) { | 1613 | ret = key_get_type_from_user(type, _type, sizeof(type)); |
1617 | if (!_type) { | 1614 | if (ret < 0) |
1618 | ret = -EINVAL; | ||
1619 | goto error; | 1615 | goto error; |
1620 | } | ||
1621 | 1616 | ||
1622 | restriction = strndup_user(_restriction, PAGE_SIZE); | 1617 | restriction = strndup_user(_restriction, PAGE_SIZE); |
1623 | if (IS_ERR(restriction)) { | 1618 | if (IS_ERR(restriction)) { |
1624 | ret = PTR_ERR(restriction); | 1619 | ret = PTR_ERR(restriction); |
1625 | goto error; | 1620 | goto error; |
1626 | } | 1621 | } |
1622 | } else { | ||
1623 | if (_restriction) | ||
1624 | goto error; | ||
1627 | } | 1625 | } |
1628 | 1626 | ||
1629 | ret = keyring_restrict(key_ref, link_reject ? NULL : type, restriction); | 1627 | ret = keyring_restrict(key_ref, _type ? type : NULL, restriction); |
1630 | kfree(restriction); | 1628 | kfree(restriction); |
1631 | |||
1632 | error: | 1629 | error: |
1633 | key_ref_put(key_ref); | 1630 | key_ref_put(key_ref); |
1634 | |||
1635 | return ret; | 1631 | return ret; |
1636 | } | 1632 | } |
1637 | 1633 | ||
diff --git a/security/keys/keyring.c b/security/keys/keyring.c index 36f842ec87f0..d0bccebbd3b5 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c | |||
@@ -565,7 +565,7 @@ static int keyring_search_iterator(const void *object, void *iterator_data) | |||
565 | 565 | ||
566 | /* skip invalidated, revoked and expired keys */ | 566 | /* skip invalidated, revoked and expired keys */ |
567 | if (ctx->flags & KEYRING_SEARCH_DO_STATE_CHECK) { | 567 | if (ctx->flags & KEYRING_SEARCH_DO_STATE_CHECK) { |
568 | time_t expiry = READ_ONCE(key->expiry); | 568 | time64_t expiry = READ_ONCE(key->expiry); |
569 | 569 | ||
570 | if (kflags & ((1 << KEY_FLAG_INVALIDATED) | | 570 | if (kflags & ((1 << KEY_FLAG_INVALIDATED) | |
571 | (1 << KEY_FLAG_REVOKED))) { | 571 | (1 << KEY_FLAG_REVOKED))) { |
@@ -574,7 +574,7 @@ static int keyring_search_iterator(const void *object, void *iterator_data) | |||
574 | goto skipped; | 574 | goto skipped; |
575 | } | 575 | } |
576 | 576 | ||
577 | if (expiry && ctx->now.tv_sec >= expiry) { | 577 | if (expiry && ctx->now >= expiry) { |
578 | if (!(ctx->flags & KEYRING_SEARCH_SKIP_EXPIRED)) | 578 | if (!(ctx->flags & KEYRING_SEARCH_SKIP_EXPIRED)) |
579 | ctx->result = ERR_PTR(-EKEYEXPIRED); | 579 | ctx->result = ERR_PTR(-EKEYEXPIRED); |
580 | kleave(" = %d [expire]", ctx->skipped_ret); | 580 | kleave(" = %d [expire]", ctx->skipped_ret); |
@@ -834,10 +834,10 @@ found: | |||
834 | key = key_ref_to_ptr(ctx->result); | 834 | key = key_ref_to_ptr(ctx->result); |
835 | key_check(key); | 835 | key_check(key); |
836 | if (!(ctx->flags & KEYRING_SEARCH_NO_UPDATE_TIME)) { | 836 | if (!(ctx->flags & KEYRING_SEARCH_NO_UPDATE_TIME)) { |
837 | key->last_used_at = ctx->now.tv_sec; | 837 | key->last_used_at = ctx->now; |
838 | keyring->last_used_at = ctx->now.tv_sec; | 838 | keyring->last_used_at = ctx->now; |
839 | while (sp > 0) | 839 | while (sp > 0) |
840 | stack[--sp].keyring->last_used_at = ctx->now.tv_sec; | 840 | stack[--sp].keyring->last_used_at = ctx->now; |
841 | } | 841 | } |
842 | kleave(" = true"); | 842 | kleave(" = true"); |
843 | return true; | 843 | return true; |
@@ -898,7 +898,7 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref, | |||
898 | } | 898 | } |
899 | 899 | ||
900 | rcu_read_lock(); | 900 | rcu_read_lock(); |
901 | ctx->now = current_kernel_time(); | 901 | ctx->now = ktime_get_real_seconds(); |
902 | if (search_nested_keyrings(keyring, ctx)) | 902 | if (search_nested_keyrings(keyring, ctx)) |
903 | __key_get(key_ref_to_ptr(ctx->result)); | 903 | __key_get(key_ref_to_ptr(ctx->result)); |
904 | rcu_read_unlock(); | 904 | rcu_read_unlock(); |
@@ -1149,7 +1149,7 @@ struct key *find_keyring_by_name(const char *name, bool uid_keyring) | |||
1149 | * (ie. it has a zero usage count) */ | 1149 | * (ie. it has a zero usage count) */ |
1150 | if (!refcount_inc_not_zero(&keyring->usage)) | 1150 | if (!refcount_inc_not_zero(&keyring->usage)) |
1151 | continue; | 1151 | continue; |
1152 | keyring->last_used_at = current_kernel_time().tv_sec; | 1152 | keyring->last_used_at = ktime_get_real_seconds(); |
1153 | goto out; | 1153 | goto out; |
1154 | } | 1154 | } |
1155 | } | 1155 | } |
@@ -1489,7 +1489,7 @@ static void keyring_revoke(struct key *keyring) | |||
1489 | static bool keyring_gc_select_iterator(void *object, void *iterator_data) | 1489 | static bool keyring_gc_select_iterator(void *object, void *iterator_data) |
1490 | { | 1490 | { |
1491 | struct key *key = keyring_ptr_to_key(object); | 1491 | struct key *key = keyring_ptr_to_key(object); |
1492 | time_t *limit = iterator_data; | 1492 | time64_t *limit = iterator_data; |
1493 | 1493 | ||
1494 | if (key_is_dead(key, *limit)) | 1494 | if (key_is_dead(key, *limit)) |
1495 | return false; | 1495 | return false; |
@@ -1500,7 +1500,7 @@ static bool keyring_gc_select_iterator(void *object, void *iterator_data) | |||
1500 | static int keyring_gc_check_iterator(const void *object, void *iterator_data) | 1500 | static int keyring_gc_check_iterator(const void *object, void *iterator_data) |
1501 | { | 1501 | { |
1502 | const struct key *key = keyring_ptr_to_key(object); | 1502 | const struct key *key = keyring_ptr_to_key(object); |
1503 | time_t *limit = iterator_data; | 1503 | time64_t *limit = iterator_data; |
1504 | 1504 | ||
1505 | key_check(key); | 1505 | key_check(key); |
1506 | return key_is_dead(key, *limit); | 1506 | return key_is_dead(key, *limit); |
@@ -1512,7 +1512,7 @@ static int keyring_gc_check_iterator(const void *object, void *iterator_data) | |||
1512 | * Not called with any locks held. The keyring's key struct will not be | 1512 | * Not called with any locks held. The keyring's key struct will not be |
1513 | * deallocated under us as only our caller may deallocate it. | 1513 | * deallocated under us as only our caller may deallocate it. |
1514 | */ | 1514 | */ |
1515 | void keyring_gc(struct key *keyring, time_t limit) | 1515 | void keyring_gc(struct key *keyring, time64_t limit) |
1516 | { | 1516 | { |
1517 | int result; | 1517 | int result; |
1518 | 1518 | ||
diff --git a/security/keys/permission.c b/security/keys/permission.c index a72b4dd70c8a..f68dc04d614e 100644 --- a/security/keys/permission.c +++ b/security/keys/permission.c | |||
@@ -89,7 +89,7 @@ EXPORT_SYMBOL(key_task_permission); | |||
89 | int key_validate(const struct key *key) | 89 | int key_validate(const struct key *key) |
90 | { | 90 | { |
91 | unsigned long flags = READ_ONCE(key->flags); | 91 | unsigned long flags = READ_ONCE(key->flags); |
92 | time_t expiry = READ_ONCE(key->expiry); | 92 | time64_t expiry = READ_ONCE(key->expiry); |
93 | 93 | ||
94 | if (flags & (1 << KEY_FLAG_INVALIDATED)) | 94 | if (flags & (1 << KEY_FLAG_INVALIDATED)) |
95 | return -ENOKEY; | 95 | return -ENOKEY; |
@@ -101,8 +101,7 @@ int key_validate(const struct key *key) | |||
101 | 101 | ||
102 | /* check it hasn't expired */ | 102 | /* check it hasn't expired */ |
103 | if (expiry) { | 103 | if (expiry) { |
104 | struct timespec now = current_kernel_time(); | 104 | if (ktime_get_real_seconds() >= expiry) |
105 | if (now.tv_sec >= expiry) | ||
106 | return -EKEYEXPIRED; | 105 | return -EKEYEXPIRED; |
107 | } | 106 | } |
108 | 107 | ||
diff --git a/security/keys/proc.c b/security/keys/proc.c index 6d1fcbba1e09..fbc4af5c6c9f 100644 --- a/security/keys/proc.c +++ b/security/keys/proc.c | |||
@@ -178,13 +178,12 @@ static int proc_keys_show(struct seq_file *m, void *v) | |||
178 | { | 178 | { |
179 | struct rb_node *_p = v; | 179 | struct rb_node *_p = v; |
180 | struct key *key = rb_entry(_p, struct key, serial_node); | 180 | struct key *key = rb_entry(_p, struct key, serial_node); |
181 | struct timespec now; | ||
182 | time_t expiry; | ||
183 | unsigned long timo; | ||
184 | unsigned long flags; | 181 | unsigned long flags; |
185 | key_ref_t key_ref, skey_ref; | 182 | key_ref_t key_ref, skey_ref; |
183 | time64_t now, expiry; | ||
186 | char xbuf[16]; | 184 | char xbuf[16]; |
187 | short state; | 185 | short state; |
186 | u64 timo; | ||
188 | int rc; | 187 | int rc; |
189 | 188 | ||
190 | struct keyring_search_context ctx = { | 189 | struct keyring_search_context ctx = { |
@@ -215,7 +214,7 @@ static int proc_keys_show(struct seq_file *m, void *v) | |||
215 | if (rc < 0) | 214 | if (rc < 0) |
216 | return 0; | 215 | return 0; |
217 | 216 | ||
218 | now = current_kernel_time(); | 217 | now = ktime_get_real_seconds(); |
219 | 218 | ||
220 | rcu_read_lock(); | 219 | rcu_read_lock(); |
221 | 220 | ||
@@ -223,21 +222,21 @@ static int proc_keys_show(struct seq_file *m, void *v) | |||
223 | expiry = READ_ONCE(key->expiry); | 222 | expiry = READ_ONCE(key->expiry); |
224 | if (expiry == 0) { | 223 | if (expiry == 0) { |
225 | memcpy(xbuf, "perm", 5); | 224 | memcpy(xbuf, "perm", 5); |
226 | } else if (now.tv_sec >= expiry) { | 225 | } else if (now >= expiry) { |
227 | memcpy(xbuf, "expd", 5); | 226 | memcpy(xbuf, "expd", 5); |
228 | } else { | 227 | } else { |
229 | timo = expiry - now.tv_sec; | 228 | timo = expiry - now; |
230 | 229 | ||
231 | if (timo < 60) | 230 | if (timo < 60) |
232 | sprintf(xbuf, "%lus", timo); | 231 | sprintf(xbuf, "%llus", timo); |
233 | else if (timo < 60*60) | 232 | else if (timo < 60*60) |
234 | sprintf(xbuf, "%lum", timo / 60); | 233 | sprintf(xbuf, "%llum", div_u64(timo, 60)); |
235 | else if (timo < 60*60*24) | 234 | else if (timo < 60*60*24) |
236 | sprintf(xbuf, "%luh", timo / (60*60)); | 235 | sprintf(xbuf, "%lluh", div_u64(timo, 60 * 60)); |
237 | else if (timo < 60*60*24*7) | 236 | else if (timo < 60*60*24*7) |
238 | sprintf(xbuf, "%lud", timo / (60*60*24)); | 237 | sprintf(xbuf, "%llud", div_u64(timo, 60 * 60 * 24)); |
239 | else | 238 | else |
240 | sprintf(xbuf, "%luw", timo / (60*60*24*7)); | 239 | sprintf(xbuf, "%lluw", div_u64(timo, 60 * 60 * 24 * 7)); |
241 | } | 240 | } |
242 | 241 | ||
243 | state = key_read_state(key); | 242 | state = key_read_state(key); |
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index 740affd65ee9..d5b25e535d3a 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c | |||
@@ -738,7 +738,7 @@ try_again: | |||
738 | if (ret < 0) | 738 | if (ret < 0) |
739 | goto invalid_key; | 739 | goto invalid_key; |
740 | 740 | ||
741 | key->last_used_at = current_kernel_time().tv_sec; | 741 | key->last_used_at = ktime_get_real_seconds(); |
742 | 742 | ||
743 | error: | 743 | error: |
744 | put_cred(ctx.cred); | 744 | put_cred(ctx.cred); |
diff --git a/security/keys/request_key.c b/security/keys/request_key.c index e8036cd0ad54..114f7408feee 100644 --- a/security/keys/request_key.c +++ b/security/keys/request_key.c | |||
@@ -251,11 +251,12 @@ static int construct_key(struct key *key, const void *callout_info, | |||
251 | * The keyring selected is returned with an extra reference upon it which the | 251 | * The keyring selected is returned with an extra reference upon it which the |
252 | * caller must release. | 252 | * caller must release. |
253 | */ | 253 | */ |
254 | static void construct_get_dest_keyring(struct key **_dest_keyring) | 254 | static int construct_get_dest_keyring(struct key **_dest_keyring) |
255 | { | 255 | { |
256 | struct request_key_auth *rka; | 256 | struct request_key_auth *rka; |
257 | const struct cred *cred = current_cred(); | 257 | const struct cred *cred = current_cred(); |
258 | struct key *dest_keyring = *_dest_keyring, *authkey; | 258 | struct key *dest_keyring = *_dest_keyring, *authkey; |
259 | int ret; | ||
259 | 260 | ||
260 | kenter("%p", dest_keyring); | 261 | kenter("%p", dest_keyring); |
261 | 262 | ||
@@ -264,6 +265,8 @@ static void construct_get_dest_keyring(struct key **_dest_keyring) | |||
264 | /* the caller supplied one */ | 265 | /* the caller supplied one */ |
265 | key_get(dest_keyring); | 266 | key_get(dest_keyring); |
266 | } else { | 267 | } else { |
268 | bool do_perm_check = true; | ||
269 | |||
267 | /* use a default keyring; falling through the cases until we | 270 | /* use a default keyring; falling through the cases until we |
268 | * find one that we actually have */ | 271 | * find one that we actually have */ |
269 | switch (cred->jit_keyring) { | 272 | switch (cred->jit_keyring) { |
@@ -278,8 +281,10 @@ static void construct_get_dest_keyring(struct key **_dest_keyring) | |||
278 | dest_keyring = | 281 | dest_keyring = |
279 | key_get(rka->dest_keyring); | 282 | key_get(rka->dest_keyring); |
280 | up_read(&authkey->sem); | 283 | up_read(&authkey->sem); |
281 | if (dest_keyring) | 284 | if (dest_keyring) { |
285 | do_perm_check = false; | ||
282 | break; | 286 | break; |
287 | } | ||
283 | } | 288 | } |
284 | 289 | ||
285 | case KEY_REQKEY_DEFL_THREAD_KEYRING: | 290 | case KEY_REQKEY_DEFL_THREAD_KEYRING: |
@@ -314,11 +319,29 @@ static void construct_get_dest_keyring(struct key **_dest_keyring) | |||
314 | default: | 319 | default: |
315 | BUG(); | 320 | BUG(); |
316 | } | 321 | } |
322 | |||
323 | /* | ||
324 | * Require Write permission on the keyring. This is essential | ||
325 | * because the default keyring may be the session keyring, and | ||
326 | * joining a keyring only requires Search permission. | ||
327 | * | ||
328 | * However, this check is skipped for the "requestor keyring" so | ||
329 | * that /sbin/request-key can itself use request_key() to add | ||
330 | * keys to the original requestor's destination keyring. | ||
331 | */ | ||
332 | if (dest_keyring && do_perm_check) { | ||
333 | ret = key_permission(make_key_ref(dest_keyring, 1), | ||
334 | KEY_NEED_WRITE); | ||
335 | if (ret) { | ||
336 | key_put(dest_keyring); | ||
337 | return ret; | ||
338 | } | ||
339 | } | ||
317 | } | 340 | } |
318 | 341 | ||
319 | *_dest_keyring = dest_keyring; | 342 | *_dest_keyring = dest_keyring; |
320 | kleave(" [dk %d]", key_serial(dest_keyring)); | 343 | kleave(" [dk %d]", key_serial(dest_keyring)); |
321 | return; | 344 | return 0; |
322 | } | 345 | } |
323 | 346 | ||
324 | /* | 347 | /* |
@@ -444,11 +467,15 @@ static struct key *construct_key_and_link(struct keyring_search_context *ctx, | |||
444 | if (ctx->index_key.type == &key_type_keyring) | 467 | if (ctx->index_key.type == &key_type_keyring) |
445 | return ERR_PTR(-EPERM); | 468 | return ERR_PTR(-EPERM); |
446 | 469 | ||
447 | user = key_user_lookup(current_fsuid()); | 470 | ret = construct_get_dest_keyring(&dest_keyring); |
448 | if (!user) | 471 | if (ret) |
449 | return ERR_PTR(-ENOMEM); | 472 | goto error; |
450 | 473 | ||
451 | construct_get_dest_keyring(&dest_keyring); | 474 | user = key_user_lookup(current_fsuid()); |
475 | if (!user) { | ||
476 | ret = -ENOMEM; | ||
477 | goto error_put_dest_keyring; | ||
478 | } | ||
452 | 479 | ||
453 | ret = construct_alloc_key(ctx, dest_keyring, flags, user, &key); | 480 | ret = construct_alloc_key(ctx, dest_keyring, flags, user, &key); |
454 | key_user_put(user); | 481 | key_user_put(user); |
@@ -463,7 +490,7 @@ static struct key *construct_key_and_link(struct keyring_search_context *ctx, | |||
463 | } else if (ret == -EINPROGRESS) { | 490 | } else if (ret == -EINPROGRESS) { |
464 | ret = 0; | 491 | ret = 0; |
465 | } else { | 492 | } else { |
466 | goto couldnt_alloc_key; | 493 | goto error_put_dest_keyring; |
467 | } | 494 | } |
468 | 495 | ||
469 | key_put(dest_keyring); | 496 | key_put(dest_keyring); |
@@ -473,8 +500,9 @@ static struct key *construct_key_and_link(struct keyring_search_context *ctx, | |||
473 | construction_failed: | 500 | construction_failed: |
474 | key_negate_and_link(key, key_negative_timeout, NULL, NULL); | 501 | key_negate_and_link(key, key_negative_timeout, NULL, NULL); |
475 | key_put(key); | 502 | key_put(key); |
476 | couldnt_alloc_key: | 503 | error_put_dest_keyring: |
477 | key_put(dest_keyring); | 504 | key_put(dest_keyring); |
505 | error: | ||
478 | kleave(" = %d", ret); | 506 | kleave(" = %d", ret); |
479 | return ERR_PTR(ret); | 507 | return ERR_PTR(ret); |
480 | } | 508 | } |
@@ -546,9 +574,7 @@ struct key *request_key_and_link(struct key_type *type, | |||
546 | if (!IS_ERR(key_ref)) { | 574 | if (!IS_ERR(key_ref)) { |
547 | key = key_ref_to_ptr(key_ref); | 575 | key = key_ref_to_ptr(key_ref); |
548 | if (dest_keyring) { | 576 | if (dest_keyring) { |
549 | construct_get_dest_keyring(&dest_keyring); | ||
550 | ret = key_link(dest_keyring, key); | 577 | ret = key_link(dest_keyring, key); |
551 | key_put(dest_keyring); | ||
552 | if (ret < 0) { | 578 | if (ret < 0) { |
553 | key_put(key); | 579 | key_put(key); |
554 | key = ERR_PTR(ret); | 580 | key = ERR_PTR(ret); |
diff --git a/security/security.c b/security/security.c index 4bf0f571b4ef..1cd8526cb0b7 100644 --- a/security/security.c +++ b/security/security.c | |||
@@ -12,6 +12,7 @@ | |||
12 | * (at your option) any later version. | 12 | * (at your option) any later version. |
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include <linux/bpf.h> | ||
15 | #include <linux/capability.h> | 16 | #include <linux/capability.h> |
16 | #include <linux/dcache.h> | 17 | #include <linux/dcache.h> |
17 | #include <linux/module.h> | 18 | #include <linux/module.h> |
@@ -1703,3 +1704,34 @@ int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule, | |||
1703 | actx); | 1704 | actx); |
1704 | } | 1705 | } |
1705 | #endif /* CONFIG_AUDIT */ | 1706 | #endif /* CONFIG_AUDIT */ |
1707 | |||
1708 | #ifdef CONFIG_BPF_SYSCALL | ||
1709 | int security_bpf(int cmd, union bpf_attr *attr, unsigned int size) | ||
1710 | { | ||
1711 | return call_int_hook(bpf, 0, cmd, attr, size); | ||
1712 | } | ||
1713 | int security_bpf_map(struct bpf_map *map, fmode_t fmode) | ||
1714 | { | ||
1715 | return call_int_hook(bpf_map, 0, map, fmode); | ||
1716 | } | ||
1717 | int security_bpf_prog(struct bpf_prog *prog) | ||
1718 | { | ||
1719 | return call_int_hook(bpf_prog, 0, prog); | ||
1720 | } | ||
1721 | int security_bpf_map_alloc(struct bpf_map *map) | ||
1722 | { | ||
1723 | return call_int_hook(bpf_map_alloc_security, 0, map); | ||
1724 | } | ||
1725 | int security_bpf_prog_alloc(struct bpf_prog_aux *aux) | ||
1726 | { | ||
1727 | return call_int_hook(bpf_prog_alloc_security, 0, aux); | ||
1728 | } | ||
1729 | void security_bpf_map_free(struct bpf_map *map) | ||
1730 | { | ||
1731 | call_void_hook(bpf_map_free_security, map); | ||
1732 | } | ||
1733 | void security_bpf_prog_free(struct bpf_prog_aux *aux) | ||
1734 | { | ||
1735 | call_void_hook(bpf_prog_free_security, aux); | ||
1736 | } | ||
1737 | #endif /* CONFIG_BPF_SYSCALL */ | ||
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index f5d304736852..8644d864e3c1 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -85,6 +85,7 @@ | |||
85 | #include <linux/export.h> | 85 | #include <linux/export.h> |
86 | #include <linux/msg.h> | 86 | #include <linux/msg.h> |
87 | #include <linux/shm.h> | 87 | #include <linux/shm.h> |
88 | #include <linux/bpf.h> | ||
88 | 89 | ||
89 | #include "avc.h" | 90 | #include "avc.h" |
90 | #include "objsec.h" | 91 | #include "objsec.h" |
@@ -1814,6 +1815,10 @@ static inline int file_path_has_perm(const struct cred *cred, | |||
1814 | return inode_has_perm(cred, file_inode(file), av, &ad); | 1815 | return inode_has_perm(cred, file_inode(file), av, &ad); |
1815 | } | 1816 | } |
1816 | 1817 | ||
1818 | #ifdef CONFIG_BPF_SYSCALL | ||
1819 | static int bpf_fd_pass(struct file *file, u32 sid); | ||
1820 | #endif | ||
1821 | |||
1817 | /* Check whether a task can use an open file descriptor to | 1822 | /* Check whether a task can use an open file descriptor to |
1818 | access an inode in a given way. Check access to the | 1823 | access an inode in a given way. Check access to the |
1819 | descriptor itself, and then use dentry_has_perm to | 1824 | descriptor itself, and then use dentry_has_perm to |
@@ -1844,6 +1849,12 @@ static int file_has_perm(const struct cred *cred, | |||
1844 | goto out; | 1849 | goto out; |
1845 | } | 1850 | } |
1846 | 1851 | ||
1852 | #ifdef CONFIG_BPF_SYSCALL | ||
1853 | rc = bpf_fd_pass(file, cred_sid(cred)); | ||
1854 | if (rc) | ||
1855 | return rc; | ||
1856 | #endif | ||
1857 | |||
1847 | /* av is zero if only checking access to the descriptor. */ | 1858 | /* av is zero if only checking access to the descriptor. */ |
1848 | rc = 0; | 1859 | rc = 0; |
1849 | if (av) | 1860 | if (av) |
@@ -2164,6 +2175,12 @@ static int selinux_binder_transfer_file(struct task_struct *from, | |||
2164 | return rc; | 2175 | return rc; |
2165 | } | 2176 | } |
2166 | 2177 | ||
2178 | #ifdef CONFIG_BPF_SYSCALL | ||
2179 | rc = bpf_fd_pass(file, sid); | ||
2180 | if (rc) | ||
2181 | return rc; | ||
2182 | #endif | ||
2183 | |||
2167 | if (unlikely(IS_PRIVATE(d_backing_inode(dentry)))) | 2184 | if (unlikely(IS_PRIVATE(d_backing_inode(dentry)))) |
2168 | return 0; | 2185 | return 0; |
2169 | 2186 | ||
@@ -2918,13 +2935,12 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir, | |||
2918 | { | 2935 | { |
2919 | const struct task_security_struct *tsec = current_security(); | 2936 | const struct task_security_struct *tsec = current_security(); |
2920 | struct superblock_security_struct *sbsec; | 2937 | struct superblock_security_struct *sbsec; |
2921 | u32 sid, newsid, clen; | 2938 | u32 newsid, clen; |
2922 | int rc; | 2939 | int rc; |
2923 | char *context; | 2940 | char *context; |
2924 | 2941 | ||
2925 | sbsec = dir->i_sb->s_security; | 2942 | sbsec = dir->i_sb->s_security; |
2926 | 2943 | ||
2927 | sid = tsec->sid; | ||
2928 | newsid = tsec->create_sid; | 2944 | newsid = tsec->create_sid; |
2929 | 2945 | ||
2930 | rc = selinux_determine_inode_label(current_security(), | 2946 | rc = selinux_determine_inode_label(current_security(), |
@@ -3124,27 +3140,6 @@ static int selinux_inode_getattr(const struct path *path) | |||
3124 | return path_has_perm(current_cred(), path, FILE__GETATTR); | 3140 | return path_has_perm(current_cred(), path, FILE__GETATTR); |
3125 | } | 3141 | } |
3126 | 3142 | ||
3127 | static int selinux_inode_setotherxattr(struct dentry *dentry, const char *name) | ||
3128 | { | ||
3129 | const struct cred *cred = current_cred(); | ||
3130 | |||
3131 | if (!strncmp(name, XATTR_SECURITY_PREFIX, | ||
3132 | sizeof XATTR_SECURITY_PREFIX - 1)) { | ||
3133 | if (!strcmp(name, XATTR_NAME_CAPS)) { | ||
3134 | if (!capable(CAP_SETFCAP)) | ||
3135 | return -EPERM; | ||
3136 | } else if (!capable(CAP_SYS_ADMIN)) { | ||
3137 | /* A different attribute in the security namespace. | ||
3138 | Restrict to administrator. */ | ||
3139 | return -EPERM; | ||
3140 | } | ||
3141 | } | ||
3142 | |||
3143 | /* Not an attribute we recognize, so just check the | ||
3144 | ordinary setattr permission. */ | ||
3145 | return dentry_has_perm(cred, dentry, FILE__SETATTR); | ||
3146 | } | ||
3147 | |||
3148 | static bool has_cap_mac_admin(bool audit) | 3143 | static bool has_cap_mac_admin(bool audit) |
3149 | { | 3144 | { |
3150 | const struct cred *cred = current_cred(); | 3145 | const struct cred *cred = current_cred(); |
@@ -3167,8 +3162,15 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name, | |||
3167 | u32 newsid, sid = current_sid(); | 3162 | u32 newsid, sid = current_sid(); |
3168 | int rc = 0; | 3163 | int rc = 0; |
3169 | 3164 | ||
3170 | if (strcmp(name, XATTR_NAME_SELINUX)) | 3165 | if (strcmp(name, XATTR_NAME_SELINUX)) { |
3171 | return selinux_inode_setotherxattr(dentry, name); | 3166 | rc = cap_inode_setxattr(dentry, name, value, size, flags); |
3167 | if (rc) | ||
3168 | return rc; | ||
3169 | |||
3170 | /* Not an attribute we recognize, so just check the | ||
3171 | ordinary setattr permission. */ | ||
3172 | return dentry_has_perm(current_cred(), dentry, FILE__SETATTR); | ||
3173 | } | ||
3172 | 3174 | ||
3173 | sbsec = inode->i_sb->s_security; | 3175 | sbsec = inode->i_sb->s_security; |
3174 | if (!(sbsec->flags & SBLABEL_MNT)) | 3176 | if (!(sbsec->flags & SBLABEL_MNT)) |
@@ -3191,18 +3193,17 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name, | |||
3191 | if (!has_cap_mac_admin(true)) { | 3193 | if (!has_cap_mac_admin(true)) { |
3192 | struct audit_buffer *ab; | 3194 | struct audit_buffer *ab; |
3193 | size_t audit_size; | 3195 | size_t audit_size; |
3194 | const char *str; | ||
3195 | 3196 | ||
3196 | /* We strip a nul only if it is at the end, otherwise the | 3197 | /* We strip a nul only if it is at the end, otherwise the |
3197 | * context contains a nul and we should audit that */ | 3198 | * context contains a nul and we should audit that */ |
3198 | if (value) { | 3199 | if (value) { |
3199 | str = value; | 3200 | const char *str = value; |
3201 | |||
3200 | if (str[size - 1] == '\0') | 3202 | if (str[size - 1] == '\0') |
3201 | audit_size = size - 1; | 3203 | audit_size = size - 1; |
3202 | else | 3204 | else |
3203 | audit_size = size; | 3205 | audit_size = size; |
3204 | } else { | 3206 | } else { |
3205 | str = ""; | ||
3206 | audit_size = 0; | 3207 | audit_size = 0; |
3207 | } | 3208 | } |
3208 | ab = audit_log_start(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR); | 3209 | ab = audit_log_start(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR); |
@@ -3282,8 +3283,15 @@ static int selinux_inode_listxattr(struct dentry *dentry) | |||
3282 | 3283 | ||
3283 | static int selinux_inode_removexattr(struct dentry *dentry, const char *name) | 3284 | static int selinux_inode_removexattr(struct dentry *dentry, const char *name) |
3284 | { | 3285 | { |
3285 | if (strcmp(name, XATTR_NAME_SELINUX)) | 3286 | if (strcmp(name, XATTR_NAME_SELINUX)) { |
3286 | return selinux_inode_setotherxattr(dentry, name); | 3287 | int rc = cap_inode_removexattr(dentry, name); |
3288 | if (rc) | ||
3289 | return rc; | ||
3290 | |||
3291 | /* Not an attribute we recognize, so just check the | ||
3292 | ordinary setattr permission. */ | ||
3293 | return dentry_has_perm(current_cred(), dentry, FILE__SETATTR); | ||
3294 | } | ||
3287 | 3295 | ||
3288 | /* No one is allowed to remove a SELinux security label. | 3296 | /* No one is allowed to remove a SELinux security label. |
3289 | You can change the label, but all data must be labeled. */ | 3297 | You can change the label, but all data must be labeled. */ |
@@ -3978,8 +3986,8 @@ static int selinux_task_getioprio(struct task_struct *p) | |||
3978 | PROCESS__GETSCHED, NULL); | 3986 | PROCESS__GETSCHED, NULL); |
3979 | } | 3987 | } |
3980 | 3988 | ||
3981 | int selinux_task_prlimit(const struct cred *cred, const struct cred *tcred, | 3989 | static int selinux_task_prlimit(const struct cred *cred, const struct cred *tcred, |
3982 | unsigned int flags) | 3990 | unsigned int flags) |
3983 | { | 3991 | { |
3984 | u32 av = 0; | 3992 | u32 av = 0; |
3985 | 3993 | ||
@@ -6252,6 +6260,139 @@ static void selinux_ib_free_security(void *ib_sec) | |||
6252 | } | 6260 | } |
6253 | #endif | 6261 | #endif |
6254 | 6262 | ||
6263 | #ifdef CONFIG_BPF_SYSCALL | ||
6264 | static int selinux_bpf(int cmd, union bpf_attr *attr, | ||
6265 | unsigned int size) | ||
6266 | { | ||
6267 | u32 sid = current_sid(); | ||
6268 | int ret; | ||
6269 | |||
6270 | switch (cmd) { | ||
6271 | case BPF_MAP_CREATE: | ||
6272 | ret = avc_has_perm(sid, sid, SECCLASS_BPF, BPF__MAP_CREATE, | ||
6273 | NULL); | ||
6274 | break; | ||
6275 | case BPF_PROG_LOAD: | ||
6276 | ret = avc_has_perm(sid, sid, SECCLASS_BPF, BPF__PROG_LOAD, | ||
6277 | NULL); | ||
6278 | break; | ||
6279 | default: | ||
6280 | ret = 0; | ||
6281 | break; | ||
6282 | } | ||
6283 | |||
6284 | return ret; | ||
6285 | } | ||
6286 | |||
6287 | static u32 bpf_map_fmode_to_av(fmode_t fmode) | ||
6288 | { | ||
6289 | u32 av = 0; | ||
6290 | |||
6291 | if (fmode & FMODE_READ) | ||
6292 | av |= BPF__MAP_READ; | ||
6293 | if (fmode & FMODE_WRITE) | ||
6294 | av |= BPF__MAP_WRITE; | ||
6295 | return av; | ||
6296 | } | ||
6297 | |||
6298 | /* This function will check the file pass through unix socket or binder to see | ||
6299 | * if it is a bpf related object. And apply correspinding checks on the bpf | ||
6300 | * object based on the type. The bpf maps and programs, not like other files and | ||
6301 | * socket, are using a shared anonymous inode inside the kernel as their inode. | ||
6302 | * So checking that inode cannot identify if the process have privilege to | ||
6303 | * access the bpf object and that's why we have to add this additional check in | ||
6304 | * selinux_file_receive and selinux_binder_transfer_files. | ||
6305 | */ | ||
6306 | static int bpf_fd_pass(struct file *file, u32 sid) | ||
6307 | { | ||
6308 | struct bpf_security_struct *bpfsec; | ||
6309 | struct bpf_prog *prog; | ||
6310 | struct bpf_map *map; | ||
6311 | int ret; | ||
6312 | |||
6313 | if (file->f_op == &bpf_map_fops) { | ||
6314 | map = file->private_data; | ||
6315 | bpfsec = map->security; | ||
6316 | ret = avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF, | ||
6317 | bpf_map_fmode_to_av(file->f_mode), NULL); | ||
6318 | if (ret) | ||
6319 | return ret; | ||
6320 | } else if (file->f_op == &bpf_prog_fops) { | ||
6321 | prog = file->private_data; | ||
6322 | bpfsec = prog->aux->security; | ||
6323 | ret = avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF, | ||
6324 | BPF__PROG_RUN, NULL); | ||
6325 | if (ret) | ||
6326 | return ret; | ||
6327 | } | ||
6328 | return 0; | ||
6329 | } | ||
6330 | |||
6331 | static int selinux_bpf_map(struct bpf_map *map, fmode_t fmode) | ||
6332 | { | ||
6333 | u32 sid = current_sid(); | ||
6334 | struct bpf_security_struct *bpfsec; | ||
6335 | |||
6336 | bpfsec = map->security; | ||
6337 | return avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF, | ||
6338 | bpf_map_fmode_to_av(fmode), NULL); | ||
6339 | } | ||
6340 | |||
6341 | static int selinux_bpf_prog(struct bpf_prog *prog) | ||
6342 | { | ||
6343 | u32 sid = current_sid(); | ||
6344 | struct bpf_security_struct *bpfsec; | ||
6345 | |||
6346 | bpfsec = prog->aux->security; | ||
6347 | return avc_has_perm(sid, bpfsec->sid, SECCLASS_BPF, | ||
6348 | BPF__PROG_RUN, NULL); | ||
6349 | } | ||
6350 | |||
6351 | static int selinux_bpf_map_alloc(struct bpf_map *map) | ||
6352 | { | ||
6353 | struct bpf_security_struct *bpfsec; | ||
6354 | |||
6355 | bpfsec = kzalloc(sizeof(*bpfsec), GFP_KERNEL); | ||
6356 | if (!bpfsec) | ||
6357 | return -ENOMEM; | ||
6358 | |||
6359 | bpfsec->sid = current_sid(); | ||
6360 | map->security = bpfsec; | ||
6361 | |||
6362 | return 0; | ||
6363 | } | ||
6364 | |||
6365 | static void selinux_bpf_map_free(struct bpf_map *map) | ||
6366 | { | ||
6367 | struct bpf_security_struct *bpfsec = map->security; | ||
6368 | |||
6369 | map->security = NULL; | ||
6370 | kfree(bpfsec); | ||
6371 | } | ||
6372 | |||
6373 | static int selinux_bpf_prog_alloc(struct bpf_prog_aux *aux) | ||
6374 | { | ||
6375 | struct bpf_security_struct *bpfsec; | ||
6376 | |||
6377 | bpfsec = kzalloc(sizeof(*bpfsec), GFP_KERNEL); | ||
6378 | if (!bpfsec) | ||
6379 | return -ENOMEM; | ||
6380 | |||
6381 | bpfsec->sid = current_sid(); | ||
6382 | aux->security = bpfsec; | ||
6383 | |||
6384 | return 0; | ||
6385 | } | ||
6386 | |||
6387 | static void selinux_bpf_prog_free(struct bpf_prog_aux *aux) | ||
6388 | { | ||
6389 | struct bpf_security_struct *bpfsec = aux->security; | ||
6390 | |||
6391 | aux->security = NULL; | ||
6392 | kfree(bpfsec); | ||
6393 | } | ||
6394 | #endif | ||
6395 | |||
6255 | static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { | 6396 | static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { |
6256 | LSM_HOOK_INIT(binder_set_context_mgr, selinux_binder_set_context_mgr), | 6397 | LSM_HOOK_INIT(binder_set_context_mgr, selinux_binder_set_context_mgr), |
6257 | LSM_HOOK_INIT(binder_transaction, selinux_binder_transaction), | 6398 | LSM_HOOK_INIT(binder_transaction, selinux_binder_transaction), |
@@ -6471,6 +6612,16 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { | |||
6471 | LSM_HOOK_INIT(audit_rule_match, selinux_audit_rule_match), | 6612 | LSM_HOOK_INIT(audit_rule_match, selinux_audit_rule_match), |
6472 | LSM_HOOK_INIT(audit_rule_free, selinux_audit_rule_free), | 6613 | LSM_HOOK_INIT(audit_rule_free, selinux_audit_rule_free), |
6473 | #endif | 6614 | #endif |
6615 | |||
6616 | #ifdef CONFIG_BPF_SYSCALL | ||
6617 | LSM_HOOK_INIT(bpf, selinux_bpf), | ||
6618 | LSM_HOOK_INIT(bpf_map, selinux_bpf_map), | ||
6619 | LSM_HOOK_INIT(bpf_prog, selinux_bpf_prog), | ||
6620 | LSM_HOOK_INIT(bpf_map_alloc_security, selinux_bpf_map_alloc), | ||
6621 | LSM_HOOK_INIT(bpf_prog_alloc_security, selinux_bpf_prog_alloc), | ||
6622 | LSM_HOOK_INIT(bpf_map_free_security, selinux_bpf_map_free), | ||
6623 | LSM_HOOK_INIT(bpf_prog_free_security, selinux_bpf_prog_free), | ||
6624 | #endif | ||
6474 | }; | 6625 | }; |
6475 | 6626 | ||
6476 | static __init int selinux_init(void) | 6627 | static __init int selinux_init(void) |
diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h index cc35695d97b4..acdee7795297 100644 --- a/security/selinux/include/classmap.h +++ b/security/selinux/include/classmap.h | |||
@@ -238,6 +238,8 @@ struct security_class_mapping secclass_map[] = { | |||
238 | { "access", NULL } }, | 238 | { "access", NULL } }, |
239 | { "infiniband_endport", | 239 | { "infiniband_endport", |
240 | { "manage_subnet", NULL } }, | 240 | { "manage_subnet", NULL } }, |
241 | { "bpf", | ||
242 | {"map_create", "map_read", "map_write", "prog_load", "prog_run"} }, | ||
241 | { NULL } | 243 | { NULL } |
242 | }; | 244 | }; |
243 | 245 | ||
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index 1649cd18eb0b..3d54468ce334 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h | |||
@@ -150,6 +150,10 @@ struct pkey_security_struct { | |||
150 | u32 sid; /* SID of pkey */ | 150 | u32 sid; /* SID of pkey */ |
151 | }; | 151 | }; |
152 | 152 | ||
153 | struct bpf_security_struct { | ||
154 | u32 sid; /*SID of bpf obj creater*/ | ||
155 | }; | ||
156 | |||
153 | extern unsigned int selinux_checkreqprot; | 157 | extern unsigned int selinux_checkreqprot; |
154 | 158 | ||
155 | #endif /* _SELINUX_OBJSEC_H_ */ | 159 | #endif /* _SELINUX_OBJSEC_H_ */ |
diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c index 771c96afe1d5..c91543a617ac 100644 --- a/security/selinux/ss/conditional.c +++ b/security/selinux/ss/conditional.c | |||
@@ -361,7 +361,6 @@ static int cond_read_av_list(struct policydb *p, void *fp, struct cond_av_list * | |||
361 | 361 | ||
362 | *ret_list = NULL; | 362 | *ret_list = NULL; |
363 | 363 | ||
364 | len = 0; | ||
365 | rc = next_entry(buf, fp, sizeof(u32)); | 364 | rc = next_entry(buf, fp, sizeof(u32)); |
366 | if (rc) | 365 | if (rc) |
367 | return rc; | 366 | return rc; |
diff --git a/security/selinux/ss/hashtab.c b/security/selinux/ss/hashtab.c index 6bd6dcd954fa..fe25b3fb2154 100644 --- a/security/selinux/ss/hashtab.c +++ b/security/selinux/ss/hashtab.c | |||
@@ -10,6 +10,8 @@ | |||
10 | #include <linux/sched.h> | 10 | #include <linux/sched.h> |
11 | #include "hashtab.h" | 11 | #include "hashtab.h" |
12 | 12 | ||
13 | static struct kmem_cache *hashtab_node_cachep; | ||
14 | |||
13 | struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, const void *key), | 15 | struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, const void *key), |
14 | int (*keycmp)(struct hashtab *h, const void *key1, const void *key2), | 16 | int (*keycmp)(struct hashtab *h, const void *key1, const void *key2), |
15 | u32 size) | 17 | u32 size) |
@@ -58,7 +60,7 @@ int hashtab_insert(struct hashtab *h, void *key, void *datum) | |||
58 | if (cur && (h->keycmp(h, key, cur->key) == 0)) | 60 | if (cur && (h->keycmp(h, key, cur->key) == 0)) |
59 | return -EEXIST; | 61 | return -EEXIST; |
60 | 62 | ||
61 | newnode = kzalloc(sizeof(*newnode), GFP_KERNEL); | 63 | newnode = kmem_cache_zalloc(hashtab_node_cachep, GFP_KERNEL); |
62 | if (!newnode) | 64 | if (!newnode) |
63 | return -ENOMEM; | 65 | return -ENOMEM; |
64 | newnode->key = key; | 66 | newnode->key = key; |
@@ -107,7 +109,7 @@ void hashtab_destroy(struct hashtab *h) | |||
107 | while (cur) { | 109 | while (cur) { |
108 | temp = cur; | 110 | temp = cur; |
109 | cur = cur->next; | 111 | cur = cur->next; |
110 | kfree(temp); | 112 | kmem_cache_free(hashtab_node_cachep, temp); |
111 | } | 113 | } |
112 | h->htable[i] = NULL; | 114 | h->htable[i] = NULL; |
113 | } | 115 | } |
@@ -149,7 +151,7 @@ void hashtab_stat(struct hashtab *h, struct hashtab_info *info) | |||
149 | 151 | ||
150 | slots_used = 0; | 152 | slots_used = 0; |
151 | max_chain_len = 0; | 153 | max_chain_len = 0; |
152 | for (slots_used = max_chain_len = i = 0; i < h->size; i++) { | 154 | for (i = 0; i < h->size; i++) { |
153 | cur = h->htable[i]; | 155 | cur = h->htable[i]; |
154 | if (cur) { | 156 | if (cur) { |
155 | slots_used++; | 157 | slots_used++; |
@@ -167,3 +169,14 @@ void hashtab_stat(struct hashtab *h, struct hashtab_info *info) | |||
167 | info->slots_used = slots_used; | 169 | info->slots_used = slots_used; |
168 | info->max_chain_len = max_chain_len; | 170 | info->max_chain_len = max_chain_len; |
169 | } | 171 | } |
172 | void hashtab_cache_init(void) | ||
173 | { | ||
174 | hashtab_node_cachep = kmem_cache_create("hashtab_node", | ||
175 | sizeof(struct hashtab_node), | ||
176 | 0, SLAB_PANIC, NULL); | ||
177 | } | ||
178 | |||
179 | void hashtab_cache_destroy(void) | ||
180 | { | ||
181 | kmem_cache_destroy(hashtab_node_cachep); | ||
182 | } | ||
diff --git a/security/selinux/ss/hashtab.h b/security/selinux/ss/hashtab.h index 3e3e42bfd150..6183ee2a2e7a 100644 --- a/security/selinux/ss/hashtab.h +++ b/security/selinux/ss/hashtab.h | |||
@@ -85,4 +85,8 @@ int hashtab_map(struct hashtab *h, | |||
85 | /* Fill info with some hash table statistics */ | 85 | /* Fill info with some hash table statistics */ |
86 | void hashtab_stat(struct hashtab *h, struct hashtab_info *info); | 86 | void hashtab_stat(struct hashtab *h, struct hashtab_info *info); |
87 | 87 | ||
88 | /* Use kmem_cache for hashtab_node */ | ||
89 | void hashtab_cache_init(void); | ||
90 | void hashtab_cache_destroy(void); | ||
91 | |||
88 | #endif /* _SS_HASHTAB_H */ | 92 | #endif /* _SS_HASHTAB_H */ |
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index e4a1c0dc561a..33cfe5d3d6cb 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
@@ -2060,10 +2060,12 @@ int security_load_policy(void *data, size_t len) | |||
2060 | if (!ss_initialized) { | 2060 | if (!ss_initialized) { |
2061 | avtab_cache_init(); | 2061 | avtab_cache_init(); |
2062 | ebitmap_cache_init(); | 2062 | ebitmap_cache_init(); |
2063 | hashtab_cache_init(); | ||
2063 | rc = policydb_read(&policydb, fp); | 2064 | rc = policydb_read(&policydb, fp); |
2064 | if (rc) { | 2065 | if (rc) { |
2065 | avtab_cache_destroy(); | 2066 | avtab_cache_destroy(); |
2066 | ebitmap_cache_destroy(); | 2067 | ebitmap_cache_destroy(); |
2068 | hashtab_cache_destroy(); | ||
2067 | goto out; | 2069 | goto out; |
2068 | } | 2070 | } |
2069 | 2071 | ||
@@ -2075,6 +2077,7 @@ int security_load_policy(void *data, size_t len) | |||
2075 | policydb_destroy(&policydb); | 2077 | policydb_destroy(&policydb); |
2076 | avtab_cache_destroy(); | 2078 | avtab_cache_destroy(); |
2077 | ebitmap_cache_destroy(); | 2079 | ebitmap_cache_destroy(); |
2080 | hashtab_cache_destroy(); | ||
2078 | goto out; | 2081 | goto out; |
2079 | } | 2082 | } |
2080 | 2083 | ||
@@ -2083,6 +2086,7 @@ int security_load_policy(void *data, size_t len) | |||
2083 | policydb_destroy(&policydb); | 2086 | policydb_destroy(&policydb); |
2084 | avtab_cache_destroy(); | 2087 | avtab_cache_destroy(); |
2085 | ebitmap_cache_destroy(); | 2088 | ebitmap_cache_destroy(); |
2089 | hashtab_cache_destroy(); | ||
2086 | goto out; | 2090 | goto out; |
2087 | } | 2091 | } |
2088 | 2092 | ||
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 286171a16ed2..14cc7940b36d 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c | |||
@@ -4600,6 +4600,82 @@ static int smack_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen) | |||
4600 | return 0; | 4600 | return 0; |
4601 | } | 4601 | } |
4602 | 4602 | ||
4603 | static int smack_inode_copy_up(struct dentry *dentry, struct cred **new) | ||
4604 | { | ||
4605 | |||
4606 | struct task_smack *tsp; | ||
4607 | struct smack_known *skp; | ||
4608 | struct inode_smack *isp; | ||
4609 | struct cred *new_creds = *new; | ||
4610 | |||
4611 | if (new_creds == NULL) { | ||
4612 | new_creds = prepare_creds(); | ||
4613 | if (new_creds == NULL) | ||
4614 | return -ENOMEM; | ||
4615 | } | ||
4616 | |||
4617 | tsp = new_creds->security; | ||
4618 | |||
4619 | /* | ||
4620 | * Get label from overlay inode and set it in create_sid | ||
4621 | */ | ||
4622 | isp = d_inode(dentry->d_parent)->i_security; | ||
4623 | skp = isp->smk_inode; | ||
4624 | tsp->smk_task = skp; | ||
4625 | *new = new_creds; | ||
4626 | return 0; | ||
4627 | } | ||
4628 | |||
4629 | static int smack_inode_copy_up_xattr(const char *name) | ||
4630 | { | ||
4631 | /* | ||
4632 | * Return 1 if this is the smack access Smack attribute. | ||
4633 | */ | ||
4634 | if (strcmp(name, XATTR_NAME_SMACK) == 0) | ||
4635 | return 1; | ||
4636 | |||
4637 | return -EOPNOTSUPP; | ||
4638 | } | ||
4639 | |||
4640 | static int smack_dentry_create_files_as(struct dentry *dentry, int mode, | ||
4641 | struct qstr *name, | ||
4642 | const struct cred *old, | ||
4643 | struct cred *new) | ||
4644 | { | ||
4645 | struct task_smack *otsp = old->security; | ||
4646 | struct task_smack *ntsp = new->security; | ||
4647 | struct inode_smack *isp; | ||
4648 | int may; | ||
4649 | |||
4650 | /* | ||
4651 | * Use the process credential unless all of | ||
4652 | * the transmuting criteria are met | ||
4653 | */ | ||
4654 | ntsp->smk_task = otsp->smk_task; | ||
4655 | |||
4656 | /* | ||
4657 | * the attribute of the containing directory | ||
4658 | */ | ||
4659 | isp = d_inode(dentry->d_parent)->i_security; | ||
4660 | |||
4661 | if (isp->smk_flags & SMK_INODE_TRANSMUTE) { | ||
4662 | rcu_read_lock(); | ||
4663 | may = smk_access_entry(otsp->smk_task->smk_known, | ||
4664 | isp->smk_inode->smk_known, | ||
4665 | &otsp->smk_task->smk_rules); | ||
4666 | rcu_read_unlock(); | ||
4667 | |||
4668 | /* | ||
4669 | * If the directory is transmuting and the rule | ||
4670 | * providing access is transmuting use the containing | ||
4671 | * directory label instead of the process label. | ||
4672 | */ | ||
4673 | if (may > 0 && (may & MAY_TRANSMUTE)) | ||
4674 | ntsp->smk_task = isp->smk_inode; | ||
4675 | } | ||
4676 | return 0; | ||
4677 | } | ||
4678 | |||
4603 | static struct security_hook_list smack_hooks[] __lsm_ro_after_init = { | 4679 | static struct security_hook_list smack_hooks[] __lsm_ro_after_init = { |
4604 | LSM_HOOK_INIT(ptrace_access_check, smack_ptrace_access_check), | 4680 | LSM_HOOK_INIT(ptrace_access_check, smack_ptrace_access_check), |
4605 | LSM_HOOK_INIT(ptrace_traceme, smack_ptrace_traceme), | 4681 | LSM_HOOK_INIT(ptrace_traceme, smack_ptrace_traceme), |
@@ -4735,6 +4811,9 @@ static struct security_hook_list smack_hooks[] __lsm_ro_after_init = { | |||
4735 | LSM_HOOK_INIT(inode_notifysecctx, smack_inode_notifysecctx), | 4811 | LSM_HOOK_INIT(inode_notifysecctx, smack_inode_notifysecctx), |
4736 | LSM_HOOK_INIT(inode_setsecctx, smack_inode_setsecctx), | 4812 | LSM_HOOK_INIT(inode_setsecctx, smack_inode_setsecctx), |
4737 | LSM_HOOK_INIT(inode_getsecctx, smack_inode_getsecctx), | 4813 | LSM_HOOK_INIT(inode_getsecctx, smack_inode_getsecctx), |
4814 | LSM_HOOK_INIT(inode_copy_up, smack_inode_copy_up), | ||
4815 | LSM_HOOK_INIT(inode_copy_up_xattr, smack_inode_copy_up_xattr), | ||
4816 | LSM_HOOK_INIT(dentry_create_files_as, smack_dentry_create_files_as), | ||
4738 | }; | 4817 | }; |
4739 | 4818 | ||
4740 | 4819 | ||
diff --git a/security/tomoyo/audit.c b/security/tomoyo/audit.c index d330b060dcff..0f73fe30e37a 100644 --- a/security/tomoyo/audit.c +++ b/security/tomoyo/audit.c | |||
@@ -157,7 +157,7 @@ static char *tomoyo_print_header(struct tomoyo_request_info *r) | |||
157 | if (!buffer) | 157 | if (!buffer) |
158 | return NULL; | 158 | return NULL; |
159 | 159 | ||
160 | tomoyo_convert_time(get_seconds(), &stamp); | 160 | tomoyo_convert_time(ktime_get_real_seconds(), &stamp); |
161 | 161 | ||
162 | pos = snprintf(buffer, tomoyo_buffer_len - 1, | 162 | pos = snprintf(buffer, tomoyo_buffer_len - 1, |
163 | "#%04u/%02u/%02u %02u:%02u:%02u# profile=%u mode=%s " | 163 | "#%04u/%02u/%02u %02u:%02u:%02u# profile=%u mode=%s " |
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index 21691b99e61f..25eed4b0b0e8 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c | |||
@@ -2257,7 +2257,7 @@ static const char * const tomoyo_memory_headers[TOMOYO_MAX_MEMORY_STAT] = { | |||
2257 | /* Timestamp counter for last updated. */ | 2257 | /* Timestamp counter for last updated. */ |
2258 | static unsigned int tomoyo_stat_updated[TOMOYO_MAX_POLICY_STAT]; | 2258 | static unsigned int tomoyo_stat_updated[TOMOYO_MAX_POLICY_STAT]; |
2259 | /* Counter for number of updates. */ | 2259 | /* Counter for number of updates. */ |
2260 | static unsigned int tomoyo_stat_modified[TOMOYO_MAX_POLICY_STAT]; | 2260 | static time64_t tomoyo_stat_modified[TOMOYO_MAX_POLICY_STAT]; |
2261 | 2261 | ||
2262 | /** | 2262 | /** |
2263 | * tomoyo_update_stat - Update statistic counters. | 2263 | * tomoyo_update_stat - Update statistic counters. |
@@ -2272,7 +2272,7 @@ void tomoyo_update_stat(const u8 index) | |||
2272 | * I don't use atomic operations because race condition is not fatal. | 2272 | * I don't use atomic operations because race condition is not fatal. |
2273 | */ | 2273 | */ |
2274 | tomoyo_stat_updated[index]++; | 2274 | tomoyo_stat_updated[index]++; |
2275 | tomoyo_stat_modified[index] = get_seconds(); | 2275 | tomoyo_stat_modified[index] = ktime_get_real_seconds(); |
2276 | } | 2276 | } |
2277 | 2277 | ||
2278 | /** | 2278 | /** |
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index e4097d7994b1..7adccdd8e36d 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h | |||
@@ -1037,7 +1037,7 @@ void tomoyo_check_acl(struct tomoyo_request_info *r, | |||
1037 | bool (*check_entry) (struct tomoyo_request_info *, | 1037 | bool (*check_entry) (struct tomoyo_request_info *, |
1038 | const struct tomoyo_acl_info *)); | 1038 | const struct tomoyo_acl_info *)); |
1039 | void tomoyo_check_profile(void); | 1039 | void tomoyo_check_profile(void); |
1040 | void tomoyo_convert_time(time_t time, struct tomoyo_time *stamp); | 1040 | void tomoyo_convert_time(time64_t time, struct tomoyo_time *stamp); |
1041 | void tomoyo_del_condition(struct list_head *element); | 1041 | void tomoyo_del_condition(struct list_head *element); |
1042 | void tomoyo_fill_path_info(struct tomoyo_path_info *ptr); | 1042 | void tomoyo_fill_path_info(struct tomoyo_path_info *ptr); |
1043 | void tomoyo_get_attributes(struct tomoyo_obj_info *obj); | 1043 | void tomoyo_get_attributes(struct tomoyo_obj_info *obj); |
diff --git a/security/tomoyo/util.c b/security/tomoyo/util.c index 580b318910f1..d3d9d9f1edb0 100644 --- a/security/tomoyo/util.c +++ b/security/tomoyo/util.c | |||
@@ -87,38 +87,17 @@ const u8 tomoyo_index2category[TOMOYO_MAX_MAC_INDEX] = { | |||
87 | * @stamp: Pointer to "struct tomoyo_time". | 87 | * @stamp: Pointer to "struct tomoyo_time". |
88 | * | 88 | * |
89 | * Returns nothing. | 89 | * Returns nothing. |
90 | * | ||
91 | * This function does not handle Y2038 problem. | ||
92 | */ | 90 | */ |
93 | void tomoyo_convert_time(time_t time, struct tomoyo_time *stamp) | 91 | void tomoyo_convert_time(time64_t time64, struct tomoyo_time *stamp) |
94 | { | 92 | { |
95 | static const u16 tomoyo_eom[2][12] = { | 93 | struct tm tm; |
96 | { 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, | 94 | time64_to_tm(time64, 0, &tm); |
97 | { 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } | 95 | stamp->sec = tm.tm_sec; |
98 | }; | 96 | stamp->min = tm.tm_min; |
99 | u16 y; | 97 | stamp->hour = tm.tm_hour; |
100 | u8 m; | 98 | stamp->day = tm.tm_mday; |
101 | bool r; | 99 | stamp->month = tm.tm_mon + 1; |
102 | stamp->sec = time % 60; | 100 | stamp->year = tm.tm_year + 1900; |
103 | time /= 60; | ||
104 | stamp->min = time % 60; | ||
105 | time /= 60; | ||
106 | stamp->hour = time % 24; | ||
107 | time /= 24; | ||
108 | for (y = 1970; ; y++) { | ||
109 | const unsigned short days = (y & 3) ? 365 : 366; | ||
110 | if (time < days) | ||
111 | break; | ||
112 | time -= days; | ||
113 | } | ||
114 | r = (y & 3) == 0; | ||
115 | for (m = 0; m < 11 && time >= tomoyo_eom[r][m]; m++) | ||
116 | ; | ||
117 | if (m) | ||
118 | time -= tomoyo_eom[r][m - 1]; | ||
119 | stamp->year = y; | ||
120 | stamp->month = ++m; | ||
121 | stamp->day = ++time; | ||
122 | } | 101 | } |
123 | 102 | ||
124 | /** | 103 | /** |