📄 keyring.c
字号:
* find a keyring with the specified name * - all named keyrings are searched * - only find keyrings with search permission for the process * - only find keyrings with a serial number greater than the one specified */struct key *find_keyring_by_name(const char *name, key_serial_t bound){ struct key *keyring; int bucket; keyring = ERR_PTR(-EINVAL); if (!name) goto error; bucket = keyring_hash(name); read_lock(&keyring_name_lock); if (keyring_name_hash[bucket].next) { /* search this hash bucket for a keyring with a matching name * that's readable and that hasn't been revoked */ list_for_each_entry(keyring, &keyring_name_hash[bucket], type_data.link ) { if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) continue; if (strcmp(keyring->description, name) != 0) continue; if (key_permission(make_key_ref(keyring, 0), KEY_SEARCH) < 0) continue; /* found a potential candidate, but we still need to * check the serial number */ if (keyring->serial <= bound) continue; /* we've got a match */ atomic_inc(&keyring->usage); read_unlock(&keyring_name_lock); goto error; } } read_unlock(&keyring_name_lock); keyring = ERR_PTR(-ENOKEY); error: return keyring;} /* end find_keyring_by_name() *//*****************************************************************************//* * see if a cycle will will be created by inserting acyclic tree B in acyclic * tree A at the topmost level (ie: as a direct child of A) * - since we are adding B to A at the top level, checking for cycles should * just be a matter of seeing if node A is somewhere in tree B */static int keyring_detect_cycle(struct key *A, struct key *B){ struct { struct keyring_list *keylist; int kix; } stack[KEYRING_SEARCH_MAX_DEPTH]; struct keyring_list *keylist; struct key *subtree, *key; int sp, kix, ret; rcu_read_lock(); ret = -EDEADLK; if (A == B) goto cycle_detected; subtree = B; sp = 0; /* start processing a new keyring */ descend: if (test_bit(KEY_FLAG_REVOKED, &subtree->flags)) goto not_this_keyring; keylist = rcu_dereference(subtree->payload.subscriptions); if (!keylist) goto not_this_keyring; kix = 0; ascend: /* iterate through the remaining keys in this keyring */ for (; kix < keylist->nkeys; kix++) { key = keylist->keys[kix]; if (key == A) goto cycle_detected; /* recursively check nested keyrings */ if (key->type == &key_type_keyring) { if (sp >= KEYRING_SEARCH_MAX_DEPTH) goto too_deep; /* stack the current position */ stack[sp].keylist = keylist; stack[sp].kix = kix; sp++; /* begin again with the new keyring */ subtree = key; goto descend; } } /* the keyring we're looking at was disqualified or didn't contain a * matching key */ not_this_keyring: if (sp > 0) { /* resume the checking of a keyring higher up in the tree */ sp--; keylist = stack[sp].keylist; kix = stack[sp].kix + 1; goto ascend; } ret = 0; /* no cycles detected */ error: rcu_read_unlock(); return ret; too_deep: ret = -ELOOP; goto error; cycle_detected: ret = -EDEADLK; goto error;} /* end keyring_detect_cycle() *//*****************************************************************************//* * dispose of a keyring list after the RCU grace period */static void keyring_link_rcu_disposal(struct rcu_head *rcu){ struct keyring_list *klist = container_of(rcu, struct keyring_list, rcu); kfree(klist);} /* end keyring_link_rcu_disposal() *//*****************************************************************************//* * dispose of a keyring list after the RCU grace period, freeing the unlinked * key */static void keyring_unlink_rcu_disposal(struct rcu_head *rcu){ struct keyring_list *klist = container_of(rcu, struct keyring_list, rcu); key_put(klist->keys[klist->delkey]); kfree(klist);} /* end keyring_unlink_rcu_disposal() *//*****************************************************************************//* * link a key into to a keyring * - must be called with the keyring's semaphore write-locked * - discard already extant link to matching key if there is one */int __key_link(struct key *keyring, struct key *key){ struct keyring_list *klist, *nklist; unsigned max; size_t size; int loop, ret; ret = -EKEYREVOKED; if (test_bit(KEY_FLAG_REVOKED, &keyring->flags)) goto error; ret = -ENOTDIR; if (keyring->type != &key_type_keyring) goto error; /* serialise link/link calls to prevent parallel calls causing a * cycle when applied to two keyring in opposite orders */ down_write(&keyring_serialise_link_sem); /* check that we aren't going to create a cycle adding one keyring to * another */ if (key->type == &key_type_keyring) { ret = keyring_detect_cycle(keyring, key); if (ret < 0) goto error2; } /* see if there's a matching key we can displace */ klist = keyring->payload.subscriptions; if (klist && klist->nkeys > 0) { struct key_type *type = key->type; for (loop = klist->nkeys - 1; loop >= 0; loop--) { if (klist->keys[loop]->type == type && strcmp(klist->keys[loop]->description, key->description) == 0 ) { /* found a match - replace with new key */ size = sizeof(struct key *) * klist->maxkeys; size += sizeof(*klist); BUG_ON(size > PAGE_SIZE); ret = -ENOMEM; nklist = kmemdup(klist, size, GFP_KERNEL); if (!nklist) goto error2; /* replace matched key */ atomic_inc(&key->usage); nklist->keys[loop] = key; rcu_assign_pointer( keyring->payload.subscriptions, nklist); /* dispose of the old keyring list and the * displaced key */ klist->delkey = loop; call_rcu(&klist->rcu, keyring_unlink_rcu_disposal); goto done; } } } /* check that we aren't going to overrun the user's quota */ ret = key_payload_reserve(keyring, keyring->datalen + KEYQUOTA_LINK_BYTES); if (ret < 0) goto error2; klist = keyring->payload.subscriptions; if (klist && klist->nkeys < klist->maxkeys) { /* there's sufficient slack space to add directly */ atomic_inc(&key->usage); klist->keys[klist->nkeys] = key; smp_wmb(); klist->nkeys++; smp_wmb(); } else { /* grow the key list */ max = 4; if (klist) max += klist->maxkeys; ret = -ENFILE; if (max > 65535) goto error3; size = sizeof(*klist) + sizeof(struct key *) * max; if (size > PAGE_SIZE) goto error3; ret = -ENOMEM; nklist = kmalloc(size, GFP_KERNEL); if (!nklist) goto error3; nklist->maxkeys = max; nklist->nkeys = 0; if (klist) { nklist->nkeys = klist->nkeys; memcpy(nklist->keys, klist->keys, sizeof(struct key *) * klist->nkeys); } /* add the key into the new space */ atomic_inc(&key->usage); nklist->keys[nklist->nkeys++] = key; rcu_assign_pointer(keyring->payload.subscriptions, nklist); /* dispose of the old keyring list */ if (klist) call_rcu(&klist->rcu, keyring_link_rcu_disposal); }done: ret = 0;error2: up_write(&keyring_serialise_link_sem);error: return ret;error3: /* undo the quota changes */ key_payload_reserve(keyring, keyring->datalen - KEYQUOTA_LINK_BYTES); goto error2;} /* end __key_link() *//*****************************************************************************//* * link a key to a keyring */int key_link(struct key *keyring, struct key *key){ int ret; key_check(keyring); key_check(key); down_write(&keyring->sem); ret = __key_link(keyring, key); up_write(&keyring->sem); return ret;} /* end key_link() */EXPORT_SYMBOL(key_link);/*****************************************************************************//* * unlink the first link to a key from a keyring */int key_unlink(struct key *keyring, struct key *key){ struct keyring_list *klist, *nklist; int loop, ret; key_check(keyring); key_check(key); ret = -ENOTDIR; if (keyring->type != &key_type_keyring) goto error; down_write(&keyring->sem); klist = keyring->payload.subscriptions; if (klist) { /* search the keyring for the key */ for (loop = 0; loop < klist->nkeys; loop++) if (klist->keys[loop] == key) goto key_is_present; } up_write(&keyring->sem); ret = -ENOENT; goto error;key_is_present: /* we need to copy the key list for RCU purposes */ nklist = kmalloc(sizeof(*klist) + sizeof(struct key *) * klist->maxkeys, GFP_KERNEL); if (!nklist) goto nomem; nklist->maxkeys = klist->maxkeys; nklist->nkeys = klist->nkeys - 1; if (loop > 0) memcpy(&nklist->keys[0], &klist->keys[0], loop * sizeof(struct key *)); if (loop < nklist->nkeys) memcpy(&nklist->keys[loop], &klist->keys[loop + 1], (nklist->nkeys - loop) * sizeof(struct key *)); /* adjust the user's quota */ key_payload_reserve(keyring, keyring->datalen - KEYQUOTA_LINK_BYTES); rcu_assign_pointer(keyring->payload.subscriptions, nklist); up_write(&keyring->sem); /* schedule for later cleanup */ klist->delkey = loop; call_rcu(&klist->rcu, keyring_unlink_rcu_disposal); ret = 0;error: return ret;nomem: ret = -ENOMEM; up_write(&keyring->sem); goto error;} /* end key_unlink() */EXPORT_SYMBOL(key_unlink);/*****************************************************************************//* * dispose of a keyring list after the RCU grace period, releasing the keys it * links to */static void keyring_clear_rcu_disposal(struct rcu_head *rcu){ struct keyring_list *klist; int loop; klist = container_of(rcu, struct keyring_list, rcu); for (loop = klist->nkeys - 1; loop >= 0; loop--) key_put(klist->keys[loop]); kfree(klist);} /* end keyring_clear_rcu_disposal() *//*****************************************************************************//* * clear the specified process keyring * - implements keyctl(KEYCTL_CLEAR) */int keyring_clear(struct key *keyring){ struct keyring_list *klist; int ret; ret = -ENOTDIR; if (keyring->type == &key_type_keyring) { /* detach the pointer block with the locks held */ down_write(&keyring->sem); klist = keyring->payload.subscriptions; if (klist) { /* adjust the quota */ key_payload_reserve(keyring, sizeof(struct keyring_list)); rcu_assign_pointer(keyring->payload.subscriptions, NULL); } up_write(&keyring->sem); /* free the keys after the locks have been dropped */ if (klist) call_rcu(&klist->rcu, keyring_clear_rcu_disposal); ret = 0; } return ret;} /* end keyring_clear() */EXPORT_SYMBOL(keyring_clear);/*****************************************************************************//* * dispose of the links from a revoked keyring * - called with the key sem write-locked */static void keyring_revoke(struct key *keyring){ struct keyring_list *klist = keyring->payload.subscriptions; /* adjust the quota */ key_payload_reserve(keyring, 0); if (klist) { rcu_assign_pointer(keyring->payload.subscriptions, NULL); call_rcu(&klist->rcu, keyring_clear_rcu_disposal); }} /* end keyring_revoke() */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -