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 25 static inline loff_t 26 s32_to_loff_t(__s32 offset) 27 { 28 return (loff_t)offset; 29 } 30 31 static inline __s32 32 loff_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 */ 50 static bool 51 svcxdr_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 71 static bool 72 svcxdr_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 103 static bool 104 svcxdr_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 129 static bool 130 svcxdr_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 148 bool 149 nlmsvc_decode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr) 150 { 151 return true; 152 } 153 154 bool 155 nlmsvc_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 172 bool 173 nlmsvc_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 197 bool 198 nlmsvc_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 217 bool 218 nlmsvc_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 231 bool 232 nlmsvc_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 244 bool 245 nlmsvc_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 270 bool 271 nlmsvc_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 297 bool 298 nlmsvc_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 316 bool 317 nlmsvc_encode_void(struct svc_rqst *rqstp, struct xdr_stream *xdr) 318 { 319 return true; 320 } 321 322 bool 323 nlmsvc_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 331 bool 332 nlmsvc_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 340 bool 341 nlmsvc_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 } 355