summaryrefslogtreecommitdiffstats
path: root/fs/afs/cmservice.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2017-01-05 05:38:36 -0500
committerDavid Howells <dhowells@redhat.com>2017-01-09 06:10:02 -0500
commit341f741f04beceebcb30daa12ae2e5e52e64e532 (patch)
tree4c49b19c44fd13d26a2a84264aa062b07b911498 /fs/afs/cmservice.c
parent210f035316f545e6f507e7d61e191495ba983e27 (diff)
afs: Refcount the afs_call struct
A static checker warning occurs in the AFS filesystem: fs/afs/cmservice.c:155 SRXAFSCB_CallBack() error: dereferencing freed memory 'call' due to the reply being sent before we access the server it points to. The act of sending the reply causes the call to be freed if an error occurs (but not if it doesn't). On top of this, the lifetime handling of afs_call structs is fragile because they get passed around through workqueues without any sort of refcounting. Deal with the issues by: (1) Fix the maybe/maybe not nature of the reply sending functions with regards to whether they release the call struct. (2) Refcount the afs_call struct and sort out places that need to get/put references. (3) Pass a ref through the work queue and release (or pass on) that ref in the work function. Care has to be taken because a work queue may already own a ref to the call. (4) Do the cleaning up in the put function only. (5) Simplify module cleanup by always incrementing afs_outstanding_calls whenever a call is allocated. (6) Set the backlog to 0 with kernel_listen() at the beginning of the process of closing the socket to prevent new incoming calls from occurring and to remove the contribution of preallocated calls from afs_outstanding_calls before we wait on it. A tracepoint is also added to monitor the afs_call refcount and lifetime. Reported-by: Dan Carpenter <dan.carpenter@oracle.com> Signed-off-by: David Howells <dhowells@redhat.com> Fixes: 08e0e7c82eea: "[AF_RXRPC]: Make the in-kernel AFS filesystem use AF_RXRPC."
Diffstat (limited to 'fs/afs/cmservice.c')
-rw-r--r--fs/afs/cmservice.c41
1 files changed, 22 insertions, 19 deletions
diff --git a/fs/afs/cmservice.c b/fs/afs/cmservice.c
index a2e1e02005f6..e349a3316303 100644
--- a/fs/afs/cmservice.c
+++ b/fs/afs/cmservice.c
@@ -24,6 +24,11 @@ static int afs_deliver_cb_callback(struct afs_call *);
24static int afs_deliver_cb_probe_uuid(struct afs_call *); 24static int afs_deliver_cb_probe_uuid(struct afs_call *);
25static int afs_deliver_cb_tell_me_about_yourself(struct afs_call *); 25static int afs_deliver_cb_tell_me_about_yourself(struct afs_call *);
26static void afs_cm_destructor(struct afs_call *); 26static void afs_cm_destructor(struct afs_call *);
27static void SRXAFSCB_CallBack(struct work_struct *);
28static void SRXAFSCB_InitCallBackState(struct work_struct *);
29static void SRXAFSCB_Probe(struct work_struct *);
30static void SRXAFSCB_ProbeUuid(struct work_struct *);
31static void SRXAFSCB_TellMeAboutYourself(struct work_struct *);
27 32
28#define CM_NAME(name) \ 33#define CM_NAME(name) \
29 const char afs_SRXCB##name##_name[] __tracepoint_string = \ 34 const char afs_SRXCB##name##_name[] __tracepoint_string = \
@@ -38,6 +43,7 @@ static const struct afs_call_type afs_SRXCBCallBack = {
38 .deliver = afs_deliver_cb_callback, 43 .deliver = afs_deliver_cb_callback,
39 .abort_to_error = afs_abort_to_error, 44 .abort_to_error = afs_abort_to_error,
40 .destructor = afs_cm_destructor, 45 .destructor = afs_cm_destructor,
46 .work = SRXAFSCB_CallBack,
41}; 47};
42 48
43/* 49/*
@@ -49,6 +55,7 @@ static const struct afs_call_type afs_SRXCBInitCallBackState = {
49 .deliver = afs_deliver_cb_init_call_back_state, 55 .deliver = afs_deliver_cb_init_call_back_state,
50 .abort_to_error = afs_abort_to_error, 56 .abort_to_error = afs_abort_to_error,
51 .destructor = afs_cm_destructor, 57 .destructor = afs_cm_destructor,
58 .work = SRXAFSCB_InitCallBackState,
52}; 59};
53 60
54/* 61/*
@@ -60,6 +67,7 @@ static const struct afs_call_type afs_SRXCBInitCallBackState3 = {
60 .deliver = afs_deliver_cb_init_call_back_state3, 67 .deliver = afs_deliver_cb_init_call_back_state3,
61 .abort_to_error = afs_abort_to_error, 68 .abort_to_error = afs_abort_to_error,
62 .destructor = afs_cm_destructor, 69 .destructor = afs_cm_destructor,
70 .work = SRXAFSCB_InitCallBackState,
63}; 71};
64 72
65/* 73/*
@@ -71,6 +79,7 @@ static const struct afs_call_type afs_SRXCBProbe = {
71 .deliver = afs_deliver_cb_probe, 79 .deliver = afs_deliver_cb_probe,
72 .abort_to_error = afs_abort_to_error, 80 .abort_to_error = afs_abort_to_error,
73 .destructor = afs_cm_destructor, 81 .destructor = afs_cm_destructor,
82 .work = SRXAFSCB_Probe,
74}; 83};
75 84
76/* 85/*
@@ -82,6 +91,7 @@ static const struct afs_call_type afs_SRXCBProbeUuid = {
82 .deliver = afs_deliver_cb_probe_uuid, 91 .deliver = afs_deliver_cb_probe_uuid,
83 .abort_to_error = afs_abort_to_error, 92 .abort_to_error = afs_abort_to_error,
84 .destructor = afs_cm_destructor, 93 .destructor = afs_cm_destructor,
94 .work = SRXAFSCB_ProbeUuid,
85}; 95};
86 96
87/* 97/*
@@ -93,6 +103,7 @@ static const struct afs_call_type afs_SRXCBTellMeAboutYourself = {
93 .deliver = afs_deliver_cb_tell_me_about_yourself, 103 .deliver = afs_deliver_cb_tell_me_about_yourself,
94 .abort_to_error = afs_abort_to_error, 104 .abort_to_error = afs_abort_to_error,
95 .destructor = afs_cm_destructor, 105 .destructor = afs_cm_destructor,
106 .work = SRXAFSCB_TellMeAboutYourself,
96}; 107};
97 108
98/* 109/*
@@ -163,6 +174,7 @@ static void SRXAFSCB_CallBack(struct work_struct *work)
163 afs_send_empty_reply(call); 174 afs_send_empty_reply(call);
164 175
165 afs_break_callbacks(call->server, call->count, call->request); 176 afs_break_callbacks(call->server, call->count, call->request);
177 afs_put_call(call);
166 _leave(""); 178 _leave("");
167} 179}
168 180
@@ -284,9 +296,7 @@ static int afs_deliver_cb_callback(struct afs_call *call)
284 return -ENOTCONN; 296 return -ENOTCONN;
285 call->server = server; 297 call->server = server;
286 298
287 INIT_WORK(&call->work, SRXAFSCB_CallBack); 299 return afs_queue_call_work(call);
288 queue_work(afs_wq, &call->work);
289 return 0;
290} 300}
291 301
292/* 302/*
@@ -300,6 +310,7 @@ static void SRXAFSCB_InitCallBackState(struct work_struct *work)
300 310
301 afs_init_callback_state(call->server); 311 afs_init_callback_state(call->server);
302 afs_send_empty_reply(call); 312 afs_send_empty_reply(call);
313 afs_put_call(call);
303 _leave(""); 314 _leave("");
304} 315}
305 316
@@ -330,9 +341,7 @@ static int afs_deliver_cb_init_call_back_state(struct afs_call *call)
330 return -ENOTCONN; 341 return -ENOTCONN;
331 call->server = server; 342 call->server = server;
332 343
333 INIT_WORK(&call->work, SRXAFSCB_InitCallBackState); 344 return afs_queue_call_work(call);
334 queue_work(afs_wq, &call->work);
335 return 0;
336} 345}
337 346
338/* 347/*
@@ -404,9 +413,7 @@ static int afs_deliver_cb_init_call_back_state3(struct afs_call *call)
404 return -ENOTCONN; 413 return -ENOTCONN;
405 call->server = server; 414 call->server = server;
406 415
407 INIT_WORK(&call->work, SRXAFSCB_InitCallBackState); 416 return afs_queue_call_work(call);
408 queue_work(afs_wq, &call->work);
409 return 0;
410} 417}
411 418
412/* 419/*
@@ -418,6 +425,7 @@ static void SRXAFSCB_Probe(struct work_struct *work)
418 425
419 _enter(""); 426 _enter("");
420 afs_send_empty_reply(call); 427 afs_send_empty_reply(call);
428 afs_put_call(call);
421 _leave(""); 429 _leave("");
422} 430}
423 431
@@ -437,9 +445,7 @@ static int afs_deliver_cb_probe(struct afs_call *call)
437 /* no unmarshalling required */ 445 /* no unmarshalling required */
438 call->state = AFS_CALL_REPLYING; 446 call->state = AFS_CALL_REPLYING;
439 447
440 INIT_WORK(&call->work, SRXAFSCB_Probe); 448 return afs_queue_call_work(call);
441 queue_work(afs_wq, &call->work);
442 return 0;
443} 449}
444 450
445/* 451/*
@@ -462,6 +468,7 @@ static void SRXAFSCB_ProbeUuid(struct work_struct *work)
462 reply.match = htonl(1); 468 reply.match = htonl(1);
463 469
464 afs_send_simple_reply(call, &reply, sizeof(reply)); 470 afs_send_simple_reply(call, &reply, sizeof(reply));
471 afs_put_call(call);
465 _leave(""); 472 _leave("");
466} 473}
467 474
@@ -520,9 +527,7 @@ static int afs_deliver_cb_probe_uuid(struct afs_call *call)
520 527
521 call->state = AFS_CALL_REPLYING; 528 call->state = AFS_CALL_REPLYING;
522 529
523 INIT_WORK(&call->work, SRXAFSCB_ProbeUuid); 530 return afs_queue_call_work(call);
524 queue_work(afs_wq, &call->work);
525 return 0;
526} 531}
527 532
528/* 533/*
@@ -584,7 +589,7 @@ static void SRXAFSCB_TellMeAboutYourself(struct work_struct *work)
584 reply.cap.capcount = htonl(1); 589 reply.cap.capcount = htonl(1);
585 reply.cap.caps[0] = htonl(AFS_CAP_ERROR_TRANSLATION); 590 reply.cap.caps[0] = htonl(AFS_CAP_ERROR_TRANSLATION);
586 afs_send_simple_reply(call, &reply, sizeof(reply)); 591 afs_send_simple_reply(call, &reply, sizeof(reply));
587 592 afs_put_call(call);
588 _leave(""); 593 _leave("");
589} 594}
590 595
@@ -604,7 +609,5 @@ static int afs_deliver_cb_tell_me_about_yourself(struct afs_call *call)
604 /* no unmarshalling required */ 609 /* no unmarshalling required */
605 call->state = AFS_CALL_REPLYING; 610 call->state = AFS_CALL_REPLYING;
606 611
607 INIT_WORK(&call->work, SRXAFSCB_TellMeAboutYourself); 612 return afs_queue_call_work(call);
608 queue_work(afs_wq, &call->work);
609 return 0;
610} 613}