diff options
Diffstat (limited to 'security/keys/keyctl.c')
-rw-r--r-- | security/keys/keyctl.c | 161 |
1 files changed, 139 insertions, 22 deletions
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index 7f09fb897d2b..74c968524592 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c | |||
@@ -103,7 +103,7 @@ SYSCALL_DEFINE5(add_key, const char __user *, _type, | |||
103 | } | 103 | } |
104 | 104 | ||
105 | /* find the target keyring (which must be writable) */ | 105 | /* find the target keyring (which must be writable) */ |
106 | keyring_ref = lookup_user_key(ringid, 1, 0, KEY_WRITE); | 106 | keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE); |
107 | if (IS_ERR(keyring_ref)) { | 107 | if (IS_ERR(keyring_ref)) { |
108 | ret = PTR_ERR(keyring_ref); | 108 | ret = PTR_ERR(keyring_ref); |
109 | goto error3; | 109 | goto error3; |
@@ -185,7 +185,8 @@ SYSCALL_DEFINE4(request_key, const char __user *, _type, | |||
185 | /* get the destination keyring if specified */ | 185 | /* get the destination keyring if specified */ |
186 | dest_ref = NULL; | 186 | dest_ref = NULL; |
187 | if (destringid) { | 187 | if (destringid) { |
188 | dest_ref = lookup_user_key(destringid, 1, 0, KEY_WRITE); | 188 | dest_ref = lookup_user_key(destringid, KEY_LOOKUP_CREATE, |
189 | KEY_WRITE); | ||
189 | if (IS_ERR(dest_ref)) { | 190 | if (IS_ERR(dest_ref)) { |
190 | ret = PTR_ERR(dest_ref); | 191 | ret = PTR_ERR(dest_ref); |
191 | goto error3; | 192 | goto error3; |
@@ -233,9 +234,11 @@ SYSCALL_DEFINE4(request_key, const char __user *, _type, | |||
233 | long keyctl_get_keyring_ID(key_serial_t id, int create) | 234 | long keyctl_get_keyring_ID(key_serial_t id, int create) |
234 | { | 235 | { |
235 | key_ref_t key_ref; | 236 | key_ref_t key_ref; |
237 | unsigned long lflags; | ||
236 | long ret; | 238 | long ret; |
237 | 239 | ||
238 | key_ref = lookup_user_key(id, create, 0, KEY_SEARCH); | 240 | lflags = create ? KEY_LOOKUP_CREATE : 0; |
241 | key_ref = lookup_user_key(id, lflags, KEY_SEARCH); | ||
239 | if (IS_ERR(key_ref)) { | 242 | if (IS_ERR(key_ref)) { |
240 | ret = PTR_ERR(key_ref); | 243 | ret = PTR_ERR(key_ref); |
241 | goto error; | 244 | goto error; |
@@ -309,7 +312,7 @@ long keyctl_update_key(key_serial_t id, | |||
309 | } | 312 | } |
310 | 313 | ||
311 | /* find the target key (which must be writable) */ | 314 | /* find the target key (which must be writable) */ |
312 | key_ref = lookup_user_key(id, 0, 0, KEY_WRITE); | 315 | key_ref = lookup_user_key(id, 0, KEY_WRITE); |
313 | if (IS_ERR(key_ref)) { | 316 | if (IS_ERR(key_ref)) { |
314 | ret = PTR_ERR(key_ref); | 317 | ret = PTR_ERR(key_ref); |
315 | goto error2; | 318 | goto error2; |
@@ -337,10 +340,16 @@ long keyctl_revoke_key(key_serial_t id) | |||
337 | key_ref_t key_ref; | 340 | key_ref_t key_ref; |
338 | long ret; | 341 | long ret; |
339 | 342 | ||
340 | key_ref = lookup_user_key(id, 0, 0, KEY_WRITE); | 343 | key_ref = lookup_user_key(id, 0, KEY_WRITE); |
341 | if (IS_ERR(key_ref)) { | 344 | if (IS_ERR(key_ref)) { |
342 | ret = PTR_ERR(key_ref); | 345 | ret = PTR_ERR(key_ref); |
343 | goto error; | 346 | if (ret != -EACCES) |
347 | goto error; | ||
348 | key_ref = lookup_user_key(id, 0, KEY_SETATTR); | ||
349 | if (IS_ERR(key_ref)) { | ||
350 | ret = PTR_ERR(key_ref); | ||
351 | goto error; | ||
352 | } | ||
344 | } | 353 | } |
345 | 354 | ||
346 | key_revoke(key_ref_to_ptr(key_ref)); | 355 | key_revoke(key_ref_to_ptr(key_ref)); |
@@ -363,7 +372,7 @@ long keyctl_keyring_clear(key_serial_t ringid) | |||
363 | key_ref_t keyring_ref; | 372 | key_ref_t keyring_ref; |
364 | long ret; | 373 | long ret; |
365 | 374 | ||
366 | keyring_ref = lookup_user_key(ringid, 1, 0, KEY_WRITE); | 375 | keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE); |
367 | if (IS_ERR(keyring_ref)) { | 376 | if (IS_ERR(keyring_ref)) { |
368 | ret = PTR_ERR(keyring_ref); | 377 | ret = PTR_ERR(keyring_ref); |
369 | goto error; | 378 | goto error; |
@@ -389,13 +398,13 @@ long keyctl_keyring_link(key_serial_t id, key_serial_t ringid) | |||
389 | key_ref_t keyring_ref, key_ref; | 398 | key_ref_t keyring_ref, key_ref; |
390 | long ret; | 399 | long ret; |
391 | 400 | ||
392 | keyring_ref = lookup_user_key(ringid, 1, 0, KEY_WRITE); | 401 | keyring_ref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE); |
393 | if (IS_ERR(keyring_ref)) { | 402 | if (IS_ERR(keyring_ref)) { |
394 | ret = PTR_ERR(keyring_ref); | 403 | ret = PTR_ERR(keyring_ref); |
395 | goto error; | 404 | goto error; |
396 | } | 405 | } |
397 | 406 | ||
398 | key_ref = lookup_user_key(id, 1, 0, KEY_LINK); | 407 | key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE, KEY_LINK); |
399 | if (IS_ERR(key_ref)) { | 408 | if (IS_ERR(key_ref)) { |
400 | ret = PTR_ERR(key_ref); | 409 | ret = PTR_ERR(key_ref); |
401 | goto error2; | 410 | goto error2; |
@@ -423,13 +432,13 @@ long keyctl_keyring_unlink(key_serial_t id, key_serial_t ringid) | |||
423 | key_ref_t keyring_ref, key_ref; | 432 | key_ref_t keyring_ref, key_ref; |
424 | long ret; | 433 | long ret; |
425 | 434 | ||
426 | keyring_ref = lookup_user_key(ringid, 0, 0, KEY_WRITE); | 435 | keyring_ref = lookup_user_key(ringid, 0, KEY_WRITE); |
427 | if (IS_ERR(keyring_ref)) { | 436 | if (IS_ERR(keyring_ref)) { |
428 | ret = PTR_ERR(keyring_ref); | 437 | ret = PTR_ERR(keyring_ref); |
429 | goto error; | 438 | goto error; |
430 | } | 439 | } |
431 | 440 | ||
432 | key_ref = lookup_user_key(id, 0, 0, 0); | 441 | key_ref = lookup_user_key(id, KEY_LOOKUP_FOR_UNLINK, 0); |
433 | if (IS_ERR(key_ref)) { | 442 | if (IS_ERR(key_ref)) { |
434 | ret = PTR_ERR(key_ref); | 443 | ret = PTR_ERR(key_ref); |
435 | goto error2; | 444 | goto error2; |
@@ -465,7 +474,7 @@ long keyctl_describe_key(key_serial_t keyid, | |||
465 | char *tmpbuf; | 474 | char *tmpbuf; |
466 | long ret; | 475 | long ret; |
467 | 476 | ||
468 | key_ref = lookup_user_key(keyid, 0, 1, KEY_VIEW); | 477 | key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, KEY_VIEW); |
469 | if (IS_ERR(key_ref)) { | 478 | if (IS_ERR(key_ref)) { |
470 | /* viewing a key under construction is permitted if we have the | 479 | /* viewing a key under construction is permitted if we have the |
471 | * authorisation token handy */ | 480 | * authorisation token handy */ |
@@ -474,7 +483,8 @@ long keyctl_describe_key(key_serial_t keyid, | |||
474 | if (!IS_ERR(instkey)) { | 483 | if (!IS_ERR(instkey)) { |
475 | key_put(instkey); | 484 | key_put(instkey); |
476 | key_ref = lookup_user_key(keyid, | 485 | key_ref = lookup_user_key(keyid, |
477 | 0, 1, 0); | 486 | KEY_LOOKUP_PARTIAL, |
487 | 0); | ||
478 | if (!IS_ERR(key_ref)) | 488 | if (!IS_ERR(key_ref)) |
479 | goto okay; | 489 | goto okay; |
480 | } | 490 | } |
@@ -558,7 +568,7 @@ long keyctl_keyring_search(key_serial_t ringid, | |||
558 | } | 568 | } |
559 | 569 | ||
560 | /* get the keyring at which to begin the search */ | 570 | /* get the keyring at which to begin the search */ |
561 | keyring_ref = lookup_user_key(ringid, 0, 0, KEY_SEARCH); | 571 | keyring_ref = lookup_user_key(ringid, 0, KEY_SEARCH); |
562 | if (IS_ERR(keyring_ref)) { | 572 | if (IS_ERR(keyring_ref)) { |
563 | ret = PTR_ERR(keyring_ref); | 573 | ret = PTR_ERR(keyring_ref); |
564 | goto error2; | 574 | goto error2; |
@@ -567,7 +577,8 @@ long keyctl_keyring_search(key_serial_t ringid, | |||
567 | /* get the destination keyring if specified */ | 577 | /* get the destination keyring if specified */ |
568 | dest_ref = NULL; | 578 | dest_ref = NULL; |
569 | if (destringid) { | 579 | if (destringid) { |
570 | dest_ref = lookup_user_key(destringid, 1, 0, KEY_WRITE); | 580 | dest_ref = lookup_user_key(destringid, KEY_LOOKUP_CREATE, |
581 | KEY_WRITE); | ||
571 | if (IS_ERR(dest_ref)) { | 582 | if (IS_ERR(dest_ref)) { |
572 | ret = PTR_ERR(dest_ref); | 583 | ret = PTR_ERR(dest_ref); |
573 | goto error3; | 584 | goto error3; |
@@ -637,7 +648,7 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen) | |||
637 | long ret; | 648 | long ret; |
638 | 649 | ||
639 | /* find the key first */ | 650 | /* find the key first */ |
640 | key_ref = lookup_user_key(keyid, 0, 0, 0); | 651 | key_ref = lookup_user_key(keyid, 0, 0); |
641 | if (IS_ERR(key_ref)) { | 652 | if (IS_ERR(key_ref)) { |
642 | ret = -ENOKEY; | 653 | ret = -ENOKEY; |
643 | goto error; | 654 | goto error; |
@@ -700,7 +711,8 @@ long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid) | |||
700 | if (uid == (uid_t) -1 && gid == (gid_t) -1) | 711 | if (uid == (uid_t) -1 && gid == (gid_t) -1) |
701 | goto error; | 712 | goto error; |
702 | 713 | ||
703 | key_ref = lookup_user_key(id, 1, 1, KEY_SETATTR); | 714 | key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL, |
715 | KEY_SETATTR); | ||
704 | if (IS_ERR(key_ref)) { | 716 | if (IS_ERR(key_ref)) { |
705 | ret = PTR_ERR(key_ref); | 717 | ret = PTR_ERR(key_ref); |
706 | goto error; | 718 | goto error; |
@@ -805,7 +817,8 @@ long keyctl_setperm_key(key_serial_t id, key_perm_t perm) | |||
805 | if (perm & ~(KEY_POS_ALL | KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL)) | 817 | if (perm & ~(KEY_POS_ALL | KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL)) |
806 | goto error; | 818 | goto error; |
807 | 819 | ||
808 | key_ref = lookup_user_key(id, 1, 1, KEY_SETATTR); | 820 | key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL, |
821 | KEY_SETATTR); | ||
809 | if (IS_ERR(key_ref)) { | 822 | if (IS_ERR(key_ref)) { |
810 | ret = PTR_ERR(key_ref); | 823 | ret = PTR_ERR(key_ref); |
811 | goto error; | 824 | goto error; |
@@ -847,7 +860,7 @@ static long get_instantiation_keyring(key_serial_t ringid, | |||
847 | 860 | ||
848 | /* if a specific keyring is nominated by ID, then use that */ | 861 | /* if a specific keyring is nominated by ID, then use that */ |
849 | if (ringid > 0) { | 862 | if (ringid > 0) { |
850 | dkref = lookup_user_key(ringid, 1, 0, KEY_WRITE); | 863 | dkref = lookup_user_key(ringid, KEY_LOOKUP_CREATE, KEY_WRITE); |
851 | if (IS_ERR(dkref)) | 864 | if (IS_ERR(dkref)) |
852 | return PTR_ERR(dkref); | 865 | return PTR_ERR(dkref); |
853 | *_dest_keyring = key_ref_to_ptr(dkref); | 866 | *_dest_keyring = key_ref_to_ptr(dkref); |
@@ -1083,7 +1096,8 @@ long keyctl_set_timeout(key_serial_t id, unsigned timeout) | |||
1083 | time_t expiry; | 1096 | time_t expiry; |
1084 | long ret; | 1097 | long ret; |
1085 | 1098 | ||
1086 | key_ref = lookup_user_key(id, 1, 1, KEY_SETATTR); | 1099 | key_ref = lookup_user_key(id, KEY_LOOKUP_CREATE | KEY_LOOKUP_PARTIAL, |
1100 | KEY_SETATTR); | ||
1087 | if (IS_ERR(key_ref)) { | 1101 | if (IS_ERR(key_ref)) { |
1088 | ret = PTR_ERR(key_ref); | 1102 | ret = PTR_ERR(key_ref); |
1089 | goto error; | 1103 | goto error; |
@@ -1101,6 +1115,7 @@ long keyctl_set_timeout(key_serial_t id, unsigned timeout) | |||
1101 | } | 1115 | } |
1102 | 1116 | ||
1103 | key->expiry = expiry; | 1117 | key->expiry = expiry; |
1118 | key_schedule_gc(key->expiry); | ||
1104 | 1119 | ||
1105 | up_write(&key->sem); | 1120 | up_write(&key->sem); |
1106 | key_put(key); | 1121 | key_put(key); |
@@ -1170,7 +1185,7 @@ long keyctl_get_security(key_serial_t keyid, | |||
1170 | char *context; | 1185 | char *context; |
1171 | long ret; | 1186 | long ret; |
1172 | 1187 | ||
1173 | key_ref = lookup_user_key(keyid, 0, 1, KEY_VIEW); | 1188 | key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, KEY_VIEW); |
1174 | if (IS_ERR(key_ref)) { | 1189 | if (IS_ERR(key_ref)) { |
1175 | if (PTR_ERR(key_ref) != -EACCES) | 1190 | if (PTR_ERR(key_ref) != -EACCES) |
1176 | return PTR_ERR(key_ref); | 1191 | return PTR_ERR(key_ref); |
@@ -1182,7 +1197,7 @@ long keyctl_get_security(key_serial_t keyid, | |||
1182 | return PTR_ERR(key_ref); | 1197 | return PTR_ERR(key_ref); |
1183 | key_put(instkey); | 1198 | key_put(instkey); |
1184 | 1199 | ||
1185 | key_ref = lookup_user_key(keyid, 0, 1, 0); | 1200 | key_ref = lookup_user_key(keyid, KEY_LOOKUP_PARTIAL, 0); |
1186 | if (IS_ERR(key_ref)) | 1201 | if (IS_ERR(key_ref)) |
1187 | return PTR_ERR(key_ref); | 1202 | return PTR_ERR(key_ref); |
1188 | } | 1203 | } |
@@ -1213,6 +1228,105 @@ long keyctl_get_security(key_serial_t keyid, | |||
1213 | return ret; | 1228 | return ret; |
1214 | } | 1229 | } |
1215 | 1230 | ||
1231 | /* | ||
1232 | * attempt to install the calling process's session keyring on the process's | ||
1233 | * parent process | ||
1234 | * - the keyring must exist and must grant us LINK permission | ||
1235 | * - implements keyctl(KEYCTL_SESSION_TO_PARENT) | ||
1236 | */ | ||
1237 | long keyctl_session_to_parent(void) | ||
1238 | { | ||
1239 | struct task_struct *me, *parent; | ||
1240 | const struct cred *mycred, *pcred; | ||
1241 | struct cred *cred, *oldcred; | ||
1242 | key_ref_t keyring_r; | ||
1243 | int ret; | ||
1244 | |||
1245 | keyring_r = lookup_user_key(KEY_SPEC_SESSION_KEYRING, 0, KEY_LINK); | ||
1246 | if (IS_ERR(keyring_r)) | ||
1247 | return PTR_ERR(keyring_r); | ||
1248 | |||
1249 | /* our parent is going to need a new cred struct, a new tgcred struct | ||
1250 | * and new security data, so we allocate them here to prevent ENOMEM in | ||
1251 | * our parent */ | ||
1252 | ret = -ENOMEM; | ||
1253 | cred = cred_alloc_blank(); | ||
1254 | if (!cred) | ||
1255 | goto error_keyring; | ||
1256 | |||
1257 | cred->tgcred->session_keyring = key_ref_to_ptr(keyring_r); | ||
1258 | keyring_r = NULL; | ||
1259 | |||
1260 | me = current; | ||
1261 | write_lock_irq(&tasklist_lock); | ||
1262 | |||
1263 | parent = me->real_parent; | ||
1264 | ret = -EPERM; | ||
1265 | |||
1266 | /* the parent mustn't be init and mustn't be a kernel thread */ | ||
1267 | if (parent->pid <= 1 || !parent->mm) | ||
1268 | goto not_permitted; | ||
1269 | |||
1270 | /* the parent must be single threaded */ | ||
1271 | if (atomic_read(&parent->signal->count) != 1) | ||
1272 | goto not_permitted; | ||
1273 | |||
1274 | /* the parent and the child must have different session keyrings or | ||
1275 | * there's no point */ | ||
1276 | mycred = current_cred(); | ||
1277 | pcred = __task_cred(parent); | ||
1278 | if (mycred == pcred || | ||
1279 | mycred->tgcred->session_keyring == pcred->tgcred->session_keyring) | ||
1280 | goto already_same; | ||
1281 | |||
1282 | /* the parent must have the same effective ownership and mustn't be | ||
1283 | * SUID/SGID */ | ||
1284 | if (pcred-> uid != mycred->euid || | ||
1285 | pcred->euid != mycred->euid || | ||
1286 | pcred->suid != mycred->euid || | ||
1287 | pcred-> gid != mycred->egid || | ||
1288 | pcred->egid != mycred->egid || | ||
1289 | pcred->sgid != mycred->egid) | ||
1290 | goto not_permitted; | ||
1291 | |||
1292 | /* the keyrings must have the same UID */ | ||
1293 | if (pcred ->tgcred->session_keyring->uid != mycred->euid || | ||
1294 | mycred->tgcred->session_keyring->uid != mycred->euid) | ||
1295 | goto not_permitted; | ||
1296 | |||
1297 | /* the LSM must permit the replacement of the parent's keyring with the | ||
1298 | * keyring from this process */ | ||
1299 | ret = security_key_session_to_parent(mycred, pcred, | ||
1300 | key_ref_to_ptr(keyring_r)); | ||
1301 | if (ret < 0) | ||
1302 | goto not_permitted; | ||
1303 | |||
1304 | /* if there's an already pending keyring replacement, then we replace | ||
1305 | * that */ | ||
1306 | oldcred = parent->replacement_session_keyring; | ||
1307 | |||
1308 | /* the replacement session keyring is applied just prior to userspace | ||
1309 | * restarting */ | ||
1310 | parent->replacement_session_keyring = cred; | ||
1311 | cred = NULL; | ||
1312 | set_ti_thread_flag(task_thread_info(parent), TIF_NOTIFY_RESUME); | ||
1313 | |||
1314 | write_unlock_irq(&tasklist_lock); | ||
1315 | if (oldcred) | ||
1316 | put_cred(oldcred); | ||
1317 | return 0; | ||
1318 | |||
1319 | already_same: | ||
1320 | ret = 0; | ||
1321 | not_permitted: | ||
1322 | put_cred(cred); | ||
1323 | return ret; | ||
1324 | |||
1325 | error_keyring: | ||
1326 | key_ref_put(keyring_r); | ||
1327 | return ret; | ||
1328 | } | ||
1329 | |||
1216 | /*****************************************************************************/ | 1330 | /*****************************************************************************/ |
1217 | /* | 1331 | /* |
1218 | * the key control system call | 1332 | * the key control system call |
@@ -1298,6 +1412,9 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3, | |||
1298 | (char __user *) arg3, | 1412 | (char __user *) arg3, |
1299 | (size_t) arg4); | 1413 | (size_t) arg4); |
1300 | 1414 | ||
1415 | case KEYCTL_SESSION_TO_PARENT: | ||
1416 | return keyctl_session_to_parent(); | ||
1417 | |||
1301 | default: | 1418 | default: |
1302 | return -EOPNOTSUPP; | 1419 | return -EOPNOTSUPP; |
1303 | } | 1420 | } |