aboutsummaryrefslogtreecommitdiffstats
path: root/security/keys/request_key.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/keys/request_key.c')
-rw-r--r--security/keys/request_key.c556
1 files changed, 271 insertions, 285 deletions
diff --git a/security/keys/request_key.c b/security/keys/request_key.c
index 557500110a13..6381e616c477 100644
--- a/security/keys/request_key.c
+++ b/security/keys/request_key.c
@@ -1,6 +1,6 @@
1/* request_key.c: request a key from userspace 1/* Request a key from userspace
2 * 2 *
3 * Copyright (C) 2004-6 Red Hat, Inc. All Rights Reserved. 3 * Copyright (C) 2004-2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com) 4 * Written by David Howells (dhowells@redhat.com)
5 * 5 *
6 * This program is free software; you can redistribute it and/or 6 * This program is free software; you can redistribute it and/or
@@ -18,27 +18,54 @@
18#include <linux/keyctl.h> 18#include <linux/keyctl.h>
19#include "internal.h" 19#include "internal.h"
20 20
21struct key_construction { 21/*
22 struct list_head link; /* link in construction queue */ 22 * wait_on_bit() sleep function for uninterruptible waiting
23 struct key *key; /* key being constructed */ 23 */
24}; 24static int key_wait_bit(void *flags)
25{
26 schedule();
27 return 0;
28}
29
30/*
31 * wait_on_bit() sleep function for interruptible waiting
32 */
33static int key_wait_bit_intr(void *flags)
34{
35 schedule();
36 return signal_pending(current) ? -ERESTARTSYS : 0;
37}
38
39/*
40 * call to complete the construction of a key
41 */
42void complete_request_key(struct key_construction *cons, int error)
43{
44 kenter("{%d,%d},%d", cons->key->serial, cons->authkey->serial, error);
25 45
26/* when waiting for someone else's keys, you get added to this */ 46 if (error < 0)
27DECLARE_WAIT_QUEUE_HEAD(request_key_conswq); 47 key_negate_and_link(cons->key, key_negative_timeout, NULL,
48 cons->authkey);
49 else
50 key_revoke(cons->authkey);
51
52 key_put(cons->key);
53 key_put(cons->authkey);
54 kfree(cons);
55}
56EXPORT_SYMBOL(complete_request_key);
28 57
29/*****************************************************************************/
30/* 58/*
31 * request userspace finish the construction of a key 59 * request userspace finish the construction of a key
32 * - execute "/sbin/request-key <op> <key> <uid> <gid> <keyring> <keyring> <keyring>" 60 * - execute "/sbin/request-key <op> <key> <uid> <gid> <keyring> <keyring> <keyring>"
33 */ 61 */
34static int call_sbin_request_key(struct key *key, 62static int call_sbin_request_key(struct key_construction *cons,
35 struct key *authkey,
36 const char *op, 63 const char *op,
37 void *aux) 64 void *aux)
38{ 65{
39 struct task_struct *tsk = current; 66 struct task_struct *tsk = current;
40 key_serial_t prkey, sskey; 67 key_serial_t prkey, sskey;
41 struct key *keyring; 68 struct key *key = cons->key, *authkey = cons->authkey, *keyring;
42 char *argv[9], *envp[3], uid_str[12], gid_str[12]; 69 char *argv[9], *envp[3], uid_str[12], gid_str[12];
43 char key_str[12], keyring_str[3][12]; 70 char key_str[12], keyring_str[3][12];
44 char desc[20]; 71 char desc[20];
@@ -82,8 +109,7 @@ static int call_sbin_request_key(struct key *key,
82 rcu_read_lock(); 109 rcu_read_lock();
83 sskey = rcu_dereference(tsk->signal->session_keyring)->serial; 110 sskey = rcu_dereference(tsk->signal->session_keyring)->serial;
84 rcu_read_unlock(); 111 rcu_read_unlock();
85 } 112 } else {
86 else {
87 sskey = tsk->user->session_keyring->serial; 113 sskey = tsk->user->session_keyring->serial;
88 } 114 }
89 115
@@ -110,228 +136,77 @@ static int call_sbin_request_key(struct key *key,
110 /* do it */ 136 /* do it */
111 ret = call_usermodehelper_keys(argv[0], argv, envp, keyring, 137 ret = call_usermodehelper_keys(argv[0], argv, envp, keyring,
112 UMH_WAIT_PROC); 138 UMH_WAIT_PROC);
139 kdebug("usermode -> 0x%x", ret);
140 if (ret >= 0) {
141 /* ret is the exit/wait code */
142 if (test_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags) ||
143 key_validate(key) < 0)
144 ret = -ENOKEY;
145 else
146 /* ignore any errors from userspace if the key was
147 * instantiated */
148 ret = 0;
149 }
113 150
114error_link: 151error_link:
115 key_put(keyring); 152 key_put(keyring);
116 153
117error_alloc: 154error_alloc:
118 kleave(" = %d", ret); 155 kleave(" = %d", ret);
156 complete_request_key(cons, ret);
119 return ret; 157 return ret;
158}
120 159
121} /* end call_sbin_request_key() */
122
123/*****************************************************************************/
124/* 160/*
125 * call out to userspace for the key 161 * call out to userspace for key construction
126 * - called with the construction sem held, but the sem is dropped here
127 * - we ignore program failure and go on key status instead 162 * - we ignore program failure and go on key status instead
128 */ 163 */
129static struct key *__request_key_construction(struct key_type *type, 164static int construct_key(struct key *key, const char *callout_info, void *aux)
130 const char *description,
131 const char *callout_info,
132 void *aux,
133 unsigned long flags)
134{ 165{
166 struct key_construction *cons;
135 request_key_actor_t actor; 167 request_key_actor_t actor;
136 struct key_construction cons; 168 struct key *authkey;
137 struct timespec now; 169 int ret;
138 struct key *key, *authkey;
139 int ret, negated;
140 170
141 kenter("%s,%s,%s,%lx", type->name, description, callout_info, flags); 171 kenter("%d,%s,%p", key->serial, callout_info, aux);
142 172
143 /* create a key and add it to the queue */ 173 cons = kmalloc(sizeof(*cons), GFP_KERNEL);
144 key = key_alloc(type, description, 174 if (!cons)
145 current->fsuid, current->fsgid, current, KEY_POS_ALL, 175 return -ENOMEM;
146 flags);
147 if (IS_ERR(key))
148 goto alloc_failed;
149
150 set_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags);
151
152 cons.key = key;
153 list_add_tail(&cons.link, &key->user->consq);
154
155 /* we drop the construction sem here on behalf of the caller */
156 up_write(&key_construction_sem);
157 176
158 /* allocate an authorisation key */ 177 /* allocate an authorisation key */
159 authkey = request_key_auth_new(key, callout_info); 178 authkey = request_key_auth_new(key, callout_info);
160 if (IS_ERR(authkey)) { 179 if (IS_ERR(authkey)) {
180 kfree(cons);
161 ret = PTR_ERR(authkey); 181 ret = PTR_ERR(authkey);
162 authkey = NULL; 182 authkey = NULL;
163 goto alloc_authkey_failed; 183 } else {
164 } 184 cons->authkey = key_get(authkey);
165 185 cons->key = key_get(key);
166 /* make the call */ 186
167 actor = call_sbin_request_key; 187 /* make the call */
168 if (type->request_key) 188 actor = call_sbin_request_key;
169 actor = type->request_key; 189 if (key->type->request_key)
170 ret = actor(key, authkey, "create", aux); 190 actor = key->type->request_key;
171 if (ret < 0) 191
172 goto request_failed; 192 ret = actor(cons, "create", aux);
173 193
174 /* if the key wasn't instantiated, then we want to give an error */ 194 /* check that the actor called complete_request_key() prior to
175 ret = -ENOKEY; 195 * returning an error */
176 if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) 196 WARN_ON(ret < 0 &&
177 goto request_failed; 197 !test_bit(KEY_FLAG_REVOKED, &authkey->flags));
178 198 key_put(authkey);
179 key_revoke(authkey);
180 key_put(authkey);
181
182 down_write(&key_construction_sem);
183 list_del(&cons.link);
184 up_write(&key_construction_sem);
185
186 /* also give an error if the key was negatively instantiated */
187check_not_negative:
188 if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) {
189 key_put(key);
190 key = ERR_PTR(-ENOKEY);
191 }
192
193out:
194 kleave(" = %p", key);
195 return key;
196
197request_failed:
198 key_revoke(authkey);
199 key_put(authkey);
200
201alloc_authkey_failed:
202 /* it wasn't instantiated
203 * - remove from construction queue
204 * - mark the key as dead
205 */
206 negated = 0;
207 down_write(&key_construction_sem);
208
209 list_del(&cons.link);
210
211 /* check it didn't get instantiated between the check and the down */
212 if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) {
213 set_bit(KEY_FLAG_NEGATIVE, &key->flags);
214 set_bit(KEY_FLAG_INSTANTIATED, &key->flags);
215 negated = 1;
216 }
217
218 clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags);
219
220 up_write(&key_construction_sem);
221
222 if (!negated)
223 goto check_not_negative; /* surprisingly, the key got
224 * instantiated */
225
226 /* set the timeout and store in the session keyring if we can */
227 now = current_kernel_time();
228 key->expiry = now.tv_sec + key_negative_timeout;
229
230 if (current->signal->session_keyring) {
231 struct key *keyring;
232
233 rcu_read_lock();
234 keyring = rcu_dereference(current->signal->session_keyring);
235 atomic_inc(&keyring->usage);
236 rcu_read_unlock();
237
238 key_link(keyring, key);
239 key_put(keyring);
240 }
241
242 key_put(key);
243
244 /* notify anyone who was waiting */
245 wake_up_all(&request_key_conswq);
246
247 key = ERR_PTR(ret);
248 goto out;
249
250alloc_failed:
251 up_write(&key_construction_sem);
252 goto out;
253
254} /* end __request_key_construction() */
255
256/*****************************************************************************/
257/*
258 * call out to userspace to request the key
259 * - we check the construction queue first to see if an appropriate key is
260 * already being constructed by userspace
261 */
262static struct key *request_key_construction(struct key_type *type,
263 const char *description,
264 const char *callout_info,
265 void *aux,
266 struct key_user *user,
267 unsigned long flags)
268{
269 struct key_construction *pcons;
270 struct key *key, *ckey;
271
272 DECLARE_WAITQUEUE(myself, current);
273
274 kenter("%s,%s,{%d},%s,%lx",
275 type->name, description, user->uid, callout_info, flags);
276
277 /* see if there's such a key under construction already */
278 down_write(&key_construction_sem);
279
280 list_for_each_entry(pcons, &user->consq, link) {
281 ckey = pcons->key;
282
283 if (ckey->type != type)
284 continue;
285
286 if (type->match(ckey, description))
287 goto found_key_under_construction;
288 } 199 }
289 200
290 /* see about getting userspace to construct the key */ 201 kleave(" = %d", ret);
291 key = __request_key_construction(type, description, callout_info, aux, 202 return ret;
292 flags); 203}
293 error:
294 kleave(" = %p", key);
295 return key;
296
297 /* someone else has the same key under construction
298 * - we want to keep an eye on their key
299 */
300 found_key_under_construction:
301 atomic_inc(&ckey->usage);
302 up_write(&key_construction_sem);
303
304 /* wait for the key to be completed one way or another */
305 add_wait_queue(&request_key_conswq, &myself);
306
307 for (;;) {
308 set_current_state(TASK_INTERRUPTIBLE);
309 if (!test_bit(KEY_FLAG_USER_CONSTRUCT, &ckey->flags))
310 break;
311 if (signal_pending(current))
312 break;
313 schedule();
314 }
315
316 set_current_state(TASK_RUNNING);
317 remove_wait_queue(&request_key_conswq, &myself);
318
319 /* we'll need to search this process's keyrings to see if the key is
320 * now there since we can't automatically assume it's also available
321 * there */
322 key_put(ckey);
323 ckey = NULL;
324
325 key = NULL; /* request a retry */
326 goto error;
327
328} /* end request_key_construction() */
329 204
330/*****************************************************************************/
331/* 205/*
332 * link a freshly minted key to an appropriate destination keyring 206 * link a key to the appropriate destination keyring
207 * - the caller must hold a write lock on the destination keyring
333 */ 208 */
334static void request_key_link(struct key *key, struct key *dest_keyring) 209static void construct_key_make_link(struct key *key, struct key *dest_keyring)
335{ 210{
336 struct task_struct *tsk = current; 211 struct task_struct *tsk = current;
337 struct key *drop = NULL; 212 struct key *drop = NULL;
@@ -363,11 +238,11 @@ static void request_key_link(struct key *key, struct key *dest_keyring)
363 break; 238 break;
364 239
365 case KEY_REQKEY_DEFL_USER_SESSION_KEYRING: 240 case KEY_REQKEY_DEFL_USER_SESSION_KEYRING:
366 dest_keyring = current->user->session_keyring; 241 dest_keyring = tsk->user->session_keyring;
367 break; 242 break;
368 243
369 case KEY_REQKEY_DEFL_USER_KEYRING: 244 case KEY_REQKEY_DEFL_USER_KEYRING:
370 dest_keyring = current->user->uid_keyring; 245 dest_keyring = tsk->user->uid_keyring;
371 break; 246 break;
372 247
373 case KEY_REQKEY_DEFL_GROUP_KEYRING: 248 case KEY_REQKEY_DEFL_GROUP_KEYRING:
@@ -377,15 +252,115 @@ static void request_key_link(struct key *key, struct key *dest_keyring)
377 } 252 }
378 253
379 /* and attach the key to it */ 254 /* and attach the key to it */
380 key_link(dest_keyring, key); 255 __key_link(dest_keyring, key);
381
382 key_put(drop); 256 key_put(drop);
383
384 kleave(""); 257 kleave("");
258}
385 259
386} /* end request_key_link() */ 260/*
261 * allocate a new key in under-construction state and attempt to link it in to
262 * the requested place
263 * - may return a key that's already under construction instead
264 */
265static int construct_alloc_key(struct key_type *type,
266 const char *description,
267 struct key *dest_keyring,
268 unsigned long flags,
269 struct key_user *user,
270 struct key **_key)
271{
272 struct key *key;
273 key_ref_t key_ref;
274
275 kenter("%s,%s,,,", type->name, description);
276
277 mutex_lock(&user->cons_lock);
278
279 key = key_alloc(type, description,
280 current->fsuid, current->fsgid, current, KEY_POS_ALL,
281 flags);
282 if (IS_ERR(key))
283 goto alloc_failed;
284
285 set_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags);
286
287 if (dest_keyring)
288 down_write(&dest_keyring->sem);
289
290 /* attach the key to the destination keyring under lock, but we do need
291 * to do another check just in case someone beat us to it whilst we
292 * waited for locks */
293 mutex_lock(&key_construction_mutex);
294
295 key_ref = search_process_keyrings(type, description, type->match,
296 current);
297 if (!IS_ERR(key_ref))
298 goto key_already_present;
299
300 if (dest_keyring)
301 construct_key_make_link(key, dest_keyring);
302
303 mutex_unlock(&key_construction_mutex);
304 if (dest_keyring)
305 up_write(&dest_keyring->sem);
306 mutex_unlock(&user->cons_lock);
307 *_key = key;
308 kleave(" = 0 [%d]", key_serial(key));
309 return 0;
310
311key_already_present:
312 mutex_unlock(&key_construction_mutex);
313 if (dest_keyring)
314 up_write(&dest_keyring->sem);
315 mutex_unlock(&user->cons_lock);
316 key_put(key);
317 *_key = key = key_ref_to_ptr(key_ref);
318 kleave(" = -EINPROGRESS [%d]", key_serial(key));
319 return -EINPROGRESS;
320
321alloc_failed:
322 mutex_unlock(&user->cons_lock);
323 *_key = NULL;
324 kleave(" = %ld", PTR_ERR(key));
325 return PTR_ERR(key);
326}
327
328/*
329 * commence key construction
330 */
331static struct key *construct_key_and_link(struct key_type *type,
332 const char *description,
333 const char *callout_info,
334 void *aux,
335 struct key *dest_keyring,
336 unsigned long flags)
337{
338 struct key_user *user;
339 struct key *key;
340 int ret;
341
342 user = key_user_lookup(current->fsuid);
343 if (!user)
344 return ERR_PTR(-ENOMEM);
345
346 ret = construct_alloc_key(type, description, dest_keyring, flags, user,
347 &key);
348 key_user_put(user);
349
350 if (ret == 0) {
351 ret = construct_key(key, callout_info, aux);
352 if (ret < 0)
353 goto construction_failed;
354 }
355
356 return key;
357
358construction_failed:
359 key_negate_and_link(key, key_negative_timeout, NULL, NULL);
360 key_put(key);
361 return ERR_PTR(ret);
362}
387 363
388/*****************************************************************************/
389/* 364/*
390 * request a key 365 * request a key
391 * - search the process's keyrings 366 * - search the process's keyrings
@@ -400,7 +375,6 @@ struct key *request_key_and_link(struct key_type *type,
400 struct key *dest_keyring, 375 struct key *dest_keyring,
401 unsigned long flags) 376 unsigned long flags)
402{ 377{
403 struct key_user *user;
404 struct key *key; 378 struct key *key;
405 key_ref_t key_ref; 379 key_ref_t key_ref;
406 380
@@ -412,112 +386,124 @@ struct key *request_key_and_link(struct key_type *type,
412 key_ref = search_process_keyrings(type, description, type->match, 386 key_ref = search_process_keyrings(type, description, type->match,
413 current); 387 current);
414 388
415 kdebug("search 1: %p", key_ref);
416
417 if (!IS_ERR(key_ref)) { 389 if (!IS_ERR(key_ref)) {
418 key = key_ref_to_ptr(key_ref); 390 key = key_ref_to_ptr(key_ref);
419 } 391 } else if (PTR_ERR(key_ref) != -EAGAIN) {
420 else if (PTR_ERR(key_ref) != -EAGAIN) {
421 key = ERR_PTR(PTR_ERR(key_ref)); 392 key = ERR_PTR(PTR_ERR(key_ref));
422 } 393 } else {
423 else {
424 /* the search failed, but the keyrings were searchable, so we 394 /* the search failed, but the keyrings were searchable, so we
425 * should consult userspace if we can */ 395 * should consult userspace if we can */
426 key = ERR_PTR(-ENOKEY); 396 key = ERR_PTR(-ENOKEY);
427 if (!callout_info) 397 if (!callout_info)
428 goto error; 398 goto error;
429 399
430 /* - get hold of the user's construction queue */ 400 key = construct_key_and_link(type, description, callout_info,
431 user = key_user_lookup(current->fsuid); 401 aux, dest_keyring, flags);
432 if (!user)
433 goto nomem;
434
435 for (;;) {
436 if (signal_pending(current))
437 goto interrupted;
438
439 /* ask userspace (returns NULL if it waited on a key
440 * being constructed) */
441 key = request_key_construction(type, description,
442 callout_info, aux,
443 user, flags);
444 if (key)
445 break;
446
447 /* someone else made the key we want, so we need to
448 * search again as it might now be available to us */
449 key_ref = search_process_keyrings(type, description,
450 type->match,
451 current);
452
453 kdebug("search 2: %p", key_ref);
454
455 if (!IS_ERR(key_ref)) {
456 key = key_ref_to_ptr(key_ref);
457 break;
458 }
459
460 if (PTR_ERR(key_ref) != -EAGAIN) {
461 key = ERR_PTR(PTR_ERR(key_ref));
462 break;
463 }
464 }
465
466 key_user_put(user);
467
468 /* link the new key into the appropriate keyring */
469 if (!IS_ERR(key))
470 request_key_link(key, dest_keyring);
471 } 402 }
472 403
473error: 404error:
474 kleave(" = %p", key); 405 kleave(" = %p", key);
475 return key; 406 return key;
407}
476 408
477nomem: 409/*
478 key = ERR_PTR(-ENOMEM); 410 * wait for construction of a key to complete
479 goto error; 411 */
480 412int wait_for_key_construction(struct key *key, bool intr)
481interrupted: 413{
482 key_user_put(user); 414 int ret;
483 key = ERR_PTR(-EINTR);
484 goto error;
485 415
486} /* end request_key_and_link() */ 416 ret = wait_on_bit(&key->flags, KEY_FLAG_USER_CONSTRUCT,
417 intr ? key_wait_bit_intr : key_wait_bit,
418 intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
419 if (ret < 0)
420 return ret;
421 return key_validate(key);
422}
423EXPORT_SYMBOL(wait_for_key_construction);
487 424
488/*****************************************************************************/
489/* 425/*
490 * request a key 426 * request a key
491 * - search the process's keyrings 427 * - search the process's keyrings
492 * - check the list of keys being created or updated 428 * - check the list of keys being created or updated
493 * - call out to userspace for a key if supplementary info was provided 429 * - call out to userspace for a key if supplementary info was provided
430 * - waits uninterruptible for creation to complete
494 */ 431 */
495struct key *request_key(struct key_type *type, 432struct key *request_key(struct key_type *type,
496 const char *description, 433 const char *description,
497 const char *callout_info) 434 const char *callout_info)
498{ 435{
499 return request_key_and_link(type, description, callout_info, NULL, 436 struct key *key;
500 NULL, KEY_ALLOC_IN_QUOTA); 437 int ret;
501 438
502} /* end request_key() */ 439 key = request_key_and_link(type, description, callout_info, NULL,
503 440 NULL, KEY_ALLOC_IN_QUOTA);
441 if (!IS_ERR(key)) {
442 ret = wait_for_key_construction(key, false);
443 if (ret < 0) {
444 key_put(key);
445 return ERR_PTR(ret);
446 }
447 }
448 return key;
449}
504EXPORT_SYMBOL(request_key); 450EXPORT_SYMBOL(request_key);
505 451
506/*****************************************************************************/
507/* 452/*
508 * request a key with auxiliary data for the upcaller 453 * request a key with auxiliary data for the upcaller
509 * - search the process's keyrings 454 * - search the process's keyrings
510 * - check the list of keys being created or updated 455 * - check the list of keys being created or updated
511 * - call out to userspace for a key if supplementary info was provided 456 * - call out to userspace for a key if supplementary info was provided
457 * - waits uninterruptible for creation to complete
512 */ 458 */
513struct key *request_key_with_auxdata(struct key_type *type, 459struct key *request_key_with_auxdata(struct key_type *type,
514 const char *description, 460 const char *description,
515 const char *callout_info, 461 const char *callout_info,
516 void *aux) 462 void *aux)
517{ 463{
518 return request_key_and_link(type, description, callout_info, aux, 464 struct key *key;
519 NULL, KEY_ALLOC_IN_QUOTA); 465 int ret;
466
467 key = request_key_and_link(type, description, callout_info, aux,
468 NULL, KEY_ALLOC_IN_QUOTA);
469 if (!IS_ERR(key)) {
470 ret = wait_for_key_construction(key, false);
471 if (ret < 0) {
472 key_put(key);
473 return ERR_PTR(ret);
474 }
475 }
476 return key;
477}
478EXPORT_SYMBOL(request_key_with_auxdata);
520 479
521} /* end request_key_with_auxdata() */ 480/*
481 * request a key (allow async construction)
482 * - search the process's keyrings
483 * - check the list of keys being created or updated
484 * - call out to userspace for a key if supplementary info was provided
485 */
486struct key *request_key_async(struct key_type *type,
487 const char *description,
488 const char *callout_info)
489{
490 return request_key_and_link(type, description, callout_info, NULL,
491 NULL, KEY_ALLOC_IN_QUOTA);
492}
493EXPORT_SYMBOL(request_key_async);
522 494
523EXPORT_SYMBOL(request_key_with_auxdata); 495/*
496 * request a key with auxiliary data for the upcaller (allow async construction)
497 * - search the process's keyrings
498 * - check the list of keys being created or updated
499 * - call out to userspace for a key if supplementary info was provided
500 */
501struct key *request_key_async_with_auxdata(struct key_type *type,
502 const char *description,
503 const char *callout_info,
504 void *aux)
505{
506 return request_key_and_link(type, description, callout_info, aux,
507 NULL, KEY_ALLOC_IN_QUOTA);
508}
509EXPORT_SYMBOL(request_key_async_with_auxdata);