mirror of
https://github.com/torvalds/linux.git
synced 2026-05-31 02:24:24 +02:00
NFSD: Add a key for signing filehandles
A future patch will enable NFSD to sign filehandles by appending a Message Authentication Code(MAC). To do this, NFSD requires a secret 128-bit key that can persist across reboots. A persisted key allows the server to accept filehandles after a restart. Enable NFSD to be configured with this key via the netlink interface. Link: https://lore.kernel.org/linux-nfs/cover.1772022373.git.bcodding@hammerspace.com Signed-off-by: Benjamin Coddington <bcodding@hammerspace.com> Reviewed-by: Jeff Layton <jlayton@kernel.org> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
This commit is contained in:
parent
116b6b7acd
commit
62346217fd
|
|
@ -81,6 +81,11 @@ attribute-sets:
|
||||||
-
|
-
|
||||||
name: min-threads
|
name: min-threads
|
||||||
type: u32
|
type: u32
|
||||||
|
-
|
||||||
|
name: fh-key
|
||||||
|
type: binary
|
||||||
|
checks:
|
||||||
|
exact-len: 16
|
||||||
-
|
-
|
||||||
name: version
|
name: version
|
||||||
attributes:
|
attributes:
|
||||||
|
|
@ -163,6 +168,7 @@ operations:
|
||||||
- leasetime
|
- leasetime
|
||||||
- scope
|
- scope
|
||||||
- min-threads
|
- min-threads
|
||||||
|
- fh-key
|
||||||
-
|
-
|
||||||
name: threads-get
|
name: threads-get
|
||||||
doc: get the maximum number of running threads
|
doc: get the maximum number of running threads
|
||||||
|
|
|
||||||
|
|
@ -24,12 +24,13 @@ const struct nla_policy nfsd_version_nl_policy[NFSD_A_VERSION_ENABLED + 1] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
/* NFSD_CMD_THREADS_SET - do */
|
/* NFSD_CMD_THREADS_SET - do */
|
||||||
static const struct nla_policy nfsd_threads_set_nl_policy[NFSD_A_SERVER_MIN_THREADS + 1] = {
|
static const struct nla_policy nfsd_threads_set_nl_policy[NFSD_A_SERVER_FH_KEY + 1] = {
|
||||||
[NFSD_A_SERVER_THREADS] = { .type = NLA_U32, },
|
[NFSD_A_SERVER_THREADS] = { .type = NLA_U32, },
|
||||||
[NFSD_A_SERVER_GRACETIME] = { .type = NLA_U32, },
|
[NFSD_A_SERVER_GRACETIME] = { .type = NLA_U32, },
|
||||||
[NFSD_A_SERVER_LEASETIME] = { .type = NLA_U32, },
|
[NFSD_A_SERVER_LEASETIME] = { .type = NLA_U32, },
|
||||||
[NFSD_A_SERVER_SCOPE] = { .type = NLA_NUL_STRING, },
|
[NFSD_A_SERVER_SCOPE] = { .type = NLA_NUL_STRING, },
|
||||||
[NFSD_A_SERVER_MIN_THREADS] = { .type = NLA_U32, },
|
[NFSD_A_SERVER_MIN_THREADS] = { .type = NLA_U32, },
|
||||||
|
[NFSD_A_SERVER_FH_KEY] = NLA_POLICY_EXACT_LEN(16),
|
||||||
};
|
};
|
||||||
|
|
||||||
/* NFSD_CMD_VERSION_SET - do */
|
/* NFSD_CMD_VERSION_SET - do */
|
||||||
|
|
@ -58,7 +59,7 @@ static const struct genl_split_ops nfsd_nl_ops[] = {
|
||||||
.cmd = NFSD_CMD_THREADS_SET,
|
.cmd = NFSD_CMD_THREADS_SET,
|
||||||
.doit = nfsd_nl_threads_set_doit,
|
.doit = nfsd_nl_threads_set_doit,
|
||||||
.policy = nfsd_threads_set_nl_policy,
|
.policy = nfsd_threads_set_nl_policy,
|
||||||
.maxattr = NFSD_A_SERVER_MIN_THREADS,
|
.maxattr = NFSD_A_SERVER_FH_KEY,
|
||||||
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
|
.flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -227,6 +227,7 @@ struct nfsd_net {
|
||||||
spinlock_t local_clients_lock;
|
spinlock_t local_clients_lock;
|
||||||
struct list_head local_clients;
|
struct list_head local_clients;
|
||||||
#endif
|
#endif
|
||||||
|
siphash_key_t *fh_key;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Simple check to find out if a given net was properly initialized */
|
/* Simple check to find out if a given net was properly initialized */
|
||||||
|
|
|
||||||
|
|
@ -1581,6 +1581,32 @@ int nfsd_nl_rpc_status_get_dumpit(struct sk_buff *skb,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* nfsd_nl_fh_key_set - helper to copy fh_key from userspace
|
||||||
|
* @attr: nlattr NFSD_A_SERVER_FH_KEY
|
||||||
|
* @nn: nfsd_net
|
||||||
|
*
|
||||||
|
* Callers should hold nfsd_mutex, returns 0 on success or negative errno.
|
||||||
|
* Callers must ensure the server is shut down (sv_nrthreads == 0),
|
||||||
|
* userspace documentation asserts the key may only be set when the server
|
||||||
|
* is not running.
|
||||||
|
*/
|
||||||
|
static int nfsd_nl_fh_key_set(const struct nlattr *attr, struct nfsd_net *nn)
|
||||||
|
{
|
||||||
|
siphash_key_t *fh_key = nn->fh_key;
|
||||||
|
|
||||||
|
if (!fh_key) {
|
||||||
|
fh_key = kmalloc(sizeof(siphash_key_t), GFP_KERNEL);
|
||||||
|
if (!fh_key)
|
||||||
|
return -ENOMEM;
|
||||||
|
nn->fh_key = fh_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
fh_key->key[0] = get_unaligned_le64(nla_data(attr));
|
||||||
|
fh_key->key[1] = get_unaligned_le64(nla_data(attr) + 8);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* nfsd_nl_threads_set_doit - set the number of running threads
|
* nfsd_nl_threads_set_doit - set the number of running threads
|
||||||
* @skb: reply buffer
|
* @skb: reply buffer
|
||||||
|
|
@ -1622,7 +1648,8 @@ int nfsd_nl_threads_set_doit(struct sk_buff *skb, struct genl_info *info)
|
||||||
|
|
||||||
if (info->attrs[NFSD_A_SERVER_GRACETIME] ||
|
if (info->attrs[NFSD_A_SERVER_GRACETIME] ||
|
||||||
info->attrs[NFSD_A_SERVER_LEASETIME] ||
|
info->attrs[NFSD_A_SERVER_LEASETIME] ||
|
||||||
info->attrs[NFSD_A_SERVER_SCOPE]) {
|
info->attrs[NFSD_A_SERVER_SCOPE] ||
|
||||||
|
info->attrs[NFSD_A_SERVER_FH_KEY]) {
|
||||||
ret = -EBUSY;
|
ret = -EBUSY;
|
||||||
if (nn->nfsd_serv && nn->nfsd_serv->sv_nrthreads)
|
if (nn->nfsd_serv && nn->nfsd_serv->sv_nrthreads)
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
|
|
@ -1651,6 +1678,14 @@ int nfsd_nl_threads_set_doit(struct sk_buff *skb, struct genl_info *info)
|
||||||
attr = info->attrs[NFSD_A_SERVER_SCOPE];
|
attr = info->attrs[NFSD_A_SERVER_SCOPE];
|
||||||
if (attr)
|
if (attr)
|
||||||
scope = nla_data(attr);
|
scope = nla_data(attr);
|
||||||
|
|
||||||
|
attr = info->attrs[NFSD_A_SERVER_FH_KEY];
|
||||||
|
if (attr) {
|
||||||
|
ret = nfsd_nl_fh_key_set(attr, nn);
|
||||||
|
trace_nfsd_ctl_fh_key_set((const char *)nn->fh_key, ret);
|
||||||
|
if (ret)
|
||||||
|
goto out_unlock;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
attr = info->attrs[NFSD_A_SERVER_MIN_THREADS];
|
attr = info->attrs[NFSD_A_SERVER_MIN_THREADS];
|
||||||
|
|
@ -2237,6 +2272,7 @@ static __net_exit void nfsd_net_exit(struct net *net)
|
||||||
{
|
{
|
||||||
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
|
||||||
|
|
||||||
|
kfree_sensitive(nn->fh_key);
|
||||||
nfsd_proc_stat_shutdown(net);
|
nfsd_proc_stat_shutdown(net);
|
||||||
percpu_counter_destroy_many(nn->counter, NFSD_STATS_COUNTERS_NUM);
|
percpu_counter_destroy_many(nn->counter, NFSD_STATS_COUNTERS_NUM);
|
||||||
nfsd_idmap_shutdown(net);
|
nfsd_idmap_shutdown(net);
|
||||||
|
|
|
||||||
|
|
@ -2240,6 +2240,28 @@ TRACE_EVENT(nfsd_end_grace,
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
TRACE_EVENT(nfsd_ctl_fh_key_set,
|
||||||
|
TP_PROTO(
|
||||||
|
const char *key,
|
||||||
|
int result
|
||||||
|
),
|
||||||
|
TP_ARGS(key, result),
|
||||||
|
TP_STRUCT__entry(
|
||||||
|
__field(u32, key_hash)
|
||||||
|
__field(int, result)
|
||||||
|
),
|
||||||
|
TP_fast_assign(
|
||||||
|
if (key)
|
||||||
|
__entry->key_hash = ~crc32_le(0xFFFFFFFF, key, 16);
|
||||||
|
else
|
||||||
|
__entry->key_hash = 0;
|
||||||
|
__entry->result = result;
|
||||||
|
),
|
||||||
|
TP_printk("key=0x%08x result=%d",
|
||||||
|
__entry->key_hash, __entry->result
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
DECLARE_EVENT_CLASS(nfsd_copy_class,
|
DECLARE_EVENT_CLASS(nfsd_copy_class,
|
||||||
TP_PROTO(
|
TP_PROTO(
|
||||||
const struct nfsd4_copy *copy
|
const struct nfsd4_copy *copy
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ enum {
|
||||||
NFSD_A_SERVER_LEASETIME,
|
NFSD_A_SERVER_LEASETIME,
|
||||||
NFSD_A_SERVER_SCOPE,
|
NFSD_A_SERVER_SCOPE,
|
||||||
NFSD_A_SERVER_MIN_THREADS,
|
NFSD_A_SERVER_MIN_THREADS,
|
||||||
|
NFSD_A_SERVER_FH_KEY,
|
||||||
|
|
||||||
__NFSD_A_SERVER_MAX,
|
__NFSD_A_SERVER_MAX,
|
||||||
NFSD_A_SERVER_MAX = (__NFSD_A_SERVER_MAX - 1)
|
NFSD_A_SERVER_MAX = (__NFSD_A_SERVER_MAX - 1)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user