aboutsummaryrefslogtreecommitdiffstats
path: root/security/keys/keyctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/keys/keyctl.c')
-rw-r--r--security/keys/keyctl.c102
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 */
1237long 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
1319already_same:
1320 ret = 0;
1321not_permitted:
1322 put_cred(cred);
1323 return ret;
1324
1325error_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 }