Showing error 1902

User: Jiri Slaby
Error type: Invalid Pointer Dereference
Error type description: A pointer which is invalid is being dereferenced
File location: net/sunrpc/auth_unix.c
Line in file: 130
Project: Linux Kernel
Project version: 2.6.28
Tools: Smatch (1.59)
Entered: 2013-09-11 08:47:26 UTC


Source:

  1/*
  2 * linux/net/sunrpc/auth_unix.c
  3 *
  4 * UNIX-style authentication; no AUTH_SHORT support
  5 *
  6 * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
  7 */
  8
  9#include <linux/types.h>
 10#include <linux/sched.h>
 11#include <linux/module.h>
 12#include <linux/sunrpc/clnt.h>
 13#include <linux/sunrpc/auth.h>
 14
 15#define NFS_NGROUPS        16
 16
 17struct unx_cred {
 18        struct rpc_cred                uc_base;
 19        gid_t                        uc_gid;
 20        gid_t                        uc_gids[NFS_NGROUPS];
 21};
 22#define uc_uid                        uc_base.cr_uid
 23
 24#define UNX_WRITESLACK                (21 + (UNX_MAXNODENAME >> 2))
 25
 26#ifdef RPC_DEBUG
 27# define RPCDBG_FACILITY        RPCDBG_AUTH
 28#endif
 29
 30static struct rpc_auth                unix_auth;
 31static struct rpc_cred_cache        unix_cred_cache;
 32static const struct rpc_credops        unix_credops;
 33
 34static struct rpc_auth *
 35unx_create(struct rpc_clnt *clnt, rpc_authflavor_t flavor)
 36{
 37        dprintk("RPC:       creating UNIX authenticator for client %p\n",
 38                        clnt);
 39        atomic_inc(&unix_auth.au_count);
 40        return &unix_auth;
 41}
 42
 43static void
 44unx_destroy(struct rpc_auth *auth)
 45{
 46        dprintk("RPC:       destroying UNIX authenticator %p\n", auth);
 47        rpcauth_clear_credcache(auth->au_credcache);
 48}
 49
 50/*
 51 * Lookup AUTH_UNIX creds for current process
 52 */
 53static struct rpc_cred *
 54unx_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
 55{
 56        return rpcauth_lookup_credcache(auth, acred, flags);
 57}
 58
 59static struct rpc_cred *
 60unx_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
 61{
 62        struct unx_cred        *cred;
 63        unsigned int groups = 0;
 64        unsigned int i;
 65
 66        dprintk("RPC:       allocating UNIX cred for uid %d gid %d\n",
 67                        acred->uid, acred->gid);
 68
 69        if (!(cred = kmalloc(sizeof(*cred), GFP_NOFS)))
 70                return ERR_PTR(-ENOMEM);
 71
 72        rpcauth_init_cred(&cred->uc_base, acred, auth, &unix_credops);
 73        cred->uc_base.cr_flags = 1UL << RPCAUTH_CRED_UPTODATE;
 74
 75        if (acred->group_info != NULL)
 76                groups = acred->group_info->ngroups;
 77        if (groups > NFS_NGROUPS)
 78                groups = NFS_NGROUPS;
 79
 80        cred->uc_gid = acred->gid;
 81        for (i = 0; i < groups; i++)
 82                cred->uc_gids[i] = GROUP_AT(acred->group_info, i);
 83        if (i < NFS_NGROUPS)
 84                cred->uc_gids[i] = NOGROUP;
 85
 86        return &cred->uc_base;
 87}
 88
 89static void
 90unx_free_cred(struct unx_cred *unx_cred)
 91{
 92        dprintk("RPC:       unx_free_cred %p\n", unx_cred);
 93        kfree(unx_cred);
 94}
 95
 96static void
 97unx_free_cred_callback(struct rcu_head *head)
 98{
 99        struct unx_cred *unx_cred = container_of(head, struct unx_cred, uc_base.cr_rcu);
100        unx_free_cred(unx_cred);
101}
102
103static void
104unx_destroy_cred(struct rpc_cred *cred)
105{
106        call_rcu(&cred->cr_rcu, unx_free_cred_callback);
107}
108
109/*
110 * Match credentials against current process creds.
111 * The root_override argument takes care of cases where the caller may
112 * request root creds (e.g. for NFS swapping).
113 */
114static int
115unx_match(struct auth_cred *acred, struct rpc_cred *rcred, int flags)
116{
117        struct unx_cred        *cred = container_of(rcred, struct unx_cred, uc_base);
118        unsigned int groups = 0;
119        unsigned int i;
120
121
122        if (cred->uc_uid != acred->uid || cred->uc_gid != acred->gid)
123                return 0;
124
125        if (acred->group_info != NULL)
126                groups = acred->group_info->ngroups;
127        if (groups > NFS_NGROUPS)
128                groups = NFS_NGROUPS;
129        for (i = 0; i < groups ; i++)
130                if (cred->uc_gids[i] != GROUP_AT(acred->group_info, i))
131                        return 0;
132        return 1;
133}
134
135/*
136 * Marshal credentials.
137 * Maybe we should keep a cached credential for performance reasons.
138 */
139static __be32 *
140unx_marshal(struct rpc_task *task, __be32 *p)
141{
142        struct rpc_clnt        *clnt = task->tk_client;
143        struct unx_cred        *cred = container_of(task->tk_msg.rpc_cred, struct unx_cred, uc_base);
144        __be32                *base, *hold;
145        int                i;
146
147        *p++ = htonl(RPC_AUTH_UNIX);
148        base = p++;
149        *p++ = htonl(jiffies/HZ);
150
151        /*
152         * Copy the UTS nodename captured when the client was created.
153         */
154        p = xdr_encode_array(p, clnt->cl_nodename, clnt->cl_nodelen);
155
156        *p++ = htonl((u32) cred->uc_uid);
157        *p++ = htonl((u32) cred->uc_gid);
158        hold = p++;
159        for (i = 0; i < 16 && cred->uc_gids[i] != (gid_t) NOGROUP; i++)
160                *p++ = htonl((u32) cred->uc_gids[i]);
161        *hold = htonl(p - hold - 1);                /* gid array length */
162        *base = htonl((p - base - 1) << 2);        /* cred length */
163
164        *p++ = htonl(RPC_AUTH_NULL);
165        *p++ = htonl(0);
166
167        return p;
168}
169
170/*
171 * Refresh credentials. This is a no-op for AUTH_UNIX
172 */
173static int
174unx_refresh(struct rpc_task *task)
175{
176        set_bit(RPCAUTH_CRED_UPTODATE, &task->tk_msg.rpc_cred->cr_flags);
177        return 0;
178}
179
180static __be32 *
181unx_validate(struct rpc_task *task, __be32 *p)
182{
183        rpc_authflavor_t        flavor;
184        u32                        size;
185
186        flavor = ntohl(*p++);
187        if (flavor != RPC_AUTH_NULL &&
188            flavor != RPC_AUTH_UNIX &&
189            flavor != RPC_AUTH_SHORT) {
190                printk("RPC: bad verf flavor: %u\n", flavor);
191                return NULL;
192        }
193
194        size = ntohl(*p++);
195        if (size > RPC_MAX_AUTH_SIZE) {
196                printk("RPC: giant verf size: %u\n", size);
197                return NULL;
198        }
199        task->tk_msg.rpc_cred->cr_auth->au_rslack = (size >> 2) + 2;
200        p += (size >> 2);
201
202        return p;
203}
204
205void __init rpc_init_authunix(void)
206{
207        spin_lock_init(&unix_cred_cache.lock);
208}
209
210const struct rpc_authops authunix_ops = {
211        .owner                = THIS_MODULE,
212        .au_flavor        = RPC_AUTH_UNIX,
213        .au_name        = "UNIX",
214        .create                = unx_create,
215        .destroy        = unx_destroy,
216        .lookup_cred        = unx_lookup_cred,
217        .crcreate        = unx_create_cred,
218};
219
220static
221struct rpc_cred_cache        unix_cred_cache = {
222};
223
224static
225struct rpc_auth                unix_auth = {
226        .au_cslack        = UNX_WRITESLACK,
227        .au_rslack        = 2,                        /* assume AUTH_NULL verf */
228        .au_ops                = &authunix_ops,
229        .au_flavor        = RPC_AUTH_UNIX,
230        .au_count        = ATOMIC_INIT(0),
231        .au_credcache        = &unix_cred_cache,
232};
233
234static
235const struct rpc_credops unix_credops = {
236        .cr_name        = "AUTH_UNIX",
237        .crdestroy        = unx_destroy_cred,
238        .crbind                = rpcauth_generic_bind_cred,
239        .crmatch        = unx_match,
240        .crmarshal        = unx_marshal,
241        .crrefresh        = unx_refresh,
242        .crvalidate        = unx_validate,
243};