diff options
Diffstat (limited to 'security/keys/keyctl.c')
-rw-r--r-- | security/keys/keyctl.c | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index 736d7800f97f..74c968524592 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c | |||
@@ -1228,6 +1228,105 @@ long keyctl_get_security(key_serial_t keyid, | |||
1228 | return ret; | 1228 | return ret; |
1229 | } | 1229 | } |
1230 | 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 | |||
1231 | /*****************************************************************************/ | 1330 | /*****************************************************************************/ |
1232 | /* | 1331 | /* |
1233 | * the key control system call | 1332 | * the key control system call |
@@ -1313,6 +1412,9 @@ SYSCALL_DEFINE5(keyctl, int, option, unsigned long, arg2, unsigned long, arg3, | |||
1313 | (char __user *) arg3, | 1412 | (char __user *) arg3, |
1314 | (size_t) arg4); | 1413 | (size_t) arg4); |
1315 | 1414 | ||
1415 | case KEYCTL_SESSION_TO_PARENT: | ||
1416 | return keyctl_session_to_parent(); | ||
1417 | |||
1316 | default: | 1418 | default: |
1317 | return -EOPNOTSUPP; | 1419 | return -EOPNOTSUPP; |
1318 | } | 1420 | } |