diff options
author | David Howells <dhowells@redhat.com> | 2006-01-08 04:02:47 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-01-08 23:13:53 -0500 |
commit | b5f545c880a2a47947ba2118b2509644ab7a2969 (patch) | |
tree | 8720e02262b0ff6309ae79603f6c63965296d378 /security | |
parent | cab8eb594e84b434d20412fc5a3985b0bee3ab9f (diff) |
[PATCH] keys: Permit running process to instantiate keys
Make it possible for a running process (such as gssapid) to be able to
instantiate a key, as was requested by Trond Myklebust for NFS4.
The patch makes the following changes:
(1) A new, optional key type method has been added. This permits a key type
to intercept requests at the point /sbin/request-key is about to be
spawned and do something else with them - passing them over the
rpc_pipefs files or netlink sockets for instance.
The uninstantiated key, the authorisation key and the intended operation
name are passed to the method.
(2) The callout_info is no longer passed as an argument to /sbin/request-key
to prevent unauthorised viewing of this data using ps or by looking in
/proc/pid/cmdline.
This means that the old /sbin/request-key program will not work with the
patched kernel as it will expect to see an extra argument that is no
longer there.
A revised keyutils package will be made available tomorrow.
(3) The callout_info is now attached to the authorisation key. Reading this
key will retrieve the information.
(4) A new field has been added to the task_struct. This holds the
authorisation key currently active for a thread. Searches now look here
for the caller's set of keys rather than looking for an auth key in the
lowest level of the session keyring.
This permits a thread to be servicing multiple requests at once and to
switch between them. Note that this is per-thread, not per-process, and
so is usable in multithreaded programs.
The setting of this field is inherited across fork and exec.
(5) A new keyctl function (KEYCTL_ASSUME_AUTHORITY) has been added that
permits a thread to assume the authority to deal with an uninstantiated
key. Assumption is only permitted if the authorisation key associated
with the uninstantiated key is somewhere in the thread's keyrings.
This function can also clear the assumption.
(6) A new magic key specifier has been added to refer to the currently
assumed authorisation key (KEY_SPEC_REQKEY_AUTH_KEY).
(7) Instantiation will only proceed if the appropriate authorisation key is
assumed first. The assumed authorisation key is discarded if
instantiation is successful.
(8) key_validate() is moved from the file of request_key functions to the
file of permissions functions.
(9) The documentation is updated.
From: <Valdis.Kletnieks@vt.edu>
Build fix.
Signed-off-by: David Howells <dhowells@redhat.com>
Cc: Trond Myklebust <trond.myklebust@fys.uio.no>
Cc: Alexander Zangerl <az@bond.edu.au>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'security')
-rw-r--r-- | security/keys/compat.c | 3 | ||||
-rw-r--r-- | security/keys/internal.h | 4 | ||||
-rw-r--r-- | security/keys/keyctl.c | 107 | ||||
-rw-r--r-- | security/keys/keyring.c | 45 | ||||
-rw-r--r-- | security/keys/permission.c | 32 | ||||
-rw-r--r-- | security/keys/process_keys.c | 71 | ||||
-rw-r--r-- | security/keys/request_key.c | 108 | ||||
-rw-r--r-- | security/keys/request_key_auth.c | 192 |
8 files changed, 327 insertions, 235 deletions
diff --git a/security/keys/compat.c b/security/keys/compat.c index e8e7ef4a290c..bcdb28533733 100644 --- a/security/keys/compat.c +++ b/security/keys/compat.c | |||
@@ -77,6 +77,9 @@ asmlinkage long compat_sys_keyctl(u32 option, | |||
77 | case KEYCTL_SET_TIMEOUT: | 77 | case KEYCTL_SET_TIMEOUT: |
78 | return keyctl_set_timeout(arg2, arg3); | 78 | return keyctl_set_timeout(arg2, arg3); |
79 | 79 | ||
80 | case KEYCTL_ASSUME_AUTHORITY: | ||
81 | return keyctl_assume_authority(arg2); | ||
82 | |||
80 | default: | 83 | default: |
81 | return -EOPNOTSUPP; | 84 | return -EOPNOTSUPP; |
82 | } | 85 | } |
diff --git a/security/keys/internal.h b/security/keys/internal.h index 51f37c0bdb32..e066e6057955 100644 --- a/security/keys/internal.h +++ b/security/keys/internal.h | |||
@@ -107,12 +107,13 @@ extern struct key *request_key_and_link(struct key_type *type, | |||
107 | struct request_key_auth { | 107 | struct request_key_auth { |
108 | struct key *target_key; | 108 | struct key *target_key; |
109 | struct task_struct *context; | 109 | struct task_struct *context; |
110 | const char *callout_info; | ||
110 | pid_t pid; | 111 | pid_t pid; |
111 | }; | 112 | }; |
112 | 113 | ||
113 | extern struct key_type key_type_request_key_auth; | 114 | extern struct key_type key_type_request_key_auth; |
114 | extern struct key *request_key_auth_new(struct key *target, | 115 | extern struct key *request_key_auth_new(struct key *target, |
115 | struct key **_rkakey); | 116 | const char *callout_info); |
116 | 117 | ||
117 | extern struct key *key_get_instantiation_authkey(key_serial_t target_id); | 118 | extern struct key *key_get_instantiation_authkey(key_serial_t target_id); |
118 | 119 | ||
@@ -137,6 +138,7 @@ extern long keyctl_instantiate_key(key_serial_t, const void __user *, | |||
137 | extern long keyctl_negate_key(key_serial_t, unsigned, key_serial_t); | 138 | extern long keyctl_negate_key(key_serial_t, unsigned, key_serial_t); |
138 | extern long keyctl_set_reqkey_keyring(int); | 139 | extern long keyctl_set_reqkey_keyring(int); |
139 | extern long keyctl_set_timeout(key_serial_t, unsigned); | 140 | extern long keyctl_set_timeout(key_serial_t, unsigned); |
141 | extern long keyctl_assume_authority(key_serial_t); | ||
140 | 142 | ||
141 | 143 | ||
142 | /* | 144 | /* |
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index 299f0ae11cf0..3d2ebae029c1 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c | |||
@@ -834,6 +834,17 @@ long keyctl_instantiate_key(key_serial_t id, | |||
834 | if (plen > 32767) | 834 | if (plen > 32767) |
835 | goto error; | 835 | goto error; |
836 | 836 | ||
837 | /* the appropriate instantiation authorisation key must have been | ||
838 | * assumed before calling this */ | ||
839 | ret = -EPERM; | ||
840 | instkey = current->request_key_auth; | ||
841 | if (!instkey) | ||
842 | goto error; | ||
843 | |||
844 | rka = instkey->payload.data; | ||
845 | if (rka->target_key->serial != id) | ||
846 | goto error; | ||
847 | |||
837 | /* pull the payload in if one was supplied */ | 848 | /* pull the payload in if one was supplied */ |
838 | payload = NULL; | 849 | payload = NULL; |
839 | 850 | ||
@@ -848,15 +859,6 @@ long keyctl_instantiate_key(key_serial_t id, | |||
848 | goto error2; | 859 | goto error2; |
849 | } | 860 | } |
850 | 861 | ||
851 | /* find the instantiation authorisation key */ | ||
852 | instkey = key_get_instantiation_authkey(id); | ||
853 | if (IS_ERR(instkey)) { | ||
854 | ret = PTR_ERR(instkey); | ||
855 | goto error2; | ||
856 | } | ||
857 | |||
858 | rka = instkey->payload.data; | ||
859 | |||
860 | /* find the destination keyring amongst those belonging to the | 862 | /* find the destination keyring amongst those belonging to the |
861 | * requesting task */ | 863 | * requesting task */ |
862 | keyring_ref = NULL; | 864 | keyring_ref = NULL; |
@@ -865,7 +867,7 @@ long keyctl_instantiate_key(key_serial_t id, | |||
865 | KEY_WRITE); | 867 | KEY_WRITE); |
866 | if (IS_ERR(keyring_ref)) { | 868 | if (IS_ERR(keyring_ref)) { |
867 | ret = PTR_ERR(keyring_ref); | 869 | ret = PTR_ERR(keyring_ref); |
868 | goto error3; | 870 | goto error2; |
869 | } | 871 | } |
870 | } | 872 | } |
871 | 873 | ||
@@ -874,11 +876,17 @@ long keyctl_instantiate_key(key_serial_t id, | |||
874 | key_ref_to_ptr(keyring_ref), instkey); | 876 | key_ref_to_ptr(keyring_ref), instkey); |
875 | 877 | ||
876 | key_ref_put(keyring_ref); | 878 | key_ref_put(keyring_ref); |
877 | error3: | 879 | |
878 | key_put(instkey); | 880 | /* discard the assumed authority if it's just been disabled by |
879 | error2: | 881 | * instantiation of the key */ |
882 | if (ret == 0) { | ||
883 | key_put(current->request_key_auth); | ||
884 | current->request_key_auth = NULL; | ||
885 | } | ||
886 | |||
887 | error2: | ||
880 | kfree(payload); | 888 | kfree(payload); |
881 | error: | 889 | error: |
882 | return ret; | 890 | return ret; |
883 | 891 | ||
884 | } /* end keyctl_instantiate_key() */ | 892 | } /* end keyctl_instantiate_key() */ |
@@ -895,14 +903,16 @@ long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid) | |||
895 | key_ref_t keyring_ref; | 903 | key_ref_t keyring_ref; |
896 | long ret; | 904 | long ret; |
897 | 905 | ||
898 | /* find the instantiation authorisation key */ | 906 | /* the appropriate instantiation authorisation key must have been |
899 | instkey = key_get_instantiation_authkey(id); | 907 | * assumed before calling this */ |
900 | if (IS_ERR(instkey)) { | 908 | ret = -EPERM; |
901 | ret = PTR_ERR(instkey); | 909 | instkey = current->request_key_auth; |
910 | if (!instkey) | ||
902 | goto error; | 911 | goto error; |
903 | } | ||
904 | 912 | ||
905 | rka = instkey->payload.data; | 913 | rka = instkey->payload.data; |
914 | if (rka->target_key->serial != id) | ||
915 | goto error; | ||
906 | 916 | ||
907 | /* find the destination keyring if present (which must also be | 917 | /* find the destination keyring if present (which must also be |
908 | * writable) */ | 918 | * writable) */ |
@@ -911,7 +921,7 @@ long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid) | |||
911 | keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE); | 921 | keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE); |
912 | if (IS_ERR(keyring_ref)) { | 922 | if (IS_ERR(keyring_ref)) { |
913 | ret = PTR_ERR(keyring_ref); | 923 | ret = PTR_ERR(keyring_ref); |
914 | goto error2; | 924 | goto error; |
915 | } | 925 | } |
916 | } | 926 | } |
917 | 927 | ||
@@ -920,9 +930,15 @@ long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid) | |||
920 | key_ref_to_ptr(keyring_ref), instkey); | 930 | key_ref_to_ptr(keyring_ref), instkey); |
921 | 931 | ||
922 | key_ref_put(keyring_ref); | 932 | key_ref_put(keyring_ref); |
923 | error2: | 933 | |
924 | key_put(instkey); | 934 | /* discard the assumed authority if it's just been disabled by |
925 | error: | 935 | * instantiation of the key */ |
936 | if (ret == 0) { | ||
937 | key_put(current->request_key_auth); | ||
938 | current->request_key_auth = NULL; | ||
939 | } | ||
940 | |||
941 | error: | ||
926 | return ret; | 942 | return ret; |
927 | 943 | ||
928 | } /* end keyctl_negate_key() */ | 944 | } /* end keyctl_negate_key() */ |
@@ -1007,6 +1023,48 @@ error: | |||
1007 | 1023 | ||
1008 | /*****************************************************************************/ | 1024 | /*****************************************************************************/ |
1009 | /* | 1025 | /* |
1026 | * assume the authority to instantiate the specified key | ||
1027 | */ | ||
1028 | long keyctl_assume_authority(key_serial_t id) | ||
1029 | { | ||
1030 | struct key *authkey; | ||
1031 | long ret; | ||
1032 | |||
1033 | /* special key IDs aren't permitted */ | ||
1034 | ret = -EINVAL; | ||
1035 | if (id < 0) | ||
1036 | goto error; | ||
1037 | |||
1038 | /* we divest ourselves of authority if given an ID of 0 */ | ||
1039 | if (id == 0) { | ||
1040 | key_put(current->request_key_auth); | ||
1041 | current->request_key_auth = NULL; | ||
1042 | ret = 0; | ||
1043 | goto error; | ||
1044 | } | ||
1045 | |||
1046 | /* attempt to assume the authority temporarily granted to us whilst we | ||
1047 | * instantiate the specified key | ||
1048 | * - the authorisation key must be in the current task's keyrings | ||
1049 | * somewhere | ||
1050 | */ | ||
1051 | authkey = key_get_instantiation_authkey(id); | ||
1052 | if (IS_ERR(authkey)) { | ||
1053 | ret = PTR_ERR(authkey); | ||
1054 | goto error; | ||
1055 | } | ||
1056 | |||
1057 | key_put(current->request_key_auth); | ||
1058 | current->request_key_auth = authkey; | ||
1059 | ret = authkey->serial; | ||
1060 | |||
1061 | error: | ||
1062 | return ret; | ||
1063 | |||
1064 | } /* end keyctl_assume_authority() */ | ||
1065 | |||
1066 | /*****************************************************************************/ | ||
1067 | /* | ||
1010 | * the key control system call | 1068 | * the key control system call |
1011 | */ | 1069 | */ |
1012 | asmlinkage long sys_keyctl(int option, unsigned long arg2, unsigned long arg3, | 1070 | asmlinkage long sys_keyctl(int option, unsigned long arg2, unsigned long arg3, |
@@ -1082,6 +1140,9 @@ asmlinkage long sys_keyctl(int option, unsigned long arg2, unsigned long arg3, | |||
1082 | return keyctl_set_timeout((key_serial_t) arg2, | 1140 | return keyctl_set_timeout((key_serial_t) arg2, |
1083 | (unsigned) arg3); | 1141 | (unsigned) arg3); |
1084 | 1142 | ||
1143 | case KEYCTL_ASSUME_AUTHORITY: | ||
1144 | return keyctl_assume_authority((key_serial_t) arg2); | ||
1145 | |||
1085 | default: | 1146 | default: |
1086 | return -EOPNOTSUPP; | 1147 | return -EOPNOTSUPP; |
1087 | } | 1148 | } |
diff --git a/security/keys/keyring.c b/security/keys/keyring.c index 09d92d52ef75..d65a180f888d 100644 --- a/security/keys/keyring.c +++ b/security/keys/keyring.c | |||
@@ -481,51 +481,6 @@ key_ref_t __keyring_search_one(key_ref_t keyring_ref, | |||
481 | 481 | ||
482 | /*****************************************************************************/ | 482 | /*****************************************************************************/ |
483 | /* | 483 | /* |
484 | * search for an instantiation authorisation key matching a target key | ||
485 | * - the RCU read lock must be held by the caller | ||
486 | * - a target_id of zero specifies any valid token | ||
487 | */ | ||
488 | struct key *keyring_search_instkey(struct key *keyring, | ||
489 | key_serial_t target_id) | ||
490 | { | ||
491 | struct request_key_auth *rka; | ||
492 | struct keyring_list *klist; | ||
493 | struct key *instkey; | ||
494 | int loop; | ||
495 | |||
496 | klist = rcu_dereference(keyring->payload.subscriptions); | ||
497 | if (klist) { | ||
498 | for (loop = 0; loop < klist->nkeys; loop++) { | ||
499 | instkey = klist->keys[loop]; | ||
500 | |||
501 | if (instkey->type != &key_type_request_key_auth) | ||
502 | continue; | ||
503 | |||
504 | rka = instkey->payload.data; | ||
505 | if (target_id && rka->target_key->serial != target_id) | ||
506 | continue; | ||
507 | |||
508 | /* the auth key is revoked during instantiation */ | ||
509 | if (!test_bit(KEY_FLAG_REVOKED, &instkey->flags)) | ||
510 | goto found; | ||
511 | |||
512 | instkey = ERR_PTR(-EKEYREVOKED); | ||
513 | goto error; | ||
514 | } | ||
515 | } | ||
516 | |||
517 | instkey = ERR_PTR(-EACCES); | ||
518 | goto error; | ||
519 | |||
520 | found: | ||
521 | atomic_inc(&instkey->usage); | ||
522 | error: | ||
523 | return instkey; | ||
524 | |||
525 | } /* end keyring_search_instkey() */ | ||
526 | |||
527 | /*****************************************************************************/ | ||
528 | /* | ||
529 | * find a keyring with the specified name | 484 | * find a keyring with the specified name |
530 | * - all named keyrings are searched | 485 | * - all named keyrings are searched |
531 | * - only find keyrings with search permission for the process | 486 | * - only find keyrings with search permission for the process |
diff --git a/security/keys/permission.c b/security/keys/permission.c index e7f579c0eaf5..3b41f9b52537 100644 --- a/security/keys/permission.c +++ b/security/keys/permission.c | |||
@@ -73,3 +73,35 @@ use_these_perms: | |||
73 | } /* end key_task_permission() */ | 73 | } /* end key_task_permission() */ |
74 | 74 | ||
75 | EXPORT_SYMBOL(key_task_permission); | 75 | EXPORT_SYMBOL(key_task_permission); |
76 | |||
77 | /*****************************************************************************/ | ||
78 | /* | ||
79 | * validate a key | ||
80 | */ | ||
81 | int key_validate(struct key *key) | ||
82 | { | ||
83 | struct timespec now; | ||
84 | int ret = 0; | ||
85 | |||
86 | if (key) { | ||
87 | /* check it's still accessible */ | ||
88 | ret = -EKEYREVOKED; | ||
89 | if (test_bit(KEY_FLAG_REVOKED, &key->flags) || | ||
90 | test_bit(KEY_FLAG_DEAD, &key->flags)) | ||
91 | goto error; | ||
92 | |||
93 | /* check it hasn't expired */ | ||
94 | ret = 0; | ||
95 | if (key->expiry) { | ||
96 | now = current_kernel_time(); | ||
97 | if (now.tv_sec >= key->expiry) | ||
98 | ret = -EKEYEXPIRED; | ||
99 | } | ||
100 | } | ||
101 | |||
102 | error: | ||
103 | return ret; | ||
104 | |||
105 | } /* end key_validate() */ | ||
106 | |||
107 | EXPORT_SYMBOL(key_validate); | ||
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index 566b1cc0118a..74cb79eb917e 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c | |||
@@ -270,9 +270,14 @@ int copy_thread_group_keys(struct task_struct *tsk) | |||
270 | int copy_keys(unsigned long clone_flags, struct task_struct *tsk) | 270 | int copy_keys(unsigned long clone_flags, struct task_struct *tsk) |
271 | { | 271 | { |
272 | key_check(tsk->thread_keyring); | 272 | key_check(tsk->thread_keyring); |
273 | key_check(tsk->request_key_auth); | ||
273 | 274 | ||
274 | /* no thread keyring yet */ | 275 | /* no thread keyring yet */ |
275 | tsk->thread_keyring = NULL; | 276 | tsk->thread_keyring = NULL; |
277 | |||
278 | /* copy the request_key() authorisation for this thread */ | ||
279 | key_get(tsk->request_key_auth); | ||
280 | |||
276 | return 0; | 281 | return 0; |
277 | 282 | ||
278 | } /* end copy_keys() */ | 283 | } /* end copy_keys() */ |
@@ -290,11 +295,12 @@ void exit_thread_group_keys(struct signal_struct *tg) | |||
290 | 295 | ||
291 | /*****************************************************************************/ | 296 | /*****************************************************************************/ |
292 | /* | 297 | /* |
293 | * dispose of keys upon thread exit | 298 | * dispose of per-thread keys upon thread exit |
294 | */ | 299 | */ |
295 | void exit_keys(struct task_struct *tsk) | 300 | void exit_keys(struct task_struct *tsk) |
296 | { | 301 | { |
297 | key_put(tsk->thread_keyring); | 302 | key_put(tsk->thread_keyring); |
303 | key_put(tsk->request_key_auth); | ||
298 | 304 | ||
299 | } /* end exit_keys() */ | 305 | } /* end exit_keys() */ |
300 | 306 | ||
@@ -382,7 +388,7 @@ key_ref_t search_process_keyrings(struct key_type *type, | |||
382 | struct task_struct *context) | 388 | struct task_struct *context) |
383 | { | 389 | { |
384 | struct request_key_auth *rka; | 390 | struct request_key_auth *rka; |
385 | key_ref_t key_ref, ret, err, instkey_ref; | 391 | key_ref_t key_ref, ret, err; |
386 | 392 | ||
387 | /* we want to return -EAGAIN or -ENOKEY if any of the keyrings were | 393 | /* we want to return -EAGAIN or -ENOKEY if any of the keyrings were |
388 | * searchable, but we failed to find a key or we found a negative key; | 394 | * searchable, but we failed to find a key or we found a negative key; |
@@ -461,30 +467,12 @@ key_ref_t search_process_keyrings(struct key_type *type, | |||
461 | err = key_ref; | 467 | err = key_ref; |
462 | break; | 468 | break; |
463 | } | 469 | } |
464 | 470 | } | |
465 | /* if this process has a session keyring and that has an | 471 | /* or search the user-session keyring */ |
466 | * instantiation authorisation key in the bottom level, then we | 472 | else { |
467 | * also search the keyrings of the process mentioned there */ | 473 | key_ref = keyring_search_aux( |
468 | if (context != current) | 474 | make_key_ref(context->user->session_keyring, 1), |
469 | goto no_key; | 475 | context, type, description, match); |
470 | |||
471 | rcu_read_lock(); | ||
472 | instkey_ref = __keyring_search_one( | ||
473 | make_key_ref(rcu_dereference( | ||
474 | context->signal->session_keyring), | ||
475 | 1), | ||
476 | &key_type_request_key_auth, NULL, 0); | ||
477 | rcu_read_unlock(); | ||
478 | |||
479 | if (IS_ERR(instkey_ref)) | ||
480 | goto no_key; | ||
481 | |||
482 | rka = key_ref_to_ptr(instkey_ref)->payload.data; | ||
483 | |||
484 | key_ref = search_process_keyrings(type, description, match, | ||
485 | rka->context); | ||
486 | key_ref_put(instkey_ref); | ||
487 | |||
488 | if (!IS_ERR(key_ref)) | 476 | if (!IS_ERR(key_ref)) |
489 | goto found; | 477 | goto found; |
490 | 478 | ||
@@ -500,11 +488,21 @@ key_ref_t search_process_keyrings(struct key_type *type, | |||
500 | break; | 488 | break; |
501 | } | 489 | } |
502 | } | 490 | } |
503 | /* or search the user-session keyring */ | 491 | |
504 | else { | 492 | /* if this process has an instantiation authorisation key, then we also |
505 | key_ref = keyring_search_aux( | 493 | * search the keyrings of the process mentioned there |
506 | make_key_ref(context->user->session_keyring, 1), | 494 | * - we don't permit access to request_key auth keys via this method |
507 | context, type, description, match); | 495 | */ |
496 | if (context->request_key_auth && | ||
497 | context == current && | ||
498 | type != &key_type_request_key_auth && | ||
499 | key_validate(context->request_key_auth) == 0 | ||
500 | ) { | ||
501 | rka = context->request_key_auth->payload.data; | ||
502 | |||
503 | key_ref = search_process_keyrings(type, description, match, | ||
504 | rka->context); | ||
505 | |||
508 | if (!IS_ERR(key_ref)) | 506 | if (!IS_ERR(key_ref)) |
509 | goto found; | 507 | goto found; |
510 | 508 | ||
@@ -521,8 +519,6 @@ key_ref_t search_process_keyrings(struct key_type *type, | |||
521 | } | 519 | } |
522 | } | 520 | } |
523 | 521 | ||
524 | |||
525 | no_key: | ||
526 | /* no key - decide on the error we're going to go for */ | 522 | /* no key - decide on the error we're going to go for */ |
527 | key_ref = ret ? ret : err; | 523 | key_ref = ret ? ret : err; |
528 | 524 | ||
@@ -628,6 +624,15 @@ key_ref_t lookup_user_key(struct task_struct *context, key_serial_t id, | |||
628 | key = ERR_PTR(-EINVAL); | 624 | key = ERR_PTR(-EINVAL); |
629 | goto error; | 625 | goto error; |
630 | 626 | ||
627 | case KEY_SPEC_REQKEY_AUTH_KEY: | ||
628 | key = context->request_key_auth; | ||
629 | if (!key) | ||
630 | goto error; | ||
631 | |||
632 | atomic_inc(&key->usage); | ||
633 | key_ref = make_key_ref(key, 1); | ||
634 | break; | ||
635 | |||
631 | default: | 636 | default: |
632 | key_ref = ERR_PTR(-EINVAL); | 637 | key_ref = ERR_PTR(-EINVAL); |
633 | if (id < 1) | 638 | if (id < 1) |
diff --git a/security/keys/request_key.c b/security/keys/request_key.c index 5cc4bba70db6..f030a0ccbb93 100644 --- a/security/keys/request_key.c +++ b/security/keys/request_key.c | |||
@@ -29,28 +29,36 @@ DECLARE_WAIT_QUEUE_HEAD(request_key_conswq); | |||
29 | /*****************************************************************************/ | 29 | /*****************************************************************************/ |
30 | /* | 30 | /* |
31 | * request userspace finish the construction of a key | 31 | * request userspace finish the construction of a key |
32 | * - execute "/sbin/request-key <op> <key> <uid> <gid> <keyring> <keyring> <keyring> <info>" | 32 | * - execute "/sbin/request-key <op> <key> <uid> <gid> <keyring> <keyring> <keyring>" |
33 | */ | 33 | */ |
34 | static int call_request_key(struct key *key, | 34 | static int call_sbin_request_key(struct key *key, |
35 | const char *op, | 35 | struct key *authkey, |
36 | const char *callout_info) | 36 | const char *op) |
37 | { | 37 | { |
38 | struct task_struct *tsk = current; | 38 | struct task_struct *tsk = current; |
39 | key_serial_t prkey, sskey; | 39 | key_serial_t prkey, sskey; |
40 | struct key *session_keyring, *rkakey; | 40 | struct key *keyring; |
41 | char *argv[10], *envp[3], uid_str[12], gid_str[12]; | 41 | char *argv[9], *envp[3], uid_str[12], gid_str[12]; |
42 | char key_str[12], keyring_str[3][12]; | 42 | char key_str[12], keyring_str[3][12]; |
43 | char desc[20]; | ||
43 | int ret, i; | 44 | int ret, i; |
44 | 45 | ||
45 | kenter("{%d},%s,%s", key->serial, op, callout_info); | 46 | kenter("{%d},{%d},%s", key->serial, authkey->serial, op); |
46 | 47 | ||
47 | /* generate a new session keyring with an auth key in it */ | 48 | /* allocate a new session keyring */ |
48 | session_keyring = request_key_auth_new(key, &rkakey); | 49 | sprintf(desc, "_req.%u", key->serial); |
49 | if (IS_ERR(session_keyring)) { | 50 | |
50 | ret = PTR_ERR(session_keyring); | 51 | keyring = keyring_alloc(desc, current->fsuid, current->fsgid, 1, NULL); |
51 | goto error; | 52 | if (IS_ERR(keyring)) { |
53 | ret = PTR_ERR(keyring); | ||
54 | goto error_alloc; | ||
52 | } | 55 | } |
53 | 56 | ||
57 | /* attach the auth key to the session keyring */ | ||
58 | ret = __key_link(keyring, authkey); | ||
59 | if (ret < 0) | ||
60 | goto error_link; | ||
61 | |||
54 | /* record the UID and GID */ | 62 | /* record the UID and GID */ |
55 | sprintf(uid_str, "%d", current->fsuid); | 63 | sprintf(uid_str, "%d", current->fsuid); |
56 | sprintf(gid_str, "%d", current->fsgid); | 64 | sprintf(gid_str, "%d", current->fsgid); |
@@ -95,22 +103,19 @@ static int call_request_key(struct key *key, | |||
95 | argv[i++] = keyring_str[0]; | 103 | argv[i++] = keyring_str[0]; |
96 | argv[i++] = keyring_str[1]; | 104 | argv[i++] = keyring_str[1]; |
97 | argv[i++] = keyring_str[2]; | 105 | argv[i++] = keyring_str[2]; |
98 | argv[i++] = (char *) callout_info; | ||
99 | argv[i] = NULL; | 106 | argv[i] = NULL; |
100 | 107 | ||
101 | /* do it */ | 108 | /* do it */ |
102 | ret = call_usermodehelper_keys(argv[0], argv, envp, session_keyring, 1); | 109 | ret = call_usermodehelper_keys(argv[0], argv, envp, keyring, 1); |
103 | 110 | ||
104 | /* dispose of the special keys */ | 111 | error_link: |
105 | key_revoke(rkakey); | 112 | key_put(keyring); |
106 | key_put(rkakey); | ||
107 | key_put(session_keyring); | ||
108 | 113 | ||
109 | error: | 114 | error_alloc: |
110 | kleave(" = %d", ret); | 115 | kleave(" = %d", ret); |
111 | return ret; | 116 | return ret; |
112 | 117 | ||
113 | } /* end call_request_key() */ | 118 | } /* end call_sbin_request_key() */ |
114 | 119 | ||
115 | /*****************************************************************************/ | 120 | /*****************************************************************************/ |
116 | /* | 121 | /* |
@@ -122,9 +127,10 @@ static struct key *__request_key_construction(struct key_type *type, | |||
122 | const char *description, | 127 | const char *description, |
123 | const char *callout_info) | 128 | const char *callout_info) |
124 | { | 129 | { |
130 | request_key_actor_t actor; | ||
125 | struct key_construction cons; | 131 | struct key_construction cons; |
126 | struct timespec now; | 132 | struct timespec now; |
127 | struct key *key; | 133 | struct key *key, *authkey; |
128 | int ret, negated; | 134 | int ret, negated; |
129 | 135 | ||
130 | kenter("%s,%s,%s", type->name, description, callout_info); | 136 | kenter("%s,%s,%s", type->name, description, callout_info); |
@@ -143,8 +149,19 @@ static struct key *__request_key_construction(struct key_type *type, | |||
143 | /* we drop the construction sem here on behalf of the caller */ | 149 | /* we drop the construction sem here on behalf of the caller */ |
144 | up_write(&key_construction_sem); | 150 | up_write(&key_construction_sem); |
145 | 151 | ||
152 | /* allocate an authorisation key */ | ||
153 | authkey = request_key_auth_new(key, callout_info); | ||
154 | if (IS_ERR(authkey)) { | ||
155 | ret = PTR_ERR(authkey); | ||
156 | authkey = NULL; | ||
157 | goto alloc_authkey_failed; | ||
158 | } | ||
159 | |||
146 | /* make the call */ | 160 | /* make the call */ |
147 | ret = call_request_key(key, "create", callout_info); | 161 | actor = call_sbin_request_key; |
162 | if (type->request_key) | ||
163 | actor = type->request_key; | ||
164 | ret = actor(key, authkey, "create"); | ||
148 | if (ret < 0) | 165 | if (ret < 0) |
149 | goto request_failed; | 166 | goto request_failed; |
150 | 167 | ||
@@ -153,22 +170,29 @@ static struct key *__request_key_construction(struct key_type *type, | |||
153 | if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) | 170 | if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) |
154 | goto request_failed; | 171 | goto request_failed; |
155 | 172 | ||
173 | key_revoke(authkey); | ||
174 | key_put(authkey); | ||
175 | |||
156 | down_write(&key_construction_sem); | 176 | down_write(&key_construction_sem); |
157 | list_del(&cons.link); | 177 | list_del(&cons.link); |
158 | up_write(&key_construction_sem); | 178 | up_write(&key_construction_sem); |
159 | 179 | ||
160 | /* also give an error if the key was negatively instantiated */ | 180 | /* also give an error if the key was negatively instantiated */ |
161 | check_not_negative: | 181 | check_not_negative: |
162 | if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) { | 182 | if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) { |
163 | key_put(key); | 183 | key_put(key); |
164 | key = ERR_PTR(-ENOKEY); | 184 | key = ERR_PTR(-ENOKEY); |
165 | } | 185 | } |
166 | 186 | ||
167 | out: | 187 | out: |
168 | kleave(" = %p", key); | 188 | kleave(" = %p", key); |
169 | return key; | 189 | return key; |
170 | 190 | ||
171 | request_failed: | 191 | request_failed: |
192 | key_revoke(authkey); | ||
193 | key_put(authkey); | ||
194 | |||
195 | alloc_authkey_failed: | ||
172 | /* it wasn't instantiated | 196 | /* it wasn't instantiated |
173 | * - remove from construction queue | 197 | * - remove from construction queue |
174 | * - mark the key as dead | 198 | * - mark the key as dead |
@@ -217,7 +241,7 @@ static struct key *__request_key_construction(struct key_type *type, | |||
217 | key = ERR_PTR(ret); | 241 | key = ERR_PTR(ret); |
218 | goto out; | 242 | goto out; |
219 | 243 | ||
220 | alloc_failed: | 244 | alloc_failed: |
221 | up_write(&key_construction_sem); | 245 | up_write(&key_construction_sem); |
222 | goto out; | 246 | goto out; |
223 | 247 | ||
@@ -464,35 +488,3 @@ struct key *request_key(struct key_type *type, | |||
464 | } /* end request_key() */ | 488 | } /* end request_key() */ |
465 | 489 | ||
466 | EXPORT_SYMBOL(request_key); | 490 | EXPORT_SYMBOL(request_key); |
467 | |||
468 | /*****************************************************************************/ | ||
469 | /* | ||
470 | * validate a key | ||
471 | */ | ||
472 | int key_validate(struct key *key) | ||
473 | { | ||
474 | struct timespec now; | ||
475 | int ret = 0; | ||
476 | |||
477 | if (key) { | ||
478 | /* check it's still accessible */ | ||
479 | ret = -EKEYREVOKED; | ||
480 | if (test_bit(KEY_FLAG_REVOKED, &key->flags) || | ||
481 | test_bit(KEY_FLAG_DEAD, &key->flags)) | ||
482 | goto error; | ||
483 | |||
484 | /* check it hasn't expired */ | ||
485 | ret = 0; | ||
486 | if (key->expiry) { | ||
487 | now = current_kernel_time(); | ||
488 | if (now.tv_sec >= key->expiry) | ||
489 | ret = -EKEYEXPIRED; | ||
490 | } | ||
491 | } | ||
492 | |||
493 | error: | ||
494 | return ret; | ||
495 | |||
496 | } /* end key_validate() */ | ||
497 | |||
498 | EXPORT_SYMBOL(key_validate); | ||
diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c index a8e4069d48cb..cce6ba6b0323 100644 --- a/security/keys/request_key_auth.c +++ b/security/keys/request_key_auth.c | |||
@@ -15,11 +15,13 @@ | |||
15 | #include <linux/sched.h> | 15 | #include <linux/sched.h> |
16 | #include <linux/err.h> | 16 | #include <linux/err.h> |
17 | #include <linux/seq_file.h> | 17 | #include <linux/seq_file.h> |
18 | #include <asm/uaccess.h> | ||
18 | #include "internal.h" | 19 | #include "internal.h" |
19 | 20 | ||
20 | static int request_key_auth_instantiate(struct key *, const void *, size_t); | 21 | static int request_key_auth_instantiate(struct key *, const void *, size_t); |
21 | static void request_key_auth_describe(const struct key *, struct seq_file *); | 22 | static void request_key_auth_describe(const struct key *, struct seq_file *); |
22 | static void request_key_auth_destroy(struct key *); | 23 | static void request_key_auth_destroy(struct key *); |
24 | static long request_key_auth_read(const struct key *, char __user *, size_t); | ||
23 | 25 | ||
24 | /* | 26 | /* |
25 | * the request-key authorisation key type definition | 27 | * the request-key authorisation key type definition |
@@ -30,51 +32,25 @@ struct key_type key_type_request_key_auth = { | |||
30 | .instantiate = request_key_auth_instantiate, | 32 | .instantiate = request_key_auth_instantiate, |
31 | .describe = request_key_auth_describe, | 33 | .describe = request_key_auth_describe, |
32 | .destroy = request_key_auth_destroy, | 34 | .destroy = request_key_auth_destroy, |
35 | .read = request_key_auth_read, | ||
33 | }; | 36 | }; |
34 | 37 | ||
35 | /*****************************************************************************/ | 38 | /*****************************************************************************/ |
36 | /* | 39 | /* |
37 | * instantiate a request-key authorisation record | 40 | * instantiate a request-key authorisation key |
38 | */ | 41 | */ |
39 | static int request_key_auth_instantiate(struct key *key, | 42 | static int request_key_auth_instantiate(struct key *key, |
40 | const void *data, | 43 | const void *data, |
41 | size_t datalen) | 44 | size_t datalen) |
42 | { | 45 | { |
43 | struct request_key_auth *rka, *irka; | 46 | key->payload.data = (struct request_key_auth *) data; |
44 | struct key *instkey; | 47 | return 0; |
45 | int ret; | ||
46 | |||
47 | ret = -ENOMEM; | ||
48 | rka = kmalloc(sizeof(*rka), GFP_KERNEL); | ||
49 | if (rka) { | ||
50 | /* see if the calling process is already servicing the key | ||
51 | * request of another process */ | ||
52 | instkey = key_get_instantiation_authkey(0); | ||
53 | if (!IS_ERR(instkey)) { | ||
54 | /* it is - use that instantiation context here too */ | ||
55 | irka = instkey->payload.data; | ||
56 | rka->context = irka->context; | ||
57 | rka->pid = irka->pid; | ||
58 | key_put(instkey); | ||
59 | } | ||
60 | else { | ||
61 | /* it isn't - use this process as the context */ | ||
62 | rka->context = current; | ||
63 | rka->pid = current->pid; | ||
64 | } | ||
65 | |||
66 | rka->target_key = key_get((struct key *) data); | ||
67 | key->payload.data = rka; | ||
68 | ret = 0; | ||
69 | } | ||
70 | |||
71 | return ret; | ||
72 | 48 | ||
73 | } /* end request_key_auth_instantiate() */ | 49 | } /* end request_key_auth_instantiate() */ |
74 | 50 | ||
75 | /*****************************************************************************/ | 51 | /*****************************************************************************/ |
76 | /* | 52 | /* |
77 | * | 53 | * reading a request-key authorisation key retrieves the callout information |
78 | */ | 54 | */ |
79 | static void request_key_auth_describe(const struct key *key, | 55 | static void request_key_auth_describe(const struct key *key, |
80 | struct seq_file *m) | 56 | struct seq_file *m) |
@@ -83,12 +59,40 @@ static void request_key_auth_describe(const struct key *key, | |||
83 | 59 | ||
84 | seq_puts(m, "key:"); | 60 | seq_puts(m, "key:"); |
85 | seq_puts(m, key->description); | 61 | seq_puts(m, key->description); |
86 | seq_printf(m, " pid:%d", rka->pid); | 62 | seq_printf(m, " pid:%d ci:%zu", rka->pid, strlen(rka->callout_info)); |
87 | 63 | ||
88 | } /* end request_key_auth_describe() */ | 64 | } /* end request_key_auth_describe() */ |
89 | 65 | ||
90 | /*****************************************************************************/ | 66 | /*****************************************************************************/ |
91 | /* | 67 | /* |
68 | * read the callout_info data | ||
69 | * - the key's semaphore is read-locked | ||
70 | */ | ||
71 | static long request_key_auth_read(const struct key *key, | ||
72 | char __user *buffer, size_t buflen) | ||
73 | { | ||
74 | struct request_key_auth *rka = key->payload.data; | ||
75 | size_t datalen; | ||
76 | long ret; | ||
77 | |||
78 | datalen = strlen(rka->callout_info); | ||
79 | ret = datalen; | ||
80 | |||
81 | /* we can return the data as is */ | ||
82 | if (buffer && buflen > 0) { | ||
83 | if (buflen > datalen) | ||
84 | buflen = datalen; | ||
85 | |||
86 | if (copy_to_user(buffer, rka->callout_info, buflen) != 0) | ||
87 | ret = -EFAULT; | ||
88 | } | ||
89 | |||
90 | return ret; | ||
91 | |||
92 | } /* end request_key_auth_read() */ | ||
93 | |||
94 | /*****************************************************************************/ | ||
95 | /* | ||
92 | * destroy an instantiation authorisation token key | 96 | * destroy an instantiation authorisation token key |
93 | */ | 97 | */ |
94 | static void request_key_auth_destroy(struct key *key) | 98 | static void request_key_auth_destroy(struct key *key) |
@@ -104,56 +108,89 @@ static void request_key_auth_destroy(struct key *key) | |||
104 | 108 | ||
105 | /*****************************************************************************/ | 109 | /*****************************************************************************/ |
106 | /* | 110 | /* |
107 | * create a session keyring to be for the invokation of /sbin/request-key and | 111 | * create an authorisation token for /sbin/request-key or whoever to gain |
108 | * stick an authorisation token in it | 112 | * access to the caller's security data |
109 | */ | 113 | */ |
110 | struct key *request_key_auth_new(struct key *target, struct key **_rkakey) | 114 | struct key *request_key_auth_new(struct key *target, const char *callout_info) |
111 | { | 115 | { |
112 | struct key *keyring, *rkakey = NULL; | 116 | struct request_key_auth *rka, *irka; |
117 | struct key *authkey = NULL; | ||
113 | char desc[20]; | 118 | char desc[20]; |
114 | int ret; | 119 | int ret; |
115 | 120 | ||
116 | kenter("%d,", target->serial); | 121 | kenter("%d,", target->serial); |
117 | 122 | ||
118 | /* allocate a new session keyring */ | 123 | /* allocate a auth record */ |
119 | sprintf(desc, "_req.%u", target->serial); | 124 | rka = kmalloc(sizeof(*rka), GFP_KERNEL); |
125 | if (!rka) { | ||
126 | kleave(" = -ENOMEM"); | ||
127 | return ERR_PTR(-ENOMEM); | ||
128 | } | ||
120 | 129 | ||
121 | keyring = keyring_alloc(desc, current->fsuid, current->fsgid, 1, NULL); | 130 | /* see if the calling process is already servicing the key request of |
122 | if (IS_ERR(keyring)) { | 131 | * another process */ |
123 | kleave("= %ld", PTR_ERR(keyring)); | 132 | if (current->request_key_auth) { |
124 | return keyring; | 133 | /* it is - use that instantiation context here too */ |
134 | irka = current->request_key_auth->payload.data; | ||
135 | rka->context = irka->context; | ||
136 | rka->pid = irka->pid; | ||
125 | } | 137 | } |
138 | else { | ||
139 | /* it isn't - use this process as the context */ | ||
140 | rka->context = current; | ||
141 | rka->pid = current->pid; | ||
142 | } | ||
143 | |||
144 | rka->target_key = key_get(target); | ||
145 | rka->callout_info = callout_info; | ||
126 | 146 | ||
127 | /* allocate the auth key */ | 147 | /* allocate the auth key */ |
128 | sprintf(desc, "%x", target->serial); | 148 | sprintf(desc, "%x", target->serial); |
129 | 149 | ||
130 | rkakey = key_alloc(&key_type_request_key_auth, desc, | 150 | authkey = key_alloc(&key_type_request_key_auth, desc, |
131 | current->fsuid, current->fsgid, | 151 | current->fsuid, current->fsgid, |
132 | KEY_POS_VIEW | KEY_USR_VIEW, 1); | 152 | KEY_POS_VIEW | KEY_POS_READ | KEY_POS_SEARCH | |
133 | if (IS_ERR(rkakey)) { | 153 | KEY_USR_VIEW, 1); |
134 | key_put(keyring); | 154 | if (IS_ERR(authkey)) { |
135 | kleave("= %ld", PTR_ERR(rkakey)); | 155 | ret = PTR_ERR(authkey); |
136 | return rkakey; | 156 | goto error_alloc; |
137 | } | 157 | } |
138 | 158 | ||
139 | /* construct and attach to the keyring */ | 159 | /* construct and attach to the keyring */ |
140 | ret = key_instantiate_and_link(rkakey, target, 0, keyring, NULL); | 160 | ret = key_instantiate_and_link(authkey, rka, 0, NULL, NULL); |
141 | if (ret < 0) { | 161 | if (ret < 0) |
142 | key_revoke(rkakey); | 162 | goto error_inst; |
143 | key_put(rkakey); | ||
144 | key_put(keyring); | ||
145 | kleave("= %d", ret); | ||
146 | return ERR_PTR(ret); | ||
147 | } | ||
148 | 163 | ||
149 | *_rkakey = rkakey; | 164 | kleave(" = {%d})", authkey->serial); |
150 | kleave(" = {%d} ({%d})", keyring->serial, rkakey->serial); | 165 | return authkey; |
151 | return keyring; | 166 | |
167 | error_inst: | ||
168 | key_revoke(authkey); | ||
169 | key_put(authkey); | ||
170 | error_alloc: | ||
171 | key_put(rka->target_key); | ||
172 | kfree(rka); | ||
173 | kleave("= %d", ret); | ||
174 | return ERR_PTR(ret); | ||
152 | 175 | ||
153 | } /* end request_key_auth_new() */ | 176 | } /* end request_key_auth_new() */ |
154 | 177 | ||
155 | /*****************************************************************************/ | 178 | /*****************************************************************************/ |
156 | /* | 179 | /* |
180 | * see if an authorisation key is associated with a particular key | ||
181 | */ | ||
182 | static int key_get_instantiation_authkey_match(const struct key *key, | ||
183 | const void *_id) | ||
184 | { | ||
185 | struct request_key_auth *rka = key->payload.data; | ||
186 | key_serial_t id = (key_serial_t)(unsigned long) _id; | ||
187 | |||
188 | return rka->target_key->serial == id; | ||
189 | |||
190 | } /* end key_get_instantiation_authkey_match() */ | ||
191 | |||
192 | /*****************************************************************************/ | ||
193 | /* | ||
157 | * get the authorisation key for instantiation of a specific key if attached to | 194 | * get the authorisation key for instantiation of a specific key if attached to |
158 | * the current process's keyrings | 195 | * the current process's keyrings |
159 | * - this key is inserted into a keyring and that is set as /sbin/request-key's | 196 | * - this key is inserted into a keyring and that is set as /sbin/request-key's |
@@ -162,22 +199,27 @@ struct key *request_key_auth_new(struct key *target, struct key **_rkakey) | |||
162 | */ | 199 | */ |
163 | struct key *key_get_instantiation_authkey(key_serial_t target_id) | 200 | struct key *key_get_instantiation_authkey(key_serial_t target_id) |
164 | { | 201 | { |
165 | struct task_struct *tsk = current; | 202 | struct key *authkey; |
166 | struct key *instkey; | 203 | key_ref_t authkey_ref; |
167 | 204 | ||
168 | /* we must have our own personal session keyring */ | 205 | authkey_ref = search_process_keyrings( |
169 | if (!tsk->signal->session_keyring) | 206 | &key_type_request_key_auth, |
170 | return ERR_PTR(-EACCES); | 207 | (void *) (unsigned long) target_id, |
171 | 208 | key_get_instantiation_authkey_match, | |
172 | /* and it must contain a suitable request authorisation key | 209 | current); |
173 | * - lock RCU against session keyring changing | 210 | |
174 | */ | 211 | if (IS_ERR(authkey_ref)) { |
175 | rcu_read_lock(); | 212 | authkey = ERR_PTR(PTR_ERR(authkey_ref)); |
213 | goto error; | ||
214 | } | ||
176 | 215 | ||
177 | instkey = keyring_search_instkey( | 216 | authkey = key_ref_to_ptr(authkey_ref); |
178 | rcu_dereference(tsk->signal->session_keyring), target_id); | 217 | if (test_bit(KEY_FLAG_REVOKED, &authkey->flags)) { |
218 | key_put(authkey); | ||
219 | authkey = ERR_PTR(-EKEYREVOKED); | ||
220 | } | ||
179 | 221 | ||
180 | rcu_read_unlock(); | 222 | error: |
181 | return instkey; | 223 | return authkey; |
182 | 224 | ||
183 | } /* end key_get_instantiation_authkey() */ | 225 | } /* end key_get_instantiation_authkey() */ |