diff options
author | Chuck Lever <chuck.lever@oracle.com> | 2008-12-05 19:02:15 -0500 |
---|---|---|
committer | J. Bruce Fields <bfields@citi.umich.edu> | 2009-01-06 11:53:53 -0500 |
commit | 03eb1dcbb799304b58730f4dba65812f49fb305e (patch) | |
tree | 310306a570ae554fd420bdde1fdabe7f1157c255 | |
parent | 36e8e668d3e6a61848a8921ddeb663b417299fa5 (diff) |
NSM: move to xdr_stream-based XDR encoders and decoders
Introduce xdr_stream-based XDR encoder and decoder functions, which are
more careful about preventing RPC buffer overflows.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
-rw-r--r-- | fs/lockd/mon.c | 130 |
1 files changed, 78 insertions, 52 deletions
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index 0fc9836db4e7..81e1cc14246f 100644 --- a/fs/lockd/mon.c +++ b/fs/lockd/mon.c | |||
@@ -193,21 +193,26 @@ nsm_create(void) | |||
193 | * Status Monitor wire protocol. | 193 | * Status Monitor wire protocol. |
194 | */ | 194 | */ |
195 | 195 | ||
196 | static __be32 *xdr_encode_nsm_string(__be32 *p, char *string) | 196 | static int encode_nsm_string(struct xdr_stream *xdr, const char *string) |
197 | { | 197 | { |
198 | size_t len = strlen(string); | 198 | const u32 len = strlen(string); |
199 | 199 | __be32 *p; | |
200 | if (len > SM_MAXSTRLEN) | 200 | |
201 | len = SM_MAXSTRLEN; | 201 | if (unlikely(len > SM_MAXSTRLEN)) |
202 | return xdr_encode_opaque(p, string, len); | 202 | return -EIO; |
203 | p = xdr_reserve_space(xdr, sizeof(u32) + len); | ||
204 | if (unlikely(p == NULL)) | ||
205 | return -EIO; | ||
206 | xdr_encode_opaque(p, string, len); | ||
207 | return 0; | ||
203 | } | 208 | } |
204 | 209 | ||
205 | /* | 210 | /* |
206 | * "mon_name" specifies the host to be monitored. | 211 | * "mon_name" specifies the host to be monitored. |
207 | */ | 212 | */ |
208 | static __be32 *xdr_encode_mon_name(__be32 *p, struct nsm_args *argp) | 213 | static int encode_mon_name(struct xdr_stream *xdr, const struct nsm_args *argp) |
209 | { | 214 | { |
210 | return xdr_encode_nsm_string(p, argp->mon_name); | 215 | return encode_nsm_string(xdr, argp->mon_name); |
211 | } | 216 | } |
212 | 217 | ||
213 | /* | 218 | /* |
@@ -216,30 +221,35 @@ static __be32 *xdr_encode_mon_name(__be32 *p, struct nsm_args *argp) | |||
216 | * (via the NLMPROC_SM_NOTIFY call) that the state of host "mon_name" | 221 | * (via the NLMPROC_SM_NOTIFY call) that the state of host "mon_name" |
217 | * has changed. | 222 | * has changed. |
218 | */ | 223 | */ |
219 | static __be32 *xdr_encode_my_id(__be32 *p, struct nsm_args *argp) | 224 | static int encode_my_id(struct xdr_stream *xdr, const struct nsm_args *argp) |
220 | { | 225 | { |
221 | p = xdr_encode_nsm_string(p, utsname()->nodename); | 226 | int status; |
222 | if (!p) | 227 | __be32 *p; |
223 | return ERR_PTR(-EIO); | 228 | |
224 | 229 | status = encode_nsm_string(xdr, utsname()->nodename); | |
230 | if (unlikely(status != 0)) | ||
231 | return status; | ||
232 | p = xdr_reserve_space(xdr, 3 * sizeof(u32)); | ||
233 | if (unlikely(p == NULL)) | ||
234 | return -EIO; | ||
225 | *p++ = htonl(argp->prog); | 235 | *p++ = htonl(argp->prog); |
226 | *p++ = htonl(argp->vers); | 236 | *p++ = htonl(argp->vers); |
227 | *p++ = htonl(argp->proc); | 237 | *p++ = htonl(argp->proc); |
228 | 238 | return 0; | |
229 | return p; | ||
230 | } | 239 | } |
231 | 240 | ||
232 | /* | 241 | /* |
233 | * The "mon_id" argument specifies the non-private arguments | 242 | * The "mon_id" argument specifies the non-private arguments |
234 | * of an NSMPROC_MON or NSMPROC_UNMON call. | 243 | * of an NSMPROC_MON or NSMPROC_UNMON call. |
235 | */ | 244 | */ |
236 | static __be32 *xdr_encode_mon_id(__be32 *p, struct nsm_args *argp) | 245 | static int encode_mon_id(struct xdr_stream *xdr, const struct nsm_args *argp) |
237 | { | 246 | { |
238 | p = xdr_encode_mon_name(p, argp); | 247 | int status; |
239 | if (!p) | ||
240 | return ERR_PTR(-EIO); | ||
241 | 248 | ||
242 | return xdr_encode_my_id(p, argp); | 249 | status = encode_mon_name(xdr, argp); |
250 | if (unlikely(status != 0)) | ||
251 | return status; | ||
252 | return encode_my_id(xdr, argp); | ||
243 | } | 253 | } |
244 | 254 | ||
245 | /* | 255 | /* |
@@ -250,55 +260,71 @@ static __be32 *xdr_encode_mon_id(__be32 *p, struct nsm_args *argp) | |||
250 | * Linux provides the raw IP address of the monitored host, | 260 | * Linux provides the raw IP address of the monitored host, |
251 | * left in network byte order. | 261 | * left in network byte order. |
252 | */ | 262 | */ |
253 | static __be32 *xdr_encode_priv(__be32 *p, struct nsm_args *argp) | 263 | static int encode_priv(struct xdr_stream *xdr, const struct nsm_args *argp) |
254 | { | 264 | { |
265 | __be32 *p; | ||
266 | |||
267 | p = xdr_reserve_space(xdr, SM_PRIV_SIZE); | ||
268 | if (unlikely(p == NULL)) | ||
269 | return -EIO; | ||
255 | *p++ = argp->addr; | 270 | *p++ = argp->addr; |
256 | *p++ = 0; | 271 | *p++ = 0; |
257 | *p++ = 0; | 272 | *p++ = 0; |
258 | *p++ = 0; | 273 | *p++ = 0; |
259 | 274 | return 0; | |
260 | return p; | ||
261 | } | 275 | } |
262 | 276 | ||
263 | static int | 277 | static int xdr_enc_mon(struct rpc_rqst *req, __be32 *p, |
264 | xdr_encode_mon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp) | 278 | const struct nsm_args *argp) |
265 | { | 279 | { |
266 | p = xdr_encode_mon_id(p, argp); | 280 | struct xdr_stream xdr; |
267 | if (IS_ERR(p)) | 281 | int status; |
268 | return PTR_ERR(p); | ||
269 | |||
270 | p = xdr_encode_priv(p, argp); | ||
271 | if (IS_ERR(p)) | ||
272 | return PTR_ERR(p); | ||
273 | 282 | ||
274 | rqstp->rq_slen = xdr_adjust_iovec(rqstp->rq_svec, p); | 283 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
275 | return 0; | 284 | status = encode_mon_id(&xdr, argp); |
285 | if (unlikely(status)) | ||
286 | return status; | ||
287 | return encode_priv(&xdr, argp); | ||
276 | } | 288 | } |
277 | 289 | ||
278 | static int | 290 | static int xdr_enc_unmon(struct rpc_rqst *req, __be32 *p, |
279 | xdr_encode_unmon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp) | 291 | const struct nsm_args *argp) |
280 | { | 292 | { |
281 | p = xdr_encode_mon_id(p, argp); | 293 | struct xdr_stream xdr; |
282 | if (IS_ERR(p)) | 294 | |
283 | return PTR_ERR(p); | 295 | xdr_init_encode(&xdr, &req->rq_snd_buf, p); |
284 | rqstp->rq_slen = xdr_adjust_iovec(rqstp->rq_svec, p); | 296 | return encode_mon_id(&xdr, argp); |
285 | return 0; | ||
286 | } | 297 | } |
287 | 298 | ||
288 | static int | 299 | static int xdr_dec_stat_res(struct rpc_rqst *rqstp, __be32 *p, |
289 | xdr_decode_stat_res(struct rpc_rqst *rqstp, __be32 *p, struct nsm_res *resp) | 300 | struct nsm_res *resp) |
290 | { | 301 | { |
302 | struct xdr_stream xdr; | ||
303 | |||
304 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | ||
305 | p = xdr_inline_decode(&xdr, 2 * sizeof(u32)); | ||
306 | if (unlikely(p == NULL)) | ||
307 | return -EIO; | ||
291 | resp->status = ntohl(*p++); | 308 | resp->status = ntohl(*p++); |
292 | resp->state = ntohl(*p++); | 309 | resp->state = ntohl(*p); |
293 | dprintk("nsm: xdr_decode_stat_res status %d state %d\n", | 310 | |
311 | dprintk("lockd: xdr_dec_stat_res status %d state %d\n", | ||
294 | resp->status, resp->state); | 312 | resp->status, resp->state); |
295 | return 0; | 313 | return 0; |
296 | } | 314 | } |
297 | 315 | ||
298 | static int | 316 | static int xdr_dec_stat(struct rpc_rqst *rqstp, __be32 *p, |
299 | xdr_decode_stat(struct rpc_rqst *rqstp, __be32 *p, struct nsm_res *resp) | 317 | struct nsm_res *resp) |
300 | { | 318 | { |
301 | resp->state = ntohl(*p++); | 319 | struct xdr_stream xdr; |
320 | |||
321 | xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); | ||
322 | p = xdr_inline_decode(&xdr, sizeof(u32)); | ||
323 | if (unlikely(p == NULL)) | ||
324 | return -EIO; | ||
325 | resp->state = ntohl(*p); | ||
326 | |||
327 | dprintk("lockd: xdr_dec_stat state %d\n", resp->state); | ||
302 | return 0; | 328 | return 0; |
303 | } | 329 | } |
304 | 330 | ||
@@ -314,8 +340,8 @@ xdr_decode_stat(struct rpc_rqst *rqstp, __be32 *p, struct nsm_res *resp) | |||
314 | static struct rpc_procinfo nsm_procedures[] = { | 340 | static struct rpc_procinfo nsm_procedures[] = { |
315 | [NSMPROC_MON] = { | 341 | [NSMPROC_MON] = { |
316 | .p_proc = NSMPROC_MON, | 342 | .p_proc = NSMPROC_MON, |
317 | .p_encode = (kxdrproc_t) xdr_encode_mon, | 343 | .p_encode = (kxdrproc_t)xdr_enc_mon, |
318 | .p_decode = (kxdrproc_t) xdr_decode_stat_res, | 344 | .p_decode = (kxdrproc_t)xdr_dec_stat_res, |
319 | .p_arglen = SM_mon_sz, | 345 | .p_arglen = SM_mon_sz, |
320 | .p_replen = SM_monres_sz, | 346 | .p_replen = SM_monres_sz, |
321 | .p_statidx = NSMPROC_MON, | 347 | .p_statidx = NSMPROC_MON, |
@@ -323,8 +349,8 @@ static struct rpc_procinfo nsm_procedures[] = { | |||
323 | }, | 349 | }, |
324 | [NSMPROC_UNMON] = { | 350 | [NSMPROC_UNMON] = { |
325 | .p_proc = NSMPROC_UNMON, | 351 | .p_proc = NSMPROC_UNMON, |
326 | .p_encode = (kxdrproc_t) xdr_encode_unmon, | 352 | .p_encode = (kxdrproc_t)xdr_enc_unmon, |
327 | .p_decode = (kxdrproc_t) xdr_decode_stat, | 353 | .p_decode = (kxdrproc_t)xdr_dec_stat, |
328 | .p_arglen = SM_mon_id_sz, | 354 | .p_arglen = SM_mon_id_sz, |
329 | .p_replen = SM_unmonres_sz, | 355 | .p_replen = SM_unmonres_sz, |
330 | .p_statidx = NSMPROC_UNMON, | 356 | .p_statidx = NSMPROC_UNMON, |