cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

auth_unix.c (5608B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * linux/net/sunrpc/auth_unix.c
      4 *
      5 * UNIX-style authentication; no AUTH_SHORT support
      6 *
      7 * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
      8 */
      9
     10#include <linux/slab.h>
     11#include <linux/types.h>
     12#include <linux/sched.h>
     13#include <linux/module.h>
     14#include <linux/mempool.h>
     15#include <linux/sunrpc/clnt.h>
     16#include <linux/sunrpc/auth.h>
     17#include <linux/user_namespace.h>
     18
     19
     20#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
     21# define RPCDBG_FACILITY	RPCDBG_AUTH
     22#endif
     23
     24static struct rpc_auth		unix_auth;
     25static const struct rpc_credops	unix_credops;
     26static mempool_t		*unix_pool;
     27
     28static struct rpc_auth *
     29unx_create(const struct rpc_auth_create_args *args, struct rpc_clnt *clnt)
     30{
     31	refcount_inc(&unix_auth.au_count);
     32	return &unix_auth;
     33}
     34
     35static void
     36unx_destroy(struct rpc_auth *auth)
     37{
     38}
     39
     40/*
     41 * Lookup AUTH_UNIX creds for current process
     42 */
     43static struct rpc_cred *unx_lookup_cred(struct rpc_auth *auth,
     44					struct auth_cred *acred, int flags)
     45{
     46	struct rpc_cred *ret;
     47
     48	ret = kmalloc(sizeof(*ret), rpc_task_gfp_mask());
     49	if (!ret) {
     50		if (!(flags & RPCAUTH_LOOKUP_ASYNC))
     51			return ERR_PTR(-ENOMEM);
     52		ret = mempool_alloc(unix_pool, GFP_NOWAIT);
     53		if (!ret)
     54			return ERR_PTR(-ENOMEM);
     55	}
     56	rpcauth_init_cred(ret, acred, auth, &unix_credops);
     57	ret->cr_flags = 1UL << RPCAUTH_CRED_UPTODATE;
     58	return ret;
     59}
     60
     61static void
     62unx_free_cred_callback(struct rcu_head *head)
     63{
     64	struct rpc_cred *rpc_cred = container_of(head, struct rpc_cred, cr_rcu);
     65
     66	put_cred(rpc_cred->cr_cred);
     67	mempool_free(rpc_cred, unix_pool);
     68}
     69
     70static void
     71unx_destroy_cred(struct rpc_cred *cred)
     72{
     73	call_rcu(&cred->cr_rcu, unx_free_cred_callback);
     74}
     75
     76/*
     77 * Match credentials against current the auth_cred.
     78 */
     79static int
     80unx_match(struct auth_cred *acred, struct rpc_cred *cred, int flags)
     81{
     82	unsigned int groups = 0;
     83	unsigned int i;
     84
     85	if (cred->cr_cred == acred->cred)
     86		return 1;
     87
     88	if (!uid_eq(cred->cr_cred->fsuid, acred->cred->fsuid) || !gid_eq(cred->cr_cred->fsgid, acred->cred->fsgid))
     89		return 0;
     90
     91	if (acred->cred->group_info != NULL)
     92		groups = acred->cred->group_info->ngroups;
     93	if (groups > UNX_NGROUPS)
     94		groups = UNX_NGROUPS;
     95	if (cred->cr_cred->group_info == NULL)
     96		return groups == 0;
     97	if (groups != cred->cr_cred->group_info->ngroups)
     98		return 0;
     99
    100	for (i = 0; i < groups ; i++)
    101		if (!gid_eq(cred->cr_cred->group_info->gid[i], acred->cred->group_info->gid[i]))
    102			return 0;
    103	return 1;
    104}
    105
    106/*
    107 * Marshal credentials.
    108 * Maybe we should keep a cached credential for performance reasons.
    109 */
    110static int
    111unx_marshal(struct rpc_task *task, struct xdr_stream *xdr)
    112{
    113	struct rpc_clnt	*clnt = task->tk_client;
    114	struct rpc_cred	*cred = task->tk_rqstp->rq_cred;
    115	__be32		*p, *cred_len, *gidarr_len;
    116	int		i;
    117	struct group_info *gi = cred->cr_cred->group_info;
    118	struct user_namespace *userns = clnt->cl_cred ?
    119		clnt->cl_cred->user_ns : &init_user_ns;
    120
    121	/* Credential */
    122
    123	p = xdr_reserve_space(xdr, 3 * sizeof(*p));
    124	if (!p)
    125		goto marshal_failed;
    126	*p++ = rpc_auth_unix;
    127	cred_len = p++;
    128	*p++ = xdr_zero;	/* stamp */
    129	if (xdr_stream_encode_opaque(xdr, clnt->cl_nodename,
    130				     clnt->cl_nodelen) < 0)
    131		goto marshal_failed;
    132	p = xdr_reserve_space(xdr, 3 * sizeof(*p));
    133	if (!p)
    134		goto marshal_failed;
    135	*p++ = cpu_to_be32(from_kuid_munged(userns, cred->cr_cred->fsuid));
    136	*p++ = cpu_to_be32(from_kgid_munged(userns, cred->cr_cred->fsgid));
    137
    138	gidarr_len = p++;
    139	if (gi)
    140		for (i = 0; i < UNX_NGROUPS && i < gi->ngroups; i++)
    141			*p++ = cpu_to_be32(from_kgid_munged(userns, gi->gid[i]));
    142	*gidarr_len = cpu_to_be32(p - gidarr_len - 1);
    143	*cred_len = cpu_to_be32((p - cred_len - 1) << 2);
    144	p = xdr_reserve_space(xdr, (p - gidarr_len - 1) << 2);
    145	if (!p)
    146		goto marshal_failed;
    147
    148	/* Verifier */
    149
    150	p = xdr_reserve_space(xdr, 2 * sizeof(*p));
    151	if (!p)
    152		goto marshal_failed;
    153	*p++ = rpc_auth_null;
    154	*p   = xdr_zero;
    155
    156	return 0;
    157
    158marshal_failed:
    159	return -EMSGSIZE;
    160}
    161
    162/*
    163 * Refresh credentials. This is a no-op for AUTH_UNIX
    164 */
    165static int
    166unx_refresh(struct rpc_task *task)
    167{
    168	set_bit(RPCAUTH_CRED_UPTODATE, &task->tk_rqstp->rq_cred->cr_flags);
    169	return 0;
    170}
    171
    172static int
    173unx_validate(struct rpc_task *task, struct xdr_stream *xdr)
    174{
    175	struct rpc_auth *auth = task->tk_rqstp->rq_cred->cr_auth;
    176	__be32 *p;
    177	u32 size;
    178
    179	p = xdr_inline_decode(xdr, 2 * sizeof(*p));
    180	if (!p)
    181		return -EIO;
    182	switch (*p++) {
    183	case rpc_auth_null:
    184	case rpc_auth_unix:
    185	case rpc_auth_short:
    186		break;
    187	default:
    188		return -EIO;
    189	}
    190	size = be32_to_cpup(p);
    191	if (size > RPC_MAX_AUTH_SIZE)
    192		return -EIO;
    193	p = xdr_inline_decode(xdr, size);
    194	if (!p)
    195		return -EIO;
    196
    197	auth->au_verfsize = XDR_QUADLEN(size) + 2;
    198	auth->au_rslack = XDR_QUADLEN(size) + 2;
    199	auth->au_ralign = XDR_QUADLEN(size) + 2;
    200	return 0;
    201}
    202
    203int __init rpc_init_authunix(void)
    204{
    205	unix_pool = mempool_create_kmalloc_pool(16, sizeof(struct rpc_cred));
    206	return unix_pool ? 0 : -ENOMEM;
    207}
    208
    209void rpc_destroy_authunix(void)
    210{
    211	mempool_destroy(unix_pool);
    212}
    213
    214const struct rpc_authops authunix_ops = {
    215	.owner		= THIS_MODULE,
    216	.au_flavor	= RPC_AUTH_UNIX,
    217	.au_name	= "UNIX",
    218	.create		= unx_create,
    219	.destroy	= unx_destroy,
    220	.lookup_cred	= unx_lookup_cred,
    221};
    222
    223static
    224struct rpc_auth		unix_auth = {
    225	.au_cslack	= UNX_CALLSLACK,
    226	.au_rslack	= NUL_REPLYSLACK,
    227	.au_verfsize	= NUL_REPLYSLACK,
    228	.au_ops		= &authunix_ops,
    229	.au_flavor	= RPC_AUTH_UNIX,
    230	.au_count	= REFCOUNT_INIT(1),
    231};
    232
    233static
    234const struct rpc_credops unix_credops = {
    235	.cr_name	= "AUTH_UNIX",
    236	.crdestroy	= unx_destroy_cred,
    237	.crmatch	= unx_match,
    238	.crmarshal	= unx_marshal,
    239	.crwrap_req	= rpcauth_wrap_req_encode,
    240	.crrefresh	= unx_refresh,
    241	.crvalidate	= unx_validate,
    242	.crunwrap_resp	= rpcauth_unwrap_resp_decode,
    243};