Skip to content

Commit 162b70d

Browse files
ayourtchflorincoras
authored andcommitted
api: Avoid the usage of the freed registration by the API calls
This issue happens if: - the API client connects via Unix socket - the client issues the *_dump API call and immediately disconnects What happens after is that the API handler keeps sending the *_details messages, however at some point the write fails, and the socket is deleted. The attempt of a use of the registration pointer results in interpreting the socket as a shared memory socket. This results in a crash, because the data in this structure then does not make sense, like the below: | |Thread 1 "vpp_main" received signal SIGSEGV, Segmentation fault. |__GI___pthread_mutex_lock (mutex=0x0) at ../nptl/pthread_mutex_lock.c:67 |67 ../nptl/pthread_mutex_lock.c: No such file or directory. |(gdb) bt |#0 __GI___pthread_mutex_lock (mutex=0x0) at ../nptl/pthread_mutex_lock.c:67 |#1 0x00007ffff500f957 in svm_queue_lock (q=0x0) at /home/ubuntu/vpp/src/svm/queue.c:101 |#2 svm_queue_add (q=0x0, elem=0x7fffa76c2de0 "\210\365\006\060\001", nowait=0) at /home/ubuntu/vpp/src/svm/queue.c:274 |#3 0x00007ffff6e131e3 in vl_api_send_msg (rp=<optimized out>, elem=<optimized out>) at /home/ubuntu/vpp/src/vlibmemory/api.h:43 |#4 send_sw_interface_details (am=<optimized out>, rp=<optimized out>, swif=0x7fffb957a0bc, interface_name=<optimized out>, context=<optimized out>) | at /home/ubuntu/vpp/src/vnet/interface_api.c:353 |#5 0x00007ffff6e0edeb in vl_api_sw_interface_dump_t_handler (mp=<optimized out>) at /home/ubuntu/vpp/src/vnet/interface_api.c:412 |#6 0x00007ffff7daeb48 in msg_handler_internal (am=<optimized out>, the_msg=0x7fffb839a5e0, trace_it=<optimized out>, do_it=1, free_it=0) | at /home/ubuntu/vpp/src/vlibapi/api_shared.c:501 |#7 vl_msg_api_socket_handler (the_msg=0x7fffb839a5e0) at /home/ubuntu/vpp/src/vlibapi/api_shared.c:790 |#8 0x00007ffff7d7c608 in vl_socket_process_api_msg (rp=<optimized out>, input_v=0x7fffa76c2de0 "\210\365\006\060\001") at /home/ubuntu/vpp/src/vlibmemory/socket_api.c:212 |#9 0x00007ffff7d89ff1 in vl_api_clnt_process (vm=<optimized out>, node=<optimized out>, f=<optimized out>) at /home/ubuntu/vpp/src/vlibmemory/vlib_api.c:405 |#10 0x00007ffff53bf9a7 in vlib_process_bootstrap (_a=<optimized out>) at /home/ubuntu/vpp/src/vlib/main.c:1490 |#11 0x00007ffff4da0b2c in clib_calljmp () from /home/ayourtch/vpp/build-root/install-vpp-native/vpp/lib/libvppinfra.so.21.06 |#12 0x00007fffa99a4d90 in ?? () |#13 0x00007ffff53b6cb2 in vlib_process_startup (vm=0x7ffff56a9880 <vlib_global_main>, p=0x7fffb5d41380, f=0x0) at /home/ubuntu/vpp/src/vlib/main.c:1515 |#14 dispatch_process (vm=0x7ffff56a9880 <vlib_global_main>, p=0x7fffb5d41380, f=0x0, last_time_stamp=<optimized out>) at /home/ubuntu/vpp/src/vlib/main.c:1571 |#15 0x0000000000000000 in ?? () |(gdb) frame 3 |#3 0x00007ffff6e131e3 in vl_api_send_msg (rp=<optimized out>, elem=<optimized out>) at /home/ubuntu/vpp/src/vlibmemory/api.h:43 |43 vl_msg_api_send_shmem (rp->vl_input_queue, (u8 *) & elem); |(gdb) l |38 { |39 vl_socket_api_send (rp, elem); |40 } |41 else |42 { |43 vl_msg_api_send_shmem (rp->vl_input_queue, (u8 *) & elem); |44 } |45 } |46 |47 always_inline int |(gdb) | The approach in this change is to avoid the closing operations "here and now", but instead mark the the registration as a zombie and place a forced RPC towards a callback that does the actual cleanup work. Forced RPC is handled via the API processing loop with barrier sync, so we are guaranteed not to have any API processing in-process. Type: fix Change-Id: I1972d42da620bdb4fd773c83262863c2781d9005 Signed-off-by: Andrew Yourtchenko <[email protected]>
1 parent 415cd67 commit 162b70d

File tree

2 files changed

+52
-23
lines changed

2 files changed

+52
-23
lines changed

src/vlibapi/api_common.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ typedef struct vl_api_registration_
5757
f64 last_heard;
5858
int last_queue_head;
5959
int unanswered_pings;
60+
int is_being_removed;
6061

6162
/** shared memory only: pointer to client input queue */
6263
svm_queue_t *vl_input_queue;

src/vlibmemory/socket_api.c

Lines changed: 51 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -148,15 +148,6 @@ vl_socket_api_send (vl_api_registration_t * rp, u8 * elem)
148148
error = clib_file_write (cf);
149149
unix_save_error (&unix_main, error);
150150

