diff options
Diffstat (limited to 'security/keys/request_key_auth.c')
-rw-r--r-- | security/keys/request_key_auth.c | 192 |
1 files changed, 117 insertions, 75 deletions
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() */ |