linux/fs/lockd/xdr.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * linux/fs/lockd/xdr.c
   4 *
   5 * XDR support for lockd and the lock client.
   6 *
   7 * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
   8 */
   9
  10#include <linux/types.h>
  11#include <linux/sched.h>
  12#include <linux/nfs.h>
  13
  14#include <linux/sunrpc/xdr.h>
  15#include <linux/sunrpc/clnt.h>
  16#include <linux/sunrpc/svc.h>
  17#include <linux/sunrpc/stats.h>
  18#include <linux/lockd/lockd.h>
  19
  20#include <uapi/linux/nfs2.h>
  21
  22#include "svcxdr.h"
  23
  24
  25static inline loff_t
  26s32_to_loff_t(__s32 offset)
  27{
  28        return (loff_t)offset;
  29}
  30
  31static inline __s32
  32loff_t_to_s32(loff_t offset)
  33{
  34        __s32 res;
  35        if (offset >= NLM_OFFSET_MAX)
  36                res = NLM_OFFSET_MAX;
  37        else if (offset <= -NLM_OFFSET_MAX)
  38                res = -NLM_OFFSET_MAX;
  39        else
  40                res = offset;
  41        return res;
  42}
  43
  44/*
  45 * NLM file handles are defined by specification to be a variable-length
  46 * XDR opaque no longer than 1024 bytes. However, this implementation
  47 * constrains their length to exactly the length of an NFSv2 file
  48 * handle.
  49 */
  50static bool
  51svcxdr_decode_fhandle(struct xdr_stream *xdr, struct nfs_fh *fh)
  52{
  53        __be32 *p;
  54        u32 len;
  55
  56        if (xdr_stream_decode_u32(xdr, &len) < 0)
  57                return false;
  58        if (len != NFS2_FHSIZE)
  59                return false;
  60
  61        p = xdr_inline_decode(xdr, len);
  62        if (!p)
  63                return false;
  64        fh->size = NFS2_FHSIZE;
  65        memcpy(fh->data, p, len);
  66        memset(fh->data + NFS2_FHSIZE, 0, sizeof(fh->data) - NFS2_FHSIZE);
  67
  68        return true;
  69}
  70
  71static bool
  72svcxdr_decode_lock(struct xdr_stream *xdr, struct nlm_lock *lock)
  73{
  74        struct file_lock *fl = &lock->fl;
  75        s32 start, len, end;
  76
  77        if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len))
  78                return false;
  79        if (!svcxdr_decode_fhandle(xdr, &lock->fh))
  80                return false;
  81        if (!svcxdr_decode_owner(xdr, &lock->oh))
  82                return false;
  83        if (xdr_stream_decode_u32(xdr, &lock->svid) < 0)
  84                return false;
  85        if (xdr_stream_decode_u32(xdr, &start) < 0)
  86                return false;
  87        if (xdr_stream_decode_u32(xdr, &len) < 0)
  88                return false;
  89
  90        locks_init_lock(fl);
  91        fl->fl_flags = FL_POSIX;
  92        fl->fl_type  = F_RDLCK;
  93        end = start + len - 1;
  94        fl->fl_start = s32_to_loff_t(start);
  95        if (len == 0 || end < 0)
  96                fl->fl_end = OFFSET_MAX;
  97        else
  98                fl->fl_end = s32_to_loff_t(end);
  99
 100        return true;
 101}
 102
 103static bool
 104svcxdr_encode_holder(struct xdr_stream *xdr, const struct nlm_lock *lock)
 105{
 106        const struct file_lock *fl = &lock->fl;
 107        s32 start, len;
 108
 109        /* exclusive */
 110        if (xdr_stream_encode_bool(xdr, fl->fl_type != F_RDLCK) < 0)
 111                return false;
 112        if (xdr_stream_encode_u32(xdr, lock->svid) < 0)
 113                return false;
 114        if (!svcxdr_encode_owner(xdr, &lock->oh))
 115                return false;
 116        start = loff_t_to_s32(fl->fl_start);
 117        if (fl->fl_end == OFFSET_MAX)
 118                len = 0;
 119        else
 120                len = loff_t_to_s32(fl->fl_end - fl->fl_start + 1);
 121        if (xdr_stream_encode_u32(xdr, start) < 0)
 122                return false;
 123        if (xdr_stream_encode_u32(xdr, len) < 0)
 124                return false;
 125
 126        return true;
 127}
 128
 129static bool
 130svcxdr_encode_testrply(struct xdr_stream *xdr, const struct nlm_res *resp)
 131{
 132        if (!svcxdr_encode_stats(xdr, resp->status))
 133                return false;
 134        switch (resp->status) {
 135        case nlm_lck_denied:
 136                if (!svcxdr_encode_holder(xdr, &resp->lock))
 137                        return false;
 138        }
 139
 140        return true;
 141}
 142
 143
 144/*
 145 * Decode Call arguments
 146 */
 147
 148int
 149nlmsvc_decode_void(struct svc_rqst *rqstp, __be32 *p)
 150{
 151        return 1;
 152}
 153
 154int
 155nlmsvc_decode_testargs(struct svc_rqst *rqstp, __be32 *p)
 156{
 157        struct xdr_stream *xdr = &rqstp->rq_arg_stream;
 158        struct nlm_args *argp = rqstp->rq_argp;
 159        u32 exclusive;
 160
 161        if (!svcxdr_decode_cookie(xdr, &argp->cookie))
 162                return 0;
 163        if (xdr_stream_decode_bool(xdr, &exclusive) < 0)
 164                return 0;
 165        if (!svcxdr_decode_lock(xdr, &argp->lock))
 166                return 0;
 167        if (exclusive)
 168                argp->lock.fl.fl_type = F_WRLCK;
 169
 170        return 1;
 171}
 172
 173int
 174nlmsvc_decode_lockargs(struct svc_rqst *rqstp, __be32 *p)
 175{
 176        struct xdr_stream *xdr = &rqstp->rq_arg_stream;
 177        struct nlm_args *argp = rqstp->rq_argp;
 178        u32 exclusive;
 179
 180        if (!svcxdr_decode_cookie(xdr, &argp->cookie))
 181                return 0;
 182        if (xdr_stream_decode_bool(xdr, &argp->block) < 0)
 183                return 0;
 184        if (xdr_stream_decode_bool(xdr, &exclusive) < 0)
 185                return 0;
 186        if (!svcxdr_decode_lock(xdr, &argp->lock))
 187                return 0;
 188        if (exclusive)
 189                argp->lock.fl.fl_type = F_WRLCK;
 190        if (xdr_stream_decode_bool(xdr, &argp->reclaim) < 0)
 191                return 0;
 192        if (xdr_stream_decode_u32(xdr, &argp->state) < 0)
 193                return 0;
 194        argp->monitor = 1;              /* monitor client by default */
 195
 196        return 1;
 197}
 198
 199int
 200nlmsvc_decode_cancargs(struct svc_rqst *rqstp, __be32 *p)
 201{
 202        struct xdr_stream *xdr = &rqstp->rq_arg_stream;
 203        struct nlm_args *argp = rqstp->rq_argp;
 204        u32 exclusive;
 205
 206        if (!svcxdr_decode_cookie(xdr, &argp->cookie))
 207                return 0;
 208        if (xdr_stream_decode_bool(xdr, &argp->block) < 0)
 209                return 0;
 210        if (xdr_stream_decode_bool(xdr, &exclusive) < 0)
 211                return 0;
 212        if (!svcxdr_decode_lock(xdr, &argp->lock))
 213                return 0;
 214        if (exclusive)
 215                argp->lock.fl.fl_type = F_WRLCK;
 216
 217        return 1;
 218}
 219
 220int
 221nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, __be32 *p)
 222{
 223        struct xdr_stream *xdr = &rqstp->rq_arg_stream;
 224        struct nlm_args *argp = rqstp->rq_argp;
 225
 226        if (!svcxdr_decode_cookie(xdr, &argp->cookie))
 227                return 0;
 228        if (!svcxdr_decode_lock(xdr, &argp->lock))
 229                return 0;
 230        argp->lock.fl.fl_type = F_UNLCK;
 231
 232        return 1;
 233}
 234
 235int
 236nlmsvc_decode_res(struct svc_rqst *rqstp, __be32 *p)
 237{
 238        struct xdr_stream *xdr = &rqstp->rq_arg_stream;
 239        struct nlm_res *resp = rqstp->rq_argp;
 240
 241        if (!svcxdr_decode_cookie(xdr, &resp->cookie))
 242                return 0;
 243        if (!svcxdr_decode_stats(xdr, &resp->status))
 244                return 0;
 245
 246        return 1;
 247}
 248
 249int
 250nlmsvc_decode_reboot(struct svc_rqst *rqstp, __be32 *p)
 251{
 252        struct xdr_stream *xdr = &rqstp->rq_arg_stream;
 253        struct nlm_reboot *argp = rqstp->rq_argp;
 254        u32 len;
 255
 256        if (xdr_stream_decode_u32(xdr, &len) < 0)
 257                return 0;
 258        if (len > SM_MAXSTRLEN)
 259                return 0;
 260        p = xdr_inline_decode(xdr, len);
 261        if (!p)
 262                return 0;
 263        argp->len = len;
 264        argp->mon = (char *)p;
 265        if (xdr_stream_decode_u32(xdr, &argp->state) < 0)
 266                return 0;
 267        p = xdr_inline_decode(xdr, SM_PRIV_SIZE);
 268        if (!p)
 269                return 0;
 270        memcpy(&argp->priv.data, p, sizeof(argp->priv.data));
 271
 272        return 1;
 273}
 274
 275int
 276nlmsvc_decode_shareargs(struct svc_rqst *rqstp, __be32 *p)
 277{
 278        struct xdr_stream *xdr = &rqstp->rq_arg_stream;
 279        struct nlm_args *argp = rqstp->rq_argp;
 280        struct nlm_lock *lock = &argp->lock;
 281
 282        memset(lock, 0, sizeof(*lock));
 283        locks_init_lock(&lock->fl);
 284        lock->svid = ~(u32)0;
 285
 286        if (!svcxdr_decode_cookie(xdr, &argp->cookie))
 287                return 0;
 288        if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len))
 289                return 0;
 290        if (!svcxdr_decode_fhandle(xdr, &lock->fh))
 291                return 0;
 292        if (!svcxdr_decode_owner(xdr, &lock->oh))
 293                return 0;
 294        /* XXX: Range checks are missing in the original code */
 295        if (xdr_stream_decode_u32(xdr, &argp->fsm_mode) < 0)
 296                return 0;
 297        if (xdr_stream_decode_u32(xdr, &argp->fsm_access) < 0)
 298                return 0;
 299
 300        return 1;
 301}
 302
 303int
 304nlmsvc_decode_notify(struct svc_rqst *rqstp, __be32 *p)
 305{
 306        struct xdr_stream *xdr = &rqstp->rq_arg_stream;
 307        struct nlm_args *argp = rqstp->rq_argp;
 308        struct nlm_lock *lock = &argp->lock;
 309
 310        if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len))
 311                return 0;
 312        if (xdr_stream_decode_u32(xdr, &argp->state) < 0)
 313                return 0;
 314
 315        return 1;
 316}
 317
 318
 319/*
 320 * Encode Reply results
 321 */
 322
 323int
 324nlmsvc_encode_void(struct svc_rqst *rqstp, __be32 *p)
 325{
 326        return 1;
 327}
 328
 329int
 330nlmsvc_encode_testres(struct svc_rqst *rqstp, __be32 *p)
 331{
 332        struct xdr_stream *xdr = &rqstp->rq_res_stream;
 333        struct nlm_res *resp = rqstp->rq_resp;
 334
 335        return svcxdr_encode_cookie(xdr, &resp->cookie) &&
 336                svcxdr_encode_testrply(xdr, resp);
 337}
 338
 339int
 340nlmsvc_encode_res(struct svc_rqst *rqstp, __be32 *p)
 341{
 342        struct xdr_stream *xdr = &rqstp->rq_res_stream;
 343        struct nlm_res *resp = rqstp->rq_resp;
 344
 345        return svcxdr_encode_cookie(xdr, &resp->cookie) &&
 346                svcxdr_encode_stats(xdr, resp->status);
 347}
 348
 349int
 350nlmsvc_encode_shareres(struct svc_rqst *rqstp, __be32 *p)
 351{
 352        struct xdr_stream *xdr = &rqstp->rq_res_stream;
 353        struct nlm_res *resp = rqstp->rq_resp;
 354
 355        if (!svcxdr_encode_cookie(xdr, &resp->cookie))
 356                return 0;
 357        if (!svcxdr_encode_stats(xdr, resp->status))
 358                return 0;
 359        /* sequence */
 360        if (xdr_stream_encode_u32(xdr, 0) < 0)
 361                return 0;
 362
 363        return 1;
 364}
 365