keys: Pass the network namespace into request_key mechanism
Create a request_key_net() function and use it to pass the network namespace domain tag into DNS revolver keys and rxrpc/AFS keys so that keys for different domains can coexist in the same keyring. Signed-off-by: David Howells <dhowells@redhat.com> cc: netdev@vger.kernel.org cc: linux-nfs@vger.kernel.org cc: linux-cifs@vger.kernel.org cc: linux-afs@lists.infradead.org
This commit is contained in:
Родитель
9b24261051
Коммит
a58946c158
|
@ -1102,26 +1102,42 @@ payload contents" for more information.
|
|||
See also Documentation/security/keys/request-key.rst.
|
||||
|
||||
|
||||
* To search for a key in a specific domain, call:
|
||||
|
||||
struct key *request_key_tag(const struct key_type *type,
|
||||
const char *description,
|
||||
struct key_tag *domain_tag,
|
||||
const char *callout_info);
|
||||
|
||||
This is identical to request_key(), except that a domain tag may be
|
||||
specifies that causes search algorithm to only match keys matching that
|
||||
tag. The domain_tag may be NULL, specifying a global domain that is
|
||||
separate from any nominated domain.
|
||||
|
||||
|
||||
* To search for a key, passing auxiliary data to the upcaller, call::
|
||||
|
||||
struct key *request_key_with_auxdata(const struct key_type *type,
|
||||
const char *description,
|
||||
struct key_tag *domain_tag,
|
||||
const void *callout_info,
|
||||
size_t callout_len,
|
||||
void *aux);
|
||||
|
||||
This is identical to request_key(), except that the auxiliary data is
|
||||
passed to the key_type->request_key() op if it exists, and the callout_info
|
||||
is a blob of length callout_len, if given (the length may be 0).
|
||||
This is identical to request_key_tag(), except that the auxiliary data is
|
||||
passed to the key_type->request_key() op if it exists, and the
|
||||
callout_info is a blob of length callout_len, if given (the length may be
|
||||
0).
|
||||
|
||||
|
||||
* To search for a key under RCU conditions, call::
|
||||
|
||||
struct key *request_key_rcu(const struct key_type *type,
|
||||
const char *description);
|
||||
const char *description,
|
||||
struct key_tag *domain_tag);
|
||||
|
||||
which is similar to request_key() except that it does not check for keys
|
||||
that are under construction and it will not call out to userspace to
|
||||
which is similar to request_key_tag() except that it does not check for
|
||||
keys that are under construction and it will not call out to userspace to
|
||||
construct a key if it can't find a match.
|
||||
|
||||
|
||||
|
|
|
@ -13,10 +13,18 @@ The process starts by either the kernel requesting a service by calling
|
|||
const char *description,
|
||||
const char *callout_info);
|
||||
|
||||
or::
|
||||
|
||||
struct key *request_key_tag(const struct key_type *type,
|
||||
const char *description,
|
||||
const struct key_tag *domain_tag,
|
||||
const char *callout_info);
|
||||
|
||||
or::
|
||||
|
||||
struct key *request_key_with_auxdata(const struct key_type *type,
|
||||
const char *description,
|
||||
const struct key_tag *domain_tag,
|
||||
const char *callout_info,
|
||||
size_t callout_len,
|
||||
void *aux);
|
||||
|
@ -24,7 +32,8 @@ or::
|
|||
or::
|
||||
|
||||
struct key *request_key_rcu(const struct key_type *type,
|
||||
const char *description);
|
||||
const char *description,
|
||||
const struct key_tag *domain_tag);
|
||||
|
||||
Or by userspace invoking the request_key system call::
|
||||
|
||||
|
@ -38,14 +47,18 @@ does not need to link the key to a keyring to prevent it from being immediately
|
|||
destroyed. The kernel interface returns a pointer directly to the key, and
|
||||
it's up to the caller to destroy the key.
|
||||
|
||||
The request_key_with_auxdata() calls is like the in-kernel request_key() call,
|
||||
except that they permit auxiliary data to be passed to the upcaller (the
|
||||
default is NULL). This is only useful for those key types that define their
|
||||
own upcall mechanism rather than using /sbin/request-key.
|
||||
The request_key_tag() call is like the in-kernel request_key(), except that it
|
||||
also takes a domain tag that allows keys to be separated by namespace and
|
||||
killed off as a group.
|
||||
|
||||
The request_key_rcu() call is like the in-kernel request_key() call, except
|
||||
that it doesn't check for keys that are under construction and doesn't attempt
|
||||
to construct missing keys.
|
||||
The request_key_with_auxdata() calls is like the request_key_tag() call, except
|
||||
that they permit auxiliary data to be passed to the upcaller (the default is
|
||||
NULL). This is only useful for those key types that define their own upcall
|
||||
mechanism rather than using /sbin/request-key.
|
||||
|
||||
The request_key_rcu() call is like the request_key_tag() call, except that it
|
||||
doesn't check for keys that are under construction and doesn't attempt to
|
||||
construct missing keys.
|
||||
|
||||
The userspace interface links the key to a keyring associated with the process
|
||||
to prevent the key from going away, and returns the serial number of the key to
|
||||
|
|
|
@ -250,8 +250,8 @@ struct afs_vlserver_list *afs_dns_query(struct afs_cell *cell, time64_t *_expiry
|
|||
|
||||
_enter("%s", cell->name);
|
||||
|
||||
ret = dns_query("afsdb", cell->name, cell->name_len, "srv=1",
|
||||
&result, _expiry, true);
|
||||
ret = dns_query(cell->net->net, "afsdb", cell->name, cell->name_len,
|
||||
"srv=1", &result, _expiry, true);
|
||||
if (ret < 0) {
|
||||
_leave(" = %d [dns]", ret);
|
||||
return ERR_PTR(ret);
|
||||
|
|
|
@ -28,6 +28,7 @@ const struct file_operations afs_dynroot_file_operations = {
|
|||
static int afs_probe_cell_name(struct dentry *dentry)
|
||||
{
|
||||
struct afs_cell *cell;
|
||||
struct afs_net *net = afs_d2net(dentry);
|
||||
const char *name = dentry->d_name.name;
|
||||
size_t len = dentry->d_name.len;
|
||||
int ret;
|
||||
|
@ -40,13 +41,14 @@ static int afs_probe_cell_name(struct dentry *dentry)
|
|||
len--;
|
||||
}
|
||||
|
||||
cell = afs_lookup_cell_rcu(afs_d2net(dentry), name, len);
|
||||
cell = afs_lookup_cell_rcu(net, name, len);
|
||||
if (!IS_ERR(cell)) {
|
||||
afs_put_cell(afs_d2net(dentry), cell);
|
||||
afs_put_cell(net, cell);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = dns_query("afsdb", name, len, "srv=1", NULL, NULL, false);
|
||||
ret = dns_query(net->net, "afsdb", name, len, "srv=1",
|
||||
NULL, NULL, false);
|
||||
if (ret == -ENODATA)
|
||||
ret = -EDESTADDRREQ;
|
||||
return ret;
|
||||
|
|
|
@ -77,7 +77,8 @@ dns_resolve_server_name_to_ip(const char *unc, char **ip_addr)
|
|||
goto name_is_IP_address;
|
||||
|
||||
/* Perform the upcall */
|
||||
rc = dns_query(NULL, hostname, len, NULL, ip_addr, NULL, false);
|
||||
rc = dns_query(current->nsproxy->net_ns, NULL, hostname, len,
|
||||
NULL, ip_addr, NULL, false);
|
||||
if (rc < 0)
|
||||
cifs_dbg(FYI, "%s: unable to resolve: %*.*s\n",
|
||||
__func__, len, len, hostname);
|
||||
|
|
|
@ -22,7 +22,8 @@ ssize_t nfs_dns_resolve_name(struct net *net, char *name, size_t namelen,
|
|||
char *ip_addr = NULL;
|
||||
int ip_len;
|
||||
|
||||
ip_len = dns_query(NULL, name, namelen, NULL, &ip_addr, NULL, false);
|
||||
ip_len = dns_query(net, NULL, name, namelen, NULL, &ip_addr, NULL,
|
||||
false);
|
||||
if (ip_len > 0)
|
||||
ret = rpc_pton(net, ip_addr, ip_len, sa, salen);
|
||||
else
|
||||
|
|
|
@ -291,7 +291,7 @@ static struct key *nfs_idmap_request_key(const char *name, size_t namelen,
|
|||
if (IS_ERR(rkey)) {
|
||||
mutex_lock(&idmap->idmap_mutex);
|
||||
rkey = request_key_with_auxdata(&key_type_id_resolver_legacy,
|
||||
desc, "", 0, idmap);
|
||||
desc, NULL, "", 0, idmap);
|
||||
mutex_unlock(&idmap->idmap_mutex);
|
||||
}
|
||||
if (!IS_ERR(rkey))
|
||||
|
|
|
@ -26,7 +26,8 @@
|
|||
|
||||
#include <uapi/linux/dns_resolver.h>
|
||||
|
||||
extern int dns_query(const char *type, const char *name, size_t namelen,
|
||||
struct net;
|
||||
extern int dns_query(struct net *net, const char *type, const char *name, size_t namelen,
|
||||
const char *options, char **_result, time64_t *_expiry,
|
||||
bool invalidate);
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ typedef int32_t key_serial_t;
|
|||
typedef uint32_t key_perm_t;
|
||||
|
||||
struct key;
|
||||
struct net;
|
||||
|
||||
#ifdef CONFIG_KEYS
|
||||
|
||||
|
@ -296,19 +297,57 @@ static inline void key_ref_put(key_ref_t key_ref)
|
|||
key_put(key_ref_to_ptr(key_ref));
|
||||
}
|
||||
|
||||
extern struct key *request_key(struct key_type *type,
|
||||
extern struct key *request_key_tag(struct key_type *type,
|
||||
const char *description,
|
||||
struct key_tag *domain_tag,
|
||||
const char *callout_info);
|
||||
|
||||
extern struct key *request_key_rcu(struct key_type *type,
|
||||
const char *description);
|
||||
const char *description,
|
||||
struct key_tag *domain_tag);
|
||||
|
||||
extern struct key *request_key_with_auxdata(struct key_type *type,
|
||||
const char *description,
|
||||
struct key_tag *domain_tag,
|
||||
const void *callout_info,
|
||||
size_t callout_len,
|
||||
void *aux);
|
||||
|
||||
/**
|
||||
* request_key - Request a key and wait for construction
|
||||
* @type: Type of key.
|
||||
* @description: The searchable description of the key.
|
||||
* @callout_info: The data to pass to the instantiation upcall (or NULL).
|
||||
*
|
||||
* As for request_key_tag(), but with the default global domain tag.
|
||||
*/
|
||||
static inline struct key *request_key(struct key_type *type,
|
||||
const char *description,
|
||||
const char *callout_info)
|
||||
{
|
||||
return request_key_tag(type, description, NULL, callout_info);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NET
|
||||
/*
|
||||
* request_key_net - Request a key for a net namespace and wait for construction
|
||||
* @type: Type of key.
|
||||
* @description: The searchable description of the key.
|
||||
* @net: The network namespace that is the key's domain of operation.
|
||||
* @callout_info: The data to pass to the instantiation upcall (or NULL).
|
||||
*
|
||||
* As for request_key() except that it does not add the returned key to a
|
||||
* keyring if found, new keys are always allocated in the user's quota, the
|
||||
* callout_info must be a NUL-terminated string and no auxiliary data can be
|
||||
* passed. Only keys that operate the specified network namespace are used.
|
||||
*
|
||||
* Furthermore, it then works as wait_for_key_construction() to wait for the
|
||||
* completion of keys undergoing construction with a non-interruptible wait.
|
||||
*/
|
||||
#define request_key_net(type, description, net, callout_info) \
|
||||
request_key_tag(type, description, net->key_domain, callout_info);
|
||||
#endif /* CONFIG_NET */
|
||||
|
||||
extern int wait_for_key_construction(struct key *key, bool intr);
|
||||
|
||||
extern int key_validate(const struct key *key);
|
||||
|
|
|
@ -1887,7 +1887,8 @@ static int ceph_dns_resolve_name(const char *name, size_t namelen,
|
|||
return -EINVAL;
|
||||
|
||||
/* do dns_resolve upcall */
|
||||
ip_len = dns_query(NULL, name, end - name, NULL, &ip_addr, NULL, false);
|
||||
ip_len = dns_query(current->nsproxy->net_ns,
|
||||
NULL, name, end - name, NULL, &ip_addr, NULL, false);
|
||||
if (ip_len > 0)
|
||||
ret = ceph_pton(ip_addr, ip_len, addr, -1, NULL);
|
||||
else
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include <linux/cred.h>
|
||||
#include <linux/dns_resolver.h>
|
||||
#include <linux/err.h>
|
||||
#include <net/net_namespace.h>
|
||||
|
||||
#include <keys/dns_resolver-type.h>
|
||||
#include <keys/user-type.h>
|
||||
|
@ -48,6 +49,7 @@
|
|||
|
||||
/**
|
||||
* dns_query - Query the DNS
|
||||
* @net: The network namespace to operate in.
|
||||
* @type: Query type (or NULL for straight host->IP lookup)
|
||||
* @name: Name to look up
|
||||
* @namelen: Length of name
|
||||
|
@ -69,7 +71,8 @@
|
|||
*
|
||||
* Returns the size of the result on success, -ve error code otherwise.
|
||||
*/
|
||||
int dns_query(const char *type, const char *name, size_t namelen,
|
||||
int dns_query(struct net *net,
|
||||
const char *type, const char *name, size_t namelen,
|
||||
const char *options, char **_result, time64_t *_expiry,
|
||||
bool invalidate)
|
||||
{
|
||||
|
@ -122,7 +125,7 @@ int dns_query(const char *type, const char *name, size_t namelen,
|
|||
* add_key() to preinstall malicious redirections
|
||||
*/
|
||||
saved_cred = override_creds(dns_resolver_cache);
|
||||
rkey = request_key(&key_type_dns_resolver, desc, options);
|
||||
rkey = request_key_net(&key_type_dns_resolver, desc, net, options);
|
||||
revert_creds(saved_cred);
|
||||
kfree(desc);
|
||||
if (IS_ERR(rkey)) {
|
||||
|
|
|
@ -914,7 +914,7 @@ int rxrpc_request_key(struct rxrpc_sock *rx, char __user *optval, int optlen)
|
|||
if (IS_ERR(description))
|
||||
return PTR_ERR(description);
|
||||
|
||||
key = request_key(&key_type_rxrpc, description, NULL);
|
||||
key = request_key_net(&key_type_rxrpc, description, sock_net(&rx->sk), NULL);
|
||||
if (IS_ERR(key)) {
|
||||
kfree(description);
|
||||
_leave(" = %ld", PTR_ERR(key));
|
||||
|
@ -945,7 +945,7 @@ int rxrpc_server_keyring(struct rxrpc_sock *rx, char __user *optval,
|
|||
if (IS_ERR(description))
|
||||
return PTR_ERR(description);
|
||||
|
||||
key = request_key(&key_type_keyring, description, NULL);
|
||||
key = request_key_net(&key_type_keyring, description, sock_net(&rx->sk), NULL);
|
||||
if (IS_ERR(key)) {
|
||||
kfree(description);
|
||||
_leave(" = %ld", PTR_ERR(key));
|
||||
|
|
|
@ -156,6 +156,7 @@ extern int install_session_keyring_to_cred(struct cred *, struct key *);
|
|||
|
||||
extern struct key *request_key_and_link(struct key_type *type,
|
||||
const char *description,
|
||||
struct key_tag *domain_tag,
|
||||
const void *callout_info,
|
||||
size_t callout_len,
|
||||
void *aux,
|
||||
|
|
|
@ -224,7 +224,7 @@ SYSCALL_DEFINE4(request_key, const char __user *, _type,
|
|||
}
|
||||
|
||||
/* do the search */
|
||||
key = request_key_and_link(ktype, description, callout_info,
|
||||
key = request_key_and_link(ktype, description, NULL, callout_info,
|
||||
callout_len, NULL, key_ref_to_ptr(dest_ref),
|
||||
KEY_ALLOC_IN_QUOTA);
|
||||
if (IS_ERR(key)) {
|
||||
|
|
|
@ -222,10 +222,13 @@ void key_set_index_key(struct keyring_index_key *index_key)
|
|||
|
||||
memcpy(index_key->desc, index_key->description, n);
|
||||
|
||||
if (!index_key->domain_tag) {
|
||||
if (index_key->type->flags & KEY_TYPE_NET_DOMAIN)
|
||||
index_key->domain_tag = current->nsproxy->net_ns->key_domain;
|
||||
else
|
||||
index_key->domain_tag = &default_domain_tag;
|
||||
}
|
||||
|
||||
hash_key_type_and_desc(index_key);
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <linux/err.h>
|
||||
#include <linux/keyctl.h>
|
||||
#include <linux/slab.h>
|
||||
#include <net/net_namespace.h>
|
||||
#include "internal.h"
|
||||
#include <keys/request_key_auth-type.h>
|
||||
|
||||
|
@ -533,16 +534,18 @@ error:
|
|||
* request_key_and_link - Request a key and cache it in a keyring.
|
||||
* @type: The type of key we want.
|
||||
* @description: The searchable description of the key.
|
||||
* @domain_tag: The domain in which the key operates.
|
||||
* @callout_info: The data to pass to the instantiation upcall (or NULL).
|
||||
* @callout_len: The length of callout_info.
|
||||
* @aux: Auxiliary data for the upcall.
|
||||
* @dest_keyring: Where to cache the key.
|
||||
* @flags: Flags to key_alloc().
|
||||
*
|
||||
* A key matching the specified criteria is searched for in the process's
|
||||
* keyrings and returned with its usage count incremented if found. Otherwise,
|
||||
* if callout_info is not NULL, a key will be allocated and some service
|
||||
* (probably in userspace) will be asked to instantiate it.
|
||||
* A key matching the specified criteria (type, description, domain_tag) is
|
||||
* searched for in the process's keyrings and returned with its usage count
|
||||
* incremented if found. Otherwise, if callout_info is not NULL, a key will be
|
||||
* allocated and some service (probably in userspace) will be asked to
|
||||
* instantiate it.
|
||||
*
|
||||
* If successfully found or created, the key will be linked to the destination
|
||||
* keyring if one is provided.
|
||||
|
@ -558,6 +561,7 @@ error:
|
|||
*/
|
||||
struct key *request_key_and_link(struct key_type *type,
|
||||
const char *description,
|
||||
struct key_tag *domain_tag,
|
||||
const void *callout_info,
|
||||
size_t callout_len,
|
||||
void *aux,
|
||||
|
@ -566,6 +570,7 @@ struct key *request_key_and_link(struct key_type *type,
|
|||
{
|
||||
struct keyring_search_context ctx = {
|
||||
.index_key.type = type,
|
||||
.index_key.domain_tag = domain_tag,
|
||||
.index_key.description = description,
|
||||
.index_key.desc_len = strlen(description),
|
||||
.cred = current_cred(),
|
||||
|
@ -672,9 +677,10 @@ int wait_for_key_construction(struct key *key, bool intr)
|
|||
EXPORT_SYMBOL(wait_for_key_construction);
|
||||
|
||||
/**
|
||||
* request_key - Request a key and wait for construction
|
||||
* request_key_tag - Request a key and wait for construction
|
||||
* @type: Type of key.
|
||||
* @description: The searchable description of the key.
|
||||
* @domain_tag: The domain in which the key operates.
|
||||
* @callout_info: The data to pass to the instantiation upcall (or NULL).
|
||||
*
|
||||
* As for request_key_and_link() except that it does not add the returned key
|
||||
|
@ -685,8 +691,9 @@ EXPORT_SYMBOL(wait_for_key_construction);
|
|||
* Furthermore, it then works as wait_for_key_construction() to wait for the
|
||||
* completion of keys undergoing construction with a non-interruptible wait.
|
||||
*/
|
||||
struct key *request_key(struct key_type *type,
|
||||
struct key *request_key_tag(struct key_type *type,
|
||||
const char *description,
|
||||
struct key_tag *domain_tag,
|
||||
const char *callout_info)
|
||||
{
|
||||
struct key *key;
|
||||
|
@ -695,7 +702,8 @@ struct key *request_key(struct key_type *type,
|
|||
|
||||
if (callout_info)
|
||||
callout_len = strlen(callout_info);
|
||||
key = request_key_and_link(type, description, callout_info, callout_len,
|
||||
key = request_key_and_link(type, description, domain_tag,
|
||||
callout_info, callout_len,
|
||||
NULL, NULL, KEY_ALLOC_IN_QUOTA);
|
||||
if (!IS_ERR(key)) {
|
||||
ret = wait_for_key_construction(key, false);
|
||||
|
@ -706,12 +714,13 @@ struct key *request_key(struct key_type *type,
|
|||
}
|
||||
return key;
|
||||
}
|
||||
EXPORT_SYMBOL(request_key);
|
||||
EXPORT_SYMBOL(request_key_tag);
|
||||
|
||||
/**
|
||||
* request_key_with_auxdata - Request a key with auxiliary data for the upcaller
|
||||
* @type: The type of key we want.
|
||||
* @description: The searchable description of the key.
|
||||
* @domain_tag: The domain in which the key operates.
|
||||
* @callout_info: The data to pass to the instantiation upcall (or NULL).
|
||||
* @callout_len: The length of callout_info.
|
||||
* @aux: Auxiliary data for the upcall.
|
||||
|
@ -724,6 +733,7 @@ EXPORT_SYMBOL(request_key);
|
|||
*/
|
||||
struct key *request_key_with_auxdata(struct key_type *type,
|
||||
const char *description,
|
||||
struct key_tag *domain_tag,
|
||||
const void *callout_info,
|
||||
size_t callout_len,
|
||||
void *aux)
|
||||
|
@ -731,7 +741,8 @@ struct key *request_key_with_auxdata(struct key_type *type,
|
|||
struct key *key;
|
||||
int ret;
|
||||
|
||||
key = request_key_and_link(type, description, callout_info, callout_len,
|
||||
key = request_key_and_link(type, description, domain_tag,
|
||||
callout_info, callout_len,
|
||||
aux, NULL, KEY_ALLOC_IN_QUOTA);
|
||||
if (!IS_ERR(key)) {
|
||||
ret = wait_for_key_construction(key, false);
|
||||
|
@ -748,6 +759,7 @@ EXPORT_SYMBOL(request_key_with_auxdata);
|
|||
* request_key_rcu - Request key from RCU-read-locked context
|
||||
* @type: The type of key we want.
|
||||
* @description: The name of the key we want.
|
||||
* @domain_tag: The domain in which the key operates.
|
||||
*
|
||||
* Request a key from a context that we may not sleep in (such as RCU-mode
|
||||
* pathwalk). Keys under construction are ignored.
|
||||
|
@ -755,10 +767,13 @@ EXPORT_SYMBOL(request_key_with_auxdata);
|
|||
* Return a pointer to the found key if successful, -ENOKEY if we couldn't find
|
||||
* a key or some other error if the key found was unsuitable or inaccessible.
|
||||
*/
|
||||
struct key *request_key_rcu(struct key_type *type, const char *description)
|
||||
struct key *request_key_rcu(struct key_type *type,
|
||||
const char *description,
|
||||
struct key_tag *domain_tag)
|
||||
{
|
||||
struct keyring_search_context ctx = {
|
||||
.index_key.type = type,
|
||||
.index_key.domain_tag = domain_tag,
|
||||
.index_key.description = description,
|
||||
.index_key.desc_len = strlen(description),
|
||||
.cred = current_cred(),
|
||||
|
|
Загрузка…
Ссылка в новой задаче