Changeset f87ede5 in rtems


Ignore:
Timestamp:
01/15/15 13:13:19 (9 years ago)
Author:
Sebastian Huber <sebastian.huber@…>
Branches:
4.11, 5, master
Children:
60d39b66
Parents:
51c88e8b
git-author:
Sebastian Huber <sebastian.huber@…> (01/15/15 13:13:19)
git-committer:
Sebastian Huber <sebastian.huber@…> (01/20/15 06:11:58)
Message:

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.

Files:
8 edited

Legend:

Unmodified
Added
Removed
  • cpukit/libnetworking/kern/uipc_socket.c

    r51c88e8b rf87ede5  
    146146}
    147147
     148static void
     149rtems_socket_close_notify(struct socket *so)
     150{
     151        if (so->so_pgid) {
     152                rtems_event_system_send(so->so_pgid, RTEMS_EVENT_SYSTEM_NETWORK_CLOSE);
     153        }
     154}
     155
     156static void
     157rtems_sockbuf_close_notify(struct socket *so, struct sockbuf *sb)
     158{
     159        if (sb->sb_flags & SB_WAIT) {
     160                rtems_event_system_send(sb->sb_sel.si_pid,
     161                    RTEMS_EVENT_SYSTEM_NETWORK_CLOSE);
     162        }
     163
     164        if (sb->sb_wakeup)
     165                (*sb->sb_wakeup)(so, sb->sb_wakeuparg);
     166}
     167
    148168/*
    149169 * Close a socket on last file table reference removal.
     
    156176        int s = splnet();               /* conservative */
    157177        int error = 0;
     178
     179        rtems_socket_close_notify(so);
     180        rtems_sockbuf_close_notify(so, &so->so_snd);
     181        rtems_sockbuf_close_notify(so, &so->so_rcv);
    158182
    159183        if (so->so_options & SO_ACCEPTCONN) {
     
    743767                        error = sbwait(&so->so_rcv);
    744768                        if (error) {
    745                                 sbunlock(&so->so_rcv);
     769                                if (error != ENXIO)
     770                                        sbunlock(&so->so_rcv);
    746771                                splx(s);
    747772                                return (0);
  • cpukit/libnetworking/rtems/rtems_bsdnet_internal.h

    r51c88e8b rf87ede5  
    220220#define NETISR_ARP_EVENT       (1L << NETISR_ARP)
    221221#define NETISR_EVENTS  (NETISR_IP_EVENT|NETISR_ARP_EVENT)
    222 #if (SBWAIT_EVENT & SOSLEEP_EVENT & NETISR_EVENTS)
     222#if (SBWAIT_EVENT & SOSLEEP_EVENT & NETISR_EVENTS & RTEMS_EVENT_SYSTEM_NETWORK_CLOSE)
    223223# error "Network event conflict"
    224224#endif
  • cpukit/libnetworking/rtems/rtems_glue.c

    r51c88e8b rf87ede5  
    433433}
    434434
     435static int
     436rtems_bsdnet_sleep(rtems_event_set in, rtems_interval ticks)
     437{
     438        rtems_status_code sc;
     439        rtems_event_set out;
     440        rtems_event_set out2;
     441
     442        in |= RTEMS_EVENT_SYSTEM_NETWORK_CLOSE;
     443
     444        /*
     445         * Soak up any pending events.  The sleep/wakeup synchronization in the
     446         * FreeBSD kernel has no memory.
     447         */
     448        rtems_event_system_receive(in, RTEMS_EVENT_ANY | RTEMS_NO_WAIT,
     449            RTEMS_NO_TIMEOUT, &out);
     450
     451        /*
     452         * Wait for the wakeup event.
     453         */
     454        sc = rtems_bsdnet_event_receive(in, RTEMS_EVENT_ANY | RTEMS_WAIT,
     455            ticks, &out);
     456
     457        /*
     458         * Get additional events that may have been received between the
     459         * rtems_event_system_receive() and the rtems_bsdnet_semaphore_obtain().
     460         */
     461        rtems_event_system_receive(in, RTEMS_EVENT_ANY | RTEMS_NO_WAIT,
     462            RTEMS_NO_TIMEOUT, &out2);
     463        out |= out2;
     464
     465        if (out & RTEMS_EVENT_SYSTEM_NETWORK_CLOSE)
     466                return (ENXIO);
     467
     468        if (sc == RTEMS_SUCCESSFUL)
     469                return (0);
     470
     471        return (EWOULDBLOCK);
     472}
     473
    435474/*
    436475 * Wait for something to happen to a socket buffer
     
    439478sbwait(struct sockbuf *sb)
    440479{
    441         rtems_event_set events;
    442         rtems_id tid;
    443         rtems_status_code sc;
    444 
    445         /*
    446          * Soak up any pending events.
    447          * The sleep/wakeup synchronization in the FreeBSD
    448          * kernel has no memory.
    449          */
    450         rtems_event_system_receive (SBWAIT_EVENT, RTEMS_EVENT_ANY | RTEMS_NO_WAIT, RTEMS_NO_TIMEOUT, &events);
     480        int error;
    451481
    452482        /*
    453483         * Set this task as the target of the wakeup operation.
    454484         */
    455         rtems_task_ident (RTEMS_SELF, 0, &tid);
    456         sb->sb_sel.si_pid = tid;
     485        sb->sb_sel.si_pid = rtems_task_self();
    457486
    458487        /*
     
    461490        sb->sb_flags |= SB_WAIT;
    462491
    463         /*
    464          * Wait for the wakeup event.
    465          */
    466         sc = rtems_bsdnet_event_receive (SBWAIT_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT, sb->sb_timeo, &events);
    467 
    468         /*
    469          * Return the status of the wait.
    470          */
    471         switch (sc) {
    472         case RTEMS_SUCCESSFUL:  return 0;
    473         case RTEMS_TIMEOUT:     return EWOULDBLOCK;
    474         default:                return ENXIO;
    475         }
     492        error = rtems_bsdnet_sleep(SBWAIT_EVENT, sb->sb_timeo);
     493        if (error != ENXIO)
     494                sb->sb_flags &= ~SB_WAIT;
     495
     496        return (error);
    476497}
    477498
     
    486507{
    487508        if (sb->sb_flags & SB_WAIT) {
    488                 sb->sb_flags &= ~SB_WAIT;
    489509                rtems_event_system_send (sb->sb_sel.si_pid, SBWAIT_EVENT);
    490510        }
     
    515535soconnsleep (struct socket *so)
    516536{
    517         rtems_event_set events;
    518         rtems_id tid;
    519         rtems_status_code sc;
    520 
    521         /*
    522          * Soak up any pending events.
    523          * The sleep/wakeup synchronization in the FreeBSD
    524          * kernel has no memory.
    525          */
    526         rtems_event_system_receive (SOSLEEP_EVENT, RTEMS_EVENT_ANY | RTEMS_NO_WAIT, RTEMS_NO_TIMEOUT, &events);
     537        int error;
    527538
    528539        /*
     
    531542        if (so->so_pgid)
    532543                rtems_panic ("Another task is already sleeping on that socket");
    533         rtems_task_ident (RTEMS_SELF, 0, &tid);
    534         so->so_pgid = tid;
    535 
    536         /*
    537          * Wait for the wakeup event.
    538          */
    539         sc = rtems_bsdnet_event_receive (SOSLEEP_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT, so->so_rcv.sb_timeo, &events);
    540 
    541         /*
    542          * Relinquish ownership of the socket.
    543          */
    544         so->so_pgid = 0;
    545 
    546         switch (sc) {
    547         case RTEMS_SUCCESSFUL:  return 0;
    548         case RTEMS_TIMEOUT:     return EWOULDBLOCK;
    549         default:                return ENXIO;
    550         }
     544        so->so_pgid = rtems_task_self();
     545
     546        error = rtems_bsdnet_sleep(SOSLEEP_EVENT, so->so_rcv.sb_timeo);
     547        if (error != ENXIO)
     548                so->so_pgid = 0;
     549
     550        return (error);
    551551}
    552552
  • cpukit/libnetworking/rtems/rtems_select.c

    r51c88e8b rf87ede5  
    120120        rtems_id tid;
    121121        rtems_interval then = 0, now;
    122         rtems_event_set events;
     122        rtems_event_set in = SBWAIT_EVENT | RTEMS_EVENT_SYSTEM_NETWORK_CLOSE;
     123        rtems_event_set out;
    123124
    124125        if (nfds < 0)
     
    146147
    147148        rtems_task_ident (RTEMS_SELF, 0, &tid);
    148         rtems_event_system_receive (SBWAIT_EVENT, RTEMS_EVENT_ANY | RTEMS_NO_WAIT, RTEMS_NO_TIMEOUT, &events);
     149        rtems_event_system_receive (in, RTEMS_EVENT_ANY | RTEMS_NO_WAIT, RTEMS_NO_TIMEOUT, &out);
    149150        for (;;) {
    150151                rtems_bsdnet_semaphore_obtain ();
     
    160161                        then = now;
    161162                }
    162                 rtems_event_system_receive (SBWAIT_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT, timo, &events);
     163                rtems_event_system_receive (in, RTEMS_EVENT_ANY | RTEMS_WAIT, timo, &out);
    163164        }
    164165
  • cpukit/libnetworking/rtems/rtems_syscall.c

    r51c88e8b rf87ede5  
    205205                return -1;
    206206        }
    207         while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
     207        error = so->so_error;
     208        while (error == 0 && (so->so_state & SS_ISCONNECTING)) {
    208209                error = soconnsleep (so);
    209210                if (error)
    210211                        break;
    211         }
    212         if (error == 0) {
    213212                error = so->so_error;
    214213                so->so_error = 0;
    215214        }
    216215    bad:
    217         so->so_state &= ~SS_ISCONNECTING;
     216        if (error != ENXIO)
     217                so->so_state &= ~SS_ISCONNECTING;
    218218        m_freem (nam);
    219219        if (error)
     
    250250        struct socket *head, *so;
    251251        struct mbuf *nam;
     252        int error;
    252253
    253254        rtems_bsdnet_semaphore_obtain ();
     
    266267                return -1;
    267268        }
    268         while (head->so_comp.tqh_first == NULL && head->so_error == 0) {
     269        error = head->so_error;
     270        while (error ==  0 && head->so_comp.tqh_first == NULL) {
    269271                if (head->so_state & SS_CANTRCVMORE) {
    270                         head->so_error = ECONNABORTED;
     272                        error = ECONNABORTED;
    271273                        break;
    272274                }
    273                 head->so_error = soconnsleep (head);
     275                error = soconnsleep (head);
    274276        }
    275         if (head->so_error) {
    276                 errno = head->so_error;
    277                 head->so_error = 0;
     277        if (error) {
     278                errno = error;
    278279                rtems_bsdnet_semaphore_release ();
    279280                return -1;
     
    716717                return -1;
    717718        }
     719        iop->data1 = NULL;
    718720        error = soclose (so);
    719721        rtems_bsdnet_semaphore_release ();
  • cpukit/rtems/include/rtems/rtems/event.h

    r51c88e8b rf87ede5  
    315315
    316316/**
     317 * @brief Reserved system event for network socket close.
     318 */
     319#define RTEMS_EVENT_SYSTEM_NETWORK_CLOSE RTEMS_EVENT_26
     320
     321/**
    317322 * @brief Reserved system event for transient usage.
    318323 */
  • testsuites/libtests/syscall01/init.c

    r51c88e8b rf87ede5  
    11/*
    2  * Copyright (c) 2012 embedded brains GmbH.  All rights reserved.
     2 * Copyright (c) 2012-2015 embedded brains GmbH.  All rights reserved.
    33 *
    44 *  embedded brains GmbH
    5  *  Obere Lagerstr. 30
     5 *  Dornierstr. 4
    66 *  82178 Puchheim
    77 *  Germany
     
    1919#include "tmacros.h"
    2020
     21#include <sys/select.h>
    2122#include <sys/socket.h>
    2223#include <sys/stat.h>
     24#include <netinet/in.h>
    2325#include <errno.h>
    2426#include <fcntl.h>
     
    3032const char rtems_test_name[] = "SYSCALL 1";
    3133
    32 /* forward declarations to avoid warnings */
    33 static rtems_task Init(rtems_task_argument argument);
    34 
    3534static const char open_driver_path [] = "/dev/open_driver";
    3635
    3736struct rtems_bsdnet_config rtems_bsdnet_config;
    3837
    39 static void test(void)
     38typedef struct {
     39  rtems_id main_task;
     40  rtems_id close_task;
     41  int fd;
     42} test_context;
     43
     44static test_context test_instance;
     45
     46static void test_sync(void)
    4047{
    4148  int rv;
     
    7784}
    7885
     86static void close_task(rtems_task_argument arg)
     87{
     88  test_context *ctx = (test_context *) arg;
     89
     90  while (true) {
     91    rtems_status_code sc;
     92    int rv;
     93
     94    rv = close(ctx->fd);
     95    rtems_test_assert(rv == 0);
     96
     97    sc = rtems_event_transient_send(ctx->main_task);
     98    rtems_test_assert(sc == RTEMS_SUCCESSFUL);
     99  }
     100}
     101
     102static void wait_for_close_task(void)
     103{
     104  rtems_status_code sc;
     105
     106  sc = rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT);
     107  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
     108}
     109
     110static void test_accept_and_close(test_context *ctx)
     111{
     112  int rv;
     113  int fd;
     114  struct sockaddr_in addr;
     115  socklen_t addrlen = sizeof(addr);
     116
     117  ctx->fd = socket(PF_INET, SOCK_STREAM, 0);
     118  rtems_test_assert(ctx->fd >= 0);
     119
     120  rv = listen(ctx->fd, 1);
     121  rtems_test_assert(rv == 0);
     122
     123  errno = 0;
     124  fd = accept(ctx->fd, (struct sockaddr *) &addr, &addrlen);
     125  rtems_test_assert(fd == -1);
     126  rtems_test_assert(errno == ENXIO);
     127
     128  errno = 0;
     129  fd = accept(ctx->fd, (struct sockaddr *) &addr, &addrlen);
     130  rtems_test_assert(fd == -1);
     131  rtems_test_assert(errno == EBADF);
     132
     133  wait_for_close_task();
     134}
     135
     136static void test_connect_and_close(test_context *ctx)
     137{
     138  int rv;
     139  struct sockaddr_in addr;
     140  socklen_t addrlen = sizeof(addr);
     141
     142  ctx->fd = socket(PF_INET, SOCK_STREAM, 0);
     143  rtems_test_assert(ctx->fd >= 0);
     144
     145  memset(&addr, 0, sizeof(addr));
     146  addr.sin_family = AF_INET;
     147  addr.sin_port = htons(1234);
     148  addr.sin_addr.s_addr = htonl(INADDR_ANY);
     149
     150  errno = 0;
     151  rv = connect(ctx->fd, (struct sockaddr *) &addr, addrlen);
     152  rtems_test_assert(rv == -1);
     153  rtems_test_assert(errno == ENXIO);
     154
     155  errno = 0;
     156  rv = connect(ctx->fd, (struct sockaddr *) &addr, addrlen);
     157  rtems_test_assert(rv == -1);
     158  rtems_test_assert(errno == EBADF);
     159
     160  wait_for_close_task();
     161}
     162
     163static void test_recv_and_close(test_context *ctx)
     164{
     165  int rv;
     166  struct sockaddr_in addr;
     167  socklen_t addrlen = sizeof(addr);
     168  char buf[1];
     169  ssize_t n;
     170
     171  ctx->fd = socket(PF_INET, SOCK_DGRAM, 0);
     172  rtems_test_assert(ctx->fd >= 0);
     173
     174  memset(&addr, 0, sizeof(addr));
     175  addr.sin_family = AF_INET;
     176  addr.sin_port = htons(1234);
     177  addr.sin_addr.s_addr = htonl(INADDR_ANY);
     178
     179  rv = bind(ctx->fd, (struct sockaddr *) &addr, addrlen);
     180  rtems_test_assert(rv == 0);
     181
     182  errno = 0;
     183  n = recv(ctx->fd, &buf[0], sizeof(buf), 0);
     184  rtems_test_assert(n == -1);
     185  rtems_test_assert(errno == ENXIO);
     186
     187  errno = 0;
     188  n = recv(ctx->fd, &buf[0], sizeof(buf), 0);
     189  rtems_test_assert(n == -1);
     190  rtems_test_assert(errno == EBADF);
     191
     192  wait_for_close_task();
     193}
     194
     195static void test_select_and_close(test_context *ctx)
     196{
     197  int rv;
     198  struct sockaddr_in addr;
     199  socklen_t addrlen = sizeof(addr);
     200  int nfds;
     201  struct fd_set set;
     202
     203  ctx->fd = socket(PF_INET, SOCK_DGRAM, 0);
     204  rtems_test_assert(ctx->fd >= 0);
     205
     206  memset(&addr, 0, sizeof(addr));
     207  addr.sin_family = AF_INET;
     208  addr.sin_port = htons(1234);
     209  addr.sin_addr.s_addr = htonl(INADDR_ANY);
     210
     211  rv = bind(ctx->fd, (struct sockaddr *) &addr, addrlen);
     212  rtems_test_assert(rv == 0);
     213
     214  nfds = ctx->fd + 1;
     215  FD_ZERO(&set);
     216  FD_SET(ctx->fd, &set);
     217
     218  errno = 0;
     219  rv = select(nfds, &set, NULL, NULL, NULL);
     220  rtems_test_assert(rv == -1);
     221  rtems_test_assert(errno == EBADF);
     222
     223  wait_for_close_task();
     224}
     225
    79226static void Init(rtems_task_argument arg)
    80227{
     228  test_context *ctx = &test_instance;
     229  rtems_status_code sc;
    81230  int rv;
    82231
    83232  TEST_BEGIN();
    84233
     234  ctx->main_task = rtems_task_self();
     235
     236  sc = rtems_task_create(
     237    rtems_build_name('C', 'L', 'O', 'S'),
     238    2,
     239    RTEMS_MINIMUM_STACK_SIZE,
     240    RTEMS_DEFAULT_MODES,
     241    RTEMS_DEFAULT_ATTRIBUTES,
     242    &ctx->close_task
     243  );
     244  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
     245
     246  sc = rtems_task_start(
     247    ctx->close_task,
     248    close_task,
     249    (rtems_task_argument) ctx
     250  );
     251  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
     252
    85253  rv = rtems_bsdnet_initialize_network();
    86254  rtems_test_assert(rv == 0);
    87255
    88   test();
     256  test_sync();
     257  test_accept_and_close(ctx);
     258  test_connect_and_close(ctx);
     259  test_recv_and_close(ctx);
     260  test_select_and_close(ctx);
     261
     262  sc = rtems_task_delete(ctx->close_task);
     263  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
    89264
    90265  TEST_END();
     
    130305#define CONFIGURE_LIBIO_MAXIMUM_FILE_DESCRIPTORS 4
    131306
    132 #define CONFIGURE_MAXIMUM_TASKS 2
     307#define CONFIGURE_MAXIMUM_TASKS 3
    133308
    134309#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
  • testsuites/samples/loopback/init.c

    r51c88e8b rf87ede5  
    168168        s1 = accept(s, (struct sockaddr *)&farAddr, &addrlen);
    169169        if (s1 < 0)
    170             rtems_panic("Can't accept connection: %s", strerror(errno));
     170            if (errno == ENXIO)
     171                rtems_task_delete(RTEMS_SELF);
     172            else
     173                rtems_panic("Can't accept connection: %s", strerror(errno));
    171174        else
    172175            printf("ACCEPTED:%lX\n", ntohl(farAddr.sin_addr.s_addr));
Note: See TracChangeset for help on using the changeset viewer.