From f87ede57a2e97f0743a85b94072c7163fa485ae9 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Thu, 15 Jan 2015 14:13:19 +0100 Subject: libnetworking: Fix close of active sockets Send a special event to notify tasks waiting for a socket state change in case this socket gets closed. This prevents a use after free. Close #785. --- cpukit/libnetworking/rtems/rtems_glue.c | 102 ++++++++++++++++---------------- 1 file changed, 51 insertions(+), 51 deletions(-) (limited to 'cpukit/libnetworking/rtems/rtems_glue.c') diff --git a/cpukit/libnetworking/rtems/rtems_glue.c b/cpukit/libnetworking/rtems/rtems_glue.c index 4c90a98a75..9d122e46a5 100644 --- a/cpukit/libnetworking/rtems/rtems_glue.c +++ b/cpukit/libnetworking/rtems/rtems_glue.c @@ -432,47 +432,68 @@ rtems_bsdnet_semaphore_release (void) #endif } -/* - * Wait for something to happen to a socket buffer - */ -int -sbwait(struct sockbuf *sb) +static int +rtems_bsdnet_sleep(rtems_event_set in, rtems_interval ticks) { - rtems_event_set events; - rtems_id tid; rtems_status_code sc; + rtems_event_set out; + rtems_event_set out2; + + in |= RTEMS_EVENT_SYSTEM_NETWORK_CLOSE; /* - * Soak up any pending events. - * The sleep/wakeup synchronization in the FreeBSD - * kernel has no memory. + * Soak up any pending events. The sleep/wakeup synchronization in the + * FreeBSD kernel has no memory. */ - rtems_event_system_receive (SBWAIT_EVENT, RTEMS_EVENT_ANY | RTEMS_NO_WAIT, RTEMS_NO_TIMEOUT, &events); + rtems_event_system_receive(in, RTEMS_EVENT_ANY | RTEMS_NO_WAIT, + RTEMS_NO_TIMEOUT, &out); /* - * Set this task as the target of the wakeup operation. + * Wait for the wakeup event. */ - rtems_task_ident (RTEMS_SELF, 0, &tid); - sb->sb_sel.si_pid = tid; + sc = rtems_bsdnet_event_receive(in, RTEMS_EVENT_ANY | RTEMS_WAIT, + ticks, &out); /* - * Show that socket is waiting + * Get additional events that may have been received between the + * rtems_event_system_receive() and the rtems_bsdnet_semaphore_obtain(). */ - sb->sb_flags |= SB_WAIT; + rtems_event_system_receive(in, RTEMS_EVENT_ANY | RTEMS_NO_WAIT, + RTEMS_NO_TIMEOUT, &out2); + out |= out2; + + if (out & RTEMS_EVENT_SYSTEM_NETWORK_CLOSE) + return (ENXIO); + + if (sc == RTEMS_SUCCESSFUL) + return (0); + + return (EWOULDBLOCK); +} + +/* + * Wait for something to happen to a socket buffer + */ +int +sbwait(struct sockbuf *sb) +{ + int error; /* - * Wait for the wakeup event. + * Set this task as the target of the wakeup operation. */ - sc = rtems_bsdnet_event_receive (SBWAIT_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT, sb->sb_timeo, &events); + sb->sb_sel.si_pid = rtems_task_self(); /* - * Return the status of the wait. + * Show that socket is waiting */ - switch (sc) { - case RTEMS_SUCCESSFUL: return 0; - case RTEMS_TIMEOUT: return EWOULDBLOCK; - default: return ENXIO; - } + sb->sb_flags |= SB_WAIT; + + error = rtems_bsdnet_sleep(SBWAIT_EVENT, sb->sb_timeo); + if (error != ENXIO) + sb->sb_flags &= ~SB_WAIT; + + return (error); } @@ -485,7 +506,6 @@ sowakeup( struct sockbuf *sb) { if (sb->sb_flags & SB_WAIT) { - sb->sb_flags &= ~SB_WAIT; rtems_event_system_send (sb->sb_sel.si_pid, SBWAIT_EVENT); } if (sb->sb_wakeup) { @@ -514,40 +534,20 @@ wakeup (void *p) int soconnsleep (struct socket *so) { - rtems_event_set events; - rtems_id tid; - rtems_status_code sc; - - /* - * Soak up any pending events. - * The sleep/wakeup synchronization in the FreeBSD - * kernel has no memory. - */ - rtems_event_system_receive (SOSLEEP_EVENT, RTEMS_EVENT_ANY | RTEMS_NO_WAIT, RTEMS_NO_TIMEOUT, &events); + int error; /* * Set this task as the target of the wakeup operation. */ if (so->so_pgid) rtems_panic ("Another task is already sleeping on that socket"); - rtems_task_ident (RTEMS_SELF, 0, &tid); - so->so_pgid = tid; - - /* - * Wait for the wakeup event. - */ - sc = rtems_bsdnet_event_receive (SOSLEEP_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT, so->so_rcv.sb_timeo, &events); + so->so_pgid = rtems_task_self(); - /* - * Relinquish ownership of the socket. - */ - so->so_pgid = 0; + error = rtems_bsdnet_sleep(SOSLEEP_EVENT, so->so_rcv.sb_timeo); + if (error != ENXIO) + so->so_pgid = 0; - switch (sc) { - case RTEMS_SUCCESSFUL: return 0; - case RTEMS_TIMEOUT: return EWOULDBLOCK; - default: return ENXIO; - } + return (error); } /* -- cgit v1.2.3