diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-21 23:27:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-21 23:27:36 -0400 |
commit | cb60e3e65c1b96a4d6444a7a13dc7dd48bc15a2b (patch) | |
tree | 4322be35db678f6299348a76ad60a2023954af7d /security | |
parent | 99262a3dafa3290866512ddfb32609198f8973e9 (diff) | |
parent | ff2bb047c4bce9742e94911eeb44b4d6ff4734ab (diff) |
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull security subsystem updates from James Morris:
"New notable features:
- The seccomp work from Will Drewry
- PR_{GET,SET}_NO_NEW_PRIVS from Andy Lutomirski
- Longer security labels for Smack from Casey Schaufler
- Additional ptrace restriction modes for Yama by Kees Cook"
Fix up trivial context conflicts in arch/x86/Kconfig and include/linux/filter.h
* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (65 commits)
apparmor: fix long path failure due to disconnected path
apparmor: fix profile lookup for unconfined
ima: fix filename hint to reflect script interpreter name
KEYS: Don't check for NULL key pointer in key_validate()
Smack: allow for significantly longer Smack labels v4
gfp flags for security_inode_alloc()?
Smack: recursive tramsmute
Yama: replace capable() with ns_capable()
TOMOYO: Accept manager programs which do not start with / .
KEYS: Add invalidation support
KEYS: Do LRU discard in full keyrings
KEYS: Permit in-place link replacement in keyring list
KEYS: Perform RCU synchronisation on keys prior to key destruction
KEYS: Announce key type (un)registration
KEYS: Reorganise keys Makefile
KEYS: Move the key config into security/keys/Kconfig
KEYS: Use the compat keyctl() syscall wrapper on Sparc64 for Sparc32 compat
Yama: remove an unused variable
samples/seccomp: fix dependencies on arch macros
Yama: add additional ptrace scopes
...
Diffstat (limited to 'security')
50 files changed, 1857 insertions, 1102 deletions
diff --git a/security/Kconfig b/security/Kconfig index ccc61f8006b2..e9c6ac724fef 100644 --- a/security/Kconfig +++ b/security/Kconfig | |||
@@ -4,73 +4,7 @@ | |||
4 | 4 | ||
5 | menu "Security options" | 5 | menu "Security options" |
6 | 6 | ||
7 | config KEYS | 7 | source security/keys/Kconfig |
8 | bool "Enable access key retention support" | ||
9 | help | ||
10 | This option provides support for retaining authentication tokens and | ||
11 | access keys in the kernel. | ||
12 | |||
13 | It also includes provision of methods by which such keys might be | ||
14 | associated with a process so that network filesystems, encryption | ||
15 | support and the like can find them. | ||
16 | |||
17 | Furthermore, a special type of key is available that acts as keyring: | ||
18 | a searchable sequence of keys. Each process is equipped with access | ||
19 | to five standard keyrings: UID-specific, GID-specific, session, | ||
20 | process and thread. | ||
21 | |||
22 | If you are unsure as to whether this is required, answer N. | ||
23 | |||
24 | config TRUSTED_KEYS | ||
25 | tristate "TRUSTED KEYS" | ||
26 | depends on KEYS && TCG_TPM | ||
27 | select CRYPTO | ||
28 | select CRYPTO_HMAC | ||
29 | select CRYPTO_SHA1 | ||
30 | help | ||
31 | This option provides support for creating, sealing, and unsealing | ||
32 | keys in the kernel. Trusted keys are random number symmetric keys, | ||
33 | generated and RSA-sealed by the TPM. The TPM only unseals the keys, | ||
34 | if the boot PCRs and other criteria match. Userspace will only ever | ||
35 | see encrypted blobs. | ||
36 | |||
37 | If you are unsure as to whether this is required, answer N. | ||
38 | |||
39 | config ENCRYPTED_KEYS | ||
40 | tristate "ENCRYPTED KEYS" | ||
41 | depends on KEYS | ||
42 | select CRYPTO | ||
43 | select CRYPTO_HMAC | ||
44 | select CRYPTO_AES | ||
45 | select CRYPTO_CBC | ||
46 | select CRYPTO_SHA256 | ||
47 | select CRYPTO_RNG | ||
48 | help | ||
49 | This option provides support for create/encrypting/decrypting keys | ||
50 | in the kernel. Encrypted keys are kernel generated random numbers, | ||
51 | which are encrypted/decrypted with a 'master' symmetric key. The | ||
52 | 'master' key can be either a trusted-key or user-key type. | ||
53 | Userspace only ever sees/stores encrypted blobs. | ||
54 | |||
55 | If you are unsure as to whether this is required, answer N. | ||
56 | |||
57 | config KEYS_DEBUG_PROC_KEYS | ||
58 | bool "Enable the /proc/keys file by which keys may be viewed" | ||
59 | depends on KEYS | ||
60 | help | ||
61 | This option turns on support for the /proc/keys file - through which | ||
62 | can be listed all the keys on the system that are viewable by the | ||
63 | reading process. | ||
64 | |||
65 | The only keys included in the list are those that grant View | ||
66 | permission to the reading process whether or not it possesses them. | ||
67 | Note that LSM security checks are still performed, and may further | ||
68 | filter out keys that the current process is not authorised to view. | ||
69 | |||
70 | Only key attributes are listed here; key payloads are not included in | ||
71 | the resulting table. | ||
72 | |||
73 | If you are unsure as to whether this is required, answer N. | ||
74 | 8 | ||
75 | config SECURITY_DMESG_RESTRICT | 9 | config SECURITY_DMESG_RESTRICT |
76 | bool "Restrict unprivileged access to the kernel syslog" | 10 | bool "Restrict unprivileged access to the kernel syslog" |
diff --git a/security/apparmor/audit.c b/security/apparmor/audit.c index cc3520d39a78..3ae28db5a64f 100644 --- a/security/apparmor/audit.c +++ b/security/apparmor/audit.c | |||
@@ -111,7 +111,7 @@ static const char *const aa_audit_type[] = { | |||
111 | static void audit_pre(struct audit_buffer *ab, void *ca) | 111 | static void audit_pre(struct audit_buffer *ab, void *ca) |
112 | { | 112 | { |
113 | struct common_audit_data *sa = ca; | 113 | struct common_audit_data *sa = ca; |
114 | struct task_struct *tsk = sa->tsk ? sa->tsk : current; | 114 | struct task_struct *tsk = sa->aad->tsk ? sa->aad->tsk : current; |
115 | 115 | ||
116 | if (aa_g_audit_header) { | 116 | if (aa_g_audit_header) { |
117 | audit_log_format(ab, "apparmor="); | 117 | audit_log_format(ab, "apparmor="); |
@@ -149,6 +149,12 @@ static void audit_pre(struct audit_buffer *ab, void *ca) | |||
149 | audit_log_format(ab, " name="); | 149 | audit_log_format(ab, " name="); |
150 | audit_log_untrustedstring(ab, sa->aad->name); | 150 | audit_log_untrustedstring(ab, sa->aad->name); |
151 | } | 151 | } |
152 | |||
153 | if (sa->aad->tsk) { | ||
154 | audit_log_format(ab, " pid=%d comm=", tsk->pid); | ||
155 | audit_log_untrustedstring(ab, tsk->comm); | ||
156 | } | ||
157 | |||
152 | } | 158 | } |
153 | 159 | ||
154 | /** | 160 | /** |
@@ -205,7 +211,8 @@ int aa_audit(int type, struct aa_profile *profile, gfp_t gfp, | |||
205 | aa_audit_msg(type, sa, cb); | 211 | aa_audit_msg(type, sa, cb); |
206 | 212 | ||
207 | if (sa->aad->type == AUDIT_APPARMOR_KILL) | 213 | if (sa->aad->type == AUDIT_APPARMOR_KILL) |
208 | (void)send_sig_info(SIGKILL, NULL, sa->tsk ? sa->tsk : current); | 214 | (void)send_sig_info(SIGKILL, NULL, |
215 | sa->aad->tsk ? sa->aad->tsk : current); | ||
209 | 216 | ||
210 | if (sa->aad->type == AUDIT_APPARMOR_ALLOWED) | 217 | if (sa->aad->type == AUDIT_APPARMOR_ALLOWED) |
211 | return complain_error(sa->aad->error); | 218 | return complain_error(sa->aad->error); |
diff --git a/security/apparmor/capability.c b/security/apparmor/capability.c index 088dba3bf7dc..887a5e948945 100644 --- a/security/apparmor/capability.c +++ b/security/apparmor/capability.c | |||
@@ -65,10 +65,10 @@ static int audit_caps(struct aa_profile *profile, struct task_struct *task, | |||
65 | int type = AUDIT_APPARMOR_AUTO; | 65 | int type = AUDIT_APPARMOR_AUTO; |
66 | struct common_audit_data sa; | 66 | struct common_audit_data sa; |
67 | struct apparmor_audit_data aad = {0,}; | 67 | struct apparmor_audit_data aad = {0,}; |
68 | COMMON_AUDIT_DATA_INIT(&sa, CAP); | 68 | sa.type = LSM_AUDIT_DATA_CAP; |
69 | sa.aad = &aad; | 69 | sa.aad = &aad; |
70 | sa.tsk = task; | ||
71 | sa.u.cap = cap; | 70 | sa.u.cap = cap; |
71 | sa.aad->tsk = task; | ||
72 | sa.aad->op = OP_CAPABLE; | 72 | sa.aad->op = OP_CAPABLE; |
73 | sa.aad->error = error; | 73 | sa.aad->error = error; |
74 | 74 | ||
diff --git a/security/apparmor/domain.c b/security/apparmor/domain.c index 6327685c101e..b81ea10a17a3 100644 --- a/security/apparmor/domain.c +++ b/security/apparmor/domain.c | |||
@@ -394,6 +394,11 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) | |||
394 | new_profile = find_attach(ns, &ns->base.profiles, name); | 394 | new_profile = find_attach(ns, &ns->base.profiles, name); |
395 | if (!new_profile) | 395 | if (!new_profile) |
396 | goto cleanup; | 396 | goto cleanup; |
397 | /* | ||
398 | * NOTE: Domain transitions from unconfined are allowed | ||
399 | * even when no_new_privs is set because this aways results | ||
400 | * in a further reduction of permissions. | ||
401 | */ | ||
397 | goto apply; | 402 | goto apply; |
398 | } | 403 | } |
399 | 404 | ||
@@ -455,6 +460,16 @@ int apparmor_bprm_set_creds(struct linux_binprm *bprm) | |||
455 | /* fail exec */ | 460 | /* fail exec */ |
456 | error = -EACCES; | 461 | error = -EACCES; |
457 | 462 | ||
463 | /* | ||
464 | * Policy has specified a domain transition, if no_new_privs then | ||
465 | * fail the exec. | ||
466 | */ | ||
467 | if (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS) { | ||
468 | aa_put_profile(new_profile); | ||
469 | error = -EPERM; | ||
470 | goto cleanup; | ||
471 | } | ||
472 | |||
458 | if (!new_profile) | 473 | if (!new_profile) |
459 | goto audit; | 474 | goto audit; |
460 | 475 | ||
@@ -609,6 +624,14 @@ int aa_change_hat(const char *hats[], int count, u64 token, bool permtest) | |||
609 | const char *target = NULL, *info = NULL; | 624 | const char *target = NULL, *info = NULL; |
610 | int error = 0; | 625 | int error = 0; |
611 | 626 | ||
627 | /* | ||
628 | * Fail explicitly requested domain transitions if no_new_privs. | ||
629 | * There is no exception for unconfined as change_hat is not | ||
630 | * available. | ||
631 | */ | ||
632 | if (current->no_new_privs) | ||
633 | return -EPERM; | ||
634 | |||
612 | /* released below */ | 635 | /* released below */ |
613 | cred = get_current_cred(); | 636 | cred = get_current_cred(); |
614 | cxt = cred->security; | 637 | cxt = cred->security; |
@@ -750,6 +773,18 @@ int aa_change_profile(const char *ns_name, const char *hname, bool onexec, | |||
750 | cxt = cred->security; | 773 | cxt = cred->security; |
751 | profile = aa_cred_profile(cred); | 774 | profile = aa_cred_profile(cred); |
752 | 775 | ||
776 | /* | ||
777 | * Fail explicitly requested domain transitions if no_new_privs | ||
778 | * and not unconfined. | ||
779 | * Domain transitions from unconfined are allowed even when | ||
780 | * no_new_privs is set because this aways results in a reduction | ||
781 | * of permissions. | ||
782 | */ | ||
783 | if (current->no_new_privs && !unconfined(profile)) { | ||
784 | put_cred(cred); | ||
785 | return -EPERM; | ||
786 | } | ||
787 | |||
753 | if (ns_name) { | 788 | if (ns_name) { |
754 | /* released below */ | 789 | /* released below */ |
755 | ns = aa_find_namespace(profile->ns, ns_name); | 790 | ns = aa_find_namespace(profile->ns, ns_name); |
diff --git a/security/apparmor/file.c b/security/apparmor/file.c index 2f8fcba9ce4b..cf19d4093ca4 100644 --- a/security/apparmor/file.c +++ b/security/apparmor/file.c | |||
@@ -108,7 +108,7 @@ int aa_audit_file(struct aa_profile *profile, struct file_perms *perms, | |||
108 | int type = AUDIT_APPARMOR_AUTO; | 108 | int type = AUDIT_APPARMOR_AUTO; |
109 | struct common_audit_data sa; | 109 | struct common_audit_data sa; |
110 | struct apparmor_audit_data aad = {0,}; | 110 | struct apparmor_audit_data aad = {0,}; |
111 | COMMON_AUDIT_DATA_INIT(&sa, NONE); | 111 | sa.type = LSM_AUDIT_DATA_NONE; |
112 | sa.aad = &aad; | 112 | sa.aad = &aad; |
113 | aad.op = op, | 113 | aad.op = op, |
114 | aad.fs.request = request; | 114 | aad.fs.request = request; |
diff --git a/security/apparmor/include/audit.h b/security/apparmor/include/audit.h index 3868b1e5d5ba..4b7e18951aea 100644 --- a/security/apparmor/include/audit.h +++ b/security/apparmor/include/audit.h | |||
@@ -110,6 +110,7 @@ struct apparmor_audit_data { | |||
110 | void *profile; | 110 | void *profile; |
111 | const char *name; | 111 | const char *name; |
112 | const char *info; | 112 | const char *info; |
113 | struct task_struct *tsk; | ||
113 | union { | 114 | union { |
114 | void *target; | 115 | void *target; |
115 | struct { | 116 | struct { |
diff --git a/security/apparmor/ipc.c b/security/apparmor/ipc.c index c3da93a5150d..cf1071b14232 100644 --- a/security/apparmor/ipc.c +++ b/security/apparmor/ipc.c | |||
@@ -42,7 +42,7 @@ static int aa_audit_ptrace(struct aa_profile *profile, | |||
42 | { | 42 | { |
43 | struct common_audit_data sa; | 43 | struct common_audit_data sa; |
44 | struct apparmor_audit_data aad = {0,}; | 44 | struct apparmor_audit_data aad = {0,}; |
45 | COMMON_AUDIT_DATA_INIT(&sa, NONE); | 45 | sa.type = LSM_AUDIT_DATA_NONE; |
46 | sa.aad = &aad; | 46 | sa.aad = &aad; |
47 | aad.op = OP_PTRACE; | 47 | aad.op = OP_PTRACE; |
48 | aad.target = target; | 48 | aad.target = target; |
diff --git a/security/apparmor/lib.c b/security/apparmor/lib.c index e75829ba0ff9..7430298116d6 100644 --- a/security/apparmor/lib.c +++ b/security/apparmor/lib.c | |||
@@ -66,7 +66,7 @@ void aa_info_message(const char *str) | |||
66 | if (audit_enabled) { | 66 | if (audit_enabled) { |
67 | struct common_audit_data sa; | 67 | struct common_audit_data sa; |
68 | struct apparmor_audit_data aad = {0,}; | 68 | struct apparmor_audit_data aad = {0,}; |
69 | COMMON_AUDIT_DATA_INIT(&sa, NONE); | 69 | sa.type = LSM_AUDIT_DATA_NONE; |
70 | sa.aad = &aad; | 70 | sa.aad = &aad; |
71 | aad.info = str; | 71 | aad.info = str; |
72 | aa_audit_msg(AUDIT_APPARMOR_STATUS, &sa, NULL); | 72 | aa_audit_msg(AUDIT_APPARMOR_STATUS, &sa, NULL); |
diff --git a/security/apparmor/lsm.c b/security/apparmor/lsm.c index ad05d391974d..032daab449b0 100644 --- a/security/apparmor/lsm.c +++ b/security/apparmor/lsm.c | |||
@@ -373,7 +373,7 @@ static int apparmor_inode_getattr(struct vfsmount *mnt, struct dentry *dentry) | |||
373 | AA_MAY_META_READ); | 373 | AA_MAY_META_READ); |
374 | } | 374 | } |
375 | 375 | ||
376 | static int apparmor_dentry_open(struct file *file, const struct cred *cred) | 376 | static int apparmor_file_open(struct file *file, const struct cred *cred) |
377 | { | 377 | { |
378 | struct aa_file_cxt *fcxt = file->f_security; | 378 | struct aa_file_cxt *fcxt = file->f_security; |
379 | struct aa_profile *profile; | 379 | struct aa_profile *profile; |
@@ -589,7 +589,7 @@ static int apparmor_setprocattr(struct task_struct *task, char *name, | |||
589 | } else { | 589 | } else { |
590 | struct common_audit_data sa; | 590 | struct common_audit_data sa; |
591 | struct apparmor_audit_data aad = {0,}; | 591 | struct apparmor_audit_data aad = {0,}; |
592 | COMMON_AUDIT_DATA_INIT(&sa, NONE); | 592 | sa.type = LSM_AUDIT_DATA_NONE; |
593 | sa.aad = &aad; | 593 | sa.aad = &aad; |
594 | aad.op = OP_SETPROCATTR; | 594 | aad.op = OP_SETPROCATTR; |
595 | aad.info = name; | 595 | aad.info = name; |
@@ -640,9 +640,9 @@ static struct security_operations apparmor_ops = { | |||
640 | .path_chmod = apparmor_path_chmod, | 640 | .path_chmod = apparmor_path_chmod, |
641 | .path_chown = apparmor_path_chown, | 641 | .path_chown = apparmor_path_chown, |
642 | .path_truncate = apparmor_path_truncate, | 642 | .path_truncate = apparmor_path_truncate, |
643 | .dentry_open = apparmor_dentry_open, | ||
644 | .inode_getattr = apparmor_inode_getattr, | 643 | .inode_getattr = apparmor_inode_getattr, |
645 | 644 | ||
645 | .file_open = apparmor_file_open, | ||
646 | .file_permission = apparmor_file_permission, | 646 | .file_permission = apparmor_file_permission, |
647 | .file_alloc_security = apparmor_file_alloc_security, | 647 | .file_alloc_security = apparmor_file_alloc_security, |
648 | .file_free_security = apparmor_file_free_security, | 648 | .file_free_security = apparmor_file_free_security, |
diff --git a/security/apparmor/path.c b/security/apparmor/path.c index 2daeea4f9266..e91ffee80162 100644 --- a/security/apparmor/path.c +++ b/security/apparmor/path.c | |||
@@ -94,6 +94,8 @@ static int d_namespace_path(struct path *path, char *buf, int buflen, | |||
94 | * be returned. | 94 | * be returned. |
95 | */ | 95 | */ |
96 | if (!res || IS_ERR(res)) { | 96 | if (!res || IS_ERR(res)) { |
97 | if (PTR_ERR(res) == -ENAMETOOLONG) | ||
98 | return -ENAMETOOLONG; | ||
97 | connected = 0; | 99 | connected = 0; |
98 | res = dentry_path_raw(path->dentry, buf, buflen); | 100 | res = dentry_path_raw(path->dentry, buf, buflen); |
99 | if (IS_ERR(res)) { | 101 | if (IS_ERR(res)) { |
diff --git a/security/apparmor/policy.c b/security/apparmor/policy.c index f1f7506a464d..cf5fd220309b 100644 --- a/security/apparmor/policy.c +++ b/security/apparmor/policy.c | |||
@@ -903,6 +903,10 @@ struct aa_profile *aa_lookup_profile(struct aa_namespace *ns, const char *hname) | |||
903 | profile = aa_get_profile(__lookup_profile(&ns->base, hname)); | 903 | profile = aa_get_profile(__lookup_profile(&ns->base, hname)); |
904 | read_unlock(&ns->lock); | 904 | read_unlock(&ns->lock); |
905 | 905 | ||
906 | /* the unconfined profile is not in the regular profile list */ | ||
907 | if (!profile && strcmp(hname, "unconfined") == 0) | ||
908 | profile = aa_get_profile(ns->unconfined); | ||
909 | |||
906 | /* refcount released by caller */ | 910 | /* refcount released by caller */ |
907 | return profile; | 911 | return profile; |
908 | } | 912 | } |
@@ -965,7 +969,7 @@ static int audit_policy(int op, gfp_t gfp, const char *name, const char *info, | |||
965 | { | 969 | { |
966 | struct common_audit_data sa; | 970 | struct common_audit_data sa; |
967 | struct apparmor_audit_data aad = {0,}; | 971 | struct apparmor_audit_data aad = {0,}; |
968 | COMMON_AUDIT_DATA_INIT(&sa, NONE); | 972 | sa.type = LSM_AUDIT_DATA_NONE; |
969 | sa.aad = &aad; | 973 | sa.aad = &aad; |
970 | aad.op = op; | 974 | aad.op = op; |
971 | aad.name = name; | 975 | aad.name = name; |
diff --git a/security/apparmor/policy_unpack.c b/security/apparmor/policy_unpack.c index deab7c7e8dc0..329b1fd30749 100644 --- a/security/apparmor/policy_unpack.c +++ b/security/apparmor/policy_unpack.c | |||
@@ -95,7 +95,7 @@ static int audit_iface(struct aa_profile *new, const char *name, | |||
95 | struct aa_profile *profile = __aa_current_profile(); | 95 | struct aa_profile *profile = __aa_current_profile(); |
96 | struct common_audit_data sa; | 96 | struct common_audit_data sa; |
97 | struct apparmor_audit_data aad = {0,}; | 97 | struct apparmor_audit_data aad = {0,}; |
98 | COMMON_AUDIT_DATA_INIT(&sa, NONE); | 98 | sa.type = LSM_AUDIT_DATA_NONE; |
99 | sa.aad = &aad; | 99 | sa.aad = &aad; |
100 | if (e) | 100 | if (e) |
101 | aad.iface.pos = e->pos - e->start; | 101 | aad.iface.pos = e->pos - e->start; |
diff --git a/security/apparmor/resource.c b/security/apparmor/resource.c index 2fe8613efe33..e1f3d7ef2c54 100644 --- a/security/apparmor/resource.c +++ b/security/apparmor/resource.c | |||
@@ -52,7 +52,7 @@ static int audit_resource(struct aa_profile *profile, unsigned int resource, | |||
52 | struct common_audit_data sa; | 52 | struct common_audit_data sa; |
53 | struct apparmor_audit_data aad = {0,}; | 53 | struct apparmor_audit_data aad = {0,}; |
54 | 54 | ||
55 | COMMON_AUDIT_DATA_INIT(&sa, NONE); | 55 | sa.type = LSM_AUDIT_DATA_NONE; |
56 | sa.aad = &aad; | 56 | sa.aad = &aad; |
57 | aad.op = OP_SETRLIMIT, | 57 | aad.op = OP_SETRLIMIT, |
58 | aad.rlim.rlim = resource; | 58 | aad.rlim.rlim = resource; |
diff --git a/security/capability.c b/security/capability.c index 5bb21b1c448c..fca889676c5e 100644 --- a/security/capability.c +++ b/security/capability.c | |||
@@ -348,7 +348,7 @@ static int cap_file_receive(struct file *file) | |||
348 | return 0; | 348 | return 0; |
349 | } | 349 | } |
350 | 350 | ||
351 | static int cap_dentry_open(struct file *file, const struct cred *cred) | 351 | static int cap_file_open(struct file *file, const struct cred *cred) |
352 | { | 352 | { |
353 | return 0; | 353 | return 0; |
354 | } | 354 | } |
@@ -956,7 +956,7 @@ void __init security_fixup_ops(struct security_operations *ops) | |||
956 | set_to_cap_if_null(ops, file_set_fowner); | 956 | set_to_cap_if_null(ops, file_set_fowner); |
957 | set_to_cap_if_null(ops, file_send_sigiotask); | 957 | set_to_cap_if_null(ops, file_send_sigiotask); |
958 | set_to_cap_if_null(ops, file_receive); | 958 | set_to_cap_if_null(ops, file_receive); |
959 | set_to_cap_if_null(ops, dentry_open); | 959 | set_to_cap_if_null(ops, file_open); |
960 | set_to_cap_if_null(ops, task_create); | 960 | set_to_cap_if_null(ops, task_create); |
961 | set_to_cap_if_null(ops, task_free); | 961 | set_to_cap_if_null(ops, task_free); |
962 | set_to_cap_if_null(ops, cred_alloc_blank); | 962 | set_to_cap_if_null(ops, cred_alloc_blank); |
diff --git a/security/commoncap.c b/security/commoncap.c index 71a166a05975..f80d11609391 100644 --- a/security/commoncap.c +++ b/security/commoncap.c | |||
@@ -512,14 +512,17 @@ skip: | |||
512 | 512 | ||
513 | 513 | ||
514 | /* Don't let someone trace a set[ug]id/setpcap binary with the revised | 514 | /* Don't let someone trace a set[ug]id/setpcap binary with the revised |
515 | * credentials unless they have the appropriate permit | 515 | * credentials unless they have the appropriate permit. |
516 | * | ||
517 | * In addition, if NO_NEW_PRIVS, then ensure we get no new privs. | ||
516 | */ | 518 | */ |
517 | if ((new->euid != old->uid || | 519 | if ((new->euid != old->uid || |
518 | new->egid != old->gid || | 520 | new->egid != old->gid || |
519 | !cap_issubset(new->cap_permitted, old->cap_permitted)) && | 521 | !cap_issubset(new->cap_permitted, old->cap_permitted)) && |
520 | bprm->unsafe & ~LSM_UNSAFE_PTRACE_CAP) { | 522 | bprm->unsafe & ~LSM_UNSAFE_PTRACE_CAP) { |
521 | /* downgrade; they get no more than they had, and maybe less */ | 523 | /* downgrade; they get no more than they had, and maybe less */ |
522 | if (!capable(CAP_SETUID)) { | 524 | if (!capable(CAP_SETUID) || |
525 | (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS)) { | ||
523 | new->euid = new->uid; | 526 | new->euid = new->uid; |
524 | new->egid = new->gid; | 527 | new->egid = new->gid; |
525 | } | 528 | } |
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c index 1eff5cb001e5..b17be79b9cf2 100644 --- a/security/integrity/ima/ima_main.c +++ b/security/integrity/ima/ima_main.c | |||
@@ -194,7 +194,9 @@ int ima_bprm_check(struct linux_binprm *bprm) | |||
194 | { | 194 | { |
195 | int rc; | 195 | int rc; |
196 | 196 | ||
197 | rc = process_measurement(bprm->file, bprm->filename, | 197 | rc = process_measurement(bprm->file, |
198 | (strcmp(bprm->filename, bprm->interp) == 0) ? | ||
199 | bprm->filename : bprm->interp, | ||
198 | MAY_EXEC, BPRM_CHECK); | 200 | MAY_EXEC, BPRM_CHECK); |
199 | return 0; | 201 | return 0; |
200 | } | 202 | } |
diff --git a/security/keys/Kconfig b/security/keys/Kconfig new file mode 100644 index 000000000000..a90d6d300dbd --- /dev/null +++ b/security/keys/Kconfig | |||
@@ -0,0 +1,71 @@ | |||
1 | # | ||
2 | # Key management configuration | ||
3 | # | ||
4 | |||
5 | config KEYS | ||
6 | bool "Enable access key retention support" | ||
7 | help | ||
8 | This option provides support for retaining authentication tokens and | ||
9 | access keys in the kernel. | ||
10 | |||
11 | It also includes provision of methods by which such keys might be | ||
12 | associated with a process so that network filesystems, encryption | ||
13 | support and the like can find them. | ||
14 | |||
15 | Furthermore, a special type of key is available that acts as keyring: | ||
16 | a searchable sequence of keys. Each process is equipped with access | ||
17 | to five standard keyrings: UID-specific, GID-specific, session, | ||
18 | process and thread. | ||
19 | |||
20 | If you are unsure as to whether this is required, answer N. | ||
21 | |||
22 | config TRUSTED_KEYS | ||
23 | tristate "TRUSTED KEYS" | ||
24 | depends on KEYS && TCG_TPM | ||
25 | select CRYPTO | ||
26 | select CRYPTO_HMAC | ||
27 | select CRYPTO_SHA1 | ||
28 | help | ||
29 | This option provides support for creating, sealing, and unsealing | ||
30 | keys in the kernel. Trusted keys are random number symmetric keys, | ||
31 | generated and RSA-sealed by the TPM. The TPM only unseals the keys, | ||
32 | if the boot PCRs and other criteria match. Userspace will only ever | ||
33 | see encrypted blobs. | ||
34 | |||
35 | If you are unsure as to whether this is required, answer N. | ||
36 | |||
37 | config ENCRYPTED_KEYS | ||
38 | tristate "ENCRYPTED KEYS" | ||
39 | depends on KEYS | ||
40 | select CRYPTO | ||
41 | select CRYPTO_HMAC | ||
42 | select CRYPTO_AES | ||
43 | select CRYPTO_CBC | ||
44 | select CRYPTO_SHA256 | ||
45 | select CRYPTO_RNG | ||
46 | help | ||
47 | This option provides support for create/encrypting/decrypting keys | ||
48 | in the kernel. Encrypted keys are kernel generated random numbers, | ||
49 | which are encrypted/decrypted with a 'master' symmetric key. The | ||
50 | 'master' key can be either a trusted-key or user-key type. | ||
51 | Userspace only ever sees/stores encrypted blobs. | ||
52 | |||
53 | If you are unsure as to whether this is required, answer N. | ||
54 | |||
55 | config KEYS_DEBUG_PROC_KEYS | ||
56 | bool "Enable the /proc/keys file by which keys may be viewed" | ||
57 | depends on KEYS | ||
58 | help | ||
59 | This option turns on support for the /proc/keys file - through which | ||
60 | can be listed all the keys on the system that are viewable by the | ||
61 | reading process. | ||
62 | |||
63 | The only keys included in the list are those that grant View | ||
64 | permission to the reading process whether or not it possesses them. | ||
65 | Note that LSM security checks are still performed, and may further | ||
66 | filter out keys that the current process is not authorised to view. | ||
67 | |||
68 | Only key attributes are listed here; key payloads are not included in | ||
69 | the resulting table. | ||
70 | |||
71 | If you are unsure as to whether this is required, answer N. | ||
diff --git a/security/keys/Makefile b/security/keys/Makefile index a56f1ffdc64d..504aaa008388 100644 --- a/security/keys/Makefile +++ b/security/keys/Makefile | |||
@@ -2,6 +2,9 @@ | |||
2 | # Makefile for key management | 2 | # Makefile for key management |
3 | # | 3 | # |
4 | 4 | ||
5 | # | ||
6 | # Core | ||
7 | # | ||
5 | obj-y := \ | 8 | obj-y := \ |
6 | gc.o \ | 9 | gc.o \ |
7 | key.o \ | 10 | key.o \ |
@@ -12,9 +15,12 @@ obj-y := \ | |||
12 | request_key.o \ | 15 | request_key.o \ |
13 | request_key_auth.o \ | 16 | request_key_auth.o \ |
14 | user_defined.o | 17 | user_defined.o |
15 | |||
16 | obj-$(CONFIG_TRUSTED_KEYS) += trusted.o | ||
17 | obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted-keys/ | ||
18 | obj-$(CONFIG_KEYS_COMPAT) += compat.o | 18 | obj-$(CONFIG_KEYS_COMPAT) += compat.o |
19 | obj-$(CONFIG_PROC_FS) += proc.o | 19 | obj-$(CONFIG_PROC_FS) += proc.o |
20 | obj-$(CONFIG_SYSCTL) += sysctl.o | 20 | obj-$(CONFIG_SYSCTL) += sysctl.o |
21 | |||
22 | # | ||
23 | # Key types | ||
24 | # | ||
25 | obj-$(CONFIG_TRUSTED_KEYS) += trusted.o | ||
26 | obj-$(CONFIG_ENCRYPTED_KEYS) += encrypted-keys/ | ||
diff --git a/security/keys/compat.c b/security/keys/compat.c index 4c48e13448f8..fab4f8dda6c6 100644 --- a/security/keys/compat.c +++ b/security/keys/compat.c | |||
@@ -135,6 +135,9 @@ asmlinkage long compat_sys_keyctl(u32 option, | |||
135 | return compat_keyctl_instantiate_key_iov( | 135 | return compat_keyctl_instantiate_key_iov( |
136 | arg2, compat_ptr(arg3), arg4, arg5); | 136 | arg2, compat_ptr(arg3), arg4, arg5); |
137 | 137 | ||
138 | case KEYCTL_INVALIDATE: | ||
139 | return keyctl_invalidate_key(arg2); | ||
140 | |||
138 | default: | 141 | default: |
139 | return -EOPNOTSUPP; | 142 | return -EOPNOTSUPP; |
140 | } | 143 | } |
diff --git a/security/keys/gc.c b/security/keys/gc.c index a42b45531aac..61ab7c82ebb1 100644 --- a/security/keys/gc.c +++ b/security/keys/gc.c | |||
@@ -72,6 +72,15 @@ void key_schedule_gc(time_t gc_at) | |||
72 | } | 72 | } |
73 | 73 | ||
74 | /* | 74 | /* |
75 | * Schedule a dead links collection run. | ||
76 | */ | ||
77 | void key_schedule_gc_links(void) | ||
78 | { | ||
79 | set_bit(KEY_GC_KEY_EXPIRED, &key_gc_flags); | ||
80 | queue_work(system_nrt_wq, &key_gc_work); | ||
81 | } | ||
82 | |||
83 | /* | ||
75 | * 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 |
76 | * reaper to go through a cycle finding expired keys. | 85 | * reaper to go through a cycle finding expired keys. |
77 | */ | 86 | */ |
@@ -79,8 +88,7 @@ static void key_gc_timer_func(unsigned long data) | |||
79 | { | 88 | { |
80 | kenter(""); | 89 | kenter(""); |
81 | key_gc_next_run = LONG_MAX; | 90 | key_gc_next_run = LONG_MAX; |
82 | set_bit(KEY_GC_KEY_EXPIRED, &key_gc_flags); | 91 | key_schedule_gc_links(); |
83 | queue_work(system_nrt_wq, &key_gc_work); | ||
84 | } | 92 | } |
85 | 93 | ||
86 | /* | 94 | /* |
@@ -131,12 +139,12 @@ void key_gc_keytype(struct key_type *ktype) | |||
131 | static void key_gc_keyring(struct key *keyring, time_t limit) | 139 | static void key_gc_keyring(struct key *keyring, time_t limit) |
132 | { | 140 | { |
133 | struct keyring_list *klist; | 141 | struct keyring_list *klist; |
134 | struct key *key; | ||
135 | int loop; | 142 | int loop; |
136 | 143 | ||
137 | kenter("%x", key_serial(keyring)); | 144 | kenter("%x", key_serial(keyring)); |
138 | 145 | ||
139 | if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) | 146 | if (keyring->flags & ((1 << KEY_FLAG_INVALIDATED) | |
147 | (1 << KEY_FLAG_REVOKED))) | ||
140 | goto dont_gc; | 148 | goto dont_gc; |
141 | 149 | ||
142 | /* scan the keyring looking for dead keys */ | 150 | /* scan the keyring looking for dead keys */ |
@@ -148,9 +156,8 @@ static void key_gc_keyring(struct key *keyring, time_t limit) | |||
148 | loop = klist->nkeys; | 156 | loop = klist->nkeys; |
149 | smp_rmb(); | 157 | smp_rmb(); |
150 | for (loop--; loop >= 0; loop--) { | 158 | for (loop--; loop >= 0; loop--) { |
151 | key = klist->keys[loop]; | 159 | struct key *key = rcu_dereference(klist->keys[loop]); |
152 | if (test_bit(KEY_FLAG_DEAD, &key->flags) || | 160 | if (key_is_dead(key, limit)) |
153 | (key->expiry > 0 && key->expiry <= limit)) | ||
154 | goto do_gc; | 161 | goto do_gc; |
155 | } | 162 | } |
156 | 163 | ||
@@ -168,38 +175,45 @@ do_gc: | |||
168 | } | 175 | } |
169 | 176 | ||
170 | /* | 177 | /* |
171 | * Garbage collect an unreferenced, detached key | 178 | * Garbage collect a list of unreferenced, detached keys |
172 | */ | 179 | */ |
173 | static noinline void key_gc_unused_key(struct key *key) | 180 | static noinline void key_gc_unused_keys(struct list_head *keys) |
174 | { | 181 | { |
175 | key_check(key); | 182 | while (!list_empty(keys)) { |
176 | 183 | struct key *key = | |
177 | security_key_free(key); | 184 | list_entry(keys->next, struct key, graveyard_link); |
178 | 185 | list_del(&key->graveyard_link); | |
179 | /* deal with the user's key tracking and quota */ | 186 | |
180 | if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) { | 187 | kdebug("- %u", key->serial); |
181 | spin_lock(&key->user->lock); | 188 | key_check(key); |
182 | key->user->qnkeys--; | 189 | |
183 | key->user->qnbytes -= key->quotalen; | 190 | security_key_free(key); |
184 | spin_unlock(&key->user->lock); | 191 | |
185 | } | 192 | /* deal with the user's key tracking and quota */ |
193 | if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) { | ||
194 | spin_lock(&key->user->lock); | ||
195 | key->user->qnkeys--; | ||
196 | key->user->qnbytes -= key->quotalen; | ||
197 | spin_unlock(&key->user->lock); | ||
198 | } | ||
186 | 199 | ||
187 | atomic_dec(&key->user->nkeys); | 200 | atomic_dec(&key->user->nkeys); |
188 | if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) | 201 | if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) |
189 | atomic_dec(&key->user->nikeys); | 202 | atomic_dec(&key->user->nikeys); |
190 | 203 | ||
191 | key_user_put(key->user); | 204 | key_user_put(key->user); |
192 | 205 | ||
193 | /* now throw away the key memory */ | 206 | /* now throw away the key memory */ |
194 | if (key->type->destroy) | 207 | if (key->type->destroy) |
195 | key->type->destroy(key); | 208 | key->type->destroy(key); |
196 | 209 | ||
197 | kfree(key->description); | 210 | kfree(key->description); |
198 | 211 | ||
199 | #ifdef KEY_DEBUGGING | 212 | #ifdef KEY_DEBUGGING |
200 | key->magic = KEY_DEBUG_MAGIC_X; | 213 | key->magic = KEY_DEBUG_MAGIC_X; |
201 | #endif | 214 | #endif |
202 | kmem_cache_free(key_jar, key); | 215 | kmem_cache_free(key_jar, key); |
216 | } | ||
203 | } | 217 | } |
204 | 218 | ||
205 | /* | 219 | /* |
@@ -211,6 +225,7 @@ static noinline void key_gc_unused_key(struct key *key) | |||
211 | */ | 225 | */ |
212 | static void key_garbage_collector(struct work_struct *work) | 226 | static void key_garbage_collector(struct work_struct *work) |
213 | { | 227 | { |
228 | static LIST_HEAD(graveyard); | ||
214 | static u8 gc_state; /* Internal persistent state */ | 229 | static u8 gc_state; /* Internal persistent state */ |
215 | #define KEY_GC_REAP_AGAIN 0x01 /* - Need another cycle */ | 230 | #define KEY_GC_REAP_AGAIN 0x01 /* - Need another cycle */ |
216 | #define KEY_GC_REAPING_LINKS 0x02 /* - We need to reap links */ | 231 | #define KEY_GC_REAPING_LINKS 0x02 /* - We need to reap links */ |
@@ -316,15 +331,22 @@ maybe_resched: | |||
316 | key_schedule_gc(new_timer); | 331 | key_schedule_gc(new_timer); |
317 | } | 332 | } |
318 | 333 | ||
319 | if (unlikely(gc_state & KEY_GC_REAPING_DEAD_2)) { | 334 | if (unlikely(gc_state & KEY_GC_REAPING_DEAD_2) || |
320 | /* Make sure everyone revalidates their keys if we marked a | 335 | !list_empty(&graveyard)) { |
321 | * bunch as being dead and make sure all keyring ex-payloads | 336 | /* Make sure that all pending keyring payload destructions are |
322 | * are destroyed. | 337 | * fulfilled and that people aren't now looking at dead or |
338 | * dying keys that they don't have a reference upon or a link | ||
339 | * to. | ||
323 | */ | 340 | */ |
324 | kdebug("dead sync"); | 341 | kdebug("gc sync"); |
325 | synchronize_rcu(); | 342 | synchronize_rcu(); |
326 | } | 343 | } |
327 | 344 | ||
345 | if (!list_empty(&graveyard)) { | ||
346 | kdebug("gc keys"); | ||
347 | key_gc_unused_keys(&graveyard); | ||
348 | } | ||
349 | |||
328 | if (unlikely(gc_state & (KEY_GC_REAPING_DEAD_1 | | 350 | if (unlikely(gc_state & (KEY_GC_REAPING_DEAD_1 | |
329 | KEY_GC_REAPING_DEAD_2))) { | 351 | KEY_GC_REAPING_DEAD_2))) { |
330 | if (!(gc_state & KEY_GC_FOUND_DEAD_KEY)) { | 352 | if (!(gc_state & KEY_GC_FOUND_DEAD_KEY)) { |
@@ -359,7 +381,7 @@ found_unreferenced_key: | |||
359 | rb_erase(&key->serial_node, &key_serial_tree); | 381 | rb_erase(&key->serial_node, &key_serial_tree); |
360 | spin_unlock(&key_serial_lock); | 382 | spin_unlock(&key_serial_lock); |
361 | 383 | ||
362 | key_gc_unused_key(key); | 384 | list_add_tail(&key->graveyard_link, &graveyard); |
363 | gc_state |= KEY_GC_REAP_AGAIN; | 385 | gc_state |= KEY_GC_REAP_AGAIN; |
364 | goto maybe_resched; | 386 | goto maybe_resched; |
365 | 387 | ||
diff --git a/security/keys/internal.h b/security/keys/internal.h index 65647f825584..f711b094ed41 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h | |||
@@ -152,7 +152,8 @@ extern long join_session_keyring(const char *name); | |||
152 | extern struct work_struct key_gc_work; | 152 | extern struct work_struct key_gc_work; |
153 | extern unsigned key_gc_delay; | 153 | extern unsigned key_gc_delay; |
154 | extern void keyring_gc(struct key *keyring, time_t limit); | 154 | extern void keyring_gc(struct key *keyring, time_t limit); |
155 | extern void key_schedule_gc(time_t expiry_at); | 155 | extern void key_schedule_gc(time_t gc_at); |
156 | extern void key_schedule_gc_links(void); | ||
156 | extern void key_gc_keytype(struct key_type *ktype); | 157 | extern void key_gc_keytype(struct key_type *ktype); |
157 | 158 | ||
158 | extern int key_task_permission(const key_ref_t key_ref, | 159 | extern int key_task_permission(const key_ref_t key_ref, |
@@ -197,6 +198,17 @@ extern struct key *request_key_auth_new(struct key *target, | |||
197 | extern struct key *key_get_instantiation_authkey(key_serial_t target_id); | 198 | extern struct key *key_get_instantiation_authkey(key_serial_t target_id); |
198 | 199 | ||
199 | /* | 200 | /* |
201 | * Determine whether a key is dead. | ||
202 | */ | ||
203 | static inline bool key_is_dead(struct key *key, time_t limit) | ||
204 | { | ||
205 | return | ||
206 | key->flags & ((1 << KEY_FLAG_DEAD) | | ||
207 | (1 << KEY_FLAG_INVALIDATED)) || | ||
208 | (key->expiry > 0 && key->expiry <= limit); | ||
209 | } | ||
210 | |||
211 | /* | ||
200 | * keyctl() functions | 212 | * keyctl() functions |
201 | */ | 213 | */ |
202 | extern long keyctl_get_keyring_ID(key_serial_t, int); | 214 | extern long keyctl_get_keyring_ID(key_serial_t, int); |
@@ -225,6 +237,7 @@ extern long keyctl_reject_key(key_serial_t, unsigned, unsigned, key_serial_t); | |||
225 | extern long keyctl_instantiate_key_iov(key_serial_t, | 237 | extern long keyctl_instantiate_key_iov(key_serial_t, |
226 | const struct iovec __user *, | 238 | const struct iovec __user *, |
227 | unsigned, key_serial_t); | 239 | unsigned, key_serial_t); |
240 | extern long keyctl_invalidate_key(key_serial_t); | ||
228 | 241 | ||
229 | extern long keyctl_instantiate_key_common(key_serial_t, | 242 | extern long keyctl_instantiate_key_common(key_serial_t, |
230 | const struct iovec __user *, | 243 | const struct iovec __user *, |
diff --git a/security/keys/key.c b/security/keys/key.c index 06783cffb3af..c9bf66ac36e0 100644 --- a/security/keys/key.c +++ b/security/keys/key.c | |||
@@ -955,6 +955,28 @@ void key_revoke(struct key *key) | |||
955 | EXPORT_SYMBOL(key_revoke); | 955 | EXPORT_SYMBOL(key_revoke); |
956 | 956 | ||
957 | /** | 957 | /** |
958 | * key_invalidate - Invalidate a key. | ||
959 | * @key: The key to be invalidated. | ||
960 | * | ||
961 | * Mark a key as being invalidated and have it cleaned up immediately. The key | ||
962 | * is ignored by all searches and other operations from this point. | ||
963 | */ | ||
964 | void key_invalidate(struct key *key) | ||
965 | { | ||
966 | kenter("%d", key_serial(key)); | ||
967 | |||
968 | key_check(key); | ||
969 | |||
970 | if (!test_bit(KEY_FLAG_INVALIDATED, &key->flags)) { | ||
971 | down_write_nested(&key->sem, 1); | ||
972 | if (!test_and_set_bit(KEY_FLAG_INVALIDATED, &key->flags)) | ||
973 | key_schedule_gc_links(); | ||
974 | up_write(&key->sem); | ||
975 | } | ||
976 | } | ||
977 | EXPORT_SYMBOL(key_invalidate); | ||
978 | |||
979 | /** | ||
958 | * register_key_type - Register a type of key. | 980 | * register_key_type - Register a type of key. |
959 | * @ktype: The new key type. | 981 | * @ktype: The new key type. |
960 | * | 982 | * |
@@ -980,6 +1002,8 @@ int register_key_type(struct key_type *ktype) | |||
980 | 1002 | ||
981 | /* store the type */ | 1003 | /* store the type */ |
982 | list_add(&ktype->link, &key_types_list); | 1004 | list_add(&ktype->link, &key_types_list); |
1005 | |||
1006 | pr_notice("Key type %s registered\n", ktype->name); | ||
983 | ret = 0; | 1007 | ret = 0; |
984 | 1008 | ||
985 | out: | 1009 | out: |
@@ -1002,6 +1026,7 @@ void unregister_key_type(struct key_type *ktype) | |||
1002 | list_del_init(&ktype->link); | 1026 | list_del_init(&ktype->link); |
1003 | downgrade_write(&key_types_sem); | 1027 | downgrade_write(&key_types_sem); |
1004 | key_gc_keytype(ktype); | 1028 | key_gc_keytype(ktype); |
1029 | pr_notice("Key type %s unregistered\n", ktype->name); | ||
1005 | up_read(&key_types_sem); | 1030 | up_read(&key_types_sem); |
1006 | } | 1031 | } |
1007 | EXPORT_SYMBOL(unregister_key_type); | 1032 | EXPORT_SYMBOL(unregister_key_type); |
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index fb767c6cd99f..ddb3e05bc5fc 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c | |||
@@ -375,6 +375,37 @@ error: | |||
375 | } | 375 | } |
376 | 376 | ||
377 | /* | 377 | /* |
378 | * Invalidate a key. | ||
379 | * | ||
380 | * The key must be grant the caller Invalidate permission for this to work. | ||
381 | * The key and any links to the key will be automatically garbage collected | ||
382 | * immediately. | ||
383 | * | ||
384 | * If successful, 0 is returned. | ||
385 | */ | ||
386 | long keyctl_invalidate_key(key_serial_t id) | ||
387 | { | ||
388 | key_ref_t key_ref; | ||
389 | long ret; | ||
390 | |||
391 | kenter("%d", id); | ||
392 | |||
393 | key_ref = lookup_user_key(id, 0, KEY_SEARCH); | ||
394 | if (IS_ERR(key_ref)) { | ||
395 | ret = PTR_ERR(key_ref); | ||
396 | goto error; | ||
397 | } | ||
398 | |||
399 | key_invalidate(key_ref_to_ptr(key_ref)); | ||
400 | ret = 0; | ||
401 | |||
402 | key_ref_put(key_ref); | ||
403 | error: | ||
404 | kleave(" = %ld", ret); | ||
405 | return ret; | ||
406 | } | ||
407 | |||
408 | /* | ||
378 | * Clear the specified keyring, creating an empty process keyring if one of the | 409 | * Clear the specified keyring, creating an empty process keyring if one of the |
379 | * special keyring IDs is used. | 410 | * special keyring IDs is used. |
380 | * | 411 | * |
@@ -1622,6 +1653,9 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3, | |||
1622 | (unsigned) arg4, | 1653 | (unsigned) arg4, |
1623 | (key_serial_t) arg5); | 1654 | (key_serial_t) arg5); |
1624 | 1655 | ||
1656 | case KEYCTL_INVALIDATE: | ||
1657 | return keyctl_invalidate_key((key_serial_t) arg2); | ||
1658 | |||
1625 | default: | 1659 | default: |
1626 | return -EOPNOTSUPP; | 1660 | return -EOPNOTSUPP; |
1627 | } | 1661 | } |
diff --git a/security/keys/keyring.c b/security/keys/keyring.c index d605f75292e4..7445875f6818 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c | |||
@@ -25,6 +25,15 @@ | |||
25 | (keyring)->payload.subscriptions, \ | 25 | (keyring)->payload.subscriptions, \ |
26 | rwsem_is_locked((struct rw_semaphore *)&(keyring)->sem))) | 26 | rwsem_is_locked((struct rw_semaphore *)&(keyring)->sem))) |
27 | 27 | ||
28 | #define rcu_deref_link_locked(klist, index, keyring) \ | ||
29 | (rcu_dereference_protected( \ | ||
30 | (klist)->keys[index], \ | ||
31 | rwsem_is_locked((struct rw_semaphore *)&(keyring)->sem))) | ||
32 | |||
33 | #define MAX_KEYRING_LINKS \ | ||
34 | min_t(size_t, USHRT_MAX - 1, \ | ||
35 | ((PAGE_SIZE - sizeof(struct keyring_list)) / sizeof(struct key *))) | ||
36 | |||
28 | #define KEY_LINK_FIXQUOTA 1UL | 37 | #define KEY_LINK_FIXQUOTA 1UL |
29 | 38 | ||
30 | /* | 39 | /* |
@@ -138,6 +147,11 @@ static int keyring_match(const struct key *keyring, const void *description) | |||
138 | /* | 147 | /* |
139 | * Clean up a keyring when it is destroyed. Unpublish its name if it had one | 148 | * Clean up a keyring when it is destroyed. Unpublish its name if it had one |
140 | * and dispose of its data. | 149 | * and dispose of its data. |
150 | * | ||
151 | * The garbage collector detects the final key_put(), removes the keyring from | ||
152 | * the serial number tree and then does RCU synchronisation before coming here, | ||
153 | * so we shouldn't need to worry about code poking around here with the RCU | ||
154 | * readlock held by this time. | ||
141 | */ | 155 | */ |
142 | static void keyring_destroy(struct key *keyring) | 156 | static void keyring_destroy(struct key *keyring) |
143 | { | 157 | { |
@@ -154,11 +168,10 @@ static void keyring_destroy(struct key *keyring) | |||
154 | write_unlock(&keyring_name_lock); | 168 | write_unlock(&keyring_name_lock); |
155 | } | 169 | } |
156 | 170 | ||
157 | klist = rcu_dereference_check(keyring->payload.subscriptions, | 171 | klist = rcu_access_pointer(keyring->payload.subscriptions); |
158 | atomic_read(&keyring->usage) == 0); | ||
159 | if (klist) { | 172 | if (klist) { |
160 | for (loop = klist->nkeys - 1; loop >= 0; loop--) | 173 | for (loop = klist->nkeys - 1; loop >= 0; loop--) |
161 | key_put(klist->keys[loop]); | 174 | key_put(rcu_access_pointer(klist->keys[loop])); |
162 | kfree(klist); | 175 | kfree(klist); |
163 | } | 176 | } |
164 | } | 177 | } |
@@ -214,7 +227,8 @@ static long keyring_read(const struct key *keyring, | |||
214 | ret = -EFAULT; | 227 | ret = -EFAULT; |
215 | 228 | ||
216 | for (loop = 0; loop < klist->nkeys; loop++) { | 229 | for (loop = 0; loop < klist->nkeys; loop++) { |
217 | key = klist->keys[loop]; | 230 | key = rcu_deref_link_locked(klist, loop, |
231 | keyring); | ||
218 | 232 | ||
219 | tmp = sizeof(key_serial_t); | 233 | tmp = sizeof(key_serial_t); |
220 | if (tmp > buflen) | 234 | if (tmp > buflen) |
@@ -309,6 +323,8 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref, | |||
309 | bool no_state_check) | 323 | bool no_state_check) |
310 | { | 324 | { |
311 | struct { | 325 | struct { |
326 | /* Need a separate keylist pointer for RCU purposes */ | ||
327 | struct key *keyring; | ||
312 | struct keyring_list *keylist; | 328 | struct keyring_list *keylist; |
313 | int kix; | 329 | int kix; |
314 | } stack[KEYRING_SEARCH_MAX_DEPTH]; | 330 | } stack[KEYRING_SEARCH_MAX_DEPTH]; |
@@ -366,13 +382,17 @@ key_ref_t keyring_search_aux(key_ref_t keyring_ref, | |||
366 | /* otherwise, the top keyring must not be revoked, expired, or | 382 | /* otherwise, the top keyring must not be revoked, expired, or |
367 | * negatively instantiated if we are to search it */ | 383 | * negatively instantiated if we are to search it */ |
368 | key_ref = ERR_PTR(-EAGAIN); | 384 | key_ref = ERR_PTR(-EAGAIN); |
369 | if (kflags & ((1 << KEY_FLAG_REVOKED) | (1 << KEY_FLAG_NEGATIVE)) || | 385 | if (kflags & ((1 << KEY_FLAG_INVALIDATED) | |
386 | (1 << KEY_FLAG_REVOKED) | | ||
387 | (1 << KEY_FLAG_NEGATIVE)) || | ||
370 | (keyring->expiry && now.tv_sec >= keyring->expiry)) | 388 | (keyring->expiry && now.tv_sec >= keyring->expiry)) |
371 | goto error_2; | 389 | goto error_2; |
372 | 390 | ||
373 | /* start processing a new keyring */ | 391 | /* start processing a new keyring */ |
374 | descend: | 392 | descend: |
375 | if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) | 393 | kflags = keyring->flags; |
394 | if (kflags & ((1 << KEY_FLAG_INVALIDATED) | | ||
395 | (1 << KEY_FLAG_REVOKED))) | ||
376 | goto not_this_keyring; | 396 | goto not_this_keyring; |
377 | 397 | ||
378 | keylist = rcu_dereference(keyring->payload.subscriptions); | 398 | keylist = rcu_dereference(keyring->payload.subscriptions); |
@@ -383,16 +403,17 @@ descend: | |||
383 | nkeys = keylist->nkeys; | 403 | nkeys = keylist->nkeys; |
384 | smp_rmb(); | 404 | smp_rmb(); |
385 | for (kix = 0; kix < nkeys; kix++) { | 405 | for (kix = 0; kix < nkeys; kix++) { |
386 | key = keylist->keys[kix]; | 406 | key = rcu_dereference(keylist->keys[kix]); |
387 | kflags = key->flags; | 407 | kflags = key->flags; |
388 | 408 | ||
389 | /* ignore keys not of this type */ | 409 | /* ignore keys not of this type */ |
390 | if (key->type != type) | 410 | if (key->type != type) |
391 | continue; | 411 | continue; |
392 | 412 | ||
393 | /* skip revoked keys and expired keys */ | 413 | /* skip invalidated, revoked and expired keys */ |
394 | if (!no_state_check) { | 414 | if (!no_state_check) { |
395 | if (kflags & (1 << KEY_FLAG_REVOKED)) | 415 | if (kflags & ((1 << KEY_FLAG_INVALIDATED) | |
416 | (1 << KEY_FLAG_REVOKED))) | ||
396 | continue; | 417 | continue; |
397 | 418 | ||
398 | if (key->expiry && now.tv_sec >= key->expiry) | 419 | if (key->expiry && now.tv_sec >= key->expiry) |
@@ -426,7 +447,7 @@ ascend: | |||
426 | nkeys = keylist->nkeys; | 447 | nkeys = keylist->nkeys; |
427 | smp_rmb(); | 448 | smp_rmb(); |
428 | for (; kix < nkeys; kix++) { | 449 | for (; kix < nkeys; kix++) { |
429 | key = keylist->keys[kix]; | 450 | key = rcu_dereference(keylist->keys[kix]); |
430 | if (key->type != &key_type_keyring) | 451 | if (key->type != &key_type_keyring) |
431 | continue; | 452 | continue; |
432 | 453 | ||
@@ -441,6 +462,7 @@ ascend: | |||
441 | continue; | 462 | continue; |
442 | 463 | ||
443 | /* stack the current position */ | 464 | /* stack the current position */ |
465 | stack[sp].keyring = keyring; | ||
444 | stack[sp].keylist = keylist; | 466 | stack[sp].keylist = keylist; |
445 | stack[sp].kix = kix; | 467 | stack[sp].kix = kix; |
446 | sp++; | 468 | sp++; |
@@ -456,6 +478,7 @@ not_this_keyring: | |||
456 | if (sp > 0) { | 478 | if (sp > 0) { |
457 | /* resume the processing of a keyring higher up in the tree */ | 479 | /* resume the processing of a keyring higher up in the tree */ |
458 | sp--; | 480 | sp--; |
481 | keyring = stack[sp].keyring; | ||
459 | keylist = stack[sp].keylist; | 482 | keylist = stack[sp].keylist; |
460 | kix = stack[sp].kix + 1; | 483 | kix = stack[sp].kix + 1; |
461 | goto ascend; | 484 | goto ascend; |
@@ -467,6 +490,10 @@ not_this_keyring: | |||
467 | /* we found a viable match */ | 490 | /* we found a viable match */ |
468 | found: | 491 | found: |
469 | atomic_inc(&key->usage); | 492 | atomic_inc(&key->usage); |
493 | key->last_used_at = now.tv_sec; | ||
494 | keyring->last_used_at = now.tv_sec; | ||
495 | while (sp > 0) | ||
496 | stack[--sp].keyring->last_used_at = now.tv_sec; | ||
470 | key_check(key); | 497 | key_check(key); |
471 | key_ref = make_key_ref(key, possessed); | 498 | key_ref = make_key_ref(key, possessed); |
472 | error_2: | 499 | error_2: |
@@ -531,14 +558,14 @@ key_ref_t __keyring_search_one(key_ref_t keyring_ref, | |||
531 | nkeys = klist->nkeys; | 558 | nkeys = klist->nkeys; |
532 | smp_rmb(); | 559 | smp_rmb(); |
533 | for (loop = 0; loop < nkeys ; loop++) { | 560 | for (loop = 0; loop < nkeys ; loop++) { |
534 | key = klist->keys[loop]; | 561 | key = rcu_dereference(klist->keys[loop]); |
535 | |||
536 | if (key->type == ktype && | 562 | if (key->type == ktype && |
537 | (!key->type->match || | 563 | (!key->type->match || |
538 | key->type->match(key, description)) && | 564 | key->type->match(key, description)) && |
539 | key_permission(make_key_ref(key, possessed), | 565 | key_permission(make_key_ref(key, possessed), |
540 | perm) == 0 && | 566 | perm) == 0 && |
541 | !test_bit(KEY_FLAG_REVOKED, &key->flags) | 567 | !(key->flags & ((1 << KEY_FLAG_INVALIDATED) | |
568 | (1 << KEY_FLAG_REVOKED))) | ||
542 | ) | 569 | ) |
543 | goto found; | 570 | goto found; |
544 | } | 571 | } |
@@ -549,6 +576,8 @@ key_ref_t __keyring_search_one(key_ref_t keyring_ref, | |||
549 | 576 | ||
550 | found: | 577 | found: |
551 | atomic_inc(&key->usage); | 578 | atomic_inc(&key->usage); |
579 | keyring->last_used_at = key->last_used_at = | ||
580 | current_kernel_time().tv_sec; | ||
552 | rcu_read_unlock(); | 581 | rcu_read_unlock(); |
553 | return make_key_ref(key, possessed); | 582 | return make_key_ref(key, possessed); |
554 | } | 583 | } |
@@ -602,6 +631,7 @@ struct key *find_keyring_by_name(const char *name, bool skip_perm_check) | |||
602 | * (ie. it has a zero usage count) */ | 631 | * (ie. it has a zero usage count) */ |
603 | if (!atomic_inc_not_zero(&keyring->usage)) | 632 | if (!atomic_inc_not_zero(&keyring->usage)) |
604 | continue; | 633 | continue; |
634 | keyring->last_used_at = current_kernel_time().tv_sec; | ||
605 | goto out; | 635 | goto out; |
606 | } | 636 | } |
607 | } | 637 | } |
@@ -654,7 +684,7 @@ ascend: | |||
654 | nkeys = keylist->nkeys; | 684 | nkeys = keylist->nkeys; |
655 | smp_rmb(); | 685 | smp_rmb(); |
656 | for (; kix < nkeys; kix++) { | 686 | for (; kix < nkeys; kix++) { |
657 | key = keylist->keys[kix]; | 687 | key = rcu_dereference(keylist->keys[kix]); |
658 | 688 | ||
659 | if (key == A) | 689 | if (key == A) |
660 | goto cycle_detected; | 690 | goto cycle_detected; |
@@ -711,7 +741,7 @@ static void keyring_unlink_rcu_disposal(struct rcu_head *rcu) | |||
711 | container_of(rcu, struct keyring_list, rcu); | 741 | container_of(rcu, struct keyring_list, rcu); |
712 | 742 | ||
713 | if (klist->delkey != USHRT_MAX) | 743 | if (klist->delkey != USHRT_MAX) |
714 | key_put(klist->keys[klist->delkey]); | 744 | key_put(rcu_access_pointer(klist->keys[klist->delkey])); |
715 | kfree(klist); | 745 | kfree(klist); |
716 | } | 746 | } |
717 | 747 | ||
@@ -725,8 +755,9 @@ int __key_link_begin(struct key *keyring, const struct key_type *type, | |||
725 | struct keyring_list *klist, *nklist; | 755 | struct keyring_list *klist, *nklist; |
726 | unsigned long prealloc; | 756 | unsigned long prealloc; |
727 | unsigned max; | 757 | unsigned max; |
758 | time_t lowest_lru; | ||
728 | size_t size; | 759 | size_t size; |
729 | int loop, ret; | 760 | int loop, lru, ret; |
730 | 761 | ||
731 | kenter("%d,%s,%s,", key_serial(keyring), type->name, description); | 762 | kenter("%d,%s,%s,", key_serial(keyring), type->name, description); |
732 | 763 | ||
@@ -747,31 +778,39 @@ int __key_link_begin(struct key *keyring, const struct key_type *type, | |||
747 | klist = rcu_dereference_locked_keyring(keyring); | 778 | klist = rcu_dereference_locked_keyring(keyring); |
748 | 779 | ||
749 | /* see if there's a matching key we can displace */ | 780 | /* see if there's a matching key we can displace */ |
781 | lru = -1; | ||
750 | if (klist && klist->nkeys > 0) { | 782 | if (klist && klist->nkeys > 0) { |
783 | lowest_lru = TIME_T_MAX; | ||
751 | for (loop = klist->nkeys - 1; loop >= 0; loop--) { | 784 | for (loop = klist->nkeys - 1; loop >= 0; loop--) { |
752 | if (klist->keys[loop]->type == type && | 785 | struct key *key = rcu_deref_link_locked(klist, loop, |
753 | strcmp(klist->keys[loop]->description, | 786 | keyring); |
754 | description) == 0 | 787 | if (key->type == type && |
755 | ) { | 788 | strcmp(key->description, description) == 0) { |
756 | /* found a match - we'll replace this one with | 789 | /* Found a match - we'll replace the link with |
757 | * the new key */ | 790 | * one to the new key. We record the slot |
758 | size = sizeof(struct key *) * klist->maxkeys; | 791 | * position. |
759 | size += sizeof(*klist); | 792 | */ |
760 | BUG_ON(size > PAGE_SIZE); | 793 | klist->delkey = loop; |
761 | 794 | prealloc = 0; | |
762 | ret = -ENOMEM; | ||
763 | nklist = kmemdup(klist, size, GFP_KERNEL); | ||
764 | if (!nklist) | ||
765 | goto error_sem; | ||
766 | |||
767 | /* note replacement slot */ | ||
768 | klist->delkey = nklist->delkey = loop; | ||
769 | prealloc = (unsigned long)nklist; | ||
770 | goto done; | 795 | goto done; |
771 | } | 796 | } |
797 | if (key->last_used_at < lowest_lru) { | ||
798 | lowest_lru = key->last_used_at; | ||
799 | lru = loop; | ||
800 | } | ||
772 | } | 801 | } |
773 | } | 802 | } |
774 | 803 | ||
804 | /* If the keyring is full then do an LRU discard */ | ||
805 | if (klist && | ||
806 | klist->nkeys == klist->maxkeys && | ||
807 | klist->maxkeys >= MAX_KEYRING_LINKS) { | ||
808 | kdebug("LRU discard %d\n", lru); | ||
809 | klist->delkey = lru; | ||
810 | prealloc = 0; | ||
811 | goto done; | ||
812 | } | ||
813 | |||
775 | /* check that we aren't going to overrun the user's quota */ | 814 | /* check that we aren't going to overrun the user's quota */ |
776 | ret = key_payload_reserve(keyring, | 815 | ret = key_payload_reserve(keyring, |
777 | keyring->datalen + KEYQUOTA_LINK_BYTES); | 816 | keyring->datalen + KEYQUOTA_LINK_BYTES); |
@@ -780,20 +819,19 @@ int __key_link_begin(struct key *keyring, const struct key_type *type, | |||
780 | 819 | ||
781 | if (klist && klist->nkeys < klist->maxkeys) { | 820 | if (klist && klist->nkeys < klist->maxkeys) { |
782 | /* there's sufficient slack space to append directly */ | 821 | /* there's sufficient slack space to append directly */ |
783 | nklist = NULL; | 822 | klist->delkey = klist->nkeys; |
784 | prealloc = KEY_LINK_FIXQUOTA; | 823 | prealloc = KEY_LINK_FIXQUOTA; |
785 | } else { | 824 | } else { |
786 | /* grow the key list */ | 825 | /* grow the key list */ |
787 | max = 4; | 826 | max = 4; |
788 | if (klist) | 827 | if (klist) { |
789 | max += klist->maxkeys; | 828 | max += klist->maxkeys; |
829 | if (max > MAX_KEYRING_LINKS) | ||
830 | max = MAX_KEYRING_LINKS; | ||
831 | BUG_ON(max <= klist->maxkeys); | ||
832 | } | ||
790 | 833 | ||
791 | ret = -ENFILE; | ||
792 | if (max > USHRT_MAX - 1) | ||
793 | goto error_quota; | ||
794 | size = sizeof(*klist) + sizeof(struct key *) * max; | 834 | size = sizeof(*klist) + sizeof(struct key *) * max; |
795 | if (size > PAGE_SIZE) | ||
796 | goto error_quota; | ||
797 | 835 | ||
798 | ret = -ENOMEM; | 836 | ret = -ENOMEM; |
799 | nklist = kmalloc(size, GFP_KERNEL); | 837 | nklist = kmalloc(size, GFP_KERNEL); |
@@ -813,10 +851,10 @@ int __key_link_begin(struct key *keyring, const struct key_type *type, | |||
813 | } | 851 | } |
814 | 852 | ||
815 | /* add the key into the new space */ | 853 | /* add the key into the new space */ |
816 | nklist->keys[nklist->delkey] = NULL; | 854 | RCU_INIT_POINTER(nklist->keys[nklist->delkey], NULL); |
855 | prealloc = (unsigned long)nklist | KEY_LINK_FIXQUOTA; | ||
817 | } | 856 | } |
818 | 857 | ||
819 | prealloc = (unsigned long)nklist | KEY_LINK_FIXQUOTA; | ||
820 | done: | 858 | done: |
821 | *_prealloc = prealloc; | 859 | *_prealloc = prealloc; |
822 | kleave(" = 0"); | 860 | kleave(" = 0"); |
@@ -862,6 +900,7 @@ void __key_link(struct key *keyring, struct key *key, | |||
862 | unsigned long *_prealloc) | 900 | unsigned long *_prealloc) |
863 | { | 901 | { |
864 | struct keyring_list *klist, *nklist; | 902 | struct keyring_list *klist, *nklist; |
903 | struct key *discard; | ||
865 | 904 | ||
866 | nklist = (struct keyring_list *)(*_prealloc & ~KEY_LINK_FIXQUOTA); | 905 | nklist = (struct keyring_list *)(*_prealloc & ~KEY_LINK_FIXQUOTA); |
867 | *_prealloc = 0; | 906 | *_prealloc = 0; |
@@ -871,14 +910,16 @@ void __key_link(struct key *keyring, struct key *key, | |||
871 | klist = rcu_dereference_locked_keyring(keyring); | 910 | klist = rcu_dereference_locked_keyring(keyring); |
872 | 911 | ||
873 | atomic_inc(&key->usage); | 912 | atomic_inc(&key->usage); |
913 | keyring->last_used_at = key->last_used_at = | ||
914 | current_kernel_time().tv_sec; | ||
874 | 915 | ||
875 | /* there's a matching key we can displace or an empty slot in a newly | 916 | /* there's a matching key we can displace or an empty slot in a newly |
876 | * allocated list we can fill */ | 917 | * allocated list we can fill */ |
877 | if (nklist) { | 918 | if (nklist) { |
878 | kdebug("replace %hu/%hu/%hu", | 919 | kdebug("reissue %hu/%hu/%hu", |
879 | nklist->delkey, nklist->nkeys, nklist->maxkeys); | 920 | nklist->delkey, nklist->nkeys, nklist->maxkeys); |
880 | 921 | ||
881 | nklist->keys[nklist->delkey] = key; | 922 | RCU_INIT_POINTER(nklist->keys[nklist->delkey], key); |
882 | 923 | ||
883 | rcu_assign_pointer(keyring->payload.subscriptions, nklist); | 924 | rcu_assign_pointer(keyring->payload.subscriptions, nklist); |
884 | 925 | ||
@@ -889,9 +930,23 @@ void __key_link(struct key *keyring, struct key *key, | |||
889 | klist->delkey, klist->nkeys, klist->maxkeys); | 930 | klist->delkey, klist->nkeys, klist->maxkeys); |
890 | call_rcu(&klist->rcu, keyring_unlink_rcu_disposal); | 931 | call_rcu(&klist->rcu, keyring_unlink_rcu_disposal); |
891 | } | 932 | } |
933 | } else if (klist->delkey < klist->nkeys) { | ||
934 | kdebug("replace %hu/%hu/%hu", | ||
935 | klist->delkey, klist->nkeys, klist->maxkeys); | ||
936 | |||
937 | discard = rcu_dereference_protected( | ||
938 | klist->keys[klist->delkey], | ||
939 | rwsem_is_locked(&keyring->sem)); | ||
940 | rcu_assign_pointer(klist->keys[klist->delkey], key); | ||
941 | /* The garbage collector will take care of RCU | ||
942 | * synchronisation */ | ||
943 | key_put(discard); | ||
892 | } else { | 944 | } else { |
893 | /* there's sufficient slack space to append directly */ | 945 | /* there's sufficient slack space to append directly */ |
894 | klist->keys[klist->nkeys] = key; | 946 | kdebug("append %hu/%hu/%hu", |
947 | klist->delkey, klist->nkeys, klist->maxkeys); | ||
948 | |||
949 | RCU_INIT_POINTER(klist->keys[klist->delkey], key); | ||
895 | smp_wmb(); | 950 | smp_wmb(); |
896 | klist->nkeys++; | 951 | klist->nkeys++; |
897 | } | 952 | } |
@@ -998,7 +1053,7 @@ int key_unlink(struct key *keyring, struct key *key) | |||
998 | if (klist) { | 1053 | if (klist) { |
999 | /* search the keyring for the key */ | 1054 | /* search the keyring for the key */ |
1000 | for (loop = 0; loop < klist->nkeys; loop++) | 1055 | for (loop = 0; loop < klist->nkeys; loop++) |
1001 | if (klist->keys[loop] == key) | 1056 | if (rcu_access_pointer(klist->keys[loop]) == key) |
1002 | goto key_is_present; | 1057 | goto key_is_present; |
1003 | } | 1058 | } |
1004 | 1059 | ||
@@ -1061,7 +1116,7 @@ static void keyring_clear_rcu_disposal(struct rcu_head *rcu) | |||
1061 | klist = container_of(rcu, struct keyring_list, rcu); | 1116 | klist = container_of(rcu, struct keyring_list, rcu); |
1062 | 1117 | ||
1063 | for (loop = klist->nkeys - 1; loop >= 0; loop--) | 1118 | for (loop = klist->nkeys - 1; loop >= 0; loop--) |
1064 | key_put(klist->keys[loop]); | 1119 | key_put(rcu_access_pointer(klist->keys[loop])); |
1065 | 1120 | ||
1066 | kfree(klist); | 1121 | kfree(klist); |
1067 | } | 1122 | } |
@@ -1128,15 +1183,6 @@ static void keyring_revoke(struct key *keyring) | |||
1128 | } | 1183 | } |
1129 | 1184 | ||
1130 | /* | 1185 | /* |
1131 | * Determine whether a key is dead. | ||
1132 | */ | ||
1133 | static bool key_is_dead(struct key *key, time_t limit) | ||
1134 | { | ||
1135 | return test_bit(KEY_FLAG_DEAD, &key->flags) || | ||
1136 | (key->expiry > 0 && key->expiry <= limit); | ||
1137 | } | ||
1138 | |||
1139 | /* | ||
1140 | * Collect garbage from the contents of a keyring, replacing the old list with | 1186 | * Collect garbage from the contents of a keyring, replacing the old list with |
1141 | * a new one with the pointers all shuffled down. | 1187 | * a new one with the pointers all shuffled down. |
1142 | * | 1188 | * |
@@ -1161,7 +1207,8 @@ void keyring_gc(struct key *keyring, time_t limit) | |||
1161 | /* work out how many subscriptions we're keeping */ | 1207 | /* work out how many subscriptions we're keeping */ |
1162 | keep = 0; | 1208 | keep = 0; |
1163 | for (loop = klist->nkeys - 1; loop >= 0; loop--) | 1209 | for (loop = klist->nkeys - 1; loop >= 0; loop--) |
1164 | if (!key_is_dead(klist->keys[loop], limit)) | 1210 | if (!key_is_dead(rcu_deref_link_locked(klist, loop, keyring), |
1211 | limit)) | ||
1165 | keep++; | 1212 | keep++; |
1166 | 1213 | ||
1167 | if (keep == klist->nkeys) | 1214 | if (keep == klist->nkeys) |
@@ -1182,11 +1229,11 @@ void keyring_gc(struct key *keyring, time_t limit) | |||
1182 | */ | 1229 | */ |
1183 | keep = 0; | 1230 | keep = 0; |
1184 | for (loop = klist->nkeys - 1; loop >= 0; loop--) { | 1231 | for (loop = klist->nkeys - 1; loop >= 0; loop--) { |
1185 | key = klist->keys[loop]; | 1232 | key = rcu_deref_link_locked(klist, loop, keyring); |
1186 | if (!key_is_dead(key, limit)) { | 1233 | if (!key_is_dead(key, limit)) { |
1187 | if (keep >= max) | 1234 | if (keep >= max) |
1188 | goto discard_new; | 1235 | goto discard_new; |
1189 | new->keys[keep++] = key_get(key); | 1236 | RCU_INIT_POINTER(new->keys[keep++], key_get(key)); |
1190 | } | 1237 | } |
1191 | } | 1238 | } |
1192 | new->nkeys = keep; | 1239 | new->nkeys = keep; |
diff --git a/security/keys/permission.c b/security/keys/permission.c index c35b5229e3cd..57d96363d7f1 100644 --- a/security/keys/permission.c +++ b/security/keys/permission.c | |||
@@ -87,32 +87,29 @@ EXPORT_SYMBOL(key_task_permission); | |||
87 | * key_validate - Validate a key. | 87 | * key_validate - Validate a key. |
88 | * @key: The key to be validated. | 88 | * @key: The key to be validated. |
89 | * | 89 | * |
90 | * Check that a key is valid, returning 0 if the key is okay, -EKEYREVOKED if | 90 | * Check that a key is valid, returning 0 if the key is okay, -ENOKEY if the |
91 | * the key's type has been removed or if the key has been revoked or | 91 | * key is invalidated, -EKEYREVOKED if the key's type has been removed or if |
92 | * -EKEYEXPIRED if the key has expired. | 92 | * the key has been revoked or -EKEYEXPIRED if the key has expired. |
93 | */ | 93 | */ |
94 | int key_validate(struct key *key) | 94 | int key_validate(const struct key *key) |
95 | { | 95 | { |
96 | struct timespec now; | 96 | unsigned long flags = key->flags; |
97 | int ret = 0; | 97 | |
98 | 98 | if (flags & (1 << KEY_FLAG_INVALIDATED)) | |
99 | if (key) { | 99 | return -ENOKEY; |
100 | /* check it's still accessible */ | 100 | |
101 | ret = -EKEYREVOKED; | 101 | /* check it's still accessible */ |
102 | if (test_bit(KEY_FLAG_REVOKED, &key->flags) || | 102 | if (flags & ((1 << KEY_FLAG_REVOKED) | |
103 | test_bit(KEY_FLAG_DEAD, &key->flags)) | 103 | (1 << KEY_FLAG_DEAD))) |
104 | goto error; | 104 | return -EKEYREVOKED; |
105 | 105 | ||
106 | /* check it hasn't expired */ | 106 | /* check it hasn't expired */ |
107 | ret = 0; | 107 | if (key->expiry) { |
108 | if (key->expiry) { | 108 | struct timespec now = current_kernel_time(); |
109 | now = current_kernel_time(); | 109 | if (now.tv_sec >= key->expiry) |
110 | if (now.tv_sec >= key->expiry) | 110 | return -EKEYEXPIRED; |
111 | ret = -EKEYEXPIRED; | ||
112 | } | ||
113 | } | 111 | } |
114 | 112 | ||
115 | error: | 113 | return 0; |
116 | return ret; | ||
117 | } | 114 | } |
118 | EXPORT_SYMBOL(key_validate); | 115 | EXPORT_SYMBOL(key_validate); |
diff --git a/security/keys/proc.c b/security/keys/proc.c index 49bbc97943ad..30d1ddfd9cef 100644 --- a/security/keys/proc.c +++ b/security/keys/proc.c | |||
@@ -242,7 +242,7 @@ static int proc_keys_show(struct seq_file *m, void *v) | |||
242 | #define showflag(KEY, LETTER, FLAG) \ | 242 | #define showflag(KEY, LETTER, FLAG) \ |
243 | (test_bit(FLAG, &(KEY)->flags) ? LETTER : '-') | 243 | (test_bit(FLAG, &(KEY)->flags) ? LETTER : '-') |
244 | 244 | ||
245 | seq_printf(m, "%08x %c%c%c%c%c%c %5d %4s %08x %5d %5d %-9.9s ", | 245 | seq_printf(m, "%08x %c%c%c%c%c%c%c %5d %4s %08x %5d %5d %-9.9s ", |
246 | key->serial, | 246 | key->serial, |
247 | showflag(key, 'I', KEY_FLAG_INSTANTIATED), | 247 | showflag(key, 'I', KEY_FLAG_INSTANTIATED), |
248 | showflag(key, 'R', KEY_FLAG_REVOKED), | 248 | showflag(key, 'R', KEY_FLAG_REVOKED), |
@@ -250,6 +250,7 @@ static int proc_keys_show(struct seq_file *m, void *v) | |||
250 | showflag(key, 'Q', KEY_FLAG_IN_QUOTA), | 250 | showflag(key, 'Q', KEY_FLAG_IN_QUOTA), |
251 | showflag(key, 'U', KEY_FLAG_USER_CONSTRUCT), | 251 | showflag(key, 'U', KEY_FLAG_USER_CONSTRUCT), |
252 | showflag(key, 'N', KEY_FLAG_NEGATIVE), | 252 | showflag(key, 'N', KEY_FLAG_NEGATIVE), |
253 | showflag(key, 'i', KEY_FLAG_INVALIDATED), | ||
253 | atomic_read(&key->usage), | 254 | atomic_read(&key->usage), |
254 | xbuf, | 255 | xbuf, |
255 | key->perm, | 256 | key->perm, |
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index be7ecb2018dd..e137fcd7042c 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c | |||
@@ -732,6 +732,8 @@ try_again: | |||
732 | if (ret < 0) | 732 | if (ret < 0) |
733 | goto invalid_key; | 733 | goto invalid_key; |
734 | 734 | ||
735 | key->last_used_at = current_kernel_time().tv_sec; | ||
736 | |||
735 | error: | 737 | error: |
736 | put_cred(cred); | 738 | put_cred(cred); |
737 | return key_ref; | 739 | return key_ref; |
diff --git a/security/lsm_audit.c b/security/lsm_audit.c index 90c129b0102f..8d8d97dbb389 100644 --- a/security/lsm_audit.c +++ b/security/lsm_audit.c | |||
@@ -213,12 +213,15 @@ static void dump_common_audit_data(struct audit_buffer *ab, | |||
213 | { | 213 | { |
214 | struct task_struct *tsk = current; | 214 | struct task_struct *tsk = current; |
215 | 215 | ||
216 | if (a->tsk) | 216 | /* |
217 | tsk = a->tsk; | 217 | * To keep stack sizes in check force programers to notice if they |
218 | if (tsk && tsk->pid) { | 218 | * start making this union too large! See struct lsm_network_audit |
219 | audit_log_format(ab, " pid=%d comm=", tsk->pid); | 219 | * as an example of how to deal with large data. |
220 | audit_log_untrustedstring(ab, tsk->comm); | 220 | */ |
221 | } | 221 | BUILD_BUG_ON(sizeof(a->u) > sizeof(void *)*2); |
222 | |||
223 | audit_log_format(ab, " pid=%d comm=", tsk->pid); | ||
224 | audit_log_untrustedstring(ab, tsk->comm); | ||
222 | 225 | ||
223 | switch (a->type) { | 226 | switch (a->type) { |
224 | case LSM_AUDIT_DATA_NONE: | 227 | case LSM_AUDIT_DATA_NONE: |
diff --git a/security/security.c b/security/security.c index bf619ffc9a4d..5497a57fba01 100644 --- a/security/security.c +++ b/security/security.c | |||
@@ -701,11 +701,11 @@ int security_file_receive(struct file *file) | |||
701 | return security_ops->file_receive(file); | 701 | return security_ops->file_receive(file); |
702 | } | 702 | } |
703 | 703 | ||
704 | int security_dentry_open(struct file *file, const struct cred *cred) | 704 | int security_file_open(struct file *file, const struct cred *cred) |
705 | { | 705 | { |
706 | int ret; | 706 | int ret; |
707 | 707 | ||
708 | ret = security_ops->dentry_open(file, cred); | 708 | ret = security_ops->file_open(file, cred); |
709 | if (ret) | 709 | if (ret) |
710 | return ret; | 710 | return ret; |
711 | 711 | ||
diff --git a/security/selinux/avc.c b/security/selinux/avc.c index 8ee42b2a5f19..68d82daed257 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c | |||
@@ -65,14 +65,8 @@ struct avc_cache { | |||
65 | }; | 65 | }; |
66 | 66 | ||
67 | struct avc_callback_node { | 67 | struct avc_callback_node { |
68 | int (*callback) (u32 event, u32 ssid, u32 tsid, | 68 | int (*callback) (u32 event); |
69 | u16 tclass, u32 perms, | ||
70 | u32 *out_retained); | ||
71 | u32 events; | 69 | u32 events; |
72 | u32 ssid; | ||
73 | u32 tsid; | ||
74 | u16 tclass; | ||
75 | u32 perms; | ||
76 | struct avc_callback_node *next; | 70 | struct avc_callback_node *next; |
77 | }; | 71 | }; |
78 | 72 | ||
@@ -436,9 +430,9 @@ static void avc_audit_pre_callback(struct audit_buffer *ab, void *a) | |||
436 | { | 430 | { |
437 | struct common_audit_data *ad = a; | 431 | struct common_audit_data *ad = a; |
438 | audit_log_format(ab, "avc: %s ", | 432 | audit_log_format(ab, "avc: %s ", |
439 | ad->selinux_audit_data->slad->denied ? "denied" : "granted"); | 433 | ad->selinux_audit_data->denied ? "denied" : "granted"); |
440 | avc_dump_av(ab, ad->selinux_audit_data->slad->tclass, | 434 | avc_dump_av(ab, ad->selinux_audit_data->tclass, |
441 | ad->selinux_audit_data->slad->audited); | 435 | ad->selinux_audit_data->audited); |
442 | audit_log_format(ab, " for "); | 436 | audit_log_format(ab, " for "); |
443 | } | 437 | } |
444 | 438 | ||
@@ -452,25 +446,23 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a) | |||
452 | { | 446 | { |
453 | struct common_audit_data *ad = a; | 447 | struct common_audit_data *ad = a; |
454 | audit_log_format(ab, " "); | 448 | audit_log_format(ab, " "); |
455 | avc_dump_query(ab, ad->selinux_audit_data->slad->ssid, | 449 | avc_dump_query(ab, ad->selinux_audit_data->ssid, |
456 | ad->selinux_audit_data->slad->tsid, | 450 | ad->selinux_audit_data->tsid, |
457 | ad->selinux_audit_data->slad->tclass); | 451 | ad->selinux_audit_data->tclass); |
458 | } | 452 | } |
459 | 453 | ||
460 | /* This is the slow part of avc audit with big stack footprint */ | 454 | /* This is the slow part of avc audit with big stack footprint */ |
461 | static noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass, | 455 | noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass, |
462 | u32 requested, u32 audited, u32 denied, | 456 | u32 requested, u32 audited, u32 denied, |
463 | struct common_audit_data *a, | 457 | struct common_audit_data *a, |
464 | unsigned flags) | 458 | unsigned flags) |
465 | { | 459 | { |
466 | struct common_audit_data stack_data; | 460 | struct common_audit_data stack_data; |
467 | struct selinux_audit_data sad = {0,}; | 461 | struct selinux_audit_data sad; |
468 | struct selinux_late_audit_data slad; | ||
469 | 462 | ||
470 | if (!a) { | 463 | if (!a) { |
471 | a = &stack_data; | 464 | a = &stack_data; |
472 | COMMON_AUDIT_DATA_INIT(a, NONE); | 465 | a->type = LSM_AUDIT_DATA_NONE; |
473 | a->selinux_audit_data = &sad; | ||
474 | } | 466 | } |
475 | 467 | ||
476 | /* | 468 | /* |
@@ -484,104 +476,34 @@ static noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass, | |||
484 | (flags & MAY_NOT_BLOCK)) | 476 | (flags & MAY_NOT_BLOCK)) |
485 | return -ECHILD; | 477 | return -ECHILD; |
486 | 478 | ||
487 | slad.tclass = tclass; | 479 | sad.tclass = tclass; |
488 | slad.requested = requested; | 480 | sad.requested = requested; |
489 | slad.ssid = ssid; | 481 | sad.ssid = ssid; |
490 | slad.tsid = tsid; | 482 | sad.tsid = tsid; |
491 | slad.audited = audited; | 483 | sad.audited = audited; |
492 | slad.denied = denied; | 484 | sad.denied = denied; |
485 | |||
486 | a->selinux_audit_data = &sad; | ||
493 | 487 | ||
494 | a->selinux_audit_data->slad = &slad; | ||
495 | common_lsm_audit(a, avc_audit_pre_callback, avc_audit_post_callback); | 488 | common_lsm_audit(a, avc_audit_pre_callback, avc_audit_post_callback); |
496 | return 0; | 489 | return 0; |
497 | } | 490 | } |
498 | 491 | ||
499 | /** | 492 | /** |
500 | * avc_audit - Audit the granting or denial of permissions. | ||
501 | * @ssid: source security identifier | ||
502 | * @tsid: target security identifier | ||
503 | * @tclass: target security class | ||
504 | * @requested: requested permissions | ||
505 | * @avd: access vector decisions | ||
506 | * @result: result from avc_has_perm_noaudit | ||
507 | * @a: auxiliary audit data | ||
508 | * @flags: VFS walk flags | ||
509 | * | ||
510 | * Audit the granting or denial of permissions in accordance | ||
511 | * with the policy. This function is typically called by | ||
512 | * avc_has_perm() after a permission check, but can also be | ||
513 | * called directly by callers who use avc_has_perm_noaudit() | ||
514 | * in order to separate the permission check from the auditing. | ||
515 | * For example, this separation is useful when the permission check must | ||
516 | * be performed under a lock, to allow the lock to be released | ||
517 | * before calling the auditing code. | ||
518 | */ | ||
519 | inline int avc_audit(u32 ssid, u32 tsid, | ||
520 | u16 tclass, u32 requested, | ||
521 | struct av_decision *avd, int result, struct common_audit_data *a, | ||
522 | unsigned flags) | ||
523 | { | ||
524 | u32 denied, audited; | ||
525 | denied = requested & ~avd->allowed; | ||
526 | if (unlikely(denied)) { | ||
527 | audited = denied & avd->auditdeny; | ||
528 | /* | ||
529 | * a->selinux_audit_data->auditdeny is TRICKY! Setting a bit in | ||
530 | * this field means that ANY denials should NOT be audited if | ||
531 | * the policy contains an explicit dontaudit rule for that | ||
532 | * permission. Take notice that this is unrelated to the | ||
533 | * actual permissions that were denied. As an example lets | ||
534 | * assume: | ||
535 | * | ||
536 | * denied == READ | ||
537 | * avd.auditdeny & ACCESS == 0 (not set means explicit rule) | ||
538 | * selinux_audit_data->auditdeny & ACCESS == 1 | ||
539 | * | ||
540 | * We will NOT audit the denial even though the denied | ||
541 | * permission was READ and the auditdeny checks were for | ||
542 | * ACCESS | ||
543 | */ | ||
544 | if (a && | ||
545 | a->selinux_audit_data->auditdeny && | ||
546 | !(a->selinux_audit_data->auditdeny & avd->auditdeny)) | ||
547 | audited = 0; | ||
548 | } else if (result) | ||
549 | audited = denied = requested; | ||
550 | else | ||
551 | audited = requested & avd->auditallow; | ||
552 | if (likely(!audited)) | ||
553 | return 0; | ||
554 | |||
555 | return slow_avc_audit(ssid, tsid, tclass, | ||
556 | requested, audited, denied, | ||
557 | a, flags); | ||
558 | } | ||
559 | |||
560 | /** | ||
561 | * avc_add_callback - Register a callback for security events. | 493 | * avc_add_callback - Register a callback for security events. |
562 | * @callback: callback function | 494 | * @callback: callback function |
563 | * @events: security events | 495 | * @events: security events |
564 | * @ssid: source security identifier or %SECSID_WILD | ||
565 | * @tsid: target security identifier or %SECSID_WILD | ||
566 | * @tclass: target security class | ||
567 | * @perms: permissions | ||
568 | * | 496 | * |
569 | * Register a callback function for events in the set @events | 497 | * Register a callback function for events in the set @events. |
570 | * related to the SID pair (@ssid, @tsid) | 498 | * Returns %0 on success or -%ENOMEM if insufficient memory |
571 | * and the permissions @perms, interpreting | 499 | * exists to add the callback. |
572 | * @perms based on @tclass. Returns %0 on success or | ||
573 | * -%ENOMEM if insufficient memory exists to add the callback. | ||
574 | */ | 500 | */ |
575 | int avc_add_callback(int (*callback)(u32 event, u32 ssid, u32 tsid, | 501 | int __init avc_add_callback(int (*callback)(u32 event), u32 events) |
576 | u16 tclass, u32 perms, | ||
577 | u32 *out_retained), | ||
578 | u32 events, u32 ssid, u32 tsid, | ||
579 | u16 tclass, u32 perms) | ||
580 | { | 502 | { |
581 | struct avc_callback_node *c; | 503 | struct avc_callback_node *c; |
582 | int rc = 0; | 504 | int rc = 0; |
583 | 505 | ||
584 | c = kmalloc(sizeof(*c), GFP_ATOMIC); | 506 | c = kmalloc(sizeof(*c), GFP_KERNEL); |
585 | if (!c) { | 507 | if (!c) { |
586 | rc = -ENOMEM; | 508 | rc = -ENOMEM; |
587 | goto out; | 509 | goto out; |
@@ -589,9 +511,6 @@ int avc_add_callback(int (*callback)(u32 event, u32 ssid, u32 tsid, | |||
589 | 511 | ||
590 | c->callback = callback; | 512 | c->callback = callback; |
591 | c->events = events; | 513 | c->events = events; |
592 | c->ssid = ssid; | ||
593 | c->tsid = tsid; | ||
594 | c->perms = perms; | ||
595 | c->next = avc_callbacks; | 514 | c->next = avc_callbacks; |
596 | avc_callbacks = c; | 515 | avc_callbacks = c; |
597 | out: | 516 | out: |
@@ -731,8 +650,7 @@ int avc_ss_reset(u32 seqno) | |||
731 | 650 | ||
732 | for (c = avc_callbacks; c; c = c->next) { | 651 | for (c = avc_callbacks; c; c = c->next) { |
733 | if (c->events & AVC_CALLBACK_RESET) { | 652 | if (c->events & AVC_CALLBACK_RESET) { |
734 | tmprc = c->callback(AVC_CALLBACK_RESET, | 653 | tmprc = c->callback(AVC_CALLBACK_RESET); |
735 | 0, 0, 0, 0, NULL); | ||
736 | /* save the first error encountered for the return | 654 | /* save the first error encountered for the return |
737 | value and continue processing the callbacks */ | 655 | value and continue processing the callbacks */ |
738 | if (!rc) | 656 | if (!rc) |
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index d85b793c9321..fa2341b68331 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c | |||
@@ -1420,16 +1420,13 @@ static int cred_has_capability(const struct cred *cred, | |||
1420 | int cap, int audit) | 1420 | int cap, int audit) |
1421 | { | 1421 | { |
1422 | struct common_audit_data ad; | 1422 | struct common_audit_data ad; |
1423 | struct selinux_audit_data sad = {0,}; | ||
1424 | struct av_decision avd; | 1423 | struct av_decision avd; |
1425 | u16 sclass; | 1424 | u16 sclass; |
1426 | u32 sid = cred_sid(cred); | 1425 | u32 sid = cred_sid(cred); |
1427 | u32 av = CAP_TO_MASK(cap); | 1426 | u32 av = CAP_TO_MASK(cap); |
1428 | int rc; | 1427 | int rc; |
1429 | 1428 | ||
1430 | COMMON_AUDIT_DATA_INIT(&ad, CAP); | 1429 | ad.type = LSM_AUDIT_DATA_CAP; |
1431 | ad.selinux_audit_data = &sad; | ||
1432 | ad.tsk = current; | ||
1433 | ad.u.cap = cap; | 1430 | ad.u.cap = cap; |
1434 | 1431 | ||
1435 | switch (CAP_TO_INDEX(cap)) { | 1432 | switch (CAP_TO_INDEX(cap)) { |
@@ -1488,20 +1485,6 @@ static int inode_has_perm(const struct cred *cred, | |||
1488 | return avc_has_perm_flags(sid, isec->sid, isec->sclass, perms, adp, flags); | 1485 | return avc_has_perm_flags(sid, isec->sid, isec->sclass, perms, adp, flags); |
1489 | } | 1486 | } |
1490 | 1487 | ||
1491 | static int inode_has_perm_noadp(const struct cred *cred, | ||
1492 | struct inode *inode, | ||
1493 | u32 perms, | ||
1494 | unsigned flags) | ||
1495 | { | ||
1496 | struct common_audit_data ad; | ||
1497 | struct selinux_audit_data sad = {0,}; | ||
1498 | |||
1499 | COMMON_AUDIT_DATA_INIT(&ad, INODE); | ||
1500 | ad.u.inode = inode; | ||
1501 | ad.selinux_audit_data = &sad; | ||
1502 | return inode_has_perm(cred, inode, perms, &ad, flags); | ||
1503 | } | ||
1504 | |||
1505 | /* Same as inode_has_perm, but pass explicit audit data containing | 1488 | /* Same as inode_has_perm, but pass explicit audit data containing |
1506 | the dentry to help the auditing code to more easily generate the | 1489 | the dentry to help the auditing code to more easily generate the |
1507 | pathname if needed. */ | 1490 | pathname if needed. */ |
@@ -1511,11 +1494,9 @@ static inline int dentry_has_perm(const struct cred *cred, | |||
1511 | { | 1494 | { |
1512 | struct inode *inode = dentry->d_inode; | 1495 | struct inode *inode = dentry->d_inode; |
1513 | struct common_audit_data ad; | 1496 | struct common_audit_data ad; |
1514 | struct selinux_audit_data sad = {0,}; | ||
1515 | 1497 | ||
1516 | COMMON_AUDIT_DATA_INIT(&ad, DENTRY); | 1498 | ad.type = LSM_AUDIT_DATA_DENTRY; |
1517 | ad.u.dentry = dentry; | 1499 | ad.u.dentry = dentry; |
1518 | ad.selinux_audit_data = &sad; | ||
1519 | return inode_has_perm(cred, inode, av, &ad, 0); | 1500 | return inode_has_perm(cred, inode, av, &ad, 0); |
1520 | } | 1501 | } |
1521 | 1502 | ||
@@ -1528,11 +1509,9 @@ static inline int path_has_perm(const struct cred *cred, | |||
1528 | { | 1509 | { |
1529 | struct inode *inode = path->dentry->d_inode; | 1510 | struct inode *inode = path->dentry->d_inode; |
1530 | struct common_audit_data ad; | 1511 | struct common_audit_data ad; |
1531 | struct selinux_audit_data sad = {0,}; | ||
1532 | 1512 | ||
1533 | COMMON_AUDIT_DATA_INIT(&ad, PATH); | 1513 | ad.type = LSM_AUDIT_DATA_PATH; |
1534 | ad.u.path = *path; | 1514 | ad.u.path = *path; |
1535 | ad.selinux_audit_data = &sad; | ||
1536 | return inode_has_perm(cred, inode, av, &ad, 0); | 1515 | return inode_has_perm(cred, inode, av, &ad, 0); |
1537 | } | 1516 | } |
1538 | 1517 | ||
@@ -1551,13 +1530,11 @@ static int file_has_perm(const struct cred *cred, | |||
1551 | struct file_security_struct *fsec = file->f_security; | 1530 | struct file_security_struct *fsec = file->f_security; |
1552 | struct inode *inode = file->f_path.dentry->d_inode; | 1531 | struct inode *inode = file->f_path.dentry->d_inode; |
1553 | struct common_audit_data ad; | 1532 | struct common_audit_data ad; |
1554 | struct selinux_audit_data sad = {0,}; | ||
1555 | u32 sid = cred_sid(cred); | 1533 | u32 sid = cred_sid(cred); |
1556 | int rc; | 1534 | int rc; |
1557 | 1535 | ||
1558 | COMMON_AUDIT_DATA_INIT(&ad, PATH); | 1536 | ad.type = LSM_AUDIT_DATA_PATH; |
1559 | ad.u.path = file->f_path; | 1537 | ad.u.path = file->f_path; |
1560 | ad.selinux_audit_data = &sad; | ||
1561 | 1538 | ||
1562 | if (sid != fsec->sid) { | 1539 | if (sid != fsec->sid) { |
1563 | rc = avc_has_perm(sid, fsec->sid, | 1540 | rc = avc_has_perm(sid, fsec->sid, |
@@ -1587,7 +1564,6 @@ static int may_create(struct inode *dir, | |||
1587 | struct superblock_security_struct *sbsec; | 1564 | struct superblock_security_struct *sbsec; |
1588 | u32 sid, newsid; | 1565 | u32 sid, newsid; |
1589 | struct common_audit_data ad; | 1566 | struct common_audit_data ad; |
1590 | struct selinux_audit_data sad = {0,}; | ||
1591 | int rc; | 1567 | int rc; |
1592 | 1568 | ||
1593 | dsec = dir->i_security; | 1569 | dsec = dir->i_security; |
@@ -1596,9 +1572,8 @@ static int may_create(struct inode *dir, | |||
1596 | sid = tsec->sid; | 1572 | sid = tsec->sid; |
1597 | newsid = tsec->create_sid; | 1573 | newsid = tsec->create_sid; |
1598 | 1574 | ||
1599 | COMMON_AUDIT_DATA_INIT(&ad, DENTRY); | 1575 | ad.type = LSM_AUDIT_DATA_DENTRY; |
1600 | ad.u.dentry = dentry; | 1576 | ad.u.dentry = dentry; |
1601 | ad.selinux_audit_data = &sad; | ||
1602 | 1577 | ||
1603 | rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR, | 1578 | rc = avc_has_perm(sid, dsec->sid, SECCLASS_DIR, |
1604 | DIR__ADD_NAME | DIR__SEARCH, | 1579 | DIR__ADD_NAME | DIR__SEARCH, |
@@ -1643,7 +1618,6 @@ static int may_link(struct inode *dir, | |||
1643 | { | 1618 | { |
1644 | struct inode_security_struct *dsec, *isec; | 1619 | struct inode_security_struct *dsec, *isec; |
1645 | struct common_audit_data ad; | 1620 | struct common_audit_data ad; |
1646 | struct selinux_audit_data sad = {0,}; | ||
1647 | u32 sid = current_sid(); | 1621 | u32 sid = current_sid(); |
1648 | u32 av; | 1622 | u32 av; |
1649 | int rc; | 1623 | int rc; |
@@ -1651,9 +1625,8 @@ static int may_link(struct inode *dir, | |||
1651 | dsec = dir->i_security; | 1625 | dsec = dir->i_security; |
1652 | isec = dentry->d_inode->i_security; | 1626 | isec = dentry->d_inode->i_security; |
1653 | 1627 | ||
1654 | COMMON_AUDIT_DATA_INIT(&ad, DENTRY); | 1628 | ad.type = LSM_AUDIT_DATA_DENTRY; |
1655 | ad.u.dentry = dentry; | 1629 | ad.u.dentry = dentry; |
1656 | ad.selinux_audit_data = &sad; | ||
1657 | 1630 | ||
1658 | av = DIR__SEARCH; | 1631 | av = DIR__SEARCH; |
1659 | av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME); | 1632 | av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME); |
@@ -1688,7 +1661,6 @@ static inline int may_rename(struct inode *old_dir, | |||
1688 | { | 1661 | { |
1689 | struct inode_security_struct *old_dsec, *new_dsec, *old_isec, *new_isec; | 1662 | struct inode_security_struct *old_dsec, *new_dsec, *old_isec, *new_isec; |
1690 | struct common_audit_data ad; | 1663 | struct common_audit_data ad; |
1691 | struct selinux_audit_data sad = {0,}; | ||
1692 | u32 sid = current_sid(); | 1664 | u32 sid = current_sid(); |
1693 | u32 av; | 1665 | u32 av; |
1694 | int old_is_dir, new_is_dir; | 1666 | int old_is_dir, new_is_dir; |
@@ -1699,8 +1671,7 @@ static inline int may_rename(struct inode *old_dir, | |||
1699 | old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode); | 1671 | old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode); |
1700 | new_dsec = new_dir->i_security; | 1672 | new_dsec = new_dir->i_security; |
1701 | 1673 | ||
1702 | COMMON_AUDIT_DATA_INIT(&ad, DENTRY); | 1674 | ad.type = LSM_AUDIT_DATA_DENTRY; |
1703 | ad.selinux_audit_data = &sad; | ||
1704 | 1675 | ||
1705 | ad.u.dentry = old_dentry; | 1676 | ad.u.dentry = old_dentry; |
1706 | rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR, | 1677 | rc = avc_has_perm(sid, old_dsec->sid, SECCLASS_DIR, |
@@ -1986,7 +1957,6 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm) | |||
1986 | struct task_security_struct *new_tsec; | 1957 | struct task_security_struct *new_tsec; |
1987 | struct inode_security_struct *isec; | 1958 | struct inode_security_struct *isec; |
1988 | struct common_audit_data ad; | 1959 | struct common_audit_data ad; |
1989 | struct selinux_audit_data sad = {0,}; | ||
1990 | struct inode *inode = bprm->file->f_path.dentry->d_inode; | 1960 | struct inode *inode = bprm->file->f_path.dentry->d_inode; |
1991 | int rc; | 1961 | int rc; |
1992 | 1962 | ||
@@ -2016,6 +1986,13 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm) | |||
2016 | new_tsec->sid = old_tsec->exec_sid; | 1986 | new_tsec->sid = old_tsec->exec_sid; |
2017 | /* Reset exec SID on execve. */ | 1987 | /* Reset exec SID on execve. */ |
2018 | new_tsec->exec_sid = 0; | 1988 | new_tsec->exec_sid = 0; |
1989 | |||
1990 | /* | ||
1991 | * Minimize confusion: if no_new_privs and a transition is | ||
1992 | * explicitly requested, then fail the exec. | ||
1993 | */ | ||
1994 | if (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS) | ||
1995 | return -EPERM; | ||
2019 | } else { | 1996 | } else { |
2020 | /* Check for a default transition on this program. */ | 1997 | /* Check for a default transition on this program. */ |
2021 | rc = security_transition_sid(old_tsec->sid, isec->sid, | 1998 | rc = security_transition_sid(old_tsec->sid, isec->sid, |
@@ -2025,11 +2002,11 @@ static int selinux_bprm_set_creds(struct linux_binprm *bprm) | |||
2025 | return rc; | 2002 | return rc; |
2026 | } | 2003 | } |
2027 | 2004 | ||
2028 | COMMON_AUDIT_DATA_INIT(&ad, PATH); | 2005 | ad.type = LSM_AUDIT_DATA_PATH; |
2029 | ad.selinux_audit_data = &sad; | ||
2030 | ad.u.path = bprm->file->f_path; | 2006 | ad.u.path = bprm->file->f_path; |
2031 | 2007 | ||
2032 | if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) | 2008 | if ((bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID) || |
2009 | (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS)) | ||
2033 | new_tsec->sid = old_tsec->sid; | 2010 | new_tsec->sid = old_tsec->sid; |
2034 | 2011 | ||
2035 | if (new_tsec->sid == old_tsec->sid) { | 2012 | if (new_tsec->sid == old_tsec->sid) { |
@@ -2115,8 +2092,6 @@ static int selinux_bprm_secureexec(struct linux_binprm *bprm) | |||
2115 | static inline void flush_unauthorized_files(const struct cred *cred, | 2092 | static inline void flush_unauthorized_files(const struct cred *cred, |
2116 | struct files_struct *files) | 2093 | struct files_struct *files) |
2117 | { | 2094 | { |
2118 | struct common_audit_data ad; | ||
2119 | struct selinux_audit_data sad = {0,}; | ||
2120 | struct file *file, *devnull = NULL; | 2095 | struct file *file, *devnull = NULL; |
2121 | struct tty_struct *tty; | 2096 | struct tty_struct *tty; |
2122 | struct fdtable *fdt; | 2097 | struct fdtable *fdt; |
@@ -2128,21 +2103,17 @@ static inline void flush_unauthorized_files(const struct cred *cred, | |||
2128 | spin_lock(&tty_files_lock); | 2103 | spin_lock(&tty_files_lock); |
2129 | if (!list_empty(&tty->tty_files)) { | 2104 | if (!list_empty(&tty->tty_files)) { |
2130 | struct tty_file_private *file_priv; | 2105 | struct tty_file_private *file_priv; |
2131 | struct inode *inode; | ||
2132 | 2106 | ||
2133 | /* Revalidate access to controlling tty. | 2107 | /* Revalidate access to controlling tty. |
2134 | Use inode_has_perm on the tty inode directly rather | 2108 | Use path_has_perm on the tty path directly rather |
2135 | than using file_has_perm, as this particular open | 2109 | than using file_has_perm, as this particular open |
2136 | file may belong to another process and we are only | 2110 | file may belong to another process and we are only |
2137 | interested in the inode-based check here. */ | 2111 | interested in the inode-based check here. */ |
2138 | file_priv = list_first_entry(&tty->tty_files, | 2112 | file_priv = list_first_entry(&tty->tty_files, |
2139 | struct tty_file_private, list); | 2113 | struct tty_file_private, list); |
2140 | file = file_priv->file; | 2114 | file = file_priv->file; |
2141 | inode = file->f_path.dentry->d_inode; | 2115 | if (path_has_perm(cred, &file->f_path, FILE__READ | FILE__WRITE)) |
2142 | if (inode_has_perm_noadp(cred, inode, | ||
2143 | FILE__READ | FILE__WRITE, 0)) { | ||
2144 | drop_tty = 1; | 2116 | drop_tty = 1; |
2145 | } | ||
2146 | } | 2117 | } |
2147 | spin_unlock(&tty_files_lock); | 2118 | spin_unlock(&tty_files_lock); |
2148 | tty_kref_put(tty); | 2119 | tty_kref_put(tty); |
@@ -2152,10 +2123,6 @@ static inline void flush_unauthorized_files(const struct cred *cred, | |||
2152 | no_tty(); | 2123 | no_tty(); |
2153 | 2124 | ||
2154 | /* Revalidate access to inherited open files. */ | 2125 | /* Revalidate access to inherited open files. */ |
2155 | |||
2156 | COMMON_AUDIT_DATA_INIT(&ad, INODE); | ||
2157 | ad.selinux_audit_data = &sad; | ||
2158 | |||
2159 | spin_lock(&files->file_lock); | 2126 | spin_lock(&files->file_lock); |
2160 | for (;;) { | 2127 | for (;;) { |
2161 | unsigned long set, i; | 2128 | unsigned long set, i; |
@@ -2492,7 +2459,6 @@ static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data) | |||
2492 | { | 2459 | { |
2493 | const struct cred *cred = current_cred(); | 2460 | const struct cred *cred = current_cred(); |
2494 | struct common_audit_data ad; | 2461 | struct common_audit_data ad; |
2495 | struct selinux_audit_data sad = {0,}; | ||
2496 | int rc; | 2462 | int rc; |
2497 | 2463 | ||
2498 | rc = superblock_doinit(sb, data); | 2464 | rc = superblock_doinit(sb, data); |
@@ -2503,8 +2469,7 @@ static int selinux_sb_kern_mount(struct super_block *sb, int flags, void *data) | |||
2503 | if (flags & MS_KERNMOUNT) | 2469 | if (flags & MS_KERNMOUNT) |
2504 | return 0; | 2470 | return 0; |
2505 | 2471 | ||
2506 | COMMON_AUDIT_DATA_INIT(&ad, DENTRY); | 2472 | ad.type = LSM_AUDIT_DATA_DENTRY; |
2507 | ad.selinux_audit_data = &sad; | ||
2508 | ad.u.dentry = sb->s_root; | 2473 | ad.u.dentry = sb->s_root; |
2509 | return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad); | 2474 | return superblock_has_perm(cred, sb, FILESYSTEM__MOUNT, &ad); |
2510 | } | 2475 | } |
@@ -2513,10 +2478,8 @@ static int selinux_sb_statfs(struct dentry *dentry) | |||
2513 | { | 2478 | { |
2514 | const struct cred *cred = current_cred(); | 2479 | const struct cred *cred = current_cred(); |
2515 | struct common_audit_data ad; | 2480 | struct common_audit_data ad; |
2516 | struct selinux_audit_data sad = {0,}; | ||
2517 | 2481 | ||
2518 | COMMON_AUDIT_DATA_INIT(&ad, DENTRY); | 2482 | ad.type = LSM_AUDIT_DATA_DENTRY; |
2519 | ad.selinux_audit_data = &sad; | ||
2520 | ad.u.dentry = dentry->d_sb->s_root; | 2483 | ad.u.dentry = dentry->d_sb->s_root; |
2521 | return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad); | 2484 | return superblock_has_perm(cred, dentry->d_sb, FILESYSTEM__GETATTR, &ad); |
2522 | } | 2485 | } |
@@ -2676,14 +2639,35 @@ static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *na | |||
2676 | return dentry_has_perm(cred, dentry, FILE__READ); | 2639 | return dentry_has_perm(cred, dentry, FILE__READ); |
2677 | } | 2640 | } |
2678 | 2641 | ||
2642 | static noinline int audit_inode_permission(struct inode *inode, | ||
2643 | u32 perms, u32 audited, u32 denied, | ||
2644 | unsigned flags) | ||
2645 | { | ||
2646 | struct common_audit_data ad; | ||
2647 | struct inode_security_struct *isec = inode->i_security; | ||
2648 | int rc; | ||
2649 | |||
2650 | ad.type = LSM_AUDIT_DATA_INODE; | ||
2651 | ad.u.inode = inode; | ||
2652 | |||
2653 | rc = slow_avc_audit(current_sid(), isec->sid, isec->sclass, perms, | ||
2654 | audited, denied, &ad, flags); | ||
2655 | if (rc) | ||
2656 | return rc; | ||
2657 | return 0; | ||
2658 | } | ||
2659 | |||
2679 | static int selinux_inode_permission(struct inode *inode, int mask) | 2660 | static int selinux_inode_permission(struct inode *inode, int mask) |
2680 | { | 2661 | { |
2681 | const struct cred *cred = current_cred(); | 2662 | const struct cred *cred = current_cred(); |
2682 | struct common_audit_data ad; | ||
2683 | struct selinux_audit_data sad = {0,}; | ||
2684 | u32 perms; | 2663 | u32 perms; |
2685 | bool from_access; | 2664 | bool from_access; |
2686 | unsigned flags = mask & MAY_NOT_BLOCK; | 2665 | unsigned flags = mask & MAY_NOT_BLOCK; |
2666 | struct inode_security_struct *isec; | ||
2667 | u32 sid; | ||
2668 | struct av_decision avd; | ||
2669 | int rc, rc2; | ||
2670 | u32 audited, denied; | ||
2687 | 2671 | ||
2688 | from_access = mask & MAY_ACCESS; | 2672 | from_access = mask & MAY_ACCESS; |
2689 | mask &= (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND); | 2673 | mask &= (MAY_READ|MAY_WRITE|MAY_EXEC|MAY_APPEND); |
@@ -2692,22 +2676,34 @@ static int selinux_inode_permission(struct inode *inode, int mask) | |||
2692 | if (!mask) | 2676 | if (!mask) |
2693 | return 0; | 2677 | return 0; |
2694 | 2678 | ||
2695 | COMMON_AUDIT_DATA_INIT(&ad, INODE); | 2679 | validate_creds(cred); |
2696 | ad.selinux_audit_data = &sad; | ||
2697 | ad.u.inode = inode; | ||
2698 | 2680 | ||
2699 | if (from_access) | 2681 | if (unlikely(IS_PRIVATE(inode))) |
2700 | ad.selinux_audit_data->auditdeny |= FILE__AUDIT_ACCESS; | 2682 | return 0; |
2701 | 2683 | ||
2702 | perms = file_mask_to_av(inode->i_mode, mask); | 2684 | perms = file_mask_to_av(inode->i_mode, mask); |
2703 | 2685 | ||
2704 | return inode_has_perm(cred, inode, perms, &ad, flags); | 2686 | sid = cred_sid(cred); |
2687 | isec = inode->i_security; | ||
2688 | |||
2689 | rc = avc_has_perm_noaudit(sid, isec->sid, isec->sclass, perms, 0, &avd); | ||
2690 | audited = avc_audit_required(perms, &avd, rc, | ||
2691 | from_access ? FILE__AUDIT_ACCESS : 0, | ||
2692 | &denied); | ||
2693 | if (likely(!audited)) | ||
2694 | return rc; | ||
2695 | |||
2696 | rc2 = audit_inode_permission(inode, perms, audited, denied, flags); | ||
2697 | if (rc2) | ||
2698 | return rc2; | ||
2699 | return rc; | ||
2705 | } | 2700 | } |
2706 | 2701 | ||
2707 | static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr) | 2702 | static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr) |
2708 | { | 2703 | { |
2709 | const struct cred *cred = current_cred(); | 2704 | const struct cred *cred = current_cred(); |
2710 | unsigned int ia_valid = iattr->ia_valid; | 2705 | unsigned int ia_valid = iattr->ia_valid; |
2706 | __u32 av = FILE__WRITE; | ||
2711 | 2707 | ||
2712 | /* ATTR_FORCE is just used for ATTR_KILL_S[UG]ID. */ | 2708 | /* ATTR_FORCE is just used for ATTR_KILL_S[UG]ID. */ |
2713 | if (ia_valid & ATTR_FORCE) { | 2709 | if (ia_valid & ATTR_FORCE) { |
@@ -2721,7 +2717,10 @@ static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr) | |||
2721 | ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET)) | 2717 | ATTR_ATIME_SET | ATTR_MTIME_SET | ATTR_TIMES_SET)) |
2722 | return dentry_has_perm(cred, dentry, FILE__SETATTR); | 2718 | return dentry_has_perm(cred, dentry, FILE__SETATTR); |
2723 | 2719 | ||
2724 | return dentry_has_perm(cred, dentry, FILE__WRITE); | 2720 | if (ia_valid & ATTR_SIZE) |
2721 | av |= FILE__OPEN; | ||
2722 | |||
2723 | return dentry_has_perm(cred, dentry, av); | ||
2725 | } | 2724 | } |
2726 | 2725 | ||
2727 | static int selinux_inode_getattr(struct vfsmount *mnt, struct dentry *dentry) | 2726 | static int selinux_inode_getattr(struct vfsmount *mnt, struct dentry *dentry) |
@@ -2763,7 +2762,6 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name, | |||
2763 | struct inode_security_struct *isec = inode->i_security; | 2762 | struct inode_security_struct *isec = inode->i_security; |
2764 | struct superblock_security_struct *sbsec; | 2763 | struct superblock_security_struct *sbsec; |
2765 | struct common_audit_data ad; | 2764 | struct common_audit_data ad; |
2766 | struct selinux_audit_data sad = {0,}; | ||
2767 | u32 newsid, sid = current_sid(); | 2765 | u32 newsid, sid = current_sid(); |
2768 | int rc = 0; | 2766 | int rc = 0; |
2769 | 2767 | ||
@@ -2777,8 +2775,7 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name, | |||
2777 | if (!inode_owner_or_capable(inode)) | 2775 | if (!inode_owner_or_capable(inode)) |
2778 | return -EPERM; | 2776 | return -EPERM; |
2779 | 2777 | ||
2780 | COMMON_AUDIT_DATA_INIT(&ad, DENTRY); | 2778 | ad.type = LSM_AUDIT_DATA_DENTRY; |
2781 | ad.selinux_audit_data = &sad; | ||
2782 | ad.u.dentry = dentry; | 2779 | ad.u.dentry = dentry; |
2783 | 2780 | ||
2784 | rc = avc_has_perm(sid, isec->sid, isec->sclass, | 2781 | rc = avc_has_perm(sid, isec->sid, isec->sclass, |
@@ -2788,8 +2785,25 @@ static int selinux_inode_setxattr(struct dentry *dentry, const char *name, | |||
2788 | 2785 | ||
2789 | rc = security_context_to_sid(value, size, &newsid); | 2786 | rc = security_context_to_sid(value, size, &newsid); |
2790 | if (rc == -EINVAL) { | 2787 | if (rc == -EINVAL) { |
2791 | if (!capable(CAP_MAC_ADMIN)) | 2788 | if (!capable(CAP_MAC_ADMIN)) { |
2789 | struct audit_buffer *ab; | ||
2790 | size_t audit_size; | ||
2791 | const char *str; | ||
2792 | |||
2793 | /* We strip a nul only if it is at the end, otherwise the | ||
2794 | * context contains a nul and we should audit that */ | ||
2795 | str = value; | ||
2796 | if (str[size - 1] == '\0') | ||
2797 | audit_size = size - 1; | ||
2798 | else | ||
2799 | audit_size = size; | ||
2800 | ab = audit_log_start(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR); | ||
2801 | audit_log_format(ab, "op=setxattr invalid_context="); | ||
2802 | audit_log_n_untrustedstring(ab, value, audit_size); | ||
2803 | audit_log_end(ab); | ||
2804 | |||
2792 | return rc; | 2805 | return rc; |
2806 | } | ||
2793 | rc = security_context_to_sid_force(value, size, &newsid); | 2807 | rc = security_context_to_sid_force(value, size, &newsid); |
2794 | } | 2808 | } |
2795 | if (rc) | 2809 | if (rc) |
@@ -2969,7 +2983,7 @@ static int selinux_file_permission(struct file *file, int mask) | |||
2969 | 2983 | ||
2970 | if (sid == fsec->sid && fsec->isid == isec->sid && | 2984 | if (sid == fsec->sid && fsec->isid == isec->sid && |
2971 | fsec->pseqno == avc_policy_seqno()) | 2985 | fsec->pseqno == avc_policy_seqno()) |
2972 | /* No change since dentry_open check. */ | 2986 | /* No change since file_open check. */ |
2973 | return 0; | 2987 | return 0; |
2974 | 2988 | ||
2975 | return selinux_revalidate_file_permission(file, mask); | 2989 | return selinux_revalidate_file_permission(file, mask); |
@@ -3228,15 +3242,13 @@ static int selinux_file_receive(struct file *file) | |||
3228 | return file_has_perm(cred, file, file_to_av(file)); | 3242 | return file_has_perm(cred, file, file_to_av(file)); |
3229 | } | 3243 | } |
3230 | 3244 | ||
3231 | static int selinux_dentry_open(struct file *file, const struct cred *cred) | 3245 | static int selinux_file_open(struct file *file, const struct cred *cred) |
3232 | { | 3246 | { |
3233 | struct file_security_struct *fsec; | 3247 | struct file_security_struct *fsec; |
3234 | struct inode *inode; | ||
3235 | struct inode_security_struct *isec; | 3248 | struct inode_security_struct *isec; |
3236 | 3249 | ||
3237 | inode = file->f_path.dentry->d_inode; | ||
3238 | fsec = file->f_security; | 3250 | fsec = file->f_security; |
3239 | isec = inode->i_security; | 3251 | isec = file->f_path.dentry->d_inode->i_security; |
3240 | /* | 3252 | /* |
3241 | * Save inode label and policy sequence number | 3253 | * Save inode label and policy sequence number |
3242 | * at open-time so that selinux_file_permission | 3254 | * at open-time so that selinux_file_permission |
@@ -3254,7 +3266,7 @@ static int selinux_dentry_open(struct file *file, const struct cred *cred) | |||
3254 | * new inode label or new policy. | 3266 | * new inode label or new policy. |
3255 | * This check is not redundant - do not remove. | 3267 | * This check is not redundant - do not remove. |
3256 | */ | 3268 | */ |
3257 | return inode_has_perm_noadp(cred, inode, open_file_to_av(file), 0); | 3269 | return path_has_perm(cred, &file->f_path, open_file_to_av(file)); |
3258 | } | 3270 | } |
3259 | 3271 | ||
3260 | /* task security operations */ | 3272 | /* task security operations */ |
@@ -3373,12 +3385,10 @@ static int selinux_kernel_module_request(char *kmod_name) | |||
3373 | { | 3385 | { |
3374 | u32 sid; | 3386 | u32 sid; |
3375 | struct common_audit_data ad; | 3387 | struct common_audit_data ad; |
3376 | struct selinux_audit_data sad = {0,}; | ||
3377 | 3388 | ||
3378 | sid = task_sid(current); | 3389 | sid = task_sid(current); |
3379 | 3390 | ||
3380 | COMMON_AUDIT_DATA_INIT(&ad, KMOD); | 3391 | ad.type = LSM_AUDIT_DATA_KMOD; |
3381 | ad.selinux_audit_data = &sad; | ||
3382 | ad.u.kmod_name = kmod_name; | 3392 | ad.u.kmod_name = kmod_name; |
3383 | 3393 | ||
3384 | return avc_has_perm(sid, SECINITSID_KERNEL, SECCLASS_SYSTEM, | 3394 | return avc_has_perm(sid, SECINITSID_KERNEL, SECCLASS_SYSTEM, |
@@ -3751,15 +3761,13 @@ static int sock_has_perm(struct task_struct *task, struct sock *sk, u32 perms) | |||
3751 | { | 3761 | { |
3752 | struct sk_security_struct *sksec = sk->sk_security; | 3762 | struct sk_security_struct *sksec = sk->sk_security; |
3753 | struct common_audit_data ad; | 3763 | struct common_audit_data ad; |
3754 | struct selinux_audit_data sad = {0,}; | ||
3755 | struct lsm_network_audit net = {0,}; | 3764 | struct lsm_network_audit net = {0,}; |
3756 | u32 tsid = task_sid(task); | 3765 | u32 tsid = task_sid(task); |
3757 | 3766 | ||
3758 | if (sksec->sid == SECINITSID_KERNEL) | 3767 | if (sksec->sid == SECINITSID_KERNEL) |
3759 | return 0; | 3768 | return 0; |
3760 | 3769 | ||
3761 | COMMON_AUDIT_DATA_INIT(&ad, NET); | 3770 | ad.type = LSM_AUDIT_DATA_NET; |
3762 | ad.selinux_audit_data = &sad; | ||
3763 | ad.u.net = &net; | 3771 | ad.u.net = &net; |
3764 | ad.u.net->sk = sk; | 3772 | ad.u.net->sk = sk; |
3765 | 3773 | ||
@@ -3839,7 +3847,6 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in | |||
3839 | char *addrp; | 3847 | char *addrp; |
3840 | struct sk_security_struct *sksec = sk->sk_security; | 3848 | struct sk_security_struct *sksec = sk->sk_security; |
3841 | struct common_audit_data ad; | 3849 | struct common_audit_data ad; |
3842 | struct selinux_audit_data sad = {0,}; | ||
3843 | struct lsm_network_audit net = {0,}; | 3850 | struct lsm_network_audit net = {0,}; |
3844 | struct sockaddr_in *addr4 = NULL; | 3851 | struct sockaddr_in *addr4 = NULL; |
3845 | struct sockaddr_in6 *addr6 = NULL; | 3852 | struct sockaddr_in6 *addr6 = NULL; |
@@ -3866,8 +3873,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in | |||
3866 | snum, &sid); | 3873 | snum, &sid); |
3867 | if (err) | 3874 | if (err) |
3868 | goto out; | 3875 | goto out; |
3869 | COMMON_AUDIT_DATA_INIT(&ad, NET); | 3876 | ad.type = LSM_AUDIT_DATA_NET; |
3870 | ad.selinux_audit_data = &sad; | ||
3871 | ad.u.net = &net; | 3877 | ad.u.net = &net; |
3872 | ad.u.net->sport = htons(snum); | 3878 | ad.u.net->sport = htons(snum); |
3873 | ad.u.net->family = family; | 3879 | ad.u.net->family = family; |
@@ -3901,8 +3907,7 @@ static int selinux_socket_bind(struct socket *sock, struct sockaddr *address, in | |||
3901 | if (err) | 3907 | if (err) |
3902 | goto out; | 3908 | goto out; |
3903 | 3909 | ||
3904 | COMMON_AUDIT_DATA_INIT(&ad, NET); | 3910 | ad.type = LSM_AUDIT_DATA_NET; |
3905 | ad.selinux_audit_data = &sad; | ||
3906 | ad.u.net = &net; | 3911 | ad.u.net = &net; |
3907 | ad.u.net->sport = htons(snum); | 3912 | ad.u.net->sport = htons(snum); |
3908 | ad.u.net->family = family; | 3913 | ad.u.net->family = family; |
@@ -3937,7 +3942,6 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, | |||
3937 | if (sksec->sclass == SECCLASS_TCP_SOCKET || | 3942 | if (sksec->sclass == SECCLASS_TCP_SOCKET || |
3938 | sksec->sclass == SECCLASS_DCCP_SOCKET) { | 3943 | sksec->sclass == SECCLASS_DCCP_SOCKET) { |
3939 | struct common_audit_data ad; | 3944 | struct common_audit_data ad; |
3940 | struct selinux_audit_data sad = {0,}; | ||
3941 | struct lsm_network_audit net = {0,}; | 3945 | struct lsm_network_audit net = {0,}; |
3942 | struct sockaddr_in *addr4 = NULL; | 3946 | struct sockaddr_in *addr4 = NULL; |
3943 | struct sockaddr_in6 *addr6 = NULL; | 3947 | struct sockaddr_in6 *addr6 = NULL; |
@@ -3963,8 +3967,7 @@ static int selinux_socket_connect(struct socket *sock, struct sockaddr *address, | |||
3963 | perm = (sksec->sclass == SECCLASS_TCP_SOCKET) ? | 3967 | perm = (sksec->sclass == SECCLASS_TCP_SOCKET) ? |
3964 | TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT; | 3968 | TCP_SOCKET__NAME_CONNECT : DCCP_SOCKET__NAME_CONNECT; |
3965 | 3969 | ||
3966 | COMMON_AUDIT_DATA_INIT(&ad, NET); | 3970 | ad.type = LSM_AUDIT_DATA_NET; |
3967 | ad.selinux_audit_data = &sad; | ||
3968 | ad.u.net = &net; | 3971 | ad.u.net = &net; |
3969 | ad.u.net->dport = htons(snum); | 3972 | ad.u.net->dport = htons(snum); |
3970 | ad.u.net->family = sk->sk_family; | 3973 | ad.u.net->family = sk->sk_family; |
@@ -4056,12 +4059,10 @@ static int selinux_socket_unix_stream_connect(struct sock *sock, | |||
4056 | struct sk_security_struct *sksec_other = other->sk_security; | 4059 | struct sk_security_struct *sksec_other = other->sk_security; |
4057 | struct sk_security_struct *sksec_new = newsk->sk_security; | 4060 | struct sk_security_struct *sksec_new = newsk->sk_security; |
4058 | struct common_audit_data ad; | 4061 | struct common_audit_data ad; |
4059 | struct selinux_audit_data sad = {0,}; | ||
4060 | struct lsm_network_audit net = {0,}; | 4062 | struct lsm_network_audit net = {0,}; |
4061 | int err; | 4063 | int err; |
4062 | 4064 | ||
4063 | COMMON_AUDIT_DATA_INIT(&ad, NET); | 4065 | ad.type = LSM_AUDIT_DATA_NET; |
4064 | ad.selinux_audit_data = &sad; | ||
4065 | ad.u.net = &net; | 4066 | ad.u.net = &net; |
4066 | ad.u.net->sk = other; | 4067 | ad.u.net->sk = other; |
4067 | 4068 | ||
@@ -4090,11 +4091,9 @@ static int selinux_socket_unix_may_send(struct socket *sock, | |||
4090 | struct sk_security_struct *ssec = sock->sk->sk_security; | 4091 | struct sk_security_struct *ssec = sock->sk->sk_security; |
4091 | struct sk_security_struct *osec = other->sk->sk_security; | 4092 | struct sk_security_struct *osec = other->sk->sk_security; |
4092 | struct common_audit_data ad; | 4093 | struct common_audit_data ad; |
4093 | struct selinux_audit_data sad = {0,}; | ||
4094 | struct lsm_network_audit net = {0,}; | 4094 | struct lsm_network_audit net = {0,}; |
4095 | 4095 | ||
4096 | COMMON_AUDIT_DATA_INIT(&ad, NET); | 4096 | ad.type = LSM_AUDIT_DATA_NET; |
4097 | ad.selinux_audit_data = &sad; | ||
4098 | ad.u.net = &net; | 4097 | ad.u.net = &net; |
4099 | ad.u.net->sk = other->sk; | 4098 | ad.u.net->sk = other->sk; |
4100 | 4099 | ||
@@ -4132,12 +4131,10 @@ static int selinux_sock_rcv_skb_compat(struct sock *sk, struct sk_buff *skb, | |||
4132 | struct sk_security_struct *sksec = sk->sk_security; | 4131 | struct sk_security_struct *sksec = sk->sk_security; |
4133 | u32 sk_sid = sksec->sid; | 4132 | u32 sk_sid = sksec->sid; |
4134 | struct common_audit_data ad; | 4133 | struct common_audit_data ad; |
4135 | struct selinux_audit_data sad = {0,}; | ||
4136 | struct lsm_network_audit net = {0,}; | 4134 | struct lsm_network_audit net = {0,}; |
4137 | char *addrp; | 4135 | char *addrp; |
4138 | 4136 | ||
4139 | COMMON_AUDIT_DATA_INIT(&ad, NET); | 4137 | ad.type = LSM_AUDIT_DATA_NET; |
4140 | ad.selinux_audit_data = &sad; | ||
4141 | ad.u.net = &net; | 4138 | ad.u.net = &net; |
4142 | ad.u.net->netif = skb->skb_iif; | 4139 | ad.u.net->netif = skb->skb_iif; |
4143 | ad.u.net->family = family; | 4140 | ad.u.net->family = family; |
@@ -4167,7 +4164,6 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
4167 | u16 family = sk->sk_family; | 4164 | u16 family = sk->sk_family; |
4168 | u32 sk_sid = sksec->sid; | 4165 | u32 sk_sid = sksec->sid; |
4169 | struct common_audit_data ad; | 4166 | struct common_audit_data ad; |
4170 | struct selinux_audit_data sad = {0,}; | ||
4171 | struct lsm_network_audit net = {0,}; | 4167 | struct lsm_network_audit net = {0,}; |
4172 | char *addrp; | 4168 | char *addrp; |
4173 | u8 secmark_active; | 4169 | u8 secmark_active; |
@@ -4192,8 +4188,7 @@ static int selinux_socket_sock_rcv_skb(struct sock *sk, struct sk_buff *skb) | |||
4192 | if (!secmark_active && !peerlbl_active) | 4188 | if (!secmark_active && !peerlbl_active) |
4193 | return 0; | 4189 | return 0; |
4194 | 4190 | ||
4195 | COMMON_AUDIT_DATA_INIT(&ad, NET); | 4191 | ad.type = LSM_AUDIT_DATA_NET; |
4196 | ad.selinux_audit_data = &sad; | ||
4197 | ad.u.net = &net; | 4192 | ad.u.net = &net; |
4198 | ad.u.net->netif = skb->skb_iif; | 4193 | ad.u.net->netif = skb->skb_iif; |
4199 | ad.u.net->family = family; | 4194 | ad.u.net->family = family; |
@@ -4531,7 +4526,6 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex, | |||
4531 | char *addrp; | 4526 | char *addrp; |
4532 | u32 peer_sid; | 4527 | u32 peer_sid; |
4533 | struct common_audit_data ad; | 4528 | struct common_audit_data ad; |
4534 | struct selinux_audit_data sad = {0,}; | ||
4535 | struct lsm_network_audit net = {0,}; | 4529 | struct lsm_network_audit net = {0,}; |
4536 | u8 secmark_active; | 4530 | u8 secmark_active; |
4537 | u8 netlbl_active; | 4531 | u8 netlbl_active; |
@@ -4549,8 +4543,7 @@ static unsigned int selinux_ip_forward(struct sk_buff *skb, int ifindex, | |||
4549 | if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0) | 4543 | if (selinux_skb_peerlbl_sid(skb, family, &peer_sid) != 0) |
4550 | return NF_DROP; | 4544 | return NF_DROP; |
4551 | 4545 | ||
4552 | COMMON_AUDIT_DATA_INIT(&ad, NET); | 4546 | ad.type = LSM_AUDIT_DATA_NET; |
4553 | ad.selinux_audit_data = &sad; | ||
4554 | ad.u.net = &net; | 4547 | ad.u.net = &net; |
4555 | ad.u.net->netif = ifindex; | 4548 | ad.u.net->netif = ifindex; |
4556 | ad.u.net->family = family; | 4549 | ad.u.net->family = family; |
@@ -4640,7 +4633,6 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb, | |||
4640 | struct sock *sk = skb->sk; | 4633 | struct sock *sk = skb->sk; |
4641 | struct sk_security_struct *sksec; | 4634 | struct sk_security_struct *sksec; |
4642 | struct common_audit_data ad; | 4635 | struct common_audit_data ad; |
4643 | struct selinux_audit_data sad = {0,}; | ||
4644 | struct lsm_network_audit net = {0,}; | 4636 | struct lsm_network_audit net = {0,}; |
4645 | char *addrp; | 4637 | char *addrp; |
4646 | u8 proto; | 4638 | u8 proto; |
@@ -4649,8 +4641,7 @@ static unsigned int selinux_ip_postroute_compat(struct sk_buff *skb, | |||
4649 | return NF_ACCEPT; | 4641 | return NF_ACCEPT; |
4650 | sksec = sk->sk_security; | 4642 | sksec = sk->sk_security; |
4651 | 4643 | ||
4652 | COMMON_AUDIT_DATA_INIT(&ad, NET); | 4644 | ad.type = LSM_AUDIT_DATA_NET; |
4653 | ad.selinux_audit_data = &sad; | ||
4654 | ad.u.net = &net; | 4645 | ad.u.net = &net; |
4655 | ad.u.net->netif = ifindex; | 4646 | ad.u.net->netif = ifindex; |
4656 | ad.u.net->family = family; | 4647 | ad.u.net->family = family; |
@@ -4675,7 +4666,6 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, | |||
4675 | u32 peer_sid; | 4666 | u32 peer_sid; |
4676 | struct sock *sk; | 4667 | struct sock *sk; |
4677 | struct common_audit_data ad; | 4668 | struct common_audit_data ad; |
4678 | struct selinux_audit_data sad = {0,}; | ||
4679 | struct lsm_network_audit net = {0,}; | 4669 | struct lsm_network_audit net = {0,}; |
4680 | char *addrp; | 4670 | char *addrp; |
4681 | u8 secmark_active; | 4671 | u8 secmark_active; |
@@ -4722,8 +4712,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, | |||
4722 | secmark_perm = PACKET__SEND; | 4712 | secmark_perm = PACKET__SEND; |
4723 | } | 4713 | } |
4724 | 4714 | ||
4725 | COMMON_AUDIT_DATA_INIT(&ad, NET); | 4715 | ad.type = LSM_AUDIT_DATA_NET; |
4726 | ad.selinux_audit_data = &sad; | ||
4727 | ad.u.net = &net; | 4716 | ad.u.net = &net; |
4728 | ad.u.net->netif = ifindex; | 4717 | ad.u.net->netif = ifindex; |
4729 | ad.u.net->family = family; | 4718 | ad.u.net->family = family; |
@@ -4841,13 +4830,11 @@ static int ipc_has_perm(struct kern_ipc_perm *ipc_perms, | |||
4841 | { | 4830 | { |
4842 | struct ipc_security_struct *isec; | 4831 | struct ipc_security_struct *isec; |
4843 | struct common_audit_data ad; | 4832 | struct common_audit_data ad; |
4844 | struct selinux_audit_data sad = {0,}; | ||
4845 | u32 sid = current_sid(); | 4833 | u32 sid = current_sid(); |
4846 | 4834 | ||
4847 | isec = ipc_perms->security; | 4835 | isec = ipc_perms->security; |
4848 | 4836 | ||
4849 | COMMON_AUDIT_DATA_INIT(&ad, IPC); | 4837 | ad.type = LSM_AUDIT_DATA_IPC; |
4850 | ad.selinux_audit_data = &sad; | ||
4851 | ad.u.ipc_id = ipc_perms->key; | 4838 | ad.u.ipc_id = ipc_perms->key; |
4852 | 4839 | ||
4853 | return avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad); | 4840 | return avc_has_perm(sid, isec->sid, isec->sclass, perms, &ad); |
@@ -4868,7 +4855,6 @@ static int selinux_msg_queue_alloc_security(struct msg_queue *msq) | |||
4868 | { | 4855 | { |
4869 | struct ipc_security_struct *isec; | 4856 | struct ipc_security_struct *isec; |
4870 | struct common_audit_data ad; | 4857 | struct common_audit_data ad; |
4871 | struct selinux_audit_data sad = {0,}; | ||
4872 | u32 sid = current_sid(); | 4858 | u32 sid = current_sid(); |
4873 | int rc; | 4859 | int rc; |
4874 | 4860 | ||
@@ -4878,8 +4864,7 @@ static int selinux_msg_queue_alloc_security(struct msg_queue *msq) | |||
4878 | 4864 | ||
4879 | isec = msq->q_perm.security; | 4865 | isec = msq->q_perm.security; |
4880 | 4866 | ||
4881 | COMMON_AUDIT_DATA_INIT(&ad, IPC); | 4867 | ad.type = LSM_AUDIT_DATA_IPC; |
4882 | ad.selinux_audit_data = &sad; | ||
4883 | ad.u.ipc_id = msq->q_perm.key; | 4868 | ad.u.ipc_id = msq->q_perm.key; |
4884 | 4869 | ||
4885 | rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ, | 4870 | rc = avc_has_perm(sid, isec->sid, SECCLASS_MSGQ, |
@@ -4900,13 +4885,11 @@ static int selinux_msg_queue_associate(struct msg_queue *msq, int msqflg) | |||
4900 | { | 4885 | { |
4901 | struct ipc_security_struct *isec; | 4886 | struct ipc_security_struct *isec; |
4902 | struct common_audit_data ad; | 4887 | struct common_audit_data ad; |
4903 | struct selinux_audit_data sad = {0,}; | ||
4904 | u32 sid = current_sid(); | 4888 | u32 sid = current_sid(); |
4905 | 4889 | ||
4906 | isec = msq->q_perm.security; | 4890 | isec = msq->q_perm.security; |
4907 | 4891 | ||
4908 | COMMON_AUDIT_DATA_INIT(&ad, IPC); | 4892 | ad.type = LSM_AUDIT_DATA_IPC; |
4909 | ad.selinux_audit_data = &sad; | ||
4910 | ad.u.ipc_id = msq->q_perm.key; | 4893 | ad.u.ipc_id = msq->q_perm.key; |
4911 | 4894 | ||
4912 | return avc_has_perm(sid, isec->sid, SECCLASS_MSGQ, | 4895 | return avc_has_perm(sid, isec->sid, SECCLASS_MSGQ, |
@@ -4946,7 +4929,6 @@ static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg, | |||
4946 | struct ipc_security_struct *isec; | 4929 | struct ipc_security_struct *isec; |
4947 | struct msg_security_struct *msec; | 4930 | struct msg_security_struct *msec; |
4948 | struct common_audit_data ad; | 4931 | struct common_audit_data ad; |
4949 | struct selinux_audit_data sad = {0,}; | ||
4950 | u32 sid = current_sid(); | 4932 | u32 sid = current_sid(); |
4951 | int rc; | 4933 | int rc; |
4952 | 4934 | ||
@@ -4967,8 +4949,7 @@ static int selinux_msg_queue_msgsnd(struct msg_queue *msq, struct msg_msg *msg, | |||
4967 | return rc; | 4949 | return rc; |
4968 | } | 4950 | } |
4969 | 4951 | ||
4970 | COMMON_AUDIT_DATA_INIT(&ad, IPC); | 4952 | ad.type = LSM_AUDIT_DATA_IPC; |
4971 | ad.selinux_audit_data = &sad; | ||
4972 | ad.u.ipc_id = msq->q_perm.key; | 4953 | ad.u.ipc_id = msq->q_perm.key; |
4973 | 4954 | ||
4974 | /* Can this process write to the queue? */ | 4955 | /* Can this process write to the queue? */ |
@@ -4993,15 +4974,13 @@ static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg, | |||
4993 | struct ipc_security_struct *isec; | 4974 | struct ipc_security_struct *isec; |
4994 | struct msg_security_struct *msec; | 4975 | struct msg_security_struct *msec; |
4995 | struct common_audit_data ad; | 4976 | struct common_audit_data ad; |
4996 | struct selinux_audit_data sad = {0,}; | ||
4997 | u32 sid = task_sid(target); | 4977 | u32 sid = task_sid(target); |
4998 | int rc; | 4978 | int rc; |
4999 | 4979 | ||
5000 | isec = msq->q_perm.security; | 4980 | isec = msq->q_perm.security; |
5001 | msec = msg->security; | 4981 | msec = msg->security; |
5002 | 4982 | ||
5003 | COMMON_AUDIT_DATA_INIT(&ad, IPC); | 4983 | ad.type = LSM_AUDIT_DATA_IPC; |
5004 | ad.selinux_audit_data = &sad; | ||
5005 | ad.u.ipc_id = msq->q_perm.key; | 4984 | ad.u.ipc_id = msq->q_perm.key; |
5006 | 4985 | ||
5007 | rc = avc_has_perm(sid, isec->sid, | 4986 | rc = avc_has_perm(sid, isec->sid, |
@@ -5017,7 +4996,6 @@ static int selinux_shm_alloc_security(struct shmid_kernel *shp) | |||
5017 | { | 4996 | { |
5018 | struct ipc_security_struct *isec; | 4997 | struct ipc_security_struct *isec; |
5019 | struct common_audit_data ad; | 4998 | struct common_audit_data ad; |
5020 | struct selinux_audit_data sad = {0,}; | ||
5021 | u32 sid = current_sid(); | 4999 | u32 sid = current_sid(); |
5022 | int rc; | 5000 | int rc; |
5023 | 5001 | ||
@@ -5027,8 +5005,7 @@ static int selinux_shm_alloc_security(struct shmid_kernel *shp) | |||
5027 | 5005 | ||
5028 | isec = shp->shm_perm.security; | 5006 | isec = shp->shm_perm.security; |
5029 | 5007 | ||
5030 | COMMON_AUDIT_DATA_INIT(&ad, IPC); | 5008 | ad.type = LSM_AUDIT_DATA_IPC; |
5031 | ad.selinux_audit_data = &sad; | ||
5032 | ad.u.ipc_id = shp->shm_perm.key; | 5009 | ad.u.ipc_id = shp->shm_perm.key; |
5033 | 5010 | ||
5034 | rc = avc_has_perm(sid, isec->sid, SECCLASS_SHM, | 5011 | rc = avc_has_perm(sid, isec->sid, SECCLASS_SHM, |
@@ -5049,13 +5026,11 @@ static int selinux_shm_associate(struct shmid_kernel *shp, int shmflg) | |||
5049 | { | 5026 | { |
5050 | struct ipc_security_struct *isec; | 5027 | struct ipc_security_struct *isec; |
5051 | struct common_audit_data ad; | 5028 | struct common_audit_data ad; |
5052 | struct selinux_audit_data sad = {0,}; | ||
5053 | u32 sid = current_sid(); | 5029 | u32 sid = current_sid(); |
5054 | 5030 | ||
5055 | isec = shp->shm_perm.security; | 5031 | isec = shp->shm_perm.security; |
5056 | 5032 | ||
5057 | COMMON_AUDIT_DATA_INIT(&ad, IPC); | 5033 | ad.type = LSM_AUDIT_DATA_IPC; |
5058 | ad.selinux_audit_data = &sad; | ||
5059 | ad.u.ipc_id = shp->shm_perm.key; | 5034 | ad.u.ipc_id = shp->shm_perm.key; |
5060 | 5035 | ||
5061 | return avc_has_perm(sid, isec->sid, SECCLASS_SHM, | 5036 | return avc_has_perm(sid, isec->sid, SECCLASS_SHM, |
@@ -5113,7 +5088,6 @@ static int selinux_sem_alloc_security(struct sem_array *sma) | |||
5113 | { | 5088 | { |
5114 | struct ipc_security_struct *isec; | 5089 | struct ipc_security_struct *isec; |
5115 | struct common_audit_data ad; | 5090 | struct common_audit_data ad; |
5116 | struct selinux_audit_data sad = {0,}; | ||
5117 | u32 sid = current_sid(); | 5091 | u32 sid = current_sid(); |
5118 | int rc; | 5092 | int rc; |
5119 | 5093 | ||
@@ -5123,8 +5097,7 @@ static int selinux_sem_alloc_security(struct sem_array *sma) | |||
5123 | 5097 | ||
5124 | isec = sma->sem_perm.security; | 5098 | isec = sma->sem_perm.security; |
5125 | 5099 | ||
5126 | COMMON_AUDIT_DATA_INIT(&ad, IPC); | 5100 | ad.type = LSM_AUDIT_DATA_IPC; |
5127 | ad.selinux_audit_data = &sad; | ||
5128 | ad.u.ipc_id = sma->sem_perm.key; | 5101 | ad.u.ipc_id = sma->sem_perm.key; |
5129 | 5102 | ||
5130 | rc = avc_has_perm(sid, isec->sid, SECCLASS_SEM, | 5103 | rc = avc_has_perm(sid, isec->sid, SECCLASS_SEM, |
@@ -5145,13 +5118,11 @@ static int selinux_sem_associate(struct sem_array *sma, int semflg) | |||
5145 | { | 5118 | { |
5146 | struct ipc_security_struct *isec; | 5119 | struct ipc_security_struct *isec; |
5147 | struct common_audit_data ad; | 5120 | struct common_audit_data ad; |
5148 | struct selinux_audit_data sad = {0,}; | ||
5149 | u32 sid = current_sid(); | 5121 | u32 sid = current_sid(); |
5150 | 5122 | ||
5151 | isec = sma->sem_perm.security; | 5123 | isec = sma->sem_perm.security; |
5152 | 5124 | ||
5153 | COMMON_AUDIT_DATA_INIT(&ad, IPC); | 5125 | ad.type = LSM_AUDIT_DATA_IPC; |
5154 | ad.selinux_audit_data = &sad; | ||
5155 | ad.u.ipc_id = sma->sem_perm.key; | 5126 | ad.u.ipc_id = sma->sem_perm.key; |
5156 | 5127 | ||
5157 | return avc_has_perm(sid, isec->sid, SECCLASS_SEM, | 5128 | return avc_has_perm(sid, isec->sid, SECCLASS_SEM, |
@@ -5331,8 +5302,23 @@ static int selinux_setprocattr(struct task_struct *p, | |||
5331 | } | 5302 | } |
5332 | error = security_context_to_sid(value, size, &sid); | 5303 | error = security_context_to_sid(value, size, &sid); |
5333 | if (error == -EINVAL && !strcmp(name, "fscreate")) { | 5304 | if (error == -EINVAL && !strcmp(name, "fscreate")) { |
5334 | if (!capable(CAP_MAC_ADMIN)) | 5305 | if (!capable(CAP_MAC_ADMIN)) { |
5306 | struct audit_buffer *ab; | ||
5307 | size_t audit_size; | ||
5308 | |||
5309 | /* We strip a nul only if it is at the end, otherwise the | ||
5310 | * context contains a nul and we should audit that */ | ||
5311 | if (str[size - 1] == '\0') | ||
5312 | audit_size = size - 1; | ||
5313 | else | ||
5314 | audit_size = size; | ||
5315 | ab = audit_log_start(current->audit_context, GFP_ATOMIC, AUDIT_SELINUX_ERR); | ||
5316 | audit_log_format(ab, "op=fscreate invalid_context="); | ||
5317 | audit_log_n_untrustedstring(ab, value, audit_size); | ||
5318 | audit_log_end(ab); | ||
5319 | |||
5335 | return error; | 5320 | return error; |
5321 | } | ||
5336 | error = security_context_to_sid_force(value, size, | 5322 | error = security_context_to_sid_force(value, size, |
5337 | &sid); | 5323 | &sid); |
5338 | } | 5324 | } |
@@ -5592,7 +5578,7 @@ static struct security_operations selinux_ops = { | |||
5592 | .file_send_sigiotask = selinux_file_send_sigiotask, | 5578 | .file_send_sigiotask = selinux_file_send_sigiotask, |
5593 | .file_receive = selinux_file_receive, | 5579 | .file_receive = selinux_file_receive, |
5594 | 5580 | ||
5595 | .dentry_open = selinux_dentry_open, | 5581 | .file_open = selinux_file_open, |
5596 | 5582 | ||
5597 | .task_create = selinux_task_create, | 5583 | .task_create = selinux_task_create, |
5598 | .cred_alloc_blank = selinux_cred_alloc_blank, | 5584 | .cred_alloc_blank = selinux_cred_alloc_blank, |
diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h index 1931370233d7..92d0ab561db8 100644 --- a/security/selinux/include/avc.h +++ b/security/selinux/include/avc.h | |||
@@ -49,7 +49,7 @@ struct avc_cache_stats { | |||
49 | /* | 49 | /* |
50 | * We only need this data after we have decided to send an audit message. | 50 | * We only need this data after we have decided to send an audit message. |
51 | */ | 51 | */ |
52 | struct selinux_late_audit_data { | 52 | struct selinux_audit_data { |
53 | u32 ssid; | 53 | u32 ssid; |
54 | u32 tsid; | 54 | u32 tsid; |
55 | u16 tclass; | 55 | u16 tclass; |
@@ -60,28 +60,86 @@ struct selinux_late_audit_data { | |||
60 | }; | 60 | }; |
61 | 61 | ||
62 | /* | 62 | /* |
63 | * We collect this at the beginning or during an selinux security operation | ||
64 | */ | ||
65 | struct selinux_audit_data { | ||
66 | /* | ||
67 | * auditdeny is a bit tricky and unintuitive. See the | ||
68 | * comments in avc.c for it's meaning and usage. | ||
69 | */ | ||
70 | u32 auditdeny; | ||
71 | struct selinux_late_audit_data *slad; | ||
72 | }; | ||
73 | |||
74 | /* | ||
75 | * AVC operations | 63 | * AVC operations |
76 | */ | 64 | */ |
77 | 65 | ||
78 | void __init avc_init(void); | 66 | void __init avc_init(void); |
79 | 67 | ||
80 | int avc_audit(u32 ssid, u32 tsid, | 68 | static inline u32 avc_audit_required(u32 requested, |
81 | u16 tclass, u32 requested, | 69 | struct av_decision *avd, |
82 | struct av_decision *avd, | 70 | int result, |
83 | int result, | 71 | u32 auditdeny, |
84 | struct common_audit_data *a, unsigned flags); | 72 | u32 *deniedp) |
73 | { | ||
74 | u32 denied, audited; | ||
75 | denied = requested & ~avd->allowed; | ||
76 | if (unlikely(denied)) { | ||
77 | audited = denied & avd->auditdeny; | ||
78 | /* | ||
79 | * auditdeny is TRICKY! Setting a bit in | ||
80 | * this field means that ANY denials should NOT be audited if | ||
81 | * the policy contains an explicit dontaudit rule for that | ||
82 | * permission. Take notice that this is unrelated to the | ||
83 | * actual permissions that were denied. As an example lets | ||
84 | * assume: | ||
85 | * | ||
86 | * denied == READ | ||
87 | * avd.auditdeny & ACCESS == 0 (not set means explicit rule) | ||
88 | * auditdeny & ACCESS == 1 | ||
89 | * | ||
90 | * We will NOT audit the denial even though the denied | ||
91 | * permission was READ and the auditdeny checks were for | ||
92 | * ACCESS | ||
93 | */ | ||
94 | if (auditdeny && !(auditdeny & avd->auditdeny)) | ||
95 | audited = 0; | ||
96 | } else if (result) | ||
97 | audited = denied = requested; | ||
98 | else | ||
99 | audited = requested & avd->auditallow; | ||
100 | *deniedp = denied; | ||
101 | return audited; | ||
102 | } | ||
103 | |||
104 | int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass, | ||
105 | u32 requested, u32 audited, u32 denied, | ||
106 | struct common_audit_data *a, | ||
107 | unsigned flags); | ||
108 | |||
109 | /** | ||
110 | * avc_audit - Audit the granting or denial of permissions. | ||
111 | * @ssid: source security identifier | ||
112 | * @tsid: target security identifier | ||
113 | * @tclass: target security class | ||
114 | * @requested: requested permissions | ||
115 | * @avd: access vector decisions | ||
116 | * @result: result from avc_has_perm_noaudit | ||
117 | * @a: auxiliary audit data | ||
118 | * @flags: VFS walk flags | ||
119 | * | ||
120 | * Audit the granting or denial of permissions in accordance | ||
121 | * with the policy. This function is typically called by | ||
122 | * avc_has_perm() after a permission check, but can also be | ||
123 | * called directly by callers who use avc_has_perm_noaudit() | ||
124 | * in order to separate the permission check from the auditing. | ||
125 | * For example, this separation is useful when the permission check must | ||
126 | * be performed under a lock, to allow the lock to be released | ||
127 | * before calling the auditing code. | ||
128 | */ | ||
129 | static inline int avc_audit(u32 ssid, u32 tsid, | ||
130 | u16 tclass, u32 requested, | ||
131 | struct av_decision *avd, | ||
132 | int result, | ||
133 | struct common_audit_data *a, unsigned flags) | ||
134 | { | ||
135 | u32 audited, denied; | ||
136 | audited = avc_audit_required(requested, avd, result, 0, &denied); | ||
137 | if (likely(!audited)) | ||
138 | return 0; | ||
139 | return slow_avc_audit(ssid, tsid, tclass, | ||
140 | requested, audited, denied, | ||
141 | a, flags); | ||
142 | } | ||
85 | 143 | ||
86 | #define AVC_STRICT 1 /* Ignore permissive mode. */ | 144 | #define AVC_STRICT 1 /* Ignore permissive mode. */ |
87 | int avc_has_perm_noaudit(u32 ssid, u32 tsid, | 145 | int avc_has_perm_noaudit(u32 ssid, u32 tsid, |
@@ -112,11 +170,7 @@ u32 avc_policy_seqno(void); | |||
112 | #define AVC_CALLBACK_AUDITDENY_ENABLE 64 | 170 | #define AVC_CALLBACK_AUDITDENY_ENABLE 64 |
113 | #define AVC_CALLBACK_AUDITDENY_DISABLE 128 | 171 | #define AVC_CALLBACK_AUDITDENY_DISABLE 128 |
114 | 172 | ||
115 | int avc_add_callback(int (*callback)(u32 event, u32 ssid, u32 tsid, | 173 | int avc_add_callback(int (*callback)(u32 event), u32 events); |
116 | u16 tclass, u32 perms, | ||
117 | u32 *out_retained), | ||
118 | u32 events, u32 ssid, u32 tsid, | ||
119 | u16 tclass, u32 perms); | ||
120 | 174 | ||
121 | /* Exported to selinuxfs */ | 175 | /* Exported to selinuxfs */ |
122 | int avc_get_hash_stats(char *page); | 176 | int avc_get_hash_stats(char *page); |
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index d871e8ad2103..dde2005407aa 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h | |||
@@ -31,13 +31,15 @@ | |||
31 | #define POLICYDB_VERSION_BOUNDARY 24 | 31 | #define POLICYDB_VERSION_BOUNDARY 24 |
32 | #define POLICYDB_VERSION_FILENAME_TRANS 25 | 32 | #define POLICYDB_VERSION_FILENAME_TRANS 25 |
33 | #define POLICYDB_VERSION_ROLETRANS 26 | 33 | #define POLICYDB_VERSION_ROLETRANS 26 |
34 | #define POLICYDB_VERSION_NEW_OBJECT_DEFAULTS 27 | ||
35 | #define POLICYDB_VERSION_DEFAULT_TYPE 28 | ||
34 | 36 | ||
35 | /* Range of policy versions we understand*/ | 37 | /* Range of policy versions we understand*/ |
36 | #define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE | 38 | #define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE |
37 | #ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX | 39 | #ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX |
38 | #define POLICYDB_VERSION_MAX CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE | 40 | #define POLICYDB_VERSION_MAX CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE |
39 | #else | 41 | #else |
40 | #define POLICYDB_VERSION_MAX POLICYDB_VERSION_ROLETRANS | 42 | #define POLICYDB_VERSION_MAX POLICYDB_VERSION_DEFAULT_TYPE |
41 | #endif | 43 | #endif |
42 | 44 | ||
43 | /* Mask for just the mount related flags */ | 45 | /* Mask for just the mount related flags */ |
diff --git a/security/selinux/netif.c b/security/selinux/netif.c index 326f22cbe405..47a49d1a6f6a 100644 --- a/security/selinux/netif.c +++ b/security/selinux/netif.c | |||
@@ -252,8 +252,7 @@ static void sel_netif_flush(void) | |||
252 | spin_unlock_bh(&sel_netif_lock); | 252 | spin_unlock_bh(&sel_netif_lock); |
253 | } | 253 | } |
254 | 254 | ||
255 | static int sel_netif_avc_callback(u32 event, u32 ssid, u32 tsid, | 255 | static int sel_netif_avc_callback(u32 event) |
256 | u16 class, u32 perms, u32 *retained) | ||
257 | { | 256 | { |
258 | if (event == AVC_CALLBACK_RESET) { | 257 | if (event == AVC_CALLBACK_RESET) { |
259 | sel_netif_flush(); | 258 | sel_netif_flush(); |
@@ -292,8 +291,7 @@ static __init int sel_netif_init(void) | |||
292 | 291 | ||
293 | register_netdevice_notifier(&sel_netif_netdev_notifier); | 292 | register_netdevice_notifier(&sel_netif_netdev_notifier); |
294 | 293 | ||
295 | err = avc_add_callback(sel_netif_avc_callback, AVC_CALLBACK_RESET, | 294 | err = avc_add_callback(sel_netif_avc_callback, AVC_CALLBACK_RESET); |
296 | SECSID_NULL, SECSID_NULL, SECCLASS_NULL, 0); | ||
297 | if (err) | 295 | if (err) |
298 | panic("avc_add_callback() failed, error %d\n", err); | 296 | panic("avc_add_callback() failed, error %d\n", err); |
299 | 297 | ||
diff --git a/security/selinux/netnode.c b/security/selinux/netnode.c index 86365857c088..28f911cdd7c7 100644 --- a/security/selinux/netnode.c +++ b/security/selinux/netnode.c | |||
@@ -297,8 +297,7 @@ static void sel_netnode_flush(void) | |||
297 | spin_unlock_bh(&sel_netnode_lock); | 297 | spin_unlock_bh(&sel_netnode_lock); |
298 | } | 298 | } |
299 | 299 | ||
300 | static int sel_netnode_avc_callback(u32 event, u32 ssid, u32 tsid, | 300 | static int sel_netnode_avc_callback(u32 event) |
301 | u16 class, u32 perms, u32 *retained) | ||
302 | { | 301 | { |
303 | if (event == AVC_CALLBACK_RESET) { | 302 | if (event == AVC_CALLBACK_RESET) { |
304 | sel_netnode_flush(); | 303 | sel_netnode_flush(); |
@@ -320,8 +319,7 @@ static __init int sel_netnode_init(void) | |||
320 | sel_netnode_hash[iter].size = 0; | 319 | sel_netnode_hash[iter].size = 0; |
321 | } | 320 | } |
322 | 321 | ||
323 | ret = avc_add_callback(sel_netnode_avc_callback, AVC_CALLBACK_RESET, | 322 | ret = avc_add_callback(sel_netnode_avc_callback, AVC_CALLBACK_RESET); |
324 | SECSID_NULL, SECSID_NULL, SECCLASS_NULL, 0); | ||
325 | if (ret != 0) | 323 | if (ret != 0) |
326 | panic("avc_add_callback() failed, error %d\n", ret); | 324 | panic("avc_add_callback() failed, error %d\n", ret); |
327 | 325 | ||
diff --git a/security/selinux/netport.c b/security/selinux/netport.c index 7b9eb1faf68b..d35379781c2c 100644 --- a/security/selinux/netport.c +++ b/security/selinux/netport.c | |||
@@ -234,8 +234,7 @@ static void sel_netport_flush(void) | |||
234 | spin_unlock_bh(&sel_netport_lock); | 234 | spin_unlock_bh(&sel_netport_lock); |
235 | } | 235 | } |
236 | 236 | ||
237 | static int sel_netport_avc_callback(u32 event, u32 ssid, u32 tsid, | 237 | static int sel_netport_avc_callback(u32 event) |
238 | u16 class, u32 perms, u32 *retained) | ||
239 | { | 238 | { |
240 | if (event == AVC_CALLBACK_RESET) { | 239 | if (event == AVC_CALLBACK_RESET) { |
241 | sel_netport_flush(); | 240 | sel_netport_flush(); |
@@ -257,8 +256,7 @@ static __init int sel_netport_init(void) | |||
257 | sel_netport_hash[iter].size = 0; | 256 | sel_netport_hash[iter].size = 0; |
258 | } | 257 | } |
259 | 258 | ||
260 | ret = avc_add_callback(sel_netport_avc_callback, AVC_CALLBACK_RESET, | 259 | ret = avc_add_callback(sel_netport_avc_callback, AVC_CALLBACK_RESET); |
261 | SECSID_NULL, SECSID_NULL, SECCLASS_NULL, 0); | ||
262 | if (ret != 0) | 260 | if (ret != 0) |
263 | panic("avc_add_callback() failed, error %d\n", ret); | 261 | panic("avc_add_callback() failed, error %d\n", ret); |
264 | 262 | ||
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index d7018bfa1f00..4e93f9ef970b 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c | |||
@@ -496,6 +496,7 @@ static const struct file_operations sel_policy_ops = { | |||
496 | .read = sel_read_policy, | 496 | .read = sel_read_policy, |
497 | .mmap = sel_mmap_policy, | 497 | .mmap = sel_mmap_policy, |
498 | .release = sel_release_policy, | 498 | .release = sel_release_policy, |
499 | .llseek = generic_file_llseek, | ||
499 | }; | 500 | }; |
500 | 501 | ||
501 | static ssize_t sel_write_load(struct file *file, const char __user *buf, | 502 | static ssize_t sel_write_load(struct file *file, const char __user *buf, |
@@ -1232,6 +1233,7 @@ static int sel_make_bools(void) | |||
1232 | kfree(bool_pending_names[i]); | 1233 | kfree(bool_pending_names[i]); |
1233 | kfree(bool_pending_names); | 1234 | kfree(bool_pending_names); |
1234 | kfree(bool_pending_values); | 1235 | kfree(bool_pending_values); |
1236 | bool_num = 0; | ||
1235 | bool_pending_names = NULL; | 1237 | bool_pending_names = NULL; |
1236 | bool_pending_values = NULL; | 1238 | bool_pending_values = NULL; |
1237 | 1239 | ||
@@ -1532,11 +1534,6 @@ static int sel_make_initcon_files(struct dentry *dir) | |||
1532 | return 0; | 1534 | return 0; |
1533 | } | 1535 | } |
1534 | 1536 | ||
1535 | static inline unsigned int sel_div(unsigned long a, unsigned long b) | ||
1536 | { | ||
1537 | return a / b - (a % b < 0); | ||
1538 | } | ||
1539 | |||
1540 | static inline unsigned long sel_class_to_ino(u16 class) | 1537 | static inline unsigned long sel_class_to_ino(u16 class) |
1541 | { | 1538 | { |
1542 | return (class * (SEL_VEC_MAX + 1)) | SEL_CLASS_INO_OFFSET; | 1539 | return (class * (SEL_VEC_MAX + 1)) | SEL_CLASS_INO_OFFSET; |
@@ -1544,7 +1541,7 @@ static inline unsigned long sel_class_to_ino(u16 class) | |||
1544 | 1541 | ||
1545 | static inline u16 sel_ino_to_class(unsigned long ino) | 1542 | static inline u16 sel_ino_to_class(unsigned long ino) |
1546 | { | 1543 | { |
1547 | return sel_div(ino & SEL_INO_MASK, SEL_VEC_MAX + 1); | 1544 | return (ino & SEL_INO_MASK) / (SEL_VEC_MAX + 1); |
1548 | } | 1545 | } |
1549 | 1546 | ||
1550 | static inline unsigned long sel_perm_to_ino(u16 class, u32 perm) | 1547 | static inline unsigned long sel_perm_to_ino(u16 class, u32 perm) |
@@ -1831,7 +1828,7 @@ static int sel_fill_super(struct super_block *sb, void *data, int silent) | |||
1831 | [SEL_REJECT_UNKNOWN] = {"reject_unknown", &sel_handle_unknown_ops, S_IRUGO}, | 1828 | [SEL_REJECT_UNKNOWN] = {"reject_unknown", &sel_handle_unknown_ops, S_IRUGO}, |
1832 | [SEL_DENY_UNKNOWN] = {"deny_unknown", &sel_handle_unknown_ops, S_IRUGO}, | 1829 | [SEL_DENY_UNKNOWN] = {"deny_unknown", &sel_handle_unknown_ops, S_IRUGO}, |
1833 | [SEL_STATUS] = {"status", &sel_handle_status_ops, S_IRUGO}, | 1830 | [SEL_STATUS] = {"status", &sel_handle_status_ops, S_IRUGO}, |
1834 | [SEL_POLICY] = {"policy", &sel_policy_ops, S_IRUSR}, | 1831 | [SEL_POLICY] = {"policy", &sel_policy_ops, S_IRUGO}, |
1835 | /* last one */ {""} | 1832 | /* last one */ {""} |
1836 | }; | 1833 | }; |
1837 | ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files); | 1834 | ret = simple_fill_super(sb, SELINUX_MAGIC, selinux_files); |
diff --git a/security/selinux/ss/context.h b/security/selinux/ss/context.h index 45e8fb0515f8..212e3479a0d9 100644 --- a/security/selinux/ss/context.h +++ b/security/selinux/ss/context.h | |||
@@ -74,6 +74,26 @@ out: | |||
74 | return rc; | 74 | return rc; |
75 | } | 75 | } |
76 | 76 | ||
77 | /* | ||
78 | * Sets both levels in the MLS range of 'dst' to the high level of 'src'. | ||
79 | */ | ||
80 | static inline int mls_context_cpy_high(struct context *dst, struct context *src) | ||
81 | { | ||
82 | int rc; | ||
83 | |||
84 | dst->range.level[0].sens = src->range.level[1].sens; | ||
85 | rc = ebitmap_cpy(&dst->range.level[0].cat, &src->range.level[1].cat); | ||
86 | if (rc) | ||
87 | goto out; | ||
88 | |||
89 | dst->range.level[1].sens = src->range.level[1].sens; | ||
90 | rc = ebitmap_cpy(&dst->range.level[1].cat, &src->range.level[1].cat); | ||
91 | if (rc) | ||
92 | ebitmap_destroy(&dst->range.level[0].cat); | ||
93 | out: | ||
94 | return rc; | ||
95 | } | ||
96 | |||
77 | static inline int mls_context_cmp(struct context *c1, struct context *c2) | 97 | static inline int mls_context_cmp(struct context *c1, struct context *c2) |
78 | { | 98 | { |
79 | return ((c1->range.level[0].sens == c2->range.level[0].sens) && | 99 | return ((c1->range.level[0].sens == c2->range.level[0].sens) && |
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c index fbf9c5816c71..40de8d3f208e 100644 --- a/security/selinux/ss/mls.c +++ b/security/selinux/ss/mls.c | |||
@@ -517,6 +517,8 @@ int mls_compute_sid(struct context *scontext, | |||
517 | { | 517 | { |
518 | struct range_trans rtr; | 518 | struct range_trans rtr; |
519 | struct mls_range *r; | 519 | struct mls_range *r; |
520 | struct class_datum *cladatum; | ||
521 | int default_range = 0; | ||
520 | 522 | ||
521 | if (!policydb.mls_enabled) | 523 | if (!policydb.mls_enabled) |
522 | return 0; | 524 | return 0; |
@@ -530,6 +532,28 @@ int mls_compute_sid(struct context *scontext, | |||
530 | r = hashtab_search(policydb.range_tr, &rtr); | 532 | r = hashtab_search(policydb.range_tr, &rtr); |
531 | if (r) | 533 | if (r) |
532 | return mls_range_set(newcontext, r); | 534 | return mls_range_set(newcontext, r); |
535 | |||
536 | if (tclass && tclass <= policydb.p_classes.nprim) { | ||
537 | cladatum = policydb.class_val_to_struct[tclass - 1]; | ||
538 | if (cladatum) | ||
539 | default_range = cladatum->default_range; | ||
540 | } | ||
541 | |||
542 | switch (default_range) { | ||
543 | case DEFAULT_SOURCE_LOW: | ||
544 | return mls_context_cpy_low(newcontext, scontext); | ||
545 | case DEFAULT_SOURCE_HIGH: | ||
546 | return mls_context_cpy_high(newcontext, scontext); | ||
547 | case DEFAULT_SOURCE_LOW_HIGH: | ||
548 | return mls_context_cpy(newcontext, scontext); | ||
549 | case DEFAULT_TARGET_LOW: | ||
550 | return mls_context_cpy_low(newcontext, tcontext); | ||
551 | case DEFAULT_TARGET_HIGH: | ||
552 | return mls_context_cpy_high(newcontext, tcontext); | ||
553 | case DEFAULT_TARGET_LOW_HIGH: | ||
554 | return mls_context_cpy(newcontext, tcontext); | ||
555 | } | ||
556 | |||
533 | /* Fallthrough */ | 557 | /* Fallthrough */ |
534 | case AVTAB_CHANGE: | 558 | case AVTAB_CHANGE: |
535 | if ((tclass == policydb.process_class) || (sock == true)) | 559 | if ((tclass == policydb.process_class) || (sock == true)) |
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index a7f61d52f05c..9cd9b7c661ec 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c | |||
@@ -133,6 +133,16 @@ static struct policydb_compat_info policydb_compat[] = { | |||
133 | .sym_num = SYM_NUM, | 133 | .sym_num = SYM_NUM, |
134 | .ocon_num = OCON_NUM, | 134 | .ocon_num = OCON_NUM, |
135 | }, | 135 | }, |
136 | { | ||
137 | .version = POLICYDB_VERSION_NEW_OBJECT_DEFAULTS, | ||
138 | .sym_num = SYM_NUM, | ||
139 | .ocon_num = OCON_NUM, | ||
140 | }, | ||
141 | { | ||
142 | .version = POLICYDB_VERSION_DEFAULT_TYPE, | ||
143 | .sym_num = SYM_NUM, | ||
144 | .ocon_num = OCON_NUM, | ||
145 | }, | ||
136 | }; | 146 | }; |
137 | 147 | ||
138 | static struct policydb_compat_info *policydb_lookup_compat(int version) | 148 | static struct policydb_compat_info *policydb_lookup_compat(int version) |
@@ -1306,6 +1316,23 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp) | |||
1306 | goto bad; | 1316 | goto bad; |
1307 | } | 1317 | } |
1308 | 1318 | ||
1319 | if (p->policyvers >= POLICYDB_VERSION_NEW_OBJECT_DEFAULTS) { | ||
1320 | rc = next_entry(buf, fp, sizeof(u32) * 3); | ||
1321 | if (rc) | ||
1322 | goto bad; | ||
1323 | |||
1324 | cladatum->default_user = le32_to_cpu(buf[0]); | ||
1325 | cladatum->default_role = le32_to_cpu(buf[1]); | ||
1326 | cladatum->default_range = le32_to_cpu(buf[2]); | ||
1327 | } | ||
1328 | |||
1329 | if (p->policyvers >= POLICYDB_VERSION_DEFAULT_TYPE) { | ||
1330 | rc = next_entry(buf, fp, sizeof(u32) * 1); | ||
1331 | if (rc) | ||
1332 | goto bad; | ||
1333 | cladatum->default_type = le32_to_cpu(buf[0]); | ||
1334 | } | ||
1335 | |||
1309 | rc = hashtab_insert(h, key, cladatum); | 1336 | rc = hashtab_insert(h, key, cladatum); |
1310 | if (rc) | 1337 | if (rc) |
1311 | goto bad; | 1338 | goto bad; |
@@ -2832,6 +2859,23 @@ static int class_write(void *vkey, void *datum, void *ptr) | |||
2832 | if (rc) | 2859 | if (rc) |
2833 | return rc; | 2860 | return rc; |
2834 | 2861 | ||
2862 | if (p->policyvers >= POLICYDB_VERSION_NEW_OBJECT_DEFAULTS) { | ||
2863 | buf[0] = cpu_to_le32(cladatum->default_user); | ||
2864 | buf[1] = cpu_to_le32(cladatum->default_role); | ||
2865 | buf[2] = cpu_to_le32(cladatum->default_range); | ||
2866 | |||
2867 | rc = put_entry(buf, sizeof(uint32_t), 3, fp); | ||
2868 | if (rc) | ||
2869 | return rc; | ||
2870 | } | ||
2871 | |||
2872 | if (p->policyvers >= POLICYDB_VERSION_DEFAULT_TYPE) { | ||
2873 | buf[0] = cpu_to_le32(cladatum->default_type); | ||
2874 | rc = put_entry(buf, sizeof(uint32_t), 1, fp); | ||
2875 | if (rc) | ||
2876 | return rc; | ||
2877 | } | ||
2878 | |||
2835 | return 0; | 2879 | return 0; |
2836 | } | 2880 | } |
2837 | 2881 | ||
diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h index b846c0387180..da637471d4ce 100644 --- a/security/selinux/ss/policydb.h +++ b/security/selinux/ss/policydb.h | |||
@@ -60,6 +60,20 @@ struct class_datum { | |||
60 | struct symtab permissions; /* class-specific permission symbol table */ | 60 | struct symtab permissions; /* class-specific permission symbol table */ |
61 | struct constraint_node *constraints; /* constraints on class permissions */ | 61 | struct constraint_node *constraints; /* constraints on class permissions */ |
62 | struct constraint_node *validatetrans; /* special transition rules */ | 62 | struct constraint_node *validatetrans; /* special transition rules */ |
63 | /* Options how a new object user, role, and type should be decided */ | ||
64 | #define DEFAULT_SOURCE 1 | ||
65 | #define DEFAULT_TARGET 2 | ||
66 | char default_user; | ||
67 | char default_role; | ||
68 | char default_type; | ||
69 | /* Options how a new object range should be decided */ | ||
70 | #define DEFAULT_SOURCE_LOW 1 | ||
71 | #define DEFAULT_SOURCE_HIGH 2 | ||
72 | #define DEFAULT_SOURCE_LOW_HIGH 3 | ||
73 | #define DEFAULT_TARGET_LOW 4 | ||
74 | #define DEFAULT_TARGET_HIGH 5 | ||
75 | #define DEFAULT_TARGET_LOW_HIGH 6 | ||
76 | char default_range; | ||
63 | }; | 77 | }; |
64 | 78 | ||
65 | /* Role attributes */ | 79 | /* Role attributes */ |
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 185f849a26f6..4321b8fc8863 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c | |||
@@ -1018,9 +1018,11 @@ static int context_struct_to_string(struct context *context, char **scontext, u3 | |||
1018 | 1018 | ||
1019 | if (context->len) { | 1019 | if (context->len) { |
1020 | *scontext_len = context->len; | 1020 | *scontext_len = context->len; |
1021 | *scontext = kstrdup(context->str, GFP_ATOMIC); | 1021 | if (scontext) { |
1022 | if (!(*scontext)) | 1022 | *scontext = kstrdup(context->str, GFP_ATOMIC); |
1023 | return -ENOMEM; | 1023 | if (!(*scontext)) |
1024 | return -ENOMEM; | ||
1025 | } | ||
1024 | return 0; | 1026 | return 0; |
1025 | } | 1027 | } |
1026 | 1028 | ||
@@ -1389,6 +1391,7 @@ static int security_compute_sid(u32 ssid, | |||
1389 | u32 *out_sid, | 1391 | u32 *out_sid, |
1390 | bool kern) | 1392 | bool kern) |
1391 | { | 1393 | { |
1394 | struct class_datum *cladatum = NULL; | ||
1392 | struct context *scontext = NULL, *tcontext = NULL, newcontext; | 1395 | struct context *scontext = NULL, *tcontext = NULL, newcontext; |
1393 | struct role_trans *roletr = NULL; | 1396 | struct role_trans *roletr = NULL; |
1394 | struct avtab_key avkey; | 1397 | struct avtab_key avkey; |
@@ -1437,12 +1440,20 @@ static int security_compute_sid(u32 ssid, | |||
1437 | goto out_unlock; | 1440 | goto out_unlock; |
1438 | } | 1441 | } |
1439 | 1442 | ||
1443 | if (tclass && tclass <= policydb.p_classes.nprim) | ||
1444 | cladatum = policydb.class_val_to_struct[tclass - 1]; | ||
1445 | |||
1440 | /* Set the user identity. */ | 1446 | /* Set the user identity. */ |
1441 | switch (specified) { | 1447 | switch (specified) { |
1442 | case AVTAB_TRANSITION: | 1448 | case AVTAB_TRANSITION: |
1443 | case AVTAB_CHANGE: | 1449 | case AVTAB_CHANGE: |
1444 | /* Use the process user identity. */ | 1450 | if (cladatum && cladatum->default_user == DEFAULT_TARGET) { |
1445 | newcontext.user = scontext->user; | 1451 | newcontext.user = tcontext->user; |
1452 | } else { | ||
1453 | /* notice this gets both DEFAULT_SOURCE and unset */ | ||
1454 | /* Use the process user identity. */ | ||
1455 | newcontext.user = scontext->user; | ||
1456 | } | ||
1446 | break; | 1457 | break; |
1447 | case AVTAB_MEMBER: | 1458 | case AVTAB_MEMBER: |
1448 | /* Use the related object owner. */ | 1459 | /* Use the related object owner. */ |
@@ -1450,16 +1461,31 @@ static int security_compute_sid(u32 ssid, | |||
1450 | break; | 1461 | break; |
1451 | } | 1462 | } |
1452 | 1463 | ||
1453 | /* Set the role and type to default values. */ | 1464 | /* Set the role to default values. */ |
1454 | if ((tclass == policydb.process_class) || (sock == true)) { | 1465 | if (cladatum && cladatum->default_role == DEFAULT_SOURCE) { |
1455 | /* Use the current role and type of process. */ | ||
1456 | newcontext.role = scontext->role; | 1466 | newcontext.role = scontext->role; |
1457 | newcontext.type = scontext->type; | 1467 | } else if (cladatum && cladatum->default_role == DEFAULT_TARGET) { |
1468 | newcontext.role = tcontext->role; | ||
1458 | } else { | 1469 | } else { |
1459 | /* Use the well-defined object role. */ | 1470 | if ((tclass == policydb.process_class) || (sock == true)) |
1460 | newcontext.role = OBJECT_R_VAL; | 1471 | newcontext.role = scontext->role; |
1461 | /* Use the type of the related object. */ | 1472 | else |
1473 | newcontext.role = OBJECT_R_VAL; | ||
1474 | } | ||
1475 | |||
1476 | /* Set the type to default values. */ | ||
1477 | if (cladatum && cladatum->default_type == DEFAULT_SOURCE) { | ||
1478 | newcontext.type = scontext->type; | ||
1479 | } else if (cladatum && cladatum->default_type == DEFAULT_TARGET) { | ||
1462 | newcontext.type = tcontext->type; | 1480 | newcontext.type = tcontext->type; |
1481 | } else { | ||
1482 | if ((tclass == policydb.process_class) || (sock == true)) { | ||
1483 | /* Use the type of process. */ | ||
1484 | newcontext.type = scontext->type; | ||
1485 | } else { | ||
1486 | /* Use the type of the related object. */ | ||
1487 | newcontext.type = tcontext->type; | ||
1488 | } | ||
1463 | } | 1489 | } |
1464 | 1490 | ||
1465 | /* Look for a type transition/member/change rule. */ | 1491 | /* Look for a type transition/member/change rule. */ |
@@ -3018,8 +3044,7 @@ out: | |||
3018 | 3044 | ||
3019 | static int (*aurule_callback)(void) = audit_update_lsm_rules; | 3045 | static int (*aurule_callback)(void) = audit_update_lsm_rules; |
3020 | 3046 | ||
3021 | static int aurule_avc_callback(u32 event, u32 ssid, u32 tsid, | 3047 | static int aurule_avc_callback(u32 event) |
3022 | u16 class, u32 perms, u32 *retained) | ||
3023 | { | 3048 | { |
3024 | int err = 0; | 3049 | int err = 0; |
3025 | 3050 | ||
@@ -3032,8 +3057,7 @@ static int __init aurule_init(void) | |||
3032 | { | 3057 | { |
3033 | int err; | 3058 | int err; |
3034 | 3059 | ||
3035 | err = avc_add_callback(aurule_avc_callback, AVC_CALLBACK_RESET, | 3060 | err = avc_add_callback(aurule_avc_callback, AVC_CALLBACK_RESET); |
3036 | SECSID_NULL, SECSID_NULL, SECCLASS_NULL, 0); | ||
3037 | if (err) | 3061 | if (err) |
3038 | panic("avc_add_callback() failed, error %d\n", err); | 3062 | panic("avc_add_callback() failed, error %d\n", err); |
3039 | 3063 | ||
diff --git a/security/smack/smack.h b/security/smack/smack.h index 4ede719922ed..cc361b8f3d13 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h | |||
@@ -23,13 +23,19 @@ | |||
23 | #include <linux/lsm_audit.h> | 23 | #include <linux/lsm_audit.h> |
24 | 24 | ||
25 | /* | 25 | /* |
26 | * Smack labels were limited to 23 characters for a long time. | ||
27 | */ | ||
28 | #define SMK_LABELLEN 24 | ||
29 | #define SMK_LONGLABEL 256 | ||
30 | |||
31 | /* | ||
32 | * Maximum number of bytes for the levels in a CIPSO IP option. | ||
26 | * Why 23? CIPSO is constrained to 30, so a 32 byte buffer is | 33 | * Why 23? CIPSO is constrained to 30, so a 32 byte buffer is |
27 | * bigger than can be used, and 24 is the next lower multiple | 34 | * bigger than can be used, and 24 is the next lower multiple |
28 | * of 8, and there are too many issues if there isn't space set | 35 | * of 8, and there are too many issues if there isn't space set |
29 | * aside for the terminating null byte. | 36 | * aside for the terminating null byte. |
30 | */ | 37 | */ |
31 | #define SMK_MAXLEN 23 | 38 | #define SMK_CIPSOLEN 24 |
32 | #define SMK_LABELLEN (SMK_MAXLEN+1) | ||
33 | 39 | ||
34 | struct superblock_smack { | 40 | struct superblock_smack { |
35 | char *smk_root; | 41 | char *smk_root; |
@@ -66,6 +72,7 @@ struct task_smack { | |||
66 | 72 | ||
67 | #define SMK_INODE_INSTANT 0x01 /* inode is instantiated */ | 73 | #define SMK_INODE_INSTANT 0x01 /* inode is instantiated */ |
68 | #define SMK_INODE_TRANSMUTE 0x02 /* directory is transmuting */ | 74 | #define SMK_INODE_TRANSMUTE 0x02 /* directory is transmuting */ |
75 | #define SMK_INODE_CHANGED 0x04 /* smack was transmuted */ | ||
69 | 76 | ||
70 | /* | 77 | /* |
71 | * A label access rule. | 78 | * A label access rule. |
@@ -78,15 +85,6 @@ struct smack_rule { | |||
78 | }; | 85 | }; |
79 | 86 | ||
80 | /* | 87 | /* |
81 | * An entry in the table mapping smack values to | ||
82 | * CIPSO level/category-set values. | ||
83 | */ | ||
84 | struct smack_cipso { | ||
85 | int smk_level; | ||
86 | char smk_catset[SMK_LABELLEN]; | ||
87 | }; | ||
88 | |||
89 | /* | ||
90 | * An entry in the table identifying hosts. | 88 | * An entry in the table identifying hosts. |
91 | */ | 89 | */ |
92 | struct smk_netlbladdr { | 90 | struct smk_netlbladdr { |
@@ -113,22 +111,19 @@ struct smk_netlbladdr { | |||
113 | * interfaces don't. The secid should go away when all of | 111 | * interfaces don't. The secid should go away when all of |
114 | * these components have been repaired. | 112 | * these components have been repaired. |
115 | * | 113 | * |
116 | * If there is a cipso value associated with the label it | 114 | * The cipso value associated with the label gets stored here, too. |
117 | * gets stored here, too. This will most likely be rare as | ||
118 | * the cipso direct mapping in used internally. | ||
119 | * | 115 | * |
120 | * Keep the access rules for this subject label here so that | 116 | * Keep the access rules for this subject label here so that |
121 | * the entire set of rules does not need to be examined every | 117 | * the entire set of rules does not need to be examined every |
122 | * time. | 118 | * time. |
123 | */ | 119 | */ |
124 | struct smack_known { | 120 | struct smack_known { |
125 | struct list_head list; | 121 | struct list_head list; |
126 | char smk_known[SMK_LABELLEN]; | 122 | char *smk_known; |
127 | u32 smk_secid; | 123 | u32 smk_secid; |
128 | struct smack_cipso *smk_cipso; | 124 | struct netlbl_lsm_secattr smk_netlabel; /* on wire labels */ |
129 | spinlock_t smk_cipsolock; /* for changing cipso map */ | 125 | struct list_head smk_rules; /* access rules */ |
130 | struct list_head smk_rules; /* access rules */ | 126 | struct mutex smk_rules_lock; /* lock for rules */ |
131 | struct mutex smk_rules_lock; /* lock for the rules */ | ||
132 | }; | 127 | }; |
133 | 128 | ||
134 | /* | 129 | /* |
@@ -165,6 +160,7 @@ struct smack_known { | |||
165 | #define SMACK_CIPSO_DOI_DEFAULT 3 /* Historical */ | 160 | #define SMACK_CIPSO_DOI_DEFAULT 3 /* Historical */ |
166 | #define SMACK_CIPSO_DOI_INVALID -1 /* Not a DOI */ | 161 | #define SMACK_CIPSO_DOI_INVALID -1 /* Not a DOI */ |
167 | #define SMACK_CIPSO_DIRECT_DEFAULT 250 /* Arbitrary */ | 162 | #define SMACK_CIPSO_DIRECT_DEFAULT 250 /* Arbitrary */ |
163 | #define SMACK_CIPSO_MAPPED_DEFAULT 251 /* Also arbitrary */ | ||
168 | #define SMACK_CIPSO_MAXCATVAL 63 /* Bigger gets harder */ | 164 | #define SMACK_CIPSO_MAXCATVAL 63 /* Bigger gets harder */ |
169 | #define SMACK_CIPSO_MAXLEVEL 255 /* CIPSO 2.2 standard */ | 165 | #define SMACK_CIPSO_MAXLEVEL 255 /* CIPSO 2.2 standard */ |
170 | #define SMACK_CIPSO_MAXCATNUM 239 /* CIPSO 2.2 standard */ | 166 | #define SMACK_CIPSO_MAXCATNUM 239 /* CIPSO 2.2 standard */ |
@@ -215,10 +211,9 @@ struct inode_smack *new_inode_smack(char *); | |||
215 | int smk_access_entry(char *, char *, struct list_head *); | 211 | int smk_access_entry(char *, char *, struct list_head *); |
216 | int smk_access(char *, char *, int, struct smk_audit_info *); | 212 | int smk_access(char *, char *, int, struct smk_audit_info *); |
217 | int smk_curacc(char *, u32, struct smk_audit_info *); | 213 | int smk_curacc(char *, u32, struct smk_audit_info *); |
218 | int smack_to_cipso(const char *, struct smack_cipso *); | ||
219 | char *smack_from_cipso(u32, char *); | ||
220 | char *smack_from_secid(const u32); | 214 | char *smack_from_secid(const u32); |
221 | void smk_parse_smack(const char *string, int len, char *smack); | 215 | char *smk_parse_smack(const char *string, int len); |
216 | int smk_netlbl_mls(int, char *, struct netlbl_lsm_secattr *, int); | ||
222 | char *smk_import(const char *, int); | 217 | char *smk_import(const char *, int); |
223 | struct smack_known *smk_import_entry(const char *, int); | 218 | struct smack_known *smk_import_entry(const char *, int); |
224 | struct smack_known *smk_find_entry(const char *); | 219 | struct smack_known *smk_find_entry(const char *); |
@@ -228,6 +223,7 @@ u32 smack_to_secid(const char *); | |||
228 | * Shared data. | 223 | * Shared data. |
229 | */ | 224 | */ |
230 | extern int smack_cipso_direct; | 225 | extern int smack_cipso_direct; |
226 | extern int smack_cipso_mapped; | ||
231 | extern char *smack_net_ambient; | 227 | extern char *smack_net_ambient; |
232 | extern char *smack_onlycap; | 228 | extern char *smack_onlycap; |
233 | extern const char *smack_cipso_option; | 229 | extern const char *smack_cipso_option; |
@@ -239,24 +235,13 @@ extern struct smack_known smack_known_invalid; | |||
239 | extern struct smack_known smack_known_star; | 235 | extern struct smack_known smack_known_star; |
240 | extern struct smack_known smack_known_web; | 236 | extern struct smack_known smack_known_web; |
241 | 237 | ||
238 | extern struct mutex smack_known_lock; | ||
242 | extern struct list_head smack_known_list; | 239 | extern struct list_head smack_known_list; |
243 | extern struct list_head smk_netlbladdr_list; | 240 | extern struct list_head smk_netlbladdr_list; |
244 | 241 | ||
245 | extern struct security_operations smack_ops; | 242 | extern struct security_operations smack_ops; |
246 | 243 | ||
247 | /* | 244 | /* |
248 | * Stricly for CIPSO level manipulation. | ||
249 | * Set the category bit number in a smack label sized buffer. | ||
250 | */ | ||
251 | static inline void smack_catset_bit(int cat, char *catsetp) | ||
252 | { | ||
253 | if (cat > SMK_LABELLEN * 8) | ||
254 | return; | ||
255 | |||
256 | catsetp[(cat - 1) / 8] |= 0x80 >> ((cat - 1) % 8); | ||
257 | } | ||
258 | |||
259 | /* | ||
260 | * Is the directory transmuting? | 245 | * Is the directory transmuting? |
261 | */ | 246 | */ |
262 | static inline int smk_inode_transmutable(const struct inode *isp) | 247 | static inline int smk_inode_transmutable(const struct inode *isp) |
@@ -319,7 +304,7 @@ void smack_log(char *subject_label, char *object_label, | |||
319 | static inline void smk_ad_init(struct smk_audit_info *a, const char *func, | 304 | static inline void smk_ad_init(struct smk_audit_info *a, const char *func, |
320 | char type) | 305 | char type) |
321 | { | 306 | { |
322 | memset(a, 0, sizeof(*a)); | 307 | memset(&a->sad, 0, sizeof(a->sad)); |
323 | a->a.type = type; | 308 | a->a.type = type; |
324 | a->a.smack_audit_data = &a->sad; | 309 | a->a.smack_audit_data = &a->sad; |
325 | a->a.smack_audit_data->function = func; | 310 | a->a.smack_audit_data->function = func; |
diff --git a/security/smack/smack_access.c b/security/smack/smack_access.c index c8115f7308f8..9f3705e92712 100644 --- a/security/smack/smack_access.c +++ b/security/smack/smack_access.c | |||
@@ -19,37 +19,31 @@ | |||
19 | struct smack_known smack_known_huh = { | 19 | struct smack_known smack_known_huh = { |
20 | .smk_known = "?", | 20 | .smk_known = "?", |
21 | .smk_secid = 2, | 21 | .smk_secid = 2, |
22 | .smk_cipso = NULL, | ||
23 | }; | 22 | }; |
24 | 23 | ||
25 | struct smack_known smack_known_hat = { | 24 | struct smack_known smack_known_hat = { |
26 | .smk_known = "^", | 25 | .smk_known = "^", |
27 | .smk_secid = 3, | 26 | .smk_secid = 3, |
28 | .smk_cipso = NULL, | ||
29 | }; | 27 | }; |
30 | 28 | ||
31 | struct smack_known smack_known_star = { | 29 | struct smack_known smack_known_star = { |
32 | .smk_known = "*", | 30 | .smk_known = "*", |
33 | .smk_secid = 4, | 31 | .smk_secid = 4, |
34 | .smk_cipso = NULL, | ||
35 | }; | 32 | }; |
36 | 33 | ||
37 | struct smack_known smack_known_floor = { | 34 | struct smack_known smack_known_floor = { |
38 | .smk_known = "_", | 35 | .smk_known = "_", |
39 | .smk_secid = 5, | 36 | .smk_secid = 5, |
40 | .smk_cipso = NULL, | ||
41 | }; | 37 | }; |
42 | 38 | ||
43 | struct smack_known smack_known_invalid = { | 39 | struct smack_known smack_known_invalid = { |
44 | .smk_known = "", | 40 | .smk_known = "", |
45 | .smk_secid = 6, | 41 | .smk_secid = 6, |
46 | .smk_cipso = NULL, | ||
47 | }; | 42 | }; |
48 | 43 | ||
49 | struct smack_known smack_known_web = { | 44 | struct smack_known smack_known_web = { |
50 | .smk_known = "@", | 45 | .smk_known = "@", |
51 | .smk_secid = 7, | 46 | .smk_secid = 7, |
52 | .smk_cipso = NULL, | ||
53 | }; | 47 | }; |
54 | 48 | ||
55 | LIST_HEAD(smack_known_list); | 49 | LIST_HEAD(smack_known_list); |
@@ -331,7 +325,7 @@ void smack_log(char *subject_label, char *object_label, int request, | |||
331 | } | 325 | } |
332 | #endif | 326 | #endif |
333 | 327 | ||
334 | static DEFINE_MUTEX(smack_known_lock); | 328 | DEFINE_MUTEX(smack_known_lock); |
335 | 329 | ||
336 | /** | 330 | /** |
337 | * smk_find_entry - find a label on the list, return the list entry | 331 | * smk_find_entry - find a label on the list, return the list entry |
@@ -345,7 +339,7 @@ struct smack_known *smk_find_entry(const char *string) | |||
345 | struct smack_known *skp; | 339 | struct smack_known *skp; |
346 | 340 | ||
347 | list_for_each_entry_rcu(skp, &smack_known_list, list) { | 341 | list_for_each_entry_rcu(skp, &smack_known_list, list) { |
348 | if (strncmp(skp->smk_known, string, SMK_MAXLEN) == 0) | 342 | if (strcmp(skp->smk_known, string) == 0) |
349 | return skp; | 343 | return skp; |
350 | } | 344 | } |
351 | 345 | ||
@@ -356,27 +350,76 @@ struct smack_known *smk_find_entry(const char *string) | |||
356 | * smk_parse_smack - parse smack label from a text string | 350 | * smk_parse_smack - parse smack label from a text string |
357 | * @string: a text string that might contain a Smack label | 351 | * @string: a text string that might contain a Smack label |
358 | * @len: the maximum size, or zero if it is NULL terminated. | 352 | * @len: the maximum size, or zero if it is NULL terminated. |
359 | * @smack: parsed smack label, or NULL if parse error | 353 | * |
354 | * Returns a pointer to the clean label, or NULL | ||
360 | */ | 355 | */ |
361 | void smk_parse_smack(const char *string, int len, char *smack) | 356 | char *smk_parse_smack(const char *string, int len) |
362 | { | 357 | { |
363 | int found; | 358 | char *smack; |
364 | int i; | 359 | int i; |
365 | 360 | ||
366 | if (len <= 0 || len > SMK_MAXLEN) | 361 | if (len <= 0) |
367 | len = SMK_MAXLEN; | 362 | len = strlen(string) + 1; |
368 | 363 | ||
369 | for (i = 0, found = 0; i < SMK_LABELLEN; i++) { | 364 | /* |
370 | if (found) | 365 | * Reserve a leading '-' as an indicator that |
371 | smack[i] = '\0'; | 366 | * this isn't a label, but an option to interfaces |
372 | else if (i >= len || string[i] > '~' || string[i] <= ' ' || | 367 | * including /smack/cipso and /smack/cipso2 |
373 | string[i] == '/' || string[i] == '"' || | 368 | */ |
374 | string[i] == '\\' || string[i] == '\'') { | 369 | if (string[0] == '-') |
375 | smack[i] = '\0'; | 370 | return NULL; |
376 | found = 1; | 371 | |
377 | } else | 372 | for (i = 0; i < len; i++) |
378 | smack[i] = string[i]; | 373 | if (string[i] > '~' || string[i] <= ' ' || string[i] == '/' || |
374 | string[i] == '"' || string[i] == '\\' || string[i] == '\'') | ||
375 | break; | ||
376 | |||
377 | if (i == 0 || i >= SMK_LONGLABEL) | ||
378 | return NULL; | ||
379 | |||
380 | smack = kzalloc(i + 1, GFP_KERNEL); | ||
381 | if (smack != NULL) { | ||
382 | strncpy(smack, string, i + 1); | ||
383 | smack[i] = '\0'; | ||
379 | } | 384 | } |
385 | return smack; | ||
386 | } | ||
387 | |||
388 | /** | ||
389 | * smk_netlbl_mls - convert a catset to netlabel mls categories | ||
390 | * @catset: the Smack categories | ||
391 | * @sap: where to put the netlabel categories | ||
392 | * | ||
393 | * Allocates and fills attr.mls | ||
394 | * Returns 0 on success, error code on failure. | ||
395 | */ | ||
396 | int smk_netlbl_mls(int level, char *catset, struct netlbl_lsm_secattr *sap, | ||
397 | int len) | ||
398 | { | ||
399 | unsigned char *cp; | ||
400 | unsigned char m; | ||
401 | int cat; | ||
402 | int rc; | ||
403 | int byte; | ||
404 | |||
405 | sap->flags |= NETLBL_SECATTR_MLS_CAT; | ||
406 | sap->attr.mls.lvl = level; | ||
407 | sap->attr.mls.cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC); | ||
408 | sap->attr.mls.cat->startbit = 0; | ||
409 | |||
410 | for (cat = 1, cp = catset, byte = 0; byte < len; cp++, byte++) | ||
411 | for (m = 0x80; m != 0; m >>= 1, cat++) { | ||
412 | if ((m & *cp) == 0) | ||
413 | continue; | ||
414 | rc = netlbl_secattr_catmap_setbit(sap->attr.mls.cat, | ||
415 | cat, GFP_ATOMIC); | ||
416 | if (rc < 0) { | ||
417 | netlbl_secattr_catmap_free(sap->attr.mls.cat); | ||
418 | return rc; | ||
419 | } | ||
420 | } | ||
421 | |||
422 | return 0; | ||
380 | } | 423 | } |
381 | 424 | ||
382 | /** | 425 | /** |
@@ -390,33 +433,59 @@ void smk_parse_smack(const char *string, int len, char *smack) | |||
390 | struct smack_known *smk_import_entry(const char *string, int len) | 433 | struct smack_known *smk_import_entry(const char *string, int len) |
391 | { | 434 | { |
392 | struct smack_known *skp; | 435 | struct smack_known *skp; |
393 | char smack[SMK_LABELLEN]; | 436 | char *smack; |
437 | int slen; | ||
438 | int rc; | ||
394 | 439 | ||
395 | smk_parse_smack(string, len, smack); | 440 | smack = smk_parse_smack(string, len); |
396 | if (smack[0] == '\0') | 441 | if (smack == NULL) |
397 | return NULL; | 442 | return NULL; |
398 | 443 | ||
399 | mutex_lock(&smack_known_lock); | 444 | mutex_lock(&smack_known_lock); |
400 | 445 | ||
401 | skp = smk_find_entry(smack); | 446 | skp = smk_find_entry(smack); |
447 | if (skp != NULL) | ||
448 | goto freeout; | ||
402 | 449 | ||
403 | if (skp == NULL) { | 450 | skp = kzalloc(sizeof(*skp), GFP_KERNEL); |
404 | skp = kzalloc(sizeof(struct smack_known), GFP_KERNEL); | 451 | if (skp == NULL) |
405 | if (skp != NULL) { | 452 | goto freeout; |
406 | strncpy(skp->smk_known, smack, SMK_MAXLEN); | ||
407 | skp->smk_secid = smack_next_secid++; | ||
408 | skp->smk_cipso = NULL; | ||
409 | INIT_LIST_HEAD(&skp->smk_rules); | ||
410 | spin_lock_init(&skp->smk_cipsolock); | ||
411 | mutex_init(&skp->smk_rules_lock); | ||
412 | /* | ||
413 | * Make sure that the entry is actually | ||
414 | * filled before putting it on the list. | ||
415 | */ | ||
416 | list_add_rcu(&skp->list, &smack_known_list); | ||
417 | } | ||
418 | } | ||
419 | 453 | ||
454 | skp->smk_known = smack; | ||
455 | skp->smk_secid = smack_next_secid++; | ||
456 | skp->smk_netlabel.domain = skp->smk_known; | ||
457 | skp->smk_netlabel.flags = | ||
458 | NETLBL_SECATTR_DOMAIN | NETLBL_SECATTR_MLS_LVL; | ||
459 | /* | ||
460 | * If direct labeling works use it. | ||
461 | * Otherwise use mapped labeling. | ||
462 | */ | ||
463 | slen = strlen(smack); | ||
464 | if (slen < SMK_CIPSOLEN) | ||
465 | rc = smk_netlbl_mls(smack_cipso_direct, skp->smk_known, | ||
466 | &skp->smk_netlabel, slen); | ||
467 | else | ||
468 | rc = smk_netlbl_mls(smack_cipso_mapped, (char *)&skp->smk_secid, | ||
469 | &skp->smk_netlabel, sizeof(skp->smk_secid)); | ||
470 | |||
471 | if (rc >= 0) { | ||
472 | INIT_LIST_HEAD(&skp->smk_rules); | ||
473 | mutex_init(&skp->smk_rules_lock); | ||
474 | /* | ||
475 | * Make sure that the entry is actually | ||
476 | * filled before putting it on the list. | ||
477 | */ | ||
478 | list_add_rcu(&skp->list, &smack_known_list); | ||
479 | goto unlockout; | ||
480 | } | ||
481 | /* | ||
482 | * smk_netlbl_mls failed. | ||
483 | */ | ||
484 | kfree(skp); | ||
485 | skp = NULL; | ||
486 | freeout: | ||
487 | kfree(smack); | ||
488 | unlockout: | ||
420 | mutex_unlock(&smack_known_lock); | 489 | mutex_unlock(&smack_known_lock); |
421 | 490 | ||
422 | return skp; | 491 | return skp; |
@@ -479,79 +548,9 @@ char *smack_from_secid(const u32 secid) | |||
479 | */ | 548 | */ |
480 | u32 smack_to_secid(const char *smack) | 549 | u32 smack_to_secid(const char *smack) |
481 | { | 550 | { |
482 | struct smack_known *skp; | 551 | struct smack_known *skp = smk_find_entry(smack); |
483 | 552 | ||
484 | rcu_read_lock(); | 553 | if (skp == NULL) |
485 | list_for_each_entry_rcu(skp, &smack_known_list, list) { | 554 | return 0; |
486 | if (strncmp(skp->smk_known, smack, SMK_MAXLEN) == 0) { | 555 | return skp->smk_secid; |
487 | rcu_read_unlock(); | ||
488 | return skp->smk_secid; | ||
489 | } | ||
490 | } | ||
491 | rcu_read_unlock(); | ||
492 | return 0; | ||
493 | } | ||
494 | |||
495 | /** | ||
496 | * smack_from_cipso - find the Smack label associated with a CIPSO option | ||
497 | * @level: Bell & LaPadula level from the network | ||
498 | * @cp: Bell & LaPadula categories from the network | ||
499 | * | ||
500 | * This is a simple lookup in the label table. | ||
501 | * | ||
502 | * Return the matching label from the label list or NULL. | ||
503 | */ | ||
504 | char *smack_from_cipso(u32 level, char *cp) | ||
505 | { | ||
506 | struct smack_known *kp; | ||
507 | char *final = NULL; | ||
508 | |||
509 | rcu_read_lock(); | ||
510 | list_for_each_entry(kp, &smack_known_list, list) { | ||
511 | if (kp->smk_cipso == NULL) | ||
512 | continue; | ||
513 | |||
514 | spin_lock_bh(&kp->smk_cipsolock); | ||
515 | |||
516 | if (kp->smk_cipso->smk_level == level && | ||
517 | memcmp(kp->smk_cipso->smk_catset, cp, SMK_LABELLEN) == 0) | ||
518 | final = kp->smk_known; | ||
519 | |||
520 | spin_unlock_bh(&kp->smk_cipsolock); | ||
521 | |||
522 | if (final != NULL) | ||
523 | break; | ||
524 | } | ||
525 | rcu_read_unlock(); | ||
526 | |||
527 | return final; | ||
528 | } | ||
529 | |||
530 | /** | ||
531 | * smack_to_cipso - find the CIPSO option to go with a Smack label | ||
532 | * @smack: a pointer to the smack label in question | ||
533 | * @cp: where to put the result | ||
534 | * | ||
535 | * Returns zero if a value is available, non-zero otherwise. | ||
536 | */ | ||
537 | int smack_to_cipso(const char *smack, struct smack_cipso *cp) | ||
538 | { | ||
539 | struct smack_known *kp; | ||
540 | int found = 0; | ||
541 | |||
542 | rcu_read_lock(); | ||
543 | list_for_each_entry_rcu(kp, &smack_known_list, list) { | ||
544 | if (kp->smk_known == smack || | ||
545 | strcmp(kp->smk_known, smack) == 0) { | ||
546 | found = 1; | ||
547 | break; | ||
548 | } | ||
549 | } | ||
550 | rcu_read_unlock(); | ||
551 | |||
552 | if (found == 0 || kp->smk_cipso == NULL) | ||
553 | return -ENOENT; | ||
554 | |||
555 | memcpy(cp, kp->smk_cipso, sizeof(struct smack_cipso)); | ||
556 | return 0; | ||
557 | } | 556 | } |
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 45c32f074166..d583c0545808 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c | |||
@@ -30,7 +30,6 @@ | |||
30 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
31 | #include <linux/mutex.h> | 31 | #include <linux/mutex.h> |
32 | #include <linux/pipe_fs_i.h> | 32 | #include <linux/pipe_fs_i.h> |
33 | #include <net/netlabel.h> | ||
34 | #include <net/cipso_ipv4.h> | 33 | #include <net/cipso_ipv4.h> |
35 | #include <linux/audit.h> | 34 | #include <linux/audit.h> |
36 | #include <linux/magic.h> | 35 | #include <linux/magic.h> |
@@ -57,16 +56,23 @@ | |||
57 | static char *smk_fetch(const char *name, struct inode *ip, struct dentry *dp) | 56 | static char *smk_fetch(const char *name, struct inode *ip, struct dentry *dp) |
58 | { | 57 | { |
59 | int rc; | 58 | int rc; |
60 | char in[SMK_LABELLEN]; | 59 | char *buffer; |
60 | char *result = NULL; | ||
61 | 61 | ||
62 | if (ip->i_op->getxattr == NULL) | 62 | if (ip->i_op->getxattr == NULL) |
63 | return NULL; | 63 | return NULL; |
64 | 64 | ||
65 | rc = ip->i_op->getxattr(dp, name, in, SMK_LABELLEN); | 65 | buffer = kzalloc(SMK_LONGLABEL, GFP_KERNEL); |
66 | if (rc < 0) | 66 | if (buffer == NULL) |
67 | return NULL; | 67 | return NULL; |
68 | 68 | ||
69 | return smk_import(in, rc); | 69 | rc = ip->i_op->getxattr(dp, name, buffer, SMK_LONGLABEL); |
70 | if (rc > 0) | ||
71 | result = smk_import(buffer, rc); | ||
72 | |||
73 | kfree(buffer); | ||
74 | |||
75 | return result; | ||
70 | } | 76 | } |
71 | 77 | ||
72 | /** | 78 | /** |
@@ -79,7 +85,7 @@ struct inode_smack *new_inode_smack(char *smack) | |||
79 | { | 85 | { |
80 | struct inode_smack *isp; | 86 | struct inode_smack *isp; |
81 | 87 | ||
82 | isp = kzalloc(sizeof(struct inode_smack), GFP_KERNEL); | 88 | isp = kzalloc(sizeof(struct inode_smack), GFP_NOFS); |
83 | if (isp == NULL) | 89 | if (isp == NULL) |
84 | return NULL; | 90 | return NULL; |
85 | 91 | ||
@@ -556,13 +562,14 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir, | |||
556 | void **value, size_t *len) | 562 | void **value, size_t *len) |
557 | { | 563 | { |
558 | struct smack_known *skp; | 564 | struct smack_known *skp; |
565 | struct inode_smack *issp = inode->i_security; | ||
559 | char *csp = smk_of_current(); | 566 | char *csp = smk_of_current(); |
560 | char *isp = smk_of_inode(inode); | 567 | char *isp = smk_of_inode(inode); |
561 | char *dsp = smk_of_inode(dir); | 568 | char *dsp = smk_of_inode(dir); |
562 | int may; | 569 | int may; |
563 | 570 | ||
564 | if (name) { | 571 | if (name) { |
565 | *name = kstrdup(XATTR_SMACK_SUFFIX, GFP_KERNEL); | 572 | *name = kstrdup(XATTR_SMACK_SUFFIX, GFP_NOFS); |
566 | if (*name == NULL) | 573 | if (*name == NULL) |
567 | return -ENOMEM; | 574 | return -ENOMEM; |
568 | } | 575 | } |
@@ -577,12 +584,15 @@ static int smack_inode_init_security(struct inode *inode, struct inode *dir, | |||
577 | * If the access rule allows transmutation and | 584 | * If the access rule allows transmutation and |
578 | * the directory requests transmutation then | 585 | * the directory requests transmutation then |
579 | * by all means transmute. | 586 | * by all means transmute. |
587 | * Mark the inode as changed. | ||
580 | */ | 588 | */ |
581 | if (may > 0 && ((may & MAY_TRANSMUTE) != 0) && | 589 | if (may > 0 && ((may & MAY_TRANSMUTE) != 0) && |
582 | smk_inode_transmutable(dir)) | 590 | smk_inode_transmutable(dir)) { |
583 | isp = dsp; | 591 | isp = dsp; |
592 | issp->smk_flags |= SMK_INODE_CHANGED; | ||
593 | } | ||
584 | 594 | ||
585 | *value = kstrdup(isp, GFP_KERNEL); | 595 | *value = kstrdup(isp, GFP_NOFS); |
586 | if (*value == NULL) | 596 | if (*value == NULL) |
587 | return -ENOMEM; | 597 | return -ENOMEM; |
588 | } | 598 | } |
@@ -821,7 +831,7 @@ static int smack_inode_setxattr(struct dentry *dentry, const char *name, | |||
821 | * check label validity here so import wont fail on | 831 | * check label validity here so import wont fail on |
822 | * post_setxattr | 832 | * post_setxattr |
823 | */ | 833 | */ |
824 | if (size == 0 || size >= SMK_LABELLEN || | 834 | if (size == 0 || size >= SMK_LONGLABEL || |
825 | smk_import(value, size) == NULL) | 835 | smk_import(value, size) == NULL) |
826 | rc = -EINVAL; | 836 | rc = -EINVAL; |
827 | } else if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) { | 837 | } else if (strcmp(name, XATTR_NAME_SMACKTRANSMUTE) == 0) { |
@@ -1349,7 +1359,7 @@ static int smack_file_receive(struct file *file) | |||
1349 | } | 1359 | } |
1350 | 1360 | ||
1351 | /** | 1361 | /** |
1352 | * smack_dentry_open - Smack dentry open processing | 1362 | * smack_file_open - Smack dentry open processing |
1353 | * @file: the object | 1363 | * @file: the object |
1354 | * @cred: unused | 1364 | * @cred: unused |
1355 | * | 1365 | * |
@@ -1357,7 +1367,7 @@ static int smack_file_receive(struct file *file) | |||
1357 | * | 1367 | * |
1358 | * Returns 0 | 1368 | * Returns 0 |
1359 | */ | 1369 | */ |
1360 | static int smack_dentry_open(struct file *file, const struct cred *cred) | 1370 | static int smack_file_open(struct file *file, const struct cred *cred) |
1361 | { | 1371 | { |
1362 | struct inode_smack *isp = file->f_path.dentry->d_inode->i_security; | 1372 | struct inode_smack *isp = file->f_path.dentry->d_inode->i_security; |
1363 | 1373 | ||
@@ -1820,65 +1830,6 @@ static char *smack_host_label(struct sockaddr_in *sip) | |||
1820 | } | 1830 | } |
1821 | 1831 | ||
1822 | /** | 1832 | /** |
1823 | * smack_set_catset - convert a capset to netlabel mls categories | ||
1824 | * @catset: the Smack categories | ||
1825 | * @sap: where to put the netlabel categories | ||
1826 | * | ||
1827 | * Allocates and fills attr.mls.cat | ||
1828 | */ | ||
1829 | static void smack_set_catset(char *catset, struct netlbl_lsm_secattr *sap) | ||
1830 | { | ||
1831 | unsigned char *cp; | ||
1832 | unsigned char m; | ||
1833 | int cat; | ||
1834 | int rc; | ||
1835 | int byte; | ||
1836 | |||
1837 | if (!catset) | ||
1838 | return; | ||
1839 | |||
1840 | sap->flags |= NETLBL_SECATTR_MLS_CAT; | ||
1841 | sap->attr.mls.cat = netlbl_secattr_catmap_alloc(GFP_ATOMIC); | ||
1842 | sap->attr.mls.cat->startbit = 0; | ||
1843 | |||
1844 | for (cat = 1, cp = catset, byte = 0; byte < SMK_LABELLEN; cp++, byte++) | ||
1845 | for (m = 0x80; m != 0; m >>= 1, cat++) { | ||
1846 | if ((m & *cp) == 0) | ||
1847 | continue; | ||
1848 | rc = netlbl_secattr_catmap_setbit(sap->attr.mls.cat, | ||
1849 | cat, GFP_ATOMIC); | ||
1850 | } | ||
1851 | } | ||
1852 | |||
1853 | /** | ||
1854 | * smack_to_secattr - fill a secattr from a smack value | ||
1855 | * @smack: the smack value | ||
1856 | * @nlsp: where the result goes | ||
1857 | * | ||
1858 | * Casey says that CIPSO is good enough for now. | ||
1859 | * It can be used to effect. | ||
1860 | * It can also be abused to effect when necessary. | ||
1861 | * Apologies to the TSIG group in general and GW in particular. | ||
1862 | */ | ||
1863 | static void smack_to_secattr(char *smack, struct netlbl_lsm_secattr *nlsp) | ||
1864 | { | ||
1865 | struct smack_cipso cipso; | ||
1866 | int rc; | ||
1867 | |||
1868 | nlsp->domain = smack; | ||
1869 | nlsp->flags = NETLBL_SECATTR_DOMAIN | NETLBL_SECATTR_MLS_LVL; | ||
1870 | |||
1871 | rc = smack_to_cipso(smack, &cipso); | ||
1872 | if (rc == 0) { | ||
1873 | nlsp->attr.mls.lvl = cipso.smk_level; | ||
1874 | smack_set_catset(cipso.smk_catset, nlsp); | ||
1875 | } else { | ||
1876 | nlsp->attr.mls.lvl = smack_cipso_direct; | ||
1877 | smack_set_catset(smack, nlsp); | ||
1878 | } | ||
1879 | } | ||
1880 | |||
1881 | /** | ||
1882 | * smack_netlabel - Set the secattr on a socket | 1833 | * smack_netlabel - Set the secattr on a socket |
1883 | * @sk: the socket | 1834 | * @sk: the socket |
1884 | * @labeled: socket label scheme | 1835 | * @labeled: socket label scheme |
@@ -1890,8 +1841,8 @@ static void smack_to_secattr(char *smack, struct netlbl_lsm_secattr *nlsp) | |||
1890 | */ | 1841 | */ |
1891 | static int smack_netlabel(struct sock *sk, int labeled) | 1842 | static int smack_netlabel(struct sock *sk, int labeled) |
1892 | { | 1843 | { |
1844 | struct smack_known *skp; | ||
1893 | struct socket_smack *ssp = sk->sk_security; | 1845 | struct socket_smack *ssp = sk->sk_security; |
1894 | struct netlbl_lsm_secattr secattr; | ||
1895 | int rc = 0; | 1846 | int rc = 0; |
1896 | 1847 | ||
1897 | /* | 1848 | /* |
@@ -1909,10 +1860,8 @@ static int smack_netlabel(struct sock *sk, int labeled) | |||
1909 | labeled == SMACK_UNLABELED_SOCKET) | 1860 | labeled == SMACK_UNLABELED_SOCKET) |
1910 | netlbl_sock_delattr(sk); | 1861 | netlbl_sock_delattr(sk); |
1911 | else { | 1862 | else { |
1912 | netlbl_secattr_init(&secattr); | 1863 | skp = smk_find_entry(ssp->smk_out); |
1913 | smack_to_secattr(ssp->smk_out, &secattr); | 1864 | rc = netlbl_sock_setattr(sk, sk->sk_family, &skp->smk_netlabel); |
1914 | rc = netlbl_sock_setattr(sk, sk->sk_family, &secattr); | ||
1915 | netlbl_secattr_destroy(&secattr); | ||
1916 | } | 1865 | } |
1917 | 1866 | ||
1918 | bh_unlock_sock(sk); | 1867 | bh_unlock_sock(sk); |
@@ -1985,7 +1934,7 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name, | |||
1985 | struct socket *sock; | 1934 | struct socket *sock; |
1986 | int rc = 0; | 1935 | int rc = 0; |
1987 | 1936 | ||
1988 | if (value == NULL || size > SMK_LABELLEN || size == 0) | 1937 | if (value == NULL || size > SMK_LONGLABEL || size == 0) |
1989 | return -EACCES; | 1938 | return -EACCES; |
1990 | 1939 | ||
1991 | sp = smk_import(value, size); | 1940 | sp = smk_import(value, size); |
@@ -2552,6 +2501,7 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) | |||
2552 | char *final; | 2501 | char *final; |
2553 | char trattr[TRANS_TRUE_SIZE]; | 2502 | char trattr[TRANS_TRUE_SIZE]; |
2554 | int transflag = 0; | 2503 | int transflag = 0; |
2504 | int rc; | ||
2555 | struct dentry *dp; | 2505 | struct dentry *dp; |
2556 | 2506 | ||
2557 | if (inode == NULL) | 2507 | if (inode == NULL) |
@@ -2670,17 +2620,38 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode) | |||
2670 | */ | 2620 | */ |
2671 | dp = dget(opt_dentry); | 2621 | dp = dget(opt_dentry); |
2672 | fetched = smk_fetch(XATTR_NAME_SMACK, inode, dp); | 2622 | fetched = smk_fetch(XATTR_NAME_SMACK, inode, dp); |
2673 | if (fetched != NULL) { | 2623 | if (fetched != NULL) |
2674 | final = fetched; | 2624 | final = fetched; |
2675 | if (S_ISDIR(inode->i_mode)) { | 2625 | |
2676 | trattr[0] = '\0'; | 2626 | /* |
2677 | inode->i_op->getxattr(dp, | 2627 | * Transmuting directory |
2628 | */ | ||
2629 | if (S_ISDIR(inode->i_mode)) { | ||
2630 | /* | ||
2631 | * If this is a new directory and the label was | ||
2632 | * transmuted when the inode was initialized | ||
2633 | * set the transmute attribute on the directory | ||
2634 | * and mark the inode. | ||
2635 | * | ||
2636 | * If there is a transmute attribute on the | ||
2637 | * directory mark the inode. | ||
2638 | */ | ||
2639 | if (isp->smk_flags & SMK_INODE_CHANGED) { | ||
2640 | isp->smk_flags &= ~SMK_INODE_CHANGED; | ||
2641 | rc = inode->i_op->setxattr(dp, | ||
2678 | XATTR_NAME_SMACKTRANSMUTE, | 2642 | XATTR_NAME_SMACKTRANSMUTE, |
2679 | trattr, TRANS_TRUE_SIZE); | 2643 | TRANS_TRUE, TRANS_TRUE_SIZE, |
2680 | if (strncmp(trattr, TRANS_TRUE, | 2644 | 0); |
2681 | TRANS_TRUE_SIZE) == 0) | 2645 | } else { |
2682 | transflag = SMK_INODE_TRANSMUTE; | 2646 | rc = inode->i_op->getxattr(dp, |
2647 | XATTR_NAME_SMACKTRANSMUTE, trattr, | ||
2648 | TRANS_TRUE_SIZE); | ||
2649 | if (rc >= 0 && strncmp(trattr, TRANS_TRUE, | ||
2650 | TRANS_TRUE_SIZE) != 0) | ||
2651 | rc = -EINVAL; | ||
2683 | } | 2652 | } |
2653 | if (rc >= 0) | ||
2654 | transflag = SMK_INODE_TRANSMUTE; | ||
2684 | } | 2655 | } |
2685 | isp->smk_task = smk_fetch(XATTR_NAME_SMACKEXEC, inode, dp); | 2656 | isp->smk_task = smk_fetch(XATTR_NAME_SMACKEXEC, inode, dp); |
2686 | isp->smk_mmap = smk_fetch(XATTR_NAME_SMACKMMAP, inode, dp); | 2657 | isp->smk_mmap = smk_fetch(XATTR_NAME_SMACKMMAP, inode, dp); |
@@ -2759,7 +2730,7 @@ static int smack_setprocattr(struct task_struct *p, char *name, | |||
2759 | if (!capable(CAP_MAC_ADMIN)) | 2730 | if (!capable(CAP_MAC_ADMIN)) |
2760 | return -EPERM; | 2731 | return -EPERM; |
2761 | 2732 | ||
2762 | if (value == NULL || size == 0 || size >= SMK_LABELLEN) | 2733 | if (value == NULL || size == 0 || size >= SMK_LONGLABEL) |
2763 | return -EINVAL; | 2734 | return -EINVAL; |
2764 | 2735 | ||
2765 | if (strcmp(name, "current") != 0) | 2736 | if (strcmp(name, "current") != 0) |
@@ -2895,10 +2866,9 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg, | |||
2895 | static char *smack_from_secattr(struct netlbl_lsm_secattr *sap, | 2866 | static char *smack_from_secattr(struct netlbl_lsm_secattr *sap, |
2896 | struct socket_smack *ssp) | 2867 | struct socket_smack *ssp) |
2897 | { | 2868 | { |
2898 | struct smack_known *skp; | 2869 | struct smack_known *kp; |
2899 | char smack[SMK_LABELLEN]; | ||
2900 | char *sp; | 2870 | char *sp; |
2901 | int pcat; | 2871 | int found = 0; |
2902 | 2872 | ||
2903 | if ((sap->flags & NETLBL_SECATTR_MLS_LVL) != 0) { | 2873 | if ((sap->flags & NETLBL_SECATTR_MLS_LVL) != 0) { |
2904 | /* | 2874 | /* |
@@ -2906,59 +2876,27 @@ static char *smack_from_secattr(struct netlbl_lsm_secattr *sap, | |||
2906 | * If there are flags but no level netlabel isn't | 2876 | * If there are flags but no level netlabel isn't |
2907 | * behaving the way we expect it to. | 2877 | * behaving the way we expect it to. |
2908 | * | 2878 | * |
2909 | * Get the categories, if any | 2879 | * Look it up in the label table |
2910 | * Without guidance regarding the smack value | 2880 | * Without guidance regarding the smack value |
2911 | * for the packet fall back on the network | 2881 | * for the packet fall back on the network |
2912 | * ambient value. | 2882 | * ambient value. |
2913 | */ | 2883 | */ |
2914 | memset(smack, '\0', SMK_LABELLEN); | 2884 | rcu_read_lock(); |
2915 | if ((sap->flags & NETLBL_SECATTR_MLS_CAT) != 0) | 2885 | list_for_each_entry(kp, &smack_known_list, list) { |
2916 | for (pcat = -1;;) { | 2886 | if (sap->attr.mls.lvl != kp->smk_netlabel.attr.mls.lvl) |
2917 | pcat = netlbl_secattr_catmap_walk( | 2887 | continue; |
2918 | sap->attr.mls.cat, pcat + 1); | 2888 | if (memcmp(sap->attr.mls.cat, |
2919 | if (pcat < 0) | 2889 | kp->smk_netlabel.attr.mls.cat, |
2920 | break; | 2890 | SMK_CIPSOLEN) != 0) |
2921 | smack_catset_bit(pcat, smack); | 2891 | continue; |
2922 | } | 2892 | found = 1; |
2923 | /* | 2893 | break; |
2924 | * If it is CIPSO using smack direct mapping | ||
2925 | * we are already done. WeeHee. | ||
2926 | */ | ||
2927 | if (sap->attr.mls.lvl == smack_cipso_direct) { | ||
2928 | /* | ||
2929 | * The label sent is usually on the label list. | ||
2930 | * | ||
2931 | * If it is not we may still want to allow the | ||
2932 | * delivery. | ||
2933 | * | ||
2934 | * If the recipient is accepting all packets | ||
2935 | * because it is using the star ("*") label | ||
2936 | * for SMACK64IPIN provide the web ("@") label | ||
2937 | * so that a directed response will succeed. | ||
2938 | * This is not very correct from a MAC point | ||
2939 | * of view, but gets around the problem that | ||
2940 | * locking prevents adding the newly discovered | ||
2941 | * label to the list. | ||
2942 | * The case where the recipient is not using | ||
2943 | * the star label should obviously fail. | ||
2944 | * The easy way to do this is to provide the | ||
2945 | * star label as the subject label. | ||
2946 | */ | ||
2947 | skp = smk_find_entry(smack); | ||
2948 | if (skp != NULL) | ||
2949 | return skp->smk_known; | ||
2950 | if (ssp != NULL && | ||
2951 | ssp->smk_in == smack_known_star.smk_known) | ||
2952 | return smack_known_web.smk_known; | ||
2953 | return smack_known_star.smk_known; | ||
2954 | } | 2894 | } |
2955 | /* | 2895 | rcu_read_unlock(); |
2956 | * Look it up in the supplied table if it is not | 2896 | |
2957 | * a direct mapping. | 2897 | if (found) |
2958 | */ | 2898 | return kp->smk_known; |
2959 | sp = smack_from_cipso(sap->attr.mls.lvl, smack); | 2899 | |
2960 | if (sp != NULL) | ||
2961 | return sp; | ||
2962 | if (ssp != NULL && ssp->smk_in == smack_known_star.smk_known) | 2900 | if (ssp != NULL && ssp->smk_in == smack_known_star.smk_known) |
2963 | return smack_known_web.smk_known; | 2901 | return smack_known_web.smk_known; |
2964 | return smack_known_star.smk_known; | 2902 | return smack_known_star.smk_known; |
@@ -3158,11 +3096,13 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb, | |||
3158 | struct request_sock *req) | 3096 | struct request_sock *req) |
3159 | { | 3097 | { |
3160 | u16 family = sk->sk_family; | 3098 | u16 family = sk->sk_family; |
3099 | struct smack_known *skp; | ||
3161 | struct socket_smack *ssp = sk->sk_security; | 3100 | struct socket_smack *ssp = sk->sk_security; |
3162 | struct netlbl_lsm_secattr secattr; | 3101 | struct netlbl_lsm_secattr secattr; |
3163 | struct sockaddr_in addr; | 3102 | struct sockaddr_in addr; |
3164 | struct iphdr *hdr; | 3103 | struct iphdr *hdr; |
3165 | char *sp; | 3104 | char *sp; |
3105 | char *hsp; | ||
3166 | int rc; | 3106 | int rc; |
3167 | struct smk_audit_info ad; | 3107 | struct smk_audit_info ad; |
3168 | #ifdef CONFIG_AUDIT | 3108 | #ifdef CONFIG_AUDIT |
@@ -3209,16 +3149,14 @@ static int smack_inet_conn_request(struct sock *sk, struct sk_buff *skb, | |||
3209 | hdr = ip_hdr(skb); | 3149 | hdr = ip_hdr(skb); |
3210 | addr.sin_addr.s_addr = hdr->saddr; | 3150 | addr.sin_addr.s_addr = hdr->saddr; |
3211 | rcu_read_lock(); | 3151 | rcu_read_lock(); |
3212 | if (smack_host_label(&addr) == NULL) { | 3152 | hsp = smack_host_label(&addr); |
3213 | rcu_read_unlock(); | 3153 | rcu_read_unlock(); |
3214 | netlbl_secattr_init(&secattr); | 3154 | |
3215 | smack_to_secattr(sp, &secattr); | 3155 | if (hsp == NULL) { |
3216 | rc = netlbl_req_setattr(req, &secattr); | 3156 | skp = smk_find_entry(sp); |
3217 | netlbl_secattr_destroy(&secattr); | 3157 | rc = netlbl_req_setattr(req, &skp->smk_netlabel); |
3218 | } else { | 3158 | } else |
3219 | rcu_read_unlock(); | ||
3220 | netlbl_req_delattr(req); | 3159 | netlbl_req_delattr(req); |
3221 | } | ||
3222 | 3160 | ||
3223 | return rc; | 3161 | return rc; |
3224 | } | 3162 | } |
@@ -3400,7 +3338,7 @@ static int smack_audit_rule_match(u32 secid, u32 field, u32 op, void *vrule, | |||
3400 | char *rule = vrule; | 3338 | char *rule = vrule; |
3401 | 3339 | ||
3402 | if (!rule) { | 3340 | if (!rule) { |
3403 | audit_log(actx, GFP_KERNEL, AUDIT_SELINUX_ERR, | 3341 | audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR, |
3404 | "Smack: missing rule\n"); | 3342 | "Smack: missing rule\n"); |
3405 | return -ENOENT; | 3343 | return -ENOENT; |
3406 | } | 3344 | } |
@@ -3549,7 +3487,7 @@ struct security_operations smack_ops = { | |||
3549 | .file_send_sigiotask = smack_file_send_sigiotask, | 3487 | .file_send_sigiotask = smack_file_send_sigiotask, |
3550 | .file_receive = smack_file_receive, | 3488 | .file_receive = smack_file_receive, |
3551 | 3489 | ||
3552 | .dentry_open = smack_dentry_open, | 3490 | .file_open = smack_file_open, |
3553 | 3491 | ||
3554 | .cred_alloc_blank = smack_cred_alloc_blank, | 3492 | .cred_alloc_blank = smack_cred_alloc_blank, |
3555 | .cred_free = smack_cred_free, | 3493 | .cred_free = smack_cred_free, |
@@ -3643,15 +3581,6 @@ struct security_operations smack_ops = { | |||
3643 | static __init void init_smack_known_list(void) | 3581 | static __init void init_smack_known_list(void) |
3644 | { | 3582 | { |
3645 | /* | 3583 | /* |
3646 | * Initialize CIPSO locks | ||
3647 | */ | ||
3648 | spin_lock_init(&smack_known_huh.smk_cipsolock); | ||
3649 | spin_lock_init(&smack_known_hat.smk_cipsolock); | ||
3650 | spin_lock_init(&smack_known_star.smk_cipsolock); | ||
3651 | spin_lock_init(&smack_known_floor.smk_cipsolock); | ||
3652 | spin_lock_init(&smack_known_invalid.smk_cipsolock); | ||
3653 | spin_lock_init(&smack_known_web.smk_cipsolock); | ||
3654 | /* | ||
3655 | * Initialize rule list locks | 3584 | * Initialize rule list locks |
3656 | */ | 3585 | */ |
3657 | mutex_init(&smack_known_huh.smk_rules_lock); | 3586 | mutex_init(&smack_known_huh.smk_rules_lock); |
diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index 038811cb7e62..1810c9a4ed48 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c | |||
@@ -22,7 +22,6 @@ | |||
22 | #include <linux/mutex.h> | 22 | #include <linux/mutex.h> |
23 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
24 | #include <net/net_namespace.h> | 24 | #include <net/net_namespace.h> |
25 | #include <net/netlabel.h> | ||
26 | #include <net/cipso_ipv4.h> | 25 | #include <net/cipso_ipv4.h> |
27 | #include <linux/seq_file.h> | 26 | #include <linux/seq_file.h> |
28 | #include <linux/ctype.h> | 27 | #include <linux/ctype.h> |
@@ -45,6 +44,11 @@ enum smk_inos { | |||
45 | SMK_LOGGING = 10, /* logging */ | 44 | SMK_LOGGING = 10, /* logging */ |
46 | SMK_LOAD_SELF = 11, /* task specific rules */ | 45 | SMK_LOAD_SELF = 11, /* task specific rules */ |
47 | SMK_ACCESSES = 12, /* access policy */ | 46 | SMK_ACCESSES = 12, /* access policy */ |
47 | SMK_MAPPED = 13, /* CIPSO level indicating mapped label */ | ||
48 | SMK_LOAD2 = 14, /* load policy with long labels */ | ||
49 | SMK_LOAD_SELF2 = 15, /* load task specific rules with long labels */ | ||
50 | SMK_ACCESS2 = 16, /* make an access check with long labels */ | ||
51 | SMK_CIPSO2 = 17, /* load long label -> CIPSO mapping */ | ||
48 | }; | 52 | }; |
49 | 53 | ||
50 | /* | 54 | /* |
@@ -60,7 +64,7 @@ static DEFINE_MUTEX(smk_netlbladdr_lock); | |||
60 | * If it isn't somehow marked, use this. | 64 | * If it isn't somehow marked, use this. |
61 | * It can be reset via smackfs/ambient | 65 | * It can be reset via smackfs/ambient |
62 | */ | 66 | */ |
63 | char *smack_net_ambient = smack_known_floor.smk_known; | 67 | char *smack_net_ambient; |
64 | 68 | ||
65 | /* | 69 | /* |
66 | * This is the level in a CIPSO header that indicates a | 70 | * This is the level in a CIPSO header that indicates a |
@@ -70,6 +74,13 @@ char *smack_net_ambient = smack_known_floor.smk_known; | |||
70 | int smack_cipso_direct = SMACK_CIPSO_DIRECT_DEFAULT; | 74 | int smack_cipso_direct = SMACK_CIPSO_DIRECT_DEFAULT; |
71 | 75 | ||
72 | /* | 76 | /* |
77 | * This is the level in a CIPSO header that indicates a | ||
78 | * secid is contained directly in the category set. | ||
79 | * It can be reset via smackfs/mapped | ||
80 | */ | ||
81 | int smack_cipso_mapped = SMACK_CIPSO_MAPPED_DEFAULT; | ||
82 | |||
83 | /* | ||
73 | * Unless a process is running with this label even | 84 | * Unless a process is running with this label even |
74 | * having CAP_MAC_OVERRIDE isn't enough to grant | 85 | * having CAP_MAC_OVERRIDE isn't enough to grant |
75 | * privilege to violate MAC policy. If no label is | 86 | * privilege to violate MAC policy. If no label is |
@@ -89,7 +100,7 @@ LIST_HEAD(smk_netlbladdr_list); | |||
89 | 100 | ||
90 | /* | 101 | /* |
91 | * Rule lists are maintained for each label. | 102 | * Rule lists are maintained for each label. |
92 | * This master list is just for reading /smack/load. | 103 | * This master list is just for reading /smack/load and /smack/load2. |
93 | */ | 104 | */ |
94 | struct smack_master_list { | 105 | struct smack_master_list { |
95 | struct list_head list; | 106 | struct list_head list; |
@@ -125,6 +136,18 @@ const char *smack_cipso_option = SMACK_CIPSO_OPTION; | |||
125 | #define SMK_OLOADLEN (SMK_LABELLEN + SMK_LABELLEN + SMK_OACCESSLEN) | 136 | #define SMK_OLOADLEN (SMK_LABELLEN + SMK_LABELLEN + SMK_OACCESSLEN) |
126 | #define SMK_LOADLEN (SMK_LABELLEN + SMK_LABELLEN + SMK_ACCESSLEN) | 137 | #define SMK_LOADLEN (SMK_LABELLEN + SMK_LABELLEN + SMK_ACCESSLEN) |
127 | 138 | ||
139 | /* | ||
140 | * Stricly for CIPSO level manipulation. | ||
141 | * Set the category bit number in a smack label sized buffer. | ||
142 | */ | ||
143 | static inline void smack_catset_bit(unsigned int cat, char *catsetp) | ||
144 | { | ||
145 | if (cat == 0 || cat > (SMK_CIPSOLEN * 8)) | ||
146 | return; | ||
147 | |||
148 | catsetp[(cat - 1) / 8] |= 0x80 >> ((cat - 1) % 8); | ||
149 | } | ||
150 | |||
128 | /** | 151 | /** |
129 | * smk_netlabel_audit_set - fill a netlbl_audit struct | 152 | * smk_netlabel_audit_set - fill a netlbl_audit struct |
130 | * @nap: structure to fill | 153 | * @nap: structure to fill |
@@ -137,12 +160,10 @@ static void smk_netlabel_audit_set(struct netlbl_audit *nap) | |||
137 | } | 160 | } |
138 | 161 | ||
139 | /* | 162 | /* |
140 | * Values for parsing single label host rules | 163 | * Value for parsing single label host rules |
141 | * "1.2.3.4 X" | 164 | * "1.2.3.4 X" |
142 | * "192.168.138.129/32 abcdefghijklmnopqrstuvw" | ||
143 | */ | 165 | */ |
144 | #define SMK_NETLBLADDRMIN 9 | 166 | #define SMK_NETLBLADDRMIN 9 |
145 | #define SMK_NETLBLADDRMAX 42 | ||
146 | 167 | ||
147 | /** | 168 | /** |
148 | * smk_set_access - add a rule to the rule list | 169 | * smk_set_access - add a rule to the rule list |
@@ -188,33 +209,47 @@ static int smk_set_access(struct smack_rule *srp, struct list_head *rule_list, | |||
188 | } | 209 | } |
189 | 210 | ||
190 | /** | 211 | /** |
191 | * smk_parse_rule - parse Smack rule from load string | 212 | * smk_fill_rule - Fill Smack rule from strings |
192 | * @data: string to be parsed whose size is SMK_LOADLEN | 213 | * @subject: subject label string |
214 | * @object: object label string | ||
215 | * @access: access string | ||
193 | * @rule: Smack rule | 216 | * @rule: Smack rule |
194 | * @import: if non-zero, import labels | 217 | * @import: if non-zero, import labels |
218 | * | ||
219 | * Returns 0 on success, -1 on failure | ||
195 | */ | 220 | */ |
196 | static int smk_parse_rule(const char *data, struct smack_rule *rule, int import) | 221 | static int smk_fill_rule(const char *subject, const char *object, |
222 | const char *access, struct smack_rule *rule, | ||
223 | int import) | ||
197 | { | 224 | { |
198 | char smack[SMK_LABELLEN]; | 225 | int rc = -1; |
226 | int done; | ||
227 | const char *cp; | ||
199 | struct smack_known *skp; | 228 | struct smack_known *skp; |
200 | 229 | ||
201 | if (import) { | 230 | if (import) { |
202 | rule->smk_subject = smk_import(data, 0); | 231 | rule->smk_subject = smk_import(subject, 0); |
203 | if (rule->smk_subject == NULL) | 232 | if (rule->smk_subject == NULL) |
204 | return -1; | 233 | return -1; |
205 | 234 | ||
206 | rule->smk_object = smk_import(data + SMK_LABELLEN, 0); | 235 | rule->smk_object = smk_import(object, 0); |
207 | if (rule->smk_object == NULL) | 236 | if (rule->smk_object == NULL) |
208 | return -1; | 237 | return -1; |
209 | } else { | 238 | } else { |
210 | smk_parse_smack(data, 0, smack); | 239 | cp = smk_parse_smack(subject, 0); |
211 | skp = smk_find_entry(smack); | 240 | if (cp == NULL) |
241 | return -1; | ||
242 | skp = smk_find_entry(cp); | ||
243 | kfree(cp); | ||
212 | if (skp == NULL) | 244 | if (skp == NULL) |
213 | return -1; | 245 | return -1; |
214 | rule->smk_subject = skp->smk_known; | 246 | rule->smk_subject = skp->smk_known; |
215 | 247 | ||
216 | smk_parse_smack(data + SMK_LABELLEN, 0, smack); | 248 | cp = smk_parse_smack(object, 0); |
217 | skp = smk_find_entry(smack); | 249 | if (cp == NULL) |
250 | return -1; | ||
251 | skp = smk_find_entry(cp); | ||
252 | kfree(cp); | ||
218 | if (skp == NULL) | 253 | if (skp == NULL) |
219 | return -1; | 254 | return -1; |
220 | rule->smk_object = skp->smk_known; | 255 | rule->smk_object = skp->smk_known; |
@@ -222,90 +257,127 @@ static int smk_parse_rule(const char *data, struct smack_rule *rule, int import) | |||
222 | 257 | ||
223 | rule->smk_access = 0; | 258 | rule->smk_access = 0; |
224 | 259 | ||
225 | switch (data[SMK_LABELLEN + SMK_LABELLEN]) { | 260 | for (cp = access, done = 0; *cp && !done; cp++) { |
226 | case '-': | 261 | switch (*cp) { |
227 | break; | 262 | case '-': |
228 | case 'r': | 263 | break; |
229 | case 'R': | 264 | case 'r': |
230 | rule->smk_access |= MAY_READ; | 265 | case 'R': |
231 | break; | 266 | rule->smk_access |= MAY_READ; |
232 | default: | 267 | break; |
233 | return -1; | 268 | case 'w': |
269 | case 'W': | ||
270 | rule->smk_access |= MAY_WRITE; | ||
271 | break; | ||
272 | case 'x': | ||
273 | case 'X': | ||
274 | rule->smk_access |= MAY_EXEC; | ||
275 | break; | ||
276 | case 'a': | ||
277 | case 'A': | ||
278 | rule->smk_access |= MAY_APPEND; | ||
279 | break; | ||
280 | case 't': | ||
281 | case 'T': | ||
282 | rule->smk_access |= MAY_TRANSMUTE; | ||
283 | break; | ||
284 | default: | ||
285 | done = 1; | ||
286 | break; | ||
287 | } | ||
234 | } | 288 | } |
289 | rc = 0; | ||
235 | 290 | ||
236 | switch (data[SMK_LABELLEN + SMK_LABELLEN + 1]) { | 291 | return rc; |
237 | case '-': | 292 | } |
238 | break; | ||
239 | case 'w': | ||
240 | case 'W': | ||
241 | rule->smk_access |= MAY_WRITE; | ||
242 | break; | ||
243 | default: | ||
244 | return -1; | ||
245 | } | ||
246 | 293 | ||
247 | switch (data[SMK_LABELLEN + SMK_LABELLEN + 2]) { | 294 | /** |
248 | case '-': | 295 | * smk_parse_rule - parse Smack rule from load string |
249 | break; | 296 | * @data: string to be parsed whose size is SMK_LOADLEN |
250 | case 'x': | 297 | * @rule: Smack rule |
251 | case 'X': | 298 | * @import: if non-zero, import labels |
252 | rule->smk_access |= MAY_EXEC; | 299 | * |
253 | break; | 300 | * Returns 0 on success, -1 on errors. |
254 | default: | 301 | */ |
255 | return -1; | 302 | static int smk_parse_rule(const char *data, struct smack_rule *rule, int import) |
256 | } | 303 | { |
304 | int rc; | ||
257 | 305 | ||
258 | switch (data[SMK_LABELLEN + SMK_LABELLEN + 3]) { | 306 | rc = smk_fill_rule(data, data + SMK_LABELLEN, |
259 | case '-': | 307 | data + SMK_LABELLEN + SMK_LABELLEN, rule, import); |
260 | break; | 308 | return rc; |
261 | case 'a': | 309 | } |
262 | case 'A': | ||
263 | rule->smk_access |= MAY_APPEND; | ||
264 | break; | ||
265 | default: | ||
266 | return -1; | ||
267 | } | ||
268 | 310 | ||
269 | switch (data[SMK_LABELLEN + SMK_LABELLEN + 4]) { | 311 | /** |
270 | case '-': | 312 | * smk_parse_long_rule - parse Smack rule from rule string |
271 | break; | 313 | * @data: string to be parsed, null terminated |
272 | case 't': | 314 | * @rule: Smack rule |
273 | case 'T': | 315 | * @import: if non-zero, import labels |
274 | rule->smk_access |= MAY_TRANSMUTE; | 316 | * |
275 | break; | 317 | * Returns 0 on success, -1 on failure |
276 | default: | 318 | */ |
277 | return -1; | 319 | static int smk_parse_long_rule(const char *data, struct smack_rule *rule, |
278 | } | 320 | int import) |
321 | { | ||
322 | char *subject; | ||
323 | char *object; | ||
324 | char *access; | ||
325 | int datalen; | ||
326 | int rc = -1; | ||
279 | 327 | ||
280 | return 0; | 328 | /* |
329 | * This is probably inefficient, but safe. | ||
330 | */ | ||
331 | datalen = strlen(data); | ||
332 | subject = kzalloc(datalen, GFP_KERNEL); | ||
333 | if (subject == NULL) | ||
334 | return -1; | ||
335 | object = kzalloc(datalen, GFP_KERNEL); | ||
336 | if (object == NULL) | ||
337 | goto free_out_s; | ||
338 | access = kzalloc(datalen, GFP_KERNEL); | ||
339 | if (access == NULL) | ||
340 | goto free_out_o; | ||
341 | |||
342 | if (sscanf(data, "%s %s %s", subject, object, access) == 3) | ||
343 | rc = smk_fill_rule(subject, object, access, rule, import); | ||
344 | |||
345 | kfree(access); | ||
346 | free_out_o: | ||
347 | kfree(object); | ||
348 | free_out_s: | ||
349 | kfree(subject); | ||
350 | return rc; | ||
281 | } | 351 | } |
282 | 352 | ||
353 | #define SMK_FIXED24_FMT 0 /* Fixed 24byte label format */ | ||
354 | #define SMK_LONG_FMT 1 /* Variable long label format */ | ||
283 | /** | 355 | /** |
284 | * smk_write_load_list - write() for any /smack/load | 356 | * smk_write_rules_list - write() for any /smack rule file |
285 | * @file: file pointer, not actually used | 357 | * @file: file pointer, not actually used |
286 | * @buf: where to get the data from | 358 | * @buf: where to get the data from |
287 | * @count: bytes sent | 359 | * @count: bytes sent |
288 | * @ppos: where to start - must be 0 | 360 | * @ppos: where to start - must be 0 |
289 | * @rule_list: the list of rules to write to | 361 | * @rule_list: the list of rules to write to |
290 | * @rule_lock: lock for the rule list | 362 | * @rule_lock: lock for the rule list |
363 | * @format: /smack/load or /smack/load2 format. | ||
291 | * | 364 | * |
292 | * Get one smack access rule from above. | 365 | * Get one smack access rule from above. |
293 | * The format is exactly: | 366 | * The format for SMK_LONG_FMT is: |
294 | * char subject[SMK_LABELLEN] | 367 | * "subject<whitespace>object<whitespace>access[<whitespace>...]" |
295 | * char object[SMK_LABELLEN] | 368 | * The format for SMK_FIXED24_FMT is exactly: |
296 | * char access[SMK_ACCESSLEN] | 369 | * "subject object rwxat" |
297 | * | ||
298 | * writes must be SMK_LABELLEN+SMK_LABELLEN+SMK_ACCESSLEN bytes. | ||
299 | */ | 370 | */ |
300 | static ssize_t smk_write_load_list(struct file *file, const char __user *buf, | 371 | static ssize_t smk_write_rules_list(struct file *file, const char __user *buf, |
301 | size_t count, loff_t *ppos, | 372 | size_t count, loff_t *ppos, |
302 | struct list_head *rule_list, | 373 | struct list_head *rule_list, |
303 | struct mutex *rule_lock) | 374 | struct mutex *rule_lock, int format) |
304 | { | 375 | { |
305 | struct smack_master_list *smlp; | 376 | struct smack_master_list *smlp; |
306 | struct smack_known *skp; | 377 | struct smack_known *skp; |
307 | struct smack_rule *rule; | 378 | struct smack_rule *rule; |
308 | char *data; | 379 | char *data; |
380 | int datalen; | ||
309 | int rc = -EINVAL; | 381 | int rc = -EINVAL; |
310 | int load = 0; | 382 | int load = 0; |
311 | 383 | ||
@@ -315,13 +387,18 @@ static ssize_t smk_write_load_list(struct file *file, const char __user *buf, | |||
315 | */ | 387 | */ |
316 | if (*ppos != 0) | 388 | if (*ppos != 0) |
317 | return -EINVAL; | 389 | return -EINVAL; |
318 | /* | ||
319 | * Minor hack for backward compatibility | ||
320 | */ | ||
321 | if (count < (SMK_OLOADLEN) || count > SMK_LOADLEN) | ||
322 | return -EINVAL; | ||
323 | 390 | ||
324 | data = kzalloc(SMK_LOADLEN, GFP_KERNEL); | 391 | if (format == SMK_FIXED24_FMT) { |
392 | /* | ||
393 | * Minor hack for backward compatibility | ||
394 | */ | ||
395 | if (count != SMK_OLOADLEN && count != SMK_LOADLEN) | ||
396 | return -EINVAL; | ||
397 | datalen = SMK_LOADLEN; | ||
398 | } else | ||
399 | datalen = count + 1; | ||
400 | |||
401 | data = kzalloc(datalen, GFP_KERNEL); | ||
325 | if (data == NULL) | 402 | if (data == NULL) |
326 | return -ENOMEM; | 403 | return -ENOMEM; |
327 | 404 | ||
@@ -330,20 +407,29 @@ static ssize_t smk_write_load_list(struct file *file, const char __user *buf, | |||
330 | goto out; | 407 | goto out; |
331 | } | 408 | } |
332 | 409 | ||
333 | /* | ||
334 | * More on the minor hack for backward compatibility | ||
335 | */ | ||
336 | if (count == (SMK_OLOADLEN)) | ||
337 | data[SMK_OLOADLEN] = '-'; | ||
338 | |||
339 | rule = kzalloc(sizeof(*rule), GFP_KERNEL); | 410 | rule = kzalloc(sizeof(*rule), GFP_KERNEL); |
340 | if (rule == NULL) { | 411 | if (rule == NULL) { |
341 | rc = -ENOMEM; | 412 | rc = -ENOMEM; |
342 | goto out; | 413 | goto out; |
343 | } | 414 | } |
344 | 415 | ||
345 | if (smk_parse_rule(data, rule, 1)) | 416 | if (format == SMK_LONG_FMT) { |
346 | goto out_free_rule; | 417 | /* |
418 | * Be sure the data string is terminated. | ||
419 | */ | ||
420 | data[count] = '\0'; | ||
421 | if (smk_parse_long_rule(data, rule, 1)) | ||
422 | goto out_free_rule; | ||
423 | } else { | ||
424 | /* | ||
425 | * More on the minor hack for backward compatibility | ||
426 | */ | ||
427 | if (count == (SMK_OLOADLEN)) | ||
428 | data[SMK_OLOADLEN] = '-'; | ||
429 | if (smk_parse_rule(data, rule, 1)) | ||
430 | goto out_free_rule; | ||
431 | } | ||
432 | |||
347 | 433 | ||
348 | if (rule_list == NULL) { | 434 | if (rule_list == NULL) { |
349 | load = 1; | 435 | load = 1; |
@@ -354,18 +440,20 @@ static ssize_t smk_write_load_list(struct file *file, const char __user *buf, | |||
354 | 440 | ||
355 | rc = count; | 441 | rc = count; |
356 | /* | 442 | /* |
357 | * If this is "load" as opposed to "load-self" and a new rule | 443 | * If this is a global as opposed to self and a new rule |
358 | * it needs to get added for reporting. | 444 | * it needs to get added for reporting. |
359 | * smk_set_access returns true if there was already a rule | 445 | * smk_set_access returns true if there was already a rule |
360 | * for the subject/object pair, and false if it was new. | 446 | * for the subject/object pair, and false if it was new. |
361 | */ | 447 | */ |
362 | if (load && !smk_set_access(rule, rule_list, rule_lock)) { | 448 | if (!smk_set_access(rule, rule_list, rule_lock)) { |
363 | smlp = kzalloc(sizeof(*smlp), GFP_KERNEL); | 449 | if (load) { |
364 | if (smlp != NULL) { | 450 | smlp = kzalloc(sizeof(*smlp), GFP_KERNEL); |
365 | smlp->smk_rule = rule; | 451 | if (smlp != NULL) { |
366 | list_add_rcu(&smlp->list, &smack_rule_list); | 452 | smlp->smk_rule = rule; |
367 | } else | 453 | list_add_rcu(&smlp->list, &smack_rule_list); |
368 | rc = -ENOMEM; | 454 | } else |
455 | rc = -ENOMEM; | ||
456 | } | ||
369 | goto out; | 457 | goto out; |
370 | } | 458 | } |
371 | 459 | ||
@@ -421,29 +509,18 @@ static void smk_seq_stop(struct seq_file *s, void *v) | |||
421 | /* No-op */ | 509 | /* No-op */ |
422 | } | 510 | } |
423 | 511 | ||
424 | /* | 512 | static void smk_rule_show(struct seq_file *s, struct smack_rule *srp, int max) |
425 | * Seq_file read operations for /smack/load | ||
426 | */ | ||
427 | |||
428 | static void *load_seq_start(struct seq_file *s, loff_t *pos) | ||
429 | { | ||
430 | return smk_seq_start(s, pos, &smack_rule_list); | ||
431 | } | ||
432 | |||
433 | static void *load_seq_next(struct seq_file *s, void *v, loff_t *pos) | ||
434 | { | 513 | { |
435 | return smk_seq_next(s, v, pos, &smack_rule_list); | 514 | /* |
436 | } | 515 | * Don't show any rules with label names too long for |
437 | 516 | * interface file (/smack/load or /smack/load2) | |
438 | static int load_seq_show(struct seq_file *s, void *v) | 517 | * because you should expect to be able to write |
439 | { | 518 | * anything you read back. |
440 | struct list_head *list = v; | 519 | */ |
441 | struct smack_master_list *smlp = | 520 | if (strlen(srp->smk_subject) >= max || strlen(srp->smk_object) >= max) |
442 | list_entry(list, struct smack_master_list, list); | 521 | return; |
443 | struct smack_rule *srp = smlp->smk_rule; | ||
444 | 522 | ||
445 | seq_printf(s, "%s %s", (char *)srp->smk_subject, | 523 | seq_printf(s, "%s %s", srp->smk_subject, srp->smk_object); |
446 | (char *)srp->smk_object); | ||
447 | 524 | ||
448 | seq_putc(s, ' '); | 525 | seq_putc(s, ' '); |
449 | 526 | ||
@@ -461,13 +538,36 @@ static int load_seq_show(struct seq_file *s, void *v) | |||
461 | seq_putc(s, '-'); | 538 | seq_putc(s, '-'); |
462 | 539 | ||
463 | seq_putc(s, '\n'); | 540 | seq_putc(s, '\n'); |
541 | } | ||
542 | |||
543 | /* | ||
544 | * Seq_file read operations for /smack/load | ||
545 | */ | ||
546 | |||
547 | static void *load2_seq_start(struct seq_file *s, loff_t *pos) | ||
548 | { | ||
549 | return smk_seq_start(s, pos, &smack_rule_list); | ||
550 | } | ||
551 | |||
552 | static void *load2_seq_next(struct seq_file *s, void *v, loff_t *pos) | ||
553 | { | ||
554 | return smk_seq_next(s, v, pos, &smack_rule_list); | ||
555 | } | ||
556 | |||
557 | static int load_seq_show(struct seq_file *s, void *v) | ||
558 | { | ||
559 | struct list_head *list = v; | ||
560 | struct smack_master_list *smlp = | ||
561 | list_entry(list, struct smack_master_list, list); | ||
562 | |||
563 | smk_rule_show(s, smlp->smk_rule, SMK_LABELLEN); | ||
464 | 564 | ||
465 | return 0; | 565 | return 0; |
466 | } | 566 | } |
467 | 567 | ||
468 | static const struct seq_operations load_seq_ops = { | 568 | static const struct seq_operations load_seq_ops = { |
469 | .start = load_seq_start, | 569 | .start = load2_seq_start, |
470 | .next = load_seq_next, | 570 | .next = load2_seq_next, |
471 | .show = load_seq_show, | 571 | .show = load_seq_show, |
472 | .stop = smk_seq_stop, | 572 | .stop = smk_seq_stop, |
473 | }; | 573 | }; |
@@ -504,7 +604,8 @@ static ssize_t smk_write_load(struct file *file, const char __user *buf, | |||
504 | if (!capable(CAP_MAC_ADMIN)) | 604 | if (!capable(CAP_MAC_ADMIN)) |
505 | return -EPERM; | 605 | return -EPERM; |
506 | 606 | ||
507 | return smk_write_load_list(file, buf, count, ppos, NULL, NULL); | 607 | return smk_write_rules_list(file, buf, count, ppos, NULL, NULL, |
608 | SMK_FIXED24_FMT); | ||
508 | } | 609 | } |
509 | 610 | ||
510 | static const struct file_operations smk_load_ops = { | 611 | static const struct file_operations smk_load_ops = { |
@@ -574,6 +675,8 @@ static void smk_unlbl_ambient(char *oldambient) | |||
574 | printk(KERN_WARNING "%s:%d remove rc = %d\n", | 675 | printk(KERN_WARNING "%s:%d remove rc = %d\n", |
575 | __func__, __LINE__, rc); | 676 | __func__, __LINE__, rc); |
576 | } | 677 | } |
678 | if (smack_net_ambient == NULL) | ||
679 | smack_net_ambient = smack_known_floor.smk_known; | ||
577 | 680 | ||
578 | rc = netlbl_cfg_unlbl_map_add(smack_net_ambient, PF_INET, | 681 | rc = netlbl_cfg_unlbl_map_add(smack_net_ambient, PF_INET, |
579 | NULL, NULL, &nai); | 682 | NULL, NULL, &nai); |
@@ -605,27 +708,28 @@ static int cipso_seq_show(struct seq_file *s, void *v) | |||
605 | struct list_head *list = v; | 708 | struct list_head *list = v; |
606 | struct smack_known *skp = | 709 | struct smack_known *skp = |
607 | list_entry(list, struct smack_known, list); | 710 | list_entry(list, struct smack_known, list); |
608 | struct smack_cipso *scp = skp->smk_cipso; | 711 | struct netlbl_lsm_secattr_catmap *cmp = skp->smk_netlabel.attr.mls.cat; |
609 | char *cbp; | ||
610 | char sep = '/'; | 712 | char sep = '/'; |
611 | int cat = 1; | ||
612 | int i; | 713 | int i; |
613 | unsigned char m; | ||
614 | 714 | ||
615 | if (scp == NULL) | 715 | /* |
716 | * Don't show a label that could not have been set using | ||
717 | * /smack/cipso. This is in support of the notion that | ||
718 | * anything read from /smack/cipso ought to be writeable | ||
719 | * to /smack/cipso. | ||
720 | * | ||
721 | * /smack/cipso2 should be used instead. | ||
722 | */ | ||
723 | if (strlen(skp->smk_known) >= SMK_LABELLEN) | ||
616 | return 0; | 724 | return 0; |
617 | 725 | ||
618 | seq_printf(s, "%s %3d", (char *)&skp->smk_known, scp->smk_level); | 726 | seq_printf(s, "%s %3d", skp->smk_known, skp->smk_netlabel.attr.mls.lvl); |
619 | 727 | ||
620 | cbp = scp->smk_catset; | 728 | for (i = netlbl_secattr_catmap_walk(cmp, 0); i >= 0; |
621 | for (i = 0; i < SMK_LABELLEN; i++) | 729 | i = netlbl_secattr_catmap_walk(cmp, i + 1)) { |
622 | for (m = 0x80; m != 0; m >>= 1) { | 730 | seq_printf(s, "%c%d", sep, i); |
623 | if (m & cbp[i]) { | 731 | sep = ','; |
624 | seq_printf(s, "%c%d", sep, cat); | 732 | } |
625 | sep = ','; | ||
626 | } | ||
627 | cat++; | ||
628 | } | ||
629 | 733 | ||
630 | seq_putc(s, '\n'); | 734 | seq_putc(s, '\n'); |
631 | 735 | ||
@@ -653,23 +757,24 @@ static int smk_open_cipso(struct inode *inode, struct file *file) | |||
653 | } | 757 | } |
654 | 758 | ||
655 | /** | 759 | /** |
656 | * smk_write_cipso - write() for /smack/cipso | 760 | * smk_set_cipso - do the work for write() for cipso and cipso2 |
657 | * @file: file pointer, not actually used | 761 | * @file: file pointer, not actually used |
658 | * @buf: where to get the data from | 762 | * @buf: where to get the data from |
659 | * @count: bytes sent | 763 | * @count: bytes sent |
660 | * @ppos: where to start | 764 | * @ppos: where to start |
765 | * @format: /smack/cipso or /smack/cipso2 | ||
661 | * | 766 | * |
662 | * Accepts only one cipso rule per write call. | 767 | * Accepts only one cipso rule per write call. |
663 | * Returns number of bytes written or error code, as appropriate | 768 | * Returns number of bytes written or error code, as appropriate |
664 | */ | 769 | */ |
665 | static ssize_t smk_write_cipso(struct file *file, const char __user *buf, | 770 | static ssize_t smk_set_cipso(struct file *file, const char __user *buf, |
666 | size_t count, loff_t *ppos) | 771 | size_t count, loff_t *ppos, int format) |
667 | { | 772 | { |
668 | struct smack_known *skp; | 773 | struct smack_known *skp; |
669 | struct smack_cipso *scp = NULL; | 774 | struct netlbl_lsm_secattr ncats; |
670 | char mapcatset[SMK_LABELLEN]; | 775 | char mapcatset[SMK_CIPSOLEN]; |
671 | int maplevel; | 776 | int maplevel; |
672 | int cat; | 777 | unsigned int cat; |
673 | int catlen; | 778 | int catlen; |
674 | ssize_t rc = -EINVAL; | 779 | ssize_t rc = -EINVAL; |
675 | char *data = NULL; | 780 | char *data = NULL; |
@@ -686,7 +791,8 @@ static ssize_t smk_write_cipso(struct file *file, const char __user *buf, | |||
686 | return -EPERM; | 791 | return -EPERM; |
687 | if (*ppos != 0) | 792 | if (*ppos != 0) |
688 | return -EINVAL; | 793 | return -EINVAL; |
689 | if (count < SMK_CIPSOMIN || count > SMK_CIPSOMAX) | 794 | if (format == SMK_FIXED24_FMT && |
795 | (count < SMK_CIPSOMIN || count > SMK_CIPSOMAX)) | ||
690 | return -EINVAL; | 796 | return -EINVAL; |
691 | 797 | ||
692 | data = kzalloc(count + 1, GFP_KERNEL); | 798 | data = kzalloc(count + 1, GFP_KERNEL); |
@@ -698,11 +804,6 @@ static ssize_t smk_write_cipso(struct file *file, const char __user *buf, | |||
698 | goto unlockedout; | 804 | goto unlockedout; |
699 | } | 805 | } |
700 | 806 | ||
701 | /* labels cannot begin with a '-' */ | ||
702 | if (data[0] == '-') { | ||
703 | rc = -EINVAL; | ||
704 | goto unlockedout; | ||
705 | } | ||
706 | data[count] = '\0'; | 807 | data[count] = '\0'; |
707 | rule = data; | 808 | rule = data; |
708 | /* | 809 | /* |
@@ -715,7 +816,11 @@ static ssize_t smk_write_cipso(struct file *file, const char __user *buf, | |||
715 | if (skp == NULL) | 816 | if (skp == NULL) |
716 | goto out; | 817 | goto out; |
717 | 818 | ||
718 | rule += SMK_LABELLEN; | 819 | if (format == SMK_FIXED24_FMT) |
820 | rule += SMK_LABELLEN; | ||
821 | else | ||
822 | rule += strlen(skp->smk_known); | ||
823 | |||
719 | ret = sscanf(rule, "%d", &maplevel); | 824 | ret = sscanf(rule, "%d", &maplevel); |
720 | if (ret != 1 || maplevel > SMACK_CIPSO_MAXLEVEL) | 825 | if (ret != 1 || maplevel > SMACK_CIPSO_MAXLEVEL) |
721 | goto out; | 826 | goto out; |
@@ -725,41 +830,29 @@ static ssize_t smk_write_cipso(struct file *file, const char __user *buf, | |||
725 | if (ret != 1 || catlen > SMACK_CIPSO_MAXCATNUM) | 830 | if (ret != 1 || catlen > SMACK_CIPSO_MAXCATNUM) |
726 | goto out; | 831 | goto out; |
727 | 832 | ||
728 | if (count != (SMK_CIPSOMIN + catlen * SMK_DIGITLEN)) | 833 | if (format == SMK_FIXED24_FMT && |
834 | count != (SMK_CIPSOMIN + catlen * SMK_DIGITLEN)) | ||
729 | goto out; | 835 | goto out; |
730 | 836 | ||
731 | memset(mapcatset, 0, sizeof(mapcatset)); | 837 | memset(mapcatset, 0, sizeof(mapcatset)); |
732 | 838 | ||
733 | for (i = 0; i < catlen; i++) { | 839 | for (i = 0; i < catlen; i++) { |
734 | rule += SMK_DIGITLEN; | 840 | rule += SMK_DIGITLEN; |
735 | ret = sscanf(rule, "%d", &cat); | 841 | ret = sscanf(rule, "%u", &cat); |
736 | if (ret != 1 || cat > SMACK_CIPSO_MAXCATVAL) | 842 | if (ret != 1 || cat > SMACK_CIPSO_MAXCATVAL) |
737 | goto out; | 843 | goto out; |
738 | 844 | ||
739 | smack_catset_bit(cat, mapcatset); | 845 | smack_catset_bit(cat, mapcatset); |
740 | } | 846 | } |
741 | 847 | ||
742 | if (skp->smk_cipso == NULL) { | 848 | rc = smk_netlbl_mls(maplevel, mapcatset, &ncats, SMK_CIPSOLEN); |
743 | scp = kzalloc(sizeof(struct smack_cipso), GFP_KERNEL); | 849 | if (rc >= 0) { |
744 | if (scp == NULL) { | 850 | netlbl_secattr_catmap_free(skp->smk_netlabel.attr.mls.cat); |
745 | rc = -ENOMEM; | 851 | skp->smk_netlabel.attr.mls.cat = ncats.attr.mls.cat; |
746 | goto out; | 852 | skp->smk_netlabel.attr.mls.lvl = ncats.attr.mls.lvl; |
747 | } | 853 | rc = count; |
748 | } | 854 | } |
749 | 855 | ||
750 | spin_lock_bh(&skp->smk_cipsolock); | ||
751 | |||
752 | if (scp == NULL) | ||
753 | scp = skp->smk_cipso; | ||
754 | else | ||
755 | skp->smk_cipso = scp; | ||
756 | |||
757 | scp->smk_level = maplevel; | ||
758 | memcpy(scp->smk_catset, mapcatset, sizeof(mapcatset)); | ||
759 | |||
760 | spin_unlock_bh(&skp->smk_cipsolock); | ||
761 | |||
762 | rc = count; | ||
763 | out: | 856 | out: |
764 | mutex_unlock(&smack_cipso_lock); | 857 | mutex_unlock(&smack_cipso_lock); |
765 | unlockedout: | 858 | unlockedout: |
@@ -767,6 +860,22 @@ unlockedout: | |||
767 | return rc; | 860 | return rc; |
768 | } | 861 | } |
769 | 862 | ||
863 | /** | ||
864 | * smk_write_cipso - write() for /smack/cipso | ||
865 | * @file: file pointer, not actually used | ||
866 | * @buf: where to get the data from | ||
867 | * @count: bytes sent | ||
868 | * @ppos: where to start | ||
869 | * | ||
870 | * Accepts only one cipso rule per write call. | ||
871 | * Returns number of bytes written or error code, as appropriate | ||
872 | */ | ||
873 | static ssize_t smk_write_cipso(struct file *file, const char __user *buf, | ||
874 | size_t count, loff_t *ppos) | ||
875 | { | ||
876 | return smk_set_cipso(file, buf, count, ppos, SMK_FIXED24_FMT); | ||
877 | } | ||
878 | |||
770 | static const struct file_operations smk_cipso_ops = { | 879 | static const struct file_operations smk_cipso_ops = { |
771 | .open = smk_open_cipso, | 880 | .open = smk_open_cipso, |
772 | .read = seq_read, | 881 | .read = seq_read, |
@@ -776,6 +885,80 @@ static const struct file_operations smk_cipso_ops = { | |||
776 | }; | 885 | }; |
777 | 886 | ||
778 | /* | 887 | /* |
888 | * Seq_file read operations for /smack/cipso2 | ||
889 | */ | ||
890 | |||
891 | /* | ||
892 | * Print cipso labels in format: | ||
893 | * label level[/cat[,cat]] | ||
894 | */ | ||
895 | static int cipso2_seq_show(struct seq_file *s, void *v) | ||
896 | { | ||
897 | struct list_head *list = v; | ||
898 | struct smack_known *skp = | ||
899 | list_entry(list, struct smack_known, list); | ||
900 | struct netlbl_lsm_secattr_catmap *cmp = skp->smk_netlabel.attr.mls.cat; | ||
901 | char sep = '/'; | ||
902 | int i; | ||
903 | |||
904 | seq_printf(s, "%s %3d", skp->smk_known, skp->smk_netlabel.attr.mls.lvl); | ||
905 | |||
906 | for (i = netlbl_secattr_catmap_walk(cmp, 0); i >= 0; | ||
907 | i = netlbl_secattr_catmap_walk(cmp, i + 1)) { | ||
908 | seq_printf(s, "%c%d", sep, i); | ||
909 | sep = ','; | ||
910 | } | ||
911 | |||
912 | seq_putc(s, '\n'); | ||
913 | |||
914 | return 0; | ||
915 | } | ||
916 | |||
917 | static const struct seq_operations cipso2_seq_ops = { | ||
918 | .start = cipso_seq_start, | ||
919 | .next = cipso_seq_next, | ||
920 | .show = cipso2_seq_show, | ||
921 | .stop = smk_seq_stop, | ||
922 | }; | ||
923 | |||
924 | /** | ||
925 | * smk_open_cipso2 - open() for /smack/cipso2 | ||
926 | * @inode: inode structure representing file | ||
927 | * @file: "cipso2" file pointer | ||
928 | * | ||
929 | * Connect our cipso_seq_* operations with /smack/cipso2 | ||
930 | * file_operations | ||
931 | */ | ||
932 | static int smk_open_cipso2(struct inode *inode, struct file *file) | ||
933 | { | ||
934 | return seq_open(file, &cipso2_seq_ops); | ||
935 | } | ||
936 | |||
937 | /** | ||
938 | * smk_write_cipso2 - write() for /smack/cipso2 | ||
939 | * @file: file pointer, not actually used | ||
940 | * @buf: where to get the data from | ||
941 | * @count: bytes sent | ||
942 | * @ppos: where to start | ||
943 | * | ||
944 | * Accepts only one cipso rule per write call. | ||
945 | * Returns number of bytes written or error code, as appropriate | ||
946 | */ | ||
947 | static ssize_t smk_write_cipso2(struct file *file, const char __user *buf, | ||
948 | size_t count, loff_t *ppos) | ||
949 | { | ||
950 | return smk_set_cipso(file, buf, count, ppos, SMK_LONG_FMT); | ||
951 | } | ||
952 | |||
953 | static const struct file_operations smk_cipso2_ops = { | ||
954 | .open = smk_open_cipso2, | ||
955 | .read = seq_read, | ||
956 | .llseek = seq_lseek, | ||
957 | .write = smk_write_cipso2, | ||
958 | .release = seq_release, | ||
959 | }; | ||
960 | |||
961 | /* | ||
779 | * Seq_file read operations for /smack/netlabel | 962 | * Seq_file read operations for /smack/netlabel |
780 | */ | 963 | */ |
781 | 964 | ||
@@ -887,9 +1070,9 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, | |||
887 | { | 1070 | { |
888 | struct smk_netlbladdr *skp; | 1071 | struct smk_netlbladdr *skp; |
889 | struct sockaddr_in newname; | 1072 | struct sockaddr_in newname; |
890 | char smack[SMK_LABELLEN]; | 1073 | char *smack; |
891 | char *sp; | 1074 | char *sp; |
892 | char data[SMK_NETLBLADDRMAX + 1]; | 1075 | char *data; |
893 | char *host = (char *)&newname.sin_addr.s_addr; | 1076 | char *host = (char *)&newname.sin_addr.s_addr; |
894 | int rc; | 1077 | int rc; |
895 | struct netlbl_audit audit_info; | 1078 | struct netlbl_audit audit_info; |
@@ -911,10 +1094,23 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, | |||
911 | return -EPERM; | 1094 | return -EPERM; |
912 | if (*ppos != 0) | 1095 | if (*ppos != 0) |
913 | return -EINVAL; | 1096 | return -EINVAL; |
914 | if (count < SMK_NETLBLADDRMIN || count > SMK_NETLBLADDRMAX) | 1097 | if (count < SMK_NETLBLADDRMIN) |
915 | return -EINVAL; | 1098 | return -EINVAL; |
916 | if (copy_from_user(data, buf, count) != 0) | 1099 | |
917 | return -EFAULT; | 1100 | data = kzalloc(count + 1, GFP_KERNEL); |
1101 | if (data == NULL) | ||
1102 | return -ENOMEM; | ||
1103 | |||
1104 | if (copy_from_user(data, buf, count) != 0) { | ||
1105 | rc = -EFAULT; | ||
1106 | goto free_data_out; | ||
1107 | } | ||
1108 | |||
1109 | smack = kzalloc(count + 1, GFP_KERNEL); | ||
1110 | if (smack == NULL) { | ||
1111 | rc = -ENOMEM; | ||
1112 | goto free_data_out; | ||
1113 | } | ||
918 | 1114 | ||
919 | data[count] = '\0'; | 1115 | data[count] = '\0'; |
920 | 1116 | ||
@@ -923,24 +1119,34 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, | |||
923 | if (rc != 6) { | 1119 | if (rc != 6) { |
924 | rc = sscanf(data, "%hhd.%hhd.%hhd.%hhd %s", | 1120 | rc = sscanf(data, "%hhd.%hhd.%hhd.%hhd %s", |
925 | &host[0], &host[1], &host[2], &host[3], smack); | 1121 | &host[0], &host[1], &host[2], &host[3], smack); |
926 | if (rc != 5) | 1122 | if (rc != 5) { |
927 | return -EINVAL; | 1123 | rc = -EINVAL; |
1124 | goto free_out; | ||
1125 | } | ||
928 | m = BEBITS; | 1126 | m = BEBITS; |
929 | } | 1127 | } |
930 | if (m > BEBITS) | 1128 | if (m > BEBITS) { |
931 | return -EINVAL; | 1129 | rc = -EINVAL; |
1130 | goto free_out; | ||
1131 | } | ||
932 | 1132 | ||
933 | /* if smack begins with '-', its an option, don't import it */ | 1133 | /* |
1134 | * If smack begins with '-', it is an option, don't import it | ||
1135 | */ | ||
934 | if (smack[0] != '-') { | 1136 | if (smack[0] != '-') { |
935 | sp = smk_import(smack, 0); | 1137 | sp = smk_import(smack, 0); |
936 | if (sp == NULL) | 1138 | if (sp == NULL) { |
937 | return -EINVAL; | 1139 | rc = -EINVAL; |
1140 | goto free_out; | ||
1141 | } | ||
938 | } else { | 1142 | } else { |
939 | /* check known options */ | 1143 | /* check known options */ |
940 | if (strcmp(smack, smack_cipso_option) == 0) | 1144 | if (strcmp(smack, smack_cipso_option) == 0) |
941 | sp = (char *)smack_cipso_option; | 1145 | sp = (char *)smack_cipso_option; |
942 | else | 1146 | else { |
943 | return -EINVAL; | 1147 | rc = -EINVAL; |
1148 | goto free_out; | ||
1149 | } | ||
944 | } | 1150 | } |
945 | 1151 | ||
946 | for (temp_mask = 0; m > 0; m--) { | 1152 | for (temp_mask = 0; m > 0; m--) { |
@@ -1006,6 +1212,11 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, | |||
1006 | 1212 | ||
1007 | mutex_unlock(&smk_netlbladdr_lock); | 1213 | mutex_unlock(&smk_netlbladdr_lock); |
1008 | 1214 | ||
1215 | free_out: | ||
1216 | kfree(smack); | ||
1217 | free_data_out: | ||
1218 | kfree(data); | ||
1219 | |||
1009 | return rc; | 1220 | return rc; |
1010 | } | 1221 | } |
1011 | 1222 | ||
@@ -1119,6 +1330,7 @@ static ssize_t smk_read_direct(struct file *filp, char __user *buf, | |||
1119 | static ssize_t smk_write_direct(struct file *file, const char __user *buf, | 1330 | static ssize_t smk_write_direct(struct file *file, const char __user *buf, |
1120 | size_t count, loff_t *ppos) | 1331 | size_t count, loff_t *ppos) |
1121 | { | 1332 | { |
1333 | struct smack_known *skp; | ||
1122 | char temp[80]; | 1334 | char temp[80]; |
1123 | int i; | 1335 | int i; |
1124 | 1336 | ||
@@ -1136,7 +1348,20 @@ static ssize_t smk_write_direct(struct file *file, const char __user *buf, | |||
1136 | if (sscanf(temp, "%d", &i) != 1) | 1348 | if (sscanf(temp, "%d", &i) != 1) |
1137 | return -EINVAL; | 1349 | return -EINVAL; |
1138 | 1350 | ||
1139 | smack_cipso_direct = i; | 1351 | /* |
1352 | * Don't do anything if the value hasn't actually changed. | ||
1353 | * If it is changing reset the level on entries that were | ||
1354 | * set up to be direct when they were created. | ||
1355 | */ | ||
1356 | if (smack_cipso_direct != i) { | ||
1357 | mutex_lock(&smack_known_lock); | ||
1358 | list_for_each_entry_rcu(skp, &smack_known_list, list) | ||
1359 | if (skp->smk_netlabel.attr.mls.lvl == | ||
1360 | smack_cipso_direct) | ||
1361 | skp->smk_netlabel.attr.mls.lvl = i; | ||
1362 | smack_cipso_direct = i; | ||
1363 | mutex_unlock(&smack_known_lock); | ||
1364 | } | ||
1140 | 1365 | ||
1141 | return count; | 1366 | return count; |
1142 | } | 1367 | } |
@@ -1148,6 +1373,84 @@ static const struct file_operations smk_direct_ops = { | |||
1148 | }; | 1373 | }; |
1149 | 1374 | ||
1150 | /** | 1375 | /** |
1376 | * smk_read_mapped - read() for /smack/mapped | ||
1377 | * @filp: file pointer, not actually used | ||
1378 | * @buf: where to put the result | ||
1379 | * @count: maximum to send along | ||
1380 | * @ppos: where to start | ||
1381 | * | ||
1382 | * Returns number of bytes read or error code, as appropriate | ||
1383 | */ | ||
1384 | static ssize_t smk_read_mapped(struct file *filp, char __user *buf, | ||
1385 | size_t count, loff_t *ppos) | ||
1386 | { | ||
1387 | char temp[80]; | ||
1388 | ssize_t rc; | ||
1389 | |||
1390 | if (*ppos != 0) | ||
1391 | return 0; | ||
1392 | |||
1393 | sprintf(temp, "%d", smack_cipso_mapped); | ||
1394 | rc = simple_read_from_buffer(buf, count, ppos, temp, strlen(temp)); | ||
1395 | |||
1396 | return rc; | ||
1397 | } | ||
1398 | |||
1399 | /** | ||
1400 | * smk_write_mapped - write() for /smack/mapped | ||
1401 | * @file: file pointer, not actually used | ||
1402 | * @buf: where to get the data from | ||
1403 | * @count: bytes sent | ||
1404 | * @ppos: where to start | ||
1405 | * | ||
1406 | * Returns number of bytes written or error code, as appropriate | ||
1407 | */ | ||
1408 | static ssize_t smk_write_mapped(struct file *file, const char __user *buf, | ||
1409 | size_t count, loff_t *ppos) | ||
1410 | { | ||
1411 | struct smack_known *skp; | ||
1412 | char temp[80]; | ||
1413 | int i; | ||
1414 | |||
1415 | if (!capable(CAP_MAC_ADMIN)) | ||
1416 | return -EPERM; | ||
1417 | |||
1418 | if (count >= sizeof(temp) || count == 0) | ||
1419 | return -EINVAL; | ||
1420 | |||
1421 | if (copy_from_user(temp, buf, count) != 0) | ||
1422 | return -EFAULT; | ||
1423 | |||
1424 | temp[count] = '\0'; | ||
1425 | |||
1426 | if (sscanf(temp, "%d", &i) != 1) | ||
1427 | return -EINVAL; | ||
1428 | |||
1429 | /* | ||
1430 | * Don't do anything if the value hasn't actually changed. | ||
1431 | * If it is changing reset the level on entries that were | ||
1432 | * set up to be mapped when they were created. | ||
1433 | */ | ||
1434 | if (smack_cipso_mapped != i) { | ||
1435 | mutex_lock(&smack_known_lock); | ||
1436 | list_for_each_entry_rcu(skp, &smack_known_list, list) | ||
1437 | if (skp->smk_netlabel.attr.mls.lvl == | ||
1438 | smack_cipso_mapped) | ||
1439 | skp->smk_netlabel.attr.mls.lvl = i; | ||
1440 | smack_cipso_mapped = i; | ||
1441 | mutex_unlock(&smack_known_lock); | ||
1442 | } | ||
1443 | |||
1444 | return count; | ||
1445 | } | ||
1446 | |||
1447 | static const struct file_operations smk_mapped_ops = { | ||
1448 | .read = smk_read_mapped, | ||
1449 | .write = smk_write_mapped, | ||
1450 | .llseek = default_llseek, | ||
1451 | }; | ||
1452 | |||
1453 | /** | ||
1151 | * smk_read_ambient - read() for /smack/ambient | 1454 | * smk_read_ambient - read() for /smack/ambient |
1152 | * @filp: file pointer, not actually used | 1455 | * @filp: file pointer, not actually used |
1153 | * @buf: where to put the result | 1456 | * @buf: where to put the result |
@@ -1195,22 +1498,28 @@ static ssize_t smk_read_ambient(struct file *filp, char __user *buf, | |||
1195 | static ssize_t smk_write_ambient(struct file *file, const char __user *buf, | 1498 | static ssize_t smk_write_ambient(struct file *file, const char __user *buf, |
1196 | size_t count, loff_t *ppos) | 1499 | size_t count, loff_t *ppos) |
1197 | { | 1500 | { |
1198 | char in[SMK_LABELLEN]; | ||
1199 | char *oldambient; | 1501 | char *oldambient; |
1200 | char *smack; | 1502 | char *smack = NULL; |
1503 | char *data; | ||
1504 | int rc = count; | ||
1201 | 1505 | ||
1202 | if (!capable(CAP_MAC_ADMIN)) | 1506 | if (!capable(CAP_MAC_ADMIN)) |
1203 | return -EPERM; | 1507 | return -EPERM; |
1204 | 1508 | ||
1205 | if (count >= SMK_LABELLEN) | 1509 | data = kzalloc(count + 1, GFP_KERNEL); |
1206 | return -EINVAL; | 1510 | if (data == NULL) |
1511 | return -ENOMEM; | ||
1207 | 1512 | ||
1208 | if (copy_from_user(in, buf, count) != 0) | 1513 | if (copy_from_user(data, buf, count) != 0) { |
1209 | return -EFAULT; | 1514 | rc = -EFAULT; |
1515 | goto out; | ||
1516 | } | ||
1210 | 1517 | ||
1211 | smack = smk_import(in, count); | 1518 | smack = smk_import(data, count); |
1212 | if (smack == NULL) | 1519 | if (smack == NULL) { |
1213 | return -EINVAL; | 1520 | rc = -EINVAL; |
1521 | goto out; | ||
1522 | } | ||
1214 | 1523 | ||
1215 | mutex_lock(&smack_ambient_lock); | 1524 | mutex_lock(&smack_ambient_lock); |
1216 | 1525 | ||
@@ -1220,7 +1529,9 @@ static ssize_t smk_write_ambient(struct file *file, const char __user *buf, | |||
1220 | 1529 | ||
1221 | mutex_unlock(&smack_ambient_lock); | 1530 | mutex_unlock(&smack_ambient_lock); |
1222 | 1531 | ||
1223 | return count; | 1532 | out: |
1533 | kfree(data); | ||
1534 | return rc; | ||
1224 | } | 1535 | } |
1225 | 1536 | ||
1226 | static const struct file_operations smk_ambient_ops = { | 1537 | static const struct file_operations smk_ambient_ops = { |
@@ -1271,8 +1582,9 @@ static ssize_t smk_read_onlycap(struct file *filp, char __user *buf, | |||
1271 | static ssize_t smk_write_onlycap(struct file *file, const char __user *buf, | 1582 | static ssize_t smk_write_onlycap(struct file *file, const char __user *buf, |
1272 | size_t count, loff_t *ppos) | 1583 | size_t count, loff_t *ppos) |
1273 | { | 1584 | { |
1274 | char in[SMK_LABELLEN]; | 1585 | char *data; |
1275 | char *sp = smk_of_task(current->cred->security); | 1586 | char *sp = smk_of_task(current->cred->security); |
1587 | int rc = count; | ||
1276 | 1588 | ||
1277 | if (!capable(CAP_MAC_ADMIN)) | 1589 | if (!capable(CAP_MAC_ADMIN)) |
1278 | return -EPERM; | 1590 | return -EPERM; |
@@ -1285,11 +1597,9 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf, | |||
1285 | if (smack_onlycap != NULL && smack_onlycap != sp) | 1597 | if (smack_onlycap != NULL && smack_onlycap != sp) |
1286 | return -EPERM; | 1598 | return -EPERM; |
1287 | 1599 | ||
1288 | if (count >= SMK_LABELLEN) | 1600 | data = kzalloc(count, GFP_KERNEL); |
1289 | return -EINVAL; | 1601 | if (data == NULL) |
1290 | 1602 | return -ENOMEM; | |
1291 | if (copy_from_user(in, buf, count) != 0) | ||
1292 | return -EFAULT; | ||
1293 | 1603 | ||
1294 | /* | 1604 | /* |
1295 | * Should the null string be passed in unset the onlycap value. | 1605 | * Should the null string be passed in unset the onlycap value. |
@@ -1297,10 +1607,17 @@ static ssize_t smk_write_onlycap(struct file *file, const char __user *buf, | |||
1297 | * smk_import only expects to return NULL for errors. It | 1607 | * smk_import only expects to return NULL for errors. It |
1298 | * is usually the case that a nullstring or "\n" would be | 1608 | * is usually the case that a nullstring or "\n" would be |
1299 | * bad to pass to smk_import but in fact this is useful here. | 1609 | * bad to pass to smk_import but in fact this is useful here. |
1610 | * | ||
1611 | * smk_import will also reject a label beginning with '-', | ||
1612 | * so "-usecapabilities" will also work. | ||
1300 | */ | 1613 | */ |
1301 | smack_onlycap = smk_import(in, count); | 1614 | if (copy_from_user(data, buf, count) != 0) |
1615 | rc = -EFAULT; | ||
1616 | else | ||
1617 | smack_onlycap = smk_import(data, count); | ||
1302 | 1618 | ||
1303 | return count; | 1619 | kfree(data); |
1620 | return rc; | ||
1304 | } | 1621 | } |
1305 | 1622 | ||
1306 | static const struct file_operations smk_onlycap_ops = { | 1623 | static const struct file_operations smk_onlycap_ops = { |
@@ -1398,25 +1715,7 @@ static int load_self_seq_show(struct seq_file *s, void *v) | |||
1398 | struct smack_rule *srp = | 1715 | struct smack_rule *srp = |
1399 | list_entry(list, struct smack_rule, list); | 1716 | list_entry(list, struct smack_rule, list); |
1400 | 1717 | ||
1401 | seq_printf(s, "%s %s", (char *)srp->smk_subject, | 1718 | smk_rule_show(s, srp, SMK_LABELLEN); |
1402 | (char *)srp->smk_object); | ||
1403 | |||
1404 | seq_putc(s, ' '); | ||
1405 | |||
1406 | if (srp->smk_access & MAY_READ) | ||
1407 | seq_putc(s, 'r'); | ||
1408 | if (srp->smk_access & MAY_WRITE) | ||
1409 | seq_putc(s, 'w'); | ||
1410 | if (srp->smk_access & MAY_EXEC) | ||
1411 | seq_putc(s, 'x'); | ||
1412 | if (srp->smk_access & MAY_APPEND) | ||
1413 | seq_putc(s, 'a'); | ||
1414 | if (srp->smk_access & MAY_TRANSMUTE) | ||
1415 | seq_putc(s, 't'); | ||
1416 | if (srp->smk_access == 0) | ||
1417 | seq_putc(s, '-'); | ||
1418 | |||
1419 | seq_putc(s, '\n'); | ||
1420 | 1719 | ||
1421 | return 0; | 1720 | return 0; |
1422 | } | 1721 | } |
@@ -1430,7 +1729,7 @@ static const struct seq_operations load_self_seq_ops = { | |||
1430 | 1729 | ||
1431 | 1730 | ||
1432 | /** | 1731 | /** |
1433 | * smk_open_load_self - open() for /smack/load-self | 1732 | * smk_open_load_self - open() for /smack/load-self2 |
1434 | * @inode: inode structure representing file | 1733 | * @inode: inode structure representing file |
1435 | * @file: "load" file pointer | 1734 | * @file: "load" file pointer |
1436 | * | 1735 | * |
@@ -1454,8 +1753,8 @@ static ssize_t smk_write_load_self(struct file *file, const char __user *buf, | |||
1454 | { | 1753 | { |
1455 | struct task_smack *tsp = current_security(); | 1754 | struct task_smack *tsp = current_security(); |
1456 | 1755 | ||
1457 | return smk_write_load_list(file, buf, count, ppos, &tsp->smk_rules, | 1756 | return smk_write_rules_list(file, buf, count, ppos, &tsp->smk_rules, |
1458 | &tsp->smk_rules_lock); | 1757 | &tsp->smk_rules_lock, SMK_FIXED24_FMT); |
1459 | } | 1758 | } |
1460 | 1759 | ||
1461 | static const struct file_operations smk_load_self_ops = { | 1760 | static const struct file_operations smk_load_self_ops = { |
@@ -1467,24 +1766,42 @@ static const struct file_operations smk_load_self_ops = { | |||
1467 | }; | 1766 | }; |
1468 | 1767 | ||
1469 | /** | 1768 | /** |
1470 | * smk_write_access - handle access check transaction | 1769 | * smk_user_access - handle access check transaction |
1471 | * @file: file pointer | 1770 | * @file: file pointer |
1472 | * @buf: data from user space | 1771 | * @buf: data from user space |
1473 | * @count: bytes sent | 1772 | * @count: bytes sent |
1474 | * @ppos: where to start - must be 0 | 1773 | * @ppos: where to start - must be 0 |
1475 | */ | 1774 | */ |
1476 | static ssize_t smk_write_access(struct file *file, const char __user *buf, | 1775 | static ssize_t smk_user_access(struct file *file, const char __user *buf, |
1477 | size_t count, loff_t *ppos) | 1776 | size_t count, loff_t *ppos, int format) |
1478 | { | 1777 | { |
1479 | struct smack_rule rule; | 1778 | struct smack_rule rule; |
1480 | char *data; | 1779 | char *data; |
1780 | char *cod; | ||
1481 | int res; | 1781 | int res; |
1482 | 1782 | ||
1483 | data = simple_transaction_get(file, buf, count); | 1783 | data = simple_transaction_get(file, buf, count); |
1484 | if (IS_ERR(data)) | 1784 | if (IS_ERR(data)) |
1485 | return PTR_ERR(data); | 1785 | return PTR_ERR(data); |
1486 | 1786 | ||
1487 | if (count < SMK_LOADLEN || smk_parse_rule(data, &rule, 0)) | 1787 | if (format == SMK_FIXED24_FMT) { |
1788 | if (count < SMK_LOADLEN) | ||
1789 | return -EINVAL; | ||
1790 | res = smk_parse_rule(data, &rule, 0); | ||
1791 | } else { | ||
1792 | /* | ||
1793 | * Copy the data to make sure the string is terminated. | ||
1794 | */ | ||
1795 | cod = kzalloc(count + 1, GFP_KERNEL); | ||
1796 | if (cod == NULL) | ||
1797 | return -ENOMEM; | ||
1798 | memcpy(cod, data, count); | ||
1799 | cod[count] = '\0'; | ||
1800 | res = smk_parse_long_rule(cod, &rule, 0); | ||
1801 | kfree(cod); | ||
1802 | } | ||
1803 | |||
1804 | if (res) | ||
1488 | return -EINVAL; | 1805 | return -EINVAL; |
1489 | 1806 | ||
1490 | res = smk_access(rule.smk_subject, rule.smk_object, rule.smk_access, | 1807 | res = smk_access(rule.smk_subject, rule.smk_object, rule.smk_access, |
@@ -1493,7 +1810,23 @@ static ssize_t smk_write_access(struct file *file, const char __user *buf, | |||
1493 | data[1] = '\0'; | 1810 | data[1] = '\0'; |
1494 | 1811 | ||
1495 | simple_transaction_set(file, 2); | 1812 | simple_transaction_set(file, 2); |
1496 | return SMK_LOADLEN; | 1813 | |
1814 | if (format == SMK_FIXED24_FMT) | ||
1815 | return SMK_LOADLEN; | ||
1816 | return count; | ||
1817 | } | ||
1818 | |||
1819 | /** | ||
1820 | * smk_write_access - handle access check transaction | ||
1821 | * @file: file pointer | ||
1822 | * @buf: data from user space | ||
1823 | * @count: bytes sent | ||
1824 | * @ppos: where to start - must be 0 | ||
1825 | */ | ||
1826 | static ssize_t smk_write_access(struct file *file, const char __user *buf, | ||
1827 | size_t count, loff_t *ppos) | ||
1828 | { | ||
1829 | return smk_user_access(file, buf, count, ppos, SMK_FIXED24_FMT); | ||
1497 | } | 1830 | } |
1498 | 1831 | ||
1499 | static const struct file_operations smk_access_ops = { | 1832 | static const struct file_operations smk_access_ops = { |
@@ -1503,6 +1836,163 @@ static const struct file_operations smk_access_ops = { | |||
1503 | .llseek = generic_file_llseek, | 1836 | .llseek = generic_file_llseek, |
1504 | }; | 1837 | }; |
1505 | 1838 | ||
1839 | |||
1840 | /* | ||
1841 | * Seq_file read operations for /smack/load2 | ||
1842 | */ | ||
1843 | |||
1844 | static int load2_seq_show(struct seq_file *s, void *v) | ||
1845 | { | ||
1846 | struct list_head *list = v; | ||
1847 | struct smack_master_list *smlp = | ||
1848 | list_entry(list, struct smack_master_list, list); | ||
1849 | |||
1850 | smk_rule_show(s, smlp->smk_rule, SMK_LONGLABEL); | ||
1851 | |||
1852 | return 0; | ||
1853 | } | ||
1854 | |||
1855 | static const struct seq_operations load2_seq_ops = { | ||
1856 | .start = load2_seq_start, | ||
1857 | .next = load2_seq_next, | ||
1858 | .show = load2_seq_show, | ||
1859 | .stop = smk_seq_stop, | ||
1860 | }; | ||
1861 | |||
1862 | /** | ||
1863 | * smk_open_load2 - open() for /smack/load2 | ||
1864 | * @inode: inode structure representing file | ||
1865 | * @file: "load2" file pointer | ||
1866 | * | ||
1867 | * For reading, use load2_seq_* seq_file reading operations. | ||
1868 | */ | ||
1869 | static int smk_open_load2(struct inode *inode, struct file *file) | ||
1870 | { | ||
1871 | return seq_open(file, &load2_seq_ops); | ||
1872 | } | ||
1873 | |||
1874 | /** | ||
1875 | * smk_write_load2 - write() for /smack/load2 | ||
1876 | * @file: file pointer, not actually used | ||
1877 | * @buf: where to get the data from | ||
1878 | * @count: bytes sent | ||
1879 | * @ppos: where to start - must be 0 | ||
1880 | * | ||
1881 | */ | ||
1882 | static ssize_t smk_write_load2(struct file *file, const char __user *buf, | ||
1883 | size_t count, loff_t *ppos) | ||
1884 | { | ||
1885 | /* | ||
1886 | * Must have privilege. | ||
1887 | */ | ||
1888 | if (!capable(CAP_MAC_ADMIN)) | ||
1889 | return -EPERM; | ||
1890 | |||
1891 | return smk_write_rules_list(file, buf, count, ppos, NULL, NULL, | ||
1892 | SMK_LONG_FMT); | ||
1893 | } | ||
1894 | |||
1895 | static const struct file_operations smk_load2_ops = { | ||
1896 | .open = smk_open_load2, | ||
1897 | .read = seq_read, | ||
1898 | .llseek = seq_lseek, | ||
1899 | .write = smk_write_load2, | ||
1900 | .release = seq_release, | ||
1901 | }; | ||
1902 | |||
1903 | /* | ||
1904 | * Seq_file read operations for /smack/load-self2 | ||
1905 | */ | ||
1906 | |||
1907 | static void *load_self2_seq_start(struct seq_file *s, loff_t *pos) | ||
1908 | { | ||
1909 | struct task_smack *tsp = current_security(); | ||
1910 | |||
1911 | return smk_seq_start(s, pos, &tsp->smk_rules); | ||
1912 | } | ||
1913 | |||
1914 | static void *load_self2_seq_next(struct seq_file *s, void *v, loff_t *pos) | ||
1915 | { | ||
1916 | struct task_smack *tsp = current_security(); | ||
1917 | |||
1918 | return smk_seq_next(s, v, pos, &tsp->smk_rules); | ||
1919 | } | ||
1920 | |||
1921 | static int load_self2_seq_show(struct seq_file *s, void *v) | ||
1922 | { | ||
1923 | struct list_head *list = v; | ||
1924 | struct smack_rule *srp = | ||
1925 | list_entry(list, struct smack_rule, list); | ||
1926 | |||
1927 | smk_rule_show(s, srp, SMK_LONGLABEL); | ||
1928 | |||
1929 | return 0; | ||
1930 | } | ||
1931 | |||
1932 | static const struct seq_operations load_self2_seq_ops = { | ||
1933 | .start = load_self2_seq_start, | ||
1934 | .next = load_self2_seq_next, | ||
1935 | .show = load_self2_seq_show, | ||
1936 | .stop = smk_seq_stop, | ||
1937 | }; | ||
1938 | |||
1939 | /** | ||
1940 | * smk_open_load_self2 - open() for /smack/load-self2 | ||
1941 | * @inode: inode structure representing file | ||
1942 | * @file: "load" file pointer | ||
1943 | * | ||
1944 | * For reading, use load_seq_* seq_file reading operations. | ||
1945 | */ | ||
1946 | static int smk_open_load_self2(struct inode *inode, struct file *file) | ||
1947 | { | ||
1948 | return seq_open(file, &load_self2_seq_ops); | ||
1949 | } | ||
1950 | |||
1951 | /** | ||
1952 | * smk_write_load_self2 - write() for /smack/load-self2 | ||
1953 | * @file: file pointer, not actually used | ||
1954 | * @buf: where to get the data from | ||
1955 | * @count: bytes sent | ||
1956 | * @ppos: where to start - must be 0 | ||
1957 | * | ||
1958 | */ | ||
1959 | static ssize_t smk_write_load_self2(struct file *file, const char __user *buf, | ||
1960 | size_t count, loff_t *ppos) | ||
1961 | { | ||
1962 | struct task_smack *tsp = current_security(); | ||
1963 | |||
1964 | return smk_write_rules_list(file, buf, count, ppos, &tsp->smk_rules, | ||
1965 | &tsp->smk_rules_lock, SMK_LONG_FMT); | ||
1966 | } | ||
1967 | |||
1968 | static const struct file_operations smk_load_self2_ops = { | ||
1969 | .open = smk_open_load_self2, | ||
1970 | .read = seq_read, | ||
1971 | .llseek = seq_lseek, | ||
1972 | .write = smk_write_load_self2, | ||
1973 | .release = seq_release, | ||
1974 | }; | ||
1975 | |||
1976 | /** | ||
1977 | * smk_write_access2 - handle access check transaction | ||
1978 | * @file: file pointer | ||
1979 | * @buf: data from user space | ||
1980 | * @count: bytes sent | ||
1981 | * @ppos: where to start - must be 0 | ||
1982 | */ | ||
1983 | static ssize_t smk_write_access2(struct file *file, const char __user *buf, | ||
1984 | size_t count, loff_t *ppos) | ||
1985 | { | ||
1986 | return smk_user_access(file, buf, count, ppos, SMK_LONG_FMT); | ||
1987 | } | ||
1988 | |||
1989 | static const struct file_operations smk_access2_ops = { | ||
1990 | .write = smk_write_access2, | ||
1991 | .read = simple_transaction_read, | ||
1992 | .release = simple_transaction_release, | ||
1993 | .llseek = generic_file_llseek, | ||
1994 | }; | ||
1995 | |||
1506 | /** | 1996 | /** |
1507 | * smk_fill_super - fill the /smackfs superblock | 1997 | * smk_fill_super - fill the /smackfs superblock |
1508 | * @sb: the empty superblock | 1998 | * @sb: the empty superblock |
@@ -1539,6 +2029,16 @@ static int smk_fill_super(struct super_block *sb, void *data, int silent) | |||
1539 | "load-self", &smk_load_self_ops, S_IRUGO|S_IWUGO}, | 2029 | "load-self", &smk_load_self_ops, S_IRUGO|S_IWUGO}, |
1540 | [SMK_ACCESSES] = { | 2030 | [SMK_ACCESSES] = { |
1541 | "access", &smk_access_ops, S_IRUGO|S_IWUGO}, | 2031 | "access", &smk_access_ops, S_IRUGO|S_IWUGO}, |
2032 | [SMK_MAPPED] = { | ||
2033 | "mapped", &smk_mapped_ops, S_IRUGO|S_IWUSR}, | ||
2034 | [SMK_LOAD2] = { | ||
2035 | "load2", &smk_load2_ops, S_IRUGO|S_IWUSR}, | ||
2036 | [SMK_LOAD_SELF2] = { | ||
2037 | "load-self2", &smk_load_self2_ops, S_IRUGO|S_IWUGO}, | ||
2038 | [SMK_ACCESS2] = { | ||
2039 | "access2", &smk_access2_ops, S_IRUGO|S_IWUGO}, | ||
2040 | [SMK_CIPSO2] = { | ||
2041 | "cipso2", &smk_cipso2_ops, S_IRUGO|S_IWUSR}, | ||
1542 | /* last one */ | 2042 | /* last one */ |
1543 | {""} | 2043 | {""} |
1544 | }; | 2044 | }; |
@@ -1581,6 +2081,15 @@ static struct file_system_type smk_fs_type = { | |||
1581 | 2081 | ||
1582 | static struct vfsmount *smackfs_mount; | 2082 | static struct vfsmount *smackfs_mount; |
1583 | 2083 | ||
2084 | static int __init smk_preset_netlabel(struct smack_known *skp) | ||
2085 | { | ||
2086 | skp->smk_netlabel.domain = skp->smk_known; | ||
2087 | skp->smk_netlabel.flags = | ||
2088 | NETLBL_SECATTR_DOMAIN | NETLBL_SECATTR_MLS_LVL; | ||
2089 | return smk_netlbl_mls(smack_cipso_direct, skp->smk_known, | ||
2090 | &skp->smk_netlabel, strlen(skp->smk_known)); | ||
2091 | } | ||
2092 | |||
1584 | /** | 2093 | /** |
1585 | * init_smk_fs - get the smackfs superblock | 2094 | * init_smk_fs - get the smackfs superblock |
1586 | * | 2095 | * |
@@ -1597,6 +2106,7 @@ static struct vfsmount *smackfs_mount; | |||
1597 | static int __init init_smk_fs(void) | 2106 | static int __init init_smk_fs(void) |
1598 | { | 2107 | { |
1599 | int err; | 2108 | int err; |
2109 | int rc; | ||
1600 | 2110 | ||
1601 | if (!security_module_enable(&smack_ops)) | 2111 | if (!security_module_enable(&smack_ops)) |
1602 | return 0; | 2112 | return 0; |
@@ -1614,6 +2124,25 @@ static int __init init_smk_fs(void) | |||
1614 | smk_cipso_doi(); | 2124 | smk_cipso_doi(); |
1615 | smk_unlbl_ambient(NULL); | 2125 | smk_unlbl_ambient(NULL); |
1616 | 2126 | ||
2127 | rc = smk_preset_netlabel(&smack_known_floor); | ||
2128 | if (err == 0 && rc < 0) | ||
2129 | err = rc; | ||
2130 | rc = smk_preset_netlabel(&smack_known_hat); | ||
2131 | if (err == 0 && rc < 0) | ||
2132 | err = rc; | ||
2133 | rc = smk_preset_netlabel(&smack_known_huh); | ||
2134 | if (err == 0 && rc < 0) | ||
2135 | err = rc; | ||
2136 | rc = smk_preset_netlabel(&smack_known_invalid); | ||
2137 | if (err == 0 && rc < 0) | ||
2138 | err = rc; | ||
2139 | rc = smk_preset_netlabel(&smack_known_star); | ||
2140 | if (err == 0 && rc < 0) | ||
2141 | err = rc; | ||
2142 | rc = smk_preset_netlabel(&smack_known_web); | ||
2143 | if (err == 0 && rc < 0) | ||
2144 | err = rc; | ||
2145 | |||
1617 | return err; | 2146 | return err; |
1618 | } | 2147 | } |
1619 | 2148 | ||
diff --git a/security/tomoyo/common.c b/security/tomoyo/common.c index 8656b16eef7b..2e0f12c62938 100644 --- a/security/tomoyo/common.c +++ b/security/tomoyo/common.c | |||
@@ -850,14 +850,9 @@ static int tomoyo_update_manager_entry(const char *manager, | |||
850 | policy_list[TOMOYO_ID_MANAGER], | 850 | policy_list[TOMOYO_ID_MANAGER], |
851 | }; | 851 | }; |
852 | int error = is_delete ? -ENOENT : -ENOMEM; | 852 | int error = is_delete ? -ENOENT : -ENOMEM; |
853 | if (tomoyo_domain_def(manager)) { | 853 | if (!tomoyo_correct_domain(manager) && |
854 | if (!tomoyo_correct_domain(manager)) | 854 | !tomoyo_correct_word(manager)) |
855 | return -EINVAL; | 855 | return -EINVAL; |
856 | e.is_domain = true; | ||
857 | } else { | ||
858 | if (!tomoyo_correct_path(manager)) | ||
859 | return -EINVAL; | ||
860 | } | ||
861 | e.manager = tomoyo_get_name(manager); | 856 | e.manager = tomoyo_get_name(manager); |
862 | if (e.manager) { | 857 | if (e.manager) { |
863 | error = tomoyo_update_policy(&e.head, sizeof(e), ¶m, | 858 | error = tomoyo_update_policy(&e.head, sizeof(e), ¶m, |
@@ -932,23 +927,14 @@ static bool tomoyo_manager(void) | |||
932 | return true; | 927 | return true; |
933 | if (!tomoyo_manage_by_non_root && (task->cred->uid || task->cred->euid)) | 928 | if (!tomoyo_manage_by_non_root && (task->cred->uid || task->cred->euid)) |
934 | return false; | 929 | return false; |
935 | list_for_each_entry_rcu(ptr, &tomoyo_kernel_namespace. | ||
936 | policy_list[TOMOYO_ID_MANAGER], head.list) { | ||
937 | if (!ptr->head.is_deleted && ptr->is_domain | ||
938 | && !tomoyo_pathcmp(domainname, ptr->manager)) { | ||
939 | found = true; | ||
940 | break; | ||
941 | } | ||
942 | } | ||
943 | if (found) | ||
944 | return true; | ||
945 | exe = tomoyo_get_exe(); | 930 | exe = tomoyo_get_exe(); |
946 | if (!exe) | 931 | if (!exe) |
947 | return false; | 932 | return false; |
948 | list_for_each_entry_rcu(ptr, &tomoyo_kernel_namespace. | 933 | list_for_each_entry_rcu(ptr, &tomoyo_kernel_namespace. |
949 | policy_list[TOMOYO_ID_MANAGER], head.list) { | 934 | policy_list[TOMOYO_ID_MANAGER], head.list) { |
950 | if (!ptr->head.is_deleted && !ptr->is_domain | 935 | if (!ptr->head.is_deleted && |
951 | && !strcmp(exe, ptr->manager->name)) { | 936 | (!tomoyo_pathcmp(domainname, ptr->manager) || |
937 | !strcmp(exe, ptr->manager->name))) { | ||
952 | found = true; | 938 | found = true; |
953 | break; | 939 | break; |
954 | } | 940 | } |
diff --git a/security/tomoyo/common.h b/security/tomoyo/common.h index 30fd98369700..75e4dc1c02a0 100644 --- a/security/tomoyo/common.h +++ b/security/tomoyo/common.h | |||
@@ -860,7 +860,6 @@ struct tomoyo_aggregator { | |||
860 | /* Structure for policy manager. */ | 860 | /* Structure for policy manager. */ |
861 | struct tomoyo_manager { | 861 | struct tomoyo_manager { |
862 | struct tomoyo_acl_head head; | 862 | struct tomoyo_acl_head head; |
863 | bool is_domain; /* True if manager is a domainname. */ | ||
864 | /* A path to program or a domainname. */ | 863 | /* A path to program or a domainname. */ |
865 | const struct tomoyo_path_info *manager; | 864 | const struct tomoyo_path_info *manager; |
866 | }; | 865 | }; |
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index 620d37c159a3..c2d04a50f76a 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c | |||
@@ -319,14 +319,14 @@ static int tomoyo_file_fcntl(struct file *file, unsigned int cmd, | |||
319 | } | 319 | } |
320 | 320 | ||
321 | /** | 321 | /** |
322 | * tomoyo_dentry_open - Target for security_dentry_open(). | 322 | * tomoyo_file_open - Target for security_file_open(). |
323 | * | 323 | * |
324 | * @f: Pointer to "struct file". | 324 | * @f: Pointer to "struct file". |
325 | * @cred: Pointer to "struct cred". | 325 | * @cred: Pointer to "struct cred". |
326 | * | 326 | * |
327 | * Returns 0 on success, negative value otherwise. | 327 | * Returns 0 on success, negative value otherwise. |
328 | */ | 328 | */ |
329 | static int tomoyo_dentry_open(struct file *f, const struct cred *cred) | 329 | static int tomoyo_file_open(struct file *f, const struct cred *cred) |
330 | { | 330 | { |
331 | int flags = f->f_flags; | 331 | int flags = f->f_flags; |
332 | /* Don't check read permission here if called from do_execve(). */ | 332 | /* Don't check read permission here if called from do_execve(). */ |
@@ -510,7 +510,7 @@ static struct security_operations tomoyo_security_ops = { | |||
510 | .bprm_set_creds = tomoyo_bprm_set_creds, | 510 | .bprm_set_creds = tomoyo_bprm_set_creds, |
511 | .bprm_check_security = tomoyo_bprm_check_security, | 511 | .bprm_check_security = tomoyo_bprm_check_security, |
512 | .file_fcntl = tomoyo_file_fcntl, | 512 | .file_fcntl = tomoyo_file_fcntl, |
513 | .dentry_open = tomoyo_dentry_open, | 513 | .file_open = tomoyo_file_open, |
514 | .path_truncate = tomoyo_path_truncate, | 514 | .path_truncate = tomoyo_path_truncate, |
515 | .path_unlink = tomoyo_path_unlink, | 515 | .path_unlink = tomoyo_path_unlink, |
516 | .path_mkdir = tomoyo_path_mkdir, | 516 | .path_mkdir = tomoyo_path_mkdir, |
diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c index 573723843a04..83554ee8a587 100644 --- a/security/yama/yama_lsm.c +++ b/security/yama/yama_lsm.c | |||
@@ -18,7 +18,12 @@ | |||
18 | #include <linux/prctl.h> | 18 | #include <linux/prctl.h> |
19 | #include <linux/ratelimit.h> | 19 | #include <linux/ratelimit.h> |
20 | 20 | ||
21 | static int ptrace_scope = 1; | 21 | #define YAMA_SCOPE_DISABLED 0 |
22 | #define YAMA_SCOPE_RELATIONAL 1 | ||
23 | #define YAMA_SCOPE_CAPABILITY 2 | ||
24 | #define YAMA_SCOPE_NO_ATTACH 3 | ||
25 | |||
26 | static int ptrace_scope = YAMA_SCOPE_RELATIONAL; | ||
22 | 27 | ||
23 | /* describe a ptrace relationship for potential exception */ | 28 | /* describe a ptrace relationship for potential exception */ |
24 | struct ptrace_relation { | 29 | struct ptrace_relation { |
@@ -251,17 +256,32 @@ static int yama_ptrace_access_check(struct task_struct *child, | |||
251 | return rc; | 256 | return rc; |
252 | 257 | ||
253 | /* require ptrace target be a child of ptracer on attach */ | 258 | /* require ptrace target be a child of ptracer on attach */ |
254 | if (mode == PTRACE_MODE_ATTACH && | 259 | if (mode == PTRACE_MODE_ATTACH) { |
255 | ptrace_scope && | 260 | switch (ptrace_scope) { |
256 | !task_is_descendant(current, child) && | 261 | case YAMA_SCOPE_DISABLED: |
257 | !ptracer_exception_found(current, child) && | 262 | /* No additional restrictions. */ |
258 | !capable(CAP_SYS_PTRACE)) | 263 | break; |
259 | rc = -EPERM; | 264 | case YAMA_SCOPE_RELATIONAL: |
265 | if (!task_is_descendant(current, child) && | ||
266 | !ptracer_exception_found(current, child) && | ||
267 | !ns_capable(task_user_ns(child), CAP_SYS_PTRACE)) | ||
268 | rc = -EPERM; | ||
269 | break; | ||
270 | case YAMA_SCOPE_CAPABILITY: | ||
271 | if (!ns_capable(task_user_ns(child), CAP_SYS_PTRACE)) | ||
272 | rc = -EPERM; | ||
273 | break; | ||
274 | case YAMA_SCOPE_NO_ATTACH: | ||
275 | default: | ||
276 | rc = -EPERM; | ||
277 | break; | ||
278 | } | ||
279 | } | ||
260 | 280 | ||
261 | if (rc) { | 281 | if (rc) { |
262 | char name[sizeof(current->comm)]; | 282 | char name[sizeof(current->comm)]; |
263 | printk_ratelimited(KERN_NOTICE "ptrace of non-child" | 283 | printk_ratelimited(KERN_NOTICE |
264 | " pid %d was attempted by: %s (pid %d)\n", | 284 | "ptrace of pid %d was attempted by: %s (pid %d)\n", |
265 | child->pid, | 285 | child->pid, |
266 | get_task_comm(name, current), | 286 | get_task_comm(name, current), |
267 | current->pid); | 287 | current->pid); |
@@ -279,8 +299,27 @@ static struct security_operations yama_ops = { | |||
279 | }; | 299 | }; |
280 | 300 | ||
281 | #ifdef CONFIG_SYSCTL | 301 | #ifdef CONFIG_SYSCTL |
302 | static int yama_dointvec_minmax(struct ctl_table *table, int write, | ||
303 | void __user *buffer, size_t *lenp, loff_t *ppos) | ||
304 | { | ||
305 | int rc; | ||
306 | |||
307 | if (write && !capable(CAP_SYS_PTRACE)) | ||
308 | return -EPERM; | ||
309 | |||
310 | rc = proc_dointvec_minmax(table, write, buffer, lenp, ppos); | ||
311 | if (rc) | ||
312 | return rc; | ||
313 | |||
314 | /* Lock the max value if it ever gets set. */ | ||
315 | if (write && *(int *)table->data == *(int *)table->extra2) | ||
316 | table->extra1 = table->extra2; | ||
317 | |||
318 | return rc; | ||
319 | } | ||
320 | |||
282 | static int zero; | 321 | static int zero; |
283 | static int one = 1; | 322 | static int max_scope = YAMA_SCOPE_NO_ATTACH; |
284 | 323 | ||
285 | struct ctl_path yama_sysctl_path[] = { | 324 | struct ctl_path yama_sysctl_path[] = { |
286 | { .procname = "kernel", }, | 325 | { .procname = "kernel", }, |
@@ -294,9 +333,9 @@ static struct ctl_table yama_sysctl_table[] = { | |||
294 | .data = &ptrace_scope, | 333 | .data = &ptrace_scope, |
295 | .maxlen = sizeof(int), | 334 | .maxlen = sizeof(int), |
296 | .mode = 0644, | 335 | .mode = 0644, |
297 | .proc_handler = proc_dointvec_minmax, | 336 | .proc_handler = yama_dointvec_minmax, |
298 | .extra1 = &zero, | 337 | .extra1 = &zero, |
299 | .extra2 = &one, | 338 | .extra2 = &max_scope, |
300 | }, | 339 | }, |
301 | { } | 340 | { } |
302 | }; | 341 | }; |