📄 keyctl.c
字号:
ret = -ENOKEY; goto error5; } /* link the resulting key to the destination keyring if we can */ if (dest_ref) { ret = key_permission(key_ref, KEY_LINK); if (ret < 0) goto error6; ret = key_link(key_ref_to_ptr(dest_ref), key_ref_to_ptr(key_ref)); if (ret < 0) goto error6; } ret = key_ref_to_ptr(key_ref)->serial; error6: key_ref_put(key_ref); error5: key_type_put(ktype); error4: key_ref_put(dest_ref); error3: key_ref_put(keyring_ref); error2: kfree(description); error: return ret;} /* end keyctl_keyring_search() *//*****************************************************************************//* * read a user key's payload * - the keyring must be readable or the key must be searchable from the * process's keyrings * - if there's a buffer, we place up to buflen bytes of data into it * - unless there's an error, we return the amount of data in the key, * irrespective of how much we may have copied * - implements keyctl(KEYCTL_READ) */long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen){ struct key *key; key_ref_t key_ref; long ret; /* find the key first */ key_ref = lookup_user_key(NULL, keyid, 0, 0, 0); if (IS_ERR(key_ref)) { ret = -ENOKEY; goto error; } key = key_ref_to_ptr(key_ref); /* see if we can read it directly */ ret = key_permission(key_ref, KEY_READ); if (ret == 0) goto can_read_key; if (ret != -EACCES) goto error; /* we can't; see if it's searchable from this process's keyrings * - we automatically take account of the fact that it may be * dangling off an instantiation key */ if (!is_key_possessed(key_ref)) { ret = -EACCES; goto error2; } /* the key is probably readable - now try to read it */ can_read_key: ret = key_validate(key); if (ret == 0) { ret = -EOPNOTSUPP; if (key->type->read) { /* read the data with the semaphore held (since we * might sleep) */ down_read(&key->sem); ret = key->type->read(key, buffer, buflen); up_read(&key->sem); } } error2: key_put(key); error: return ret;} /* end keyctl_read_key() *//*****************************************************************************//* * change the ownership of a key * - the keyring owned by the changer * - if the uid or gid is -1, then that parameter is not changed * - implements keyctl(KEYCTL_CHOWN) */long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid){ struct key_user *newowner, *zapowner = NULL; struct key *key; key_ref_t key_ref; long ret; ret = 0; if (uid == (uid_t) -1 && gid == (gid_t) -1) goto error; key_ref = lookup_user_key(NULL, id, 1, 1, KEY_SETATTR); if (IS_ERR(key_ref)) { ret = PTR_ERR(key_ref); goto error; } key = key_ref_to_ptr(key_ref); /* make the changes with the locks held to prevent chown/chown races */ ret = -EACCES; down_write(&key->sem); if (!capable(CAP_SYS_ADMIN)) { /* only the sysadmin can chown a key to some other UID */ if (uid != (uid_t) -1 && key->uid != uid) goto error_put; /* only the sysadmin can set the key's GID to a group other * than one of those that the current process subscribes to */ if (gid != (gid_t) -1 && gid != key->gid && !in_group_p(gid)) goto error_put; } /* change the UID */ if (uid != (uid_t) -1 && uid != key->uid) { ret = -ENOMEM; newowner = key_user_lookup(uid); if (!newowner) goto error_put; /* transfer the quota burden to the new user */ if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) { spin_lock(&newowner->lock); if (newowner->qnkeys + 1 >= KEYQUOTA_MAX_KEYS || newowner->qnbytes + key->quotalen >= KEYQUOTA_MAX_BYTES) goto quota_overrun; newowner->qnkeys++; newowner->qnbytes += key->quotalen; spin_unlock(&newowner->lock); spin_lock(&key->user->lock); key->user->qnkeys--; key->user->qnbytes -= key->quotalen; spin_unlock(&key->user->lock); } atomic_dec(&key->user->nkeys); atomic_inc(&newowner->nkeys); if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) { atomic_dec(&key->user->nikeys); atomic_inc(&newowner->nikeys); } zapowner = key->user; key->user = newowner; key->uid = uid; } /* change the GID */ if (gid != (gid_t) -1) key->gid = gid; ret = 0;error_put: up_write(&key->sem); key_put(key); if (zapowner) key_user_put(zapowner);error: return ret;quota_overrun: spin_unlock(&newowner->lock); zapowner = newowner; ret = -EDQUOT; goto error_put;} /* end keyctl_chown_key() *//*****************************************************************************//* * change the permission mask on a key * - the keyring owned by the changer * - implements keyctl(KEYCTL_SETPERM) */long keyctl_setperm_key(key_serial_t id, key_perm_t perm){ struct key *key; key_ref_t key_ref; long ret; ret = -EINVAL; if (perm & ~(KEY_POS_ALL | KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL)) goto error; key_ref = lookup_user_key(NULL, id, 1, 1, KEY_SETATTR); if (IS_ERR(key_ref)) { ret = PTR_ERR(key_ref); goto error; } key = key_ref_to_ptr(key_ref); /* make the changes with the locks held to prevent chown/chmod races */ ret = -EACCES; down_write(&key->sem); /* if we're not the sysadmin, we can only change a key that we own */ if (capable(CAP_SYS_ADMIN) || key->uid == current->fsuid) { key->perm = perm; ret = 0; } up_write(&key->sem); key_put(key);error: return ret;} /* end keyctl_setperm_key() *//*****************************************************************************//* * instantiate the key with the specified payload, and, if one is given, link * the key into the keyring */long keyctl_instantiate_key(key_serial_t id, const void __user *_payload, size_t plen, key_serial_t ringid){ struct request_key_auth *rka; struct key *instkey; key_ref_t keyring_ref; void *payload; long ret; ret = -EINVAL; if (plen > 32767) goto error; /* the appropriate instantiation authorisation key must have been * assumed before calling this */ ret = -EPERM; instkey = current->request_key_auth; if (!instkey) goto error; rka = instkey->payload.data; if (rka->target_key->serial != id) goto error; /* pull the payload in if one was supplied */ payload = NULL; if (_payload) { ret = -ENOMEM; payload = kmalloc(plen, GFP_KERNEL); if (!payload) goto error; ret = -EFAULT; if (copy_from_user(payload, _payload, plen) != 0) goto error2; } /* find the destination keyring amongst those belonging to the * requesting task */ keyring_ref = NULL; if (ringid) { keyring_ref = lookup_user_key(rka->context, ringid, 1, 0, KEY_WRITE); if (IS_ERR(keyring_ref)) { ret = PTR_ERR(keyring_ref); goto error2; } } /* instantiate the key and link it into a keyring */ ret = key_instantiate_and_link(rka->target_key, payload, plen, key_ref_to_ptr(keyring_ref), instkey); key_ref_put(keyring_ref); /* discard the assumed authority if it's just been disabled by * instantiation of the key */ if (ret == 0) { key_put(current->request_key_auth); current->request_key_auth = NULL; }error2: kfree(payload);error: return ret;} /* end keyctl_instantiate_key() *//*****************************************************************************//* * negatively instantiate the key with the given timeout (in seconds), and, if * one is given, link the key into the keyring */long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid){ struct request_key_auth *rka; struct key *instkey; key_ref_t keyring_ref; long ret; /* the appropriate instantiation authorisation key must have been * assumed before calling this */ ret = -EPERM; instkey = current->request_key_auth; if (!instkey) goto error; rka = instkey->payload.data; if (rka->target_key->serial != id) goto error; /* find the destination keyring if present (which must also be * writable) */ keyring_ref = NULL; if (ringid) { keyring_ref = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE); if (IS_ERR(keyring_ref)) { ret = PTR_ERR(keyring_ref); goto error; } } /* instantiate the key and link it into a keyring */ ret = key_negate_and_link(rka->target_key, timeout, key_ref_to_ptr(keyring_ref), instkey); key_ref_put(keyring_ref); /* discard the assumed authority if it's just been disabled by * instantiation of the key */ if (ret == 0) { key_put(current->request_key_auth); current->request_key_auth = NULL; }error: return ret;} /* end keyctl_negate_key() *//*****************************************************************************//* * set the default keyring in which request_key() will cache keys * - return the old setting */long keyctl_set_reqkey_keyring(int reqkey_defl){ int ret; switch (reqkey_defl) { case KEY_REQKEY_DEFL_THREAD_KEYRING: ret = install_thread_keyring(current); if (ret < 0) return ret; goto set; case KEY_REQKEY_DEFL_PROCESS_KEYRING: ret = install_process_keyring(current); if (ret < 0) return ret; case KEY_REQKEY_DEFL_DEFAULT: case KEY_REQKEY_DEFL_SESSION_KEYRING: case KEY_REQKEY_DEFL_USER_KEYRING: case KEY_REQKEY_DEFL_USER_SESSION_KEYRING: set: current->jit_keyring = reqkey_defl; case KEY_REQKEY_DEFL_NO_CHANGE: return current->jit_keyring; case KEY_REQKEY_DEFL_GROUP_KEYRING: default: return -EINVAL; }} /* end keyctl_set_reqkey_keyring() *//*****************************************************************************//* * set or clear the timeout for a key */long keyctl_set_timeout(key_serial_t id, unsigned timeout){ struct timespec now; struct key *key; key_ref_t key_ref; time_t expiry; long ret; key_ref = lookup_user_key(NULL, id, 1, 1, KEY_SETATTR); if (IS_ERR(key_ref)) { ret = PTR_ERR(key_ref); goto error; } key = key_ref_to_ptr(key_ref); /* make the changes with the locks held to prevent races */ down_write(&key->sem); expiry = 0; if (timeout > 0) { now = current_kernel_time(); expiry = now.tv_sec + timeout; } key->expiry = expiry; up_write(&key->sem); key_put(key); ret = 0;error: return ret;} /* end keyctl_set_timeout() *//*****************************************************************************//* * assume the authority to instantiate the specified key */long keyctl_assume_authority(key_serial_t id){ struct key *authkey; long ret; /* special key IDs aren't permitted */ ret = -EINVAL; if (id < 0) goto error; /* we divest ourselves of authority if given an ID of 0 */ if (id == 0) { key_put(current->request_key_auth); current->request_key_auth = NULL; ret = 0; goto error; } /* attempt to assume the authority temporarily granted to us whilst we * instantiate the specified key * - the authorisation key must be in the current task's keyrings * somewhere */ authkey = key_get_instantiation_authkey(id); if (IS_ERR(authkey)) { ret = PTR_ERR(authkey); goto error; } key_put(current->request_key_auth); current->request_key_auth = authkey; ret = authkey->serial;error: return ret;} /* end keyctl_assume_authority() *//*****************************************************************************//* * the key control system call */asmlinkage long sys_keyctl(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5){ switch (option) { case KEYCTL_GET_KEYRING_ID: return keyctl_get_keyring_ID((key_serial_t) arg2, (int) arg3); case KEYCTL_JOIN_SESSION_KEYRING: return keyctl_join_session_keyring((const char __user *) arg2); case KEYCTL_UPDATE: return keyctl_update_key((key_serial_t) arg2, (const void __user *) arg3, (size_t) arg4); case KEYCTL_REVOKE: return keyctl_revoke_key((key_serial_t) arg2); case KEYCTL_DESCRIBE: return keyctl_describe_key((key_serial_t) arg2, (char __user *) arg3, (unsigned) arg4); case KEYCTL_CLEAR: return keyctl_keyring_clear((key_serial_t) arg2); case KEYCTL_LINK: return keyctl_keyring_link((key_serial_t) arg2, (key_serial_t) arg3); case KEYCTL_UNLINK: return keyctl_keyring_unlink((key_serial_t) arg2, (key_serial_t) arg3); case KEYCTL_SEARCH: return keyctl_keyring_search((key_serial_t) arg2, (const char __user *) arg3, (const char __user *) arg4, (key_serial_t) arg5); case KEYCTL_READ: return keyctl_read_key((key_serial_t) arg2, (char __user *) arg3, (size_t) arg4); case KEYCTL_CHOWN: return keyctl_chown_key((key_serial_t) arg2, (uid_t) arg3, (gid_t) arg4); case KEYCTL_SETPERM: return keyctl_setperm_key((key_serial_t) arg2, (key_perm_t) arg3); case KEYCTL_INSTANTIATE: return keyctl_instantiate_key((key_serial_t) arg2, (const void __user *) arg3, (size_t) arg4, (key_serial_t) arg5); case KEYCTL_NEGATE: return keyctl_negate_key((key_serial_t) arg2, (unsigned) arg3, (key_serial_t) arg4); case KEYCTL_SET_REQKEY_KEYRING: return keyctl_set_reqkey_keyring(arg2); case KEYCTL_SET_TIMEOUT: return keyctl_set_timeout((key_serial_t) arg2, (unsigned) arg3); case KEYCTL_ASSUME_AUTHORITY: return keyctl_assume_authority((key_serial_t) arg2); default: return -EOPNOTSUPP; }} /* end sys_keyctl() */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -