xdr.c (7739B)
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 148bool 149nlmsvc_decode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr) 150{ 151 return true; 152} 153 154bool 155nlmsvc_decode_testargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) 156{ 157 struct nlm_args *argp = rqstp->rq_argp; 158 u32 exclusive; 159 160 if (!svcxdr_decode_cookie(xdr, &argp->cookie)) 161 return false; 162 if (xdr_stream_decode_bool(xdr, &exclusive) < 0) 163 return false; 164 if (!svcxdr_decode_lock(xdr, &argp->lock)) 165 return false; 166 if (exclusive) 167 argp->lock.fl.fl_type = F_WRLCK; 168 169 return true; 170} 171 172bool 173nlmsvc_decode_lockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) 174{ 175 struct nlm_args *argp = rqstp->rq_argp; 176 u32 exclusive; 177 178 if (!svcxdr_decode_cookie(xdr, &argp->cookie)) 179 return false; 180 if (xdr_stream_decode_bool(xdr, &argp->block) < 0) 181 return false; 182 if (xdr_stream_decode_bool(xdr, &exclusive) < 0) 183 return false; 184 if (!svcxdr_decode_lock(xdr, &argp->lock)) 185 return false; 186 if (exclusive) 187 argp->lock.fl.fl_type = F_WRLCK; 188 if (xdr_stream_decode_bool(xdr, &argp->reclaim) < 0) 189 return false; 190 if (xdr_stream_decode_u32(xdr, &argp->state) < 0) 191 return false; 192 argp->monitor = 1; /* monitor client by default */ 193 194 return true; 195} 196 197bool 198nlmsvc_decode_cancargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) 199{ 200 struct nlm_args *argp = rqstp->rq_argp; 201 u32 exclusive; 202 203 if (!svcxdr_decode_cookie(xdr, &argp->cookie)) 204 return false; 205 if (xdr_stream_decode_bool(xdr, &argp->block) < 0) 206 return false; 207 if (xdr_stream_decode_bool(xdr, &exclusive) < 0) 208 return false; 209 if (!svcxdr_decode_lock(xdr, &argp->lock)) 210 return false; 211 if (exclusive) 212 argp->lock.fl.fl_type = F_WRLCK; 213 214 return true; 215} 216 217bool 218nlmsvc_decode_unlockargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) 219{ 220 struct nlm_args *argp = rqstp->rq_argp; 221 222 if (!svcxdr_decode_cookie(xdr, &argp->cookie)) 223 return false; 224 if (!svcxdr_decode_lock(xdr, &argp->lock)) 225 return false; 226 argp->lock.fl.fl_type = F_UNLCK; 227 228 return true; 229} 230 231bool 232nlmsvc_decode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr) 233{ 234 struct nlm_res *resp = rqstp->rq_argp; 235 236 if (!svcxdr_decode_cookie(xdr, &resp->cookie)) 237 return false; 238 if (!svcxdr_decode_stats(xdr, &resp->status)) 239 return false; 240 241 return true; 242} 243 244bool 245nlmsvc_decode_reboot(struct svc_rqst *rqstp, struct xdr_stream *xdr) 246{ 247 struct nlm_reboot *argp = rqstp->rq_argp; 248 __be32 *p; 249 u32 len; 250 251 if (xdr_stream_decode_u32(xdr, &len) < 0) 252 return false; 253 if (len > SM_MAXSTRLEN) 254 return false; 255 p = xdr_inline_decode(xdr, len); 256 if (!p) 257 return false; 258 argp->len = len; 259 argp->mon = (char *)p; 260 if (xdr_stream_decode_u32(xdr, &argp->state) < 0) 261 return false; 262 p = xdr_inline_decode(xdr, SM_PRIV_SIZE); 263 if (!p) 264 return false; 265 memcpy(&argp->priv.data, p, sizeof(argp->priv.data)); 266 267 return true; 268} 269 270bool 271nlmsvc_decode_shareargs(struct svc_rqst *rqstp, struct xdr_stream *xdr) 272{ 273 struct nlm_args *argp = rqstp->rq_argp; 274 struct nlm_lock *lock = &argp->lock; 275 276 memset(lock, 0, sizeof(*lock)); 277 locks_init_lock(&lock->fl); 278 lock->svid = ~(u32)0; 279 280 if (!svcxdr_decode_cookie(xdr, &argp->cookie)) 281 return false; 282 if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len)) 283 return false; 284 if (!svcxdr_decode_fhandle(xdr, &lock->fh)) 285 return false; 286 if (!svcxdr_decode_owner(xdr, &lock->oh)) 287 return false; 288 /* XXX: Range checks are missing in the original code */ 289 if (xdr_stream_decode_u32(xdr, &argp->fsm_mode) < 0) 290 return false; 291 if (xdr_stream_decode_u32(xdr, &argp->fsm_access) < 0) 292 return false; 293 294 return true; 295} 296 297bool 298nlmsvc_decode_notify(struct svc_rqst *rqstp, struct xdr_stream *xdr) 299{ 300 struct nlm_args *argp = rqstp->rq_argp; 301 struct nlm_lock *lock = &argp->lock; 302 303 if (!svcxdr_decode_string(xdr, &lock->caller, &lock->len)) 304 return false; 305 if (xdr_stream_decode_u32(xdr, &argp->state) < 0) 306 return false; 307 308 return true; 309} 310 311 312/* 313 * Encode Reply results 314 */ 315 316bool 317nlmsvc_encode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr) 318{ 319 return true; 320} 321 322bool 323nlmsvc_encode_testres(struct svc_rqst *rqstp, struct xdr_stream *xdr) 324{ 325 struct nlm_res *resp = rqstp->rq_resp; 326 327 return svcxdr_encode_cookie(xdr, &resp->cookie) && 328 svcxdr_encode_testrply(xdr, resp); 329} 330 331bool 332nlmsvc_encode_res(struct svc_rqst *rqstp, struct xdr_stream *xdr) 333{ 334 struct nlm_res *resp = rqstp->rq_resp; 335 336 return svcxdr_encode_cookie(xdr, &resp->cookie) && 337 svcxdr_encode_stats(xdr, resp->status); 338} 339 340bool 341nlmsvc_encode_shareres(struct svc_rqst *rqstp, struct xdr_stream *xdr) 342{ 343 struct nlm_res *resp = rqstp->rq_resp; 344 345 if (!svcxdr_encode_cookie(xdr, &resp->cookie)) 346 return false; 347 if (!svcxdr_encode_stats(xdr, resp->status)) 348 return false; 349 /* sequence */ 350 if (xdr_stream_encode_u32(xdr, 0) < 0) 351 return false; 352 353 return true; 354}