151-
/* Make sure cf not removed in clib_file_write */
152-
cf = vl_api_registration_file (rp);
153-
if (!cf)
154-
{
155-
clib_warning ("cf removed");
156-
vl_msg_api_free ((void *) elem);
157-
return;
158-
}
159-
160151
/* If we didn't finish sending everything, wait for tx space */
161152
if (vec_len (sock_rp->output_vector) > 0
162153
&& !(cf->flags & UNIX_FILE_DATA_AVAILABLE_TO_WRITE))
@@ -213,6 +204,42 @@ vl_socket_process_api_msg (vl_api_registration_t * rp, i8 * input_v)
213204
socket_main.current_rp = 0;
214205
}
215206

207+
int
208+
is_being_removed_reg_index (u32 reg_index)
209+
{
210+
vl_api_registration_t *rp = vl_socket_get_registration (reg_index);
211+
ALWAYS_ASSERT (rp != 0);
212+
return (rp->is_being_removed);
213+
}
214+
215+
static void
216+
socket_cleanup_pending_remove_registration_cb (u32 *preg_index)
217+
{
218+
vl_api_registration_t *rp = vl_socket_get_registration (*preg_index);
219+
clib_file_main_t *fm = &file_main;
220+
u32 pending_remove_file_index = vl_api_registration_file_index (rp);
221+
222+
clib_file_t *zf = fm->file_pool + pending_remove_file_index;
223+
224+
clib_file_del (fm, zf);
225+
vl_socket_free_registration_index (rp - socket_main.registration_pool);
226+
}
227+
228+
static void
229+
vl_socket_request_remove_reg_index (u32 reg_index)
230+
{
231+
vl_api_registration_t *rp = vl_socket_get_registration (reg_index);
232+
ALWAYS_ASSERT (rp != 0);
233+
if (rp->is_being_removed)
234+
{
235+
return;
236+
}
237+
rp->is_being_removed = 1;
238+
vl_api_force_rpc_call_main_thread (
239+
socket_cleanup_pending_remove_registration_cb, (void *) &reg_index,
240+
sizeof (u32));
241+
}
242+
216243
/*
217244
* Read function for API socket.
218245
*
@@ -232,7 +259,6 @@ vl_socket_process_api_msg (vl_api_registration_t * rp, i8 * input_v)
232259
clib_error_t *
233260
vl_socket_read_ready (clib_file_t * uf)
234261
{
235-
clib_file_main_t *fm = &file_main;
236262
vlib_main_t *vm = vlib_get_main ();
237263
vl_api_registration_t *rp;
238264
/* n is the size of data read to input_buffer */
@@ -246,6 +272,10 @@ vl_socket_read_ready (clib_file_t * uf)
246272
u32 save_input_buffer_length = vec_len (socket_main.input_buffer);
247273
vl_socket_args_for_process_t *a;
248274
u32 reg_index = uf->private_data;
275+
if (is_being_removed_reg_index (reg_index))
276+
{
277+
return 0;
278+
}
249279

250280
rp = vl_socket_get_registration (reg_index);
251281

@@ -258,8 +288,7 @@ vl_socket_read_ready (clib_file_t * uf)
258288
if (errno != EAGAIN)
259289
{
260290
/* Severe error, close the file. */
261-
clib_file_del (fm, uf);
262-
vl_socket_free_registration_index (reg_index);
291+
vl_socket_request_remove_reg_index (reg_index);
263292
}
264293
/* EAGAIN means we do not close the file, but no data to process anyway. */
265294
return 0;
@@ -354,7 +383,13 @@ vl_socket_write_ready (clib_file_t * uf)
354383
vl_api_registration_t *rp;
355384
int n;
356385

357-
rp = pool_elt_at_index (socket_main.registration_pool, uf->private_data);
386+
u32 reg_index = uf->private_data;
387+
if (is_being_removed_reg_index (reg_index))
388+
{
389+
return 0;
390+
}
391+
392+
rp = pool_elt_at_index (socket_main.registration_pool, reg_index);
358393

359394
/* Flush output vector. */
360395
size_t total_bytes = vec_len (rp->output_vector);
@@ -373,9 +408,7 @@ vl_socket_write_ready (clib_file_t * uf)
373408
#if DEBUG > 2
374409
clib_warning ("write error, close the file...\n");
375410
#endif
376-
clib_file_del (fm, uf);
377-
vl_socket_free_registration_index (rp -
378-
socket_main.registration_pool);
411+
vl_socket_request_remove_reg_index (reg_index);
379412
return 0;
380413
}
381414
remaining_bytes -= bytes_to_send;
@@ -396,13 +429,8 @@ vl_socket_write_ready (clib_file_t * uf)
396429
clib_error_t *
397430
vl_socket_error_ready (clib_file_t * uf)
398431
{
399-
vl_api_registration_t *rp;
400-
clib_file_main_t *fm = &file_main;
401-
402-
rp = pool_elt_at_index (socket_main.registration_pool, uf->private_data);
403-
clib_file_del (fm, uf);
404-
vl_socket_free_registration_index (rp - socket_main.registration_pool);
405-
432+
u32 reg_index = uf->private_data;
433+
vl_socket_request_remove_reg_index (reg_index);
406434
return 0;
407435
}
408436

0 commit comments

Comments
 (0)