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