Changeset c2287ba2 in rtems


Ignore:
Timestamp:
Mar 10, 2020, 4:07:19 PM (4 months ago)
Author:
Sebastian Huber <sebastian.huber@…>
Branches:
5, master
Children:
aa2d5d93
Parents:
2ff83634
git-author:
Sebastian Huber <sebastian.huber@…> (03/10/20 16:07:19)
git-committer:
Sebastian Huber <sebastian.huber@…> (03/13/20 08:57:04)
Message:

libio: Robust file descriptor reference counting

There was a race conditon in the reference counting of file descriptors
during a close() operation. After the call to the close handler, the
rtems_libio_free() function cleared the flags to zero. However, at this
point in time there may still exist some holders of the file descriptor.
With RTEMS_DEBUG enabled this could lead to failed assertions in
rtems_libio_iop_drop().

Change the code to use only atomic read-modify-write operations on the
rtems_libio_iop::flags.

Files:
10 edited

Legend:

Unmodified
Added
Removed
  • cpukit/include/rtems/libio.h

    r2ff83634 rc2287ba2  
    13191319 */
    13201320struct rtems_libio_tt {
     1321  Atomic_Uint                             flags;
    13211322  off_t                                   offset;    /* current offset into file */
    1322   Atomic_Uint                             flags;
    13231323  rtems_filesystem_location_info_t        pathinfo;
    13241324  uint32_t                                data0;     /* private to "driver" */
  • cpukit/include/rtems/libio_.h

    r2ff83634 rc2287ba2  
    8484 */
    8585extern rtems_filesystem_global_location_t rtems_filesystem_global_location_null;
    86 
    87 /**
    88  * @brief Sets the iop flags to the specified flags together with
    89  * LIBIO_FLAGS_OPEN.
    90  *
    91  * Use this once a file descriptor allocated via rtems_libio_allocate() is
    92  * fully initialized.
    93  *
    94  * @param[in] iop The iop.
    95  * @param[in] flags The flags.
    96  */
    97 static inline void rtems_libio_iop_flags_initialize(
    98   rtems_libio_t *iop,
    99   uint32_t       flags
    100 )
    101 {
    102   _Atomic_Store_uint(
    103     &iop->flags,
    104     LIBIO_FLAGS_OPEN | flags,
    105     ATOMIC_ORDER_RELEASE
    106   );
    107 }
    10886
    10987/**
     
    223201#define rtems_libio_check_is_open(_iop) \
    224202  do {                                               \
    225       if (((_iop)->flags & LIBIO_FLAGS_OPEN) == 0) { \
     203      if ((rtems_libio_iop_flags(_iop) & LIBIO_FLAGS_OPEN) == 0) { \
    226204          errno = EBADF;                             \
    227205          return -1;                                 \
  • cpukit/libcsupport/src/fcntl.c

    r2ff83634 rc2287ba2  
    4646    rv = (*diop->pathinfo.handlers->open_h)( diop, NULL, oflag, 0 );
    4747    if ( rv == 0 ) {
    48       rtems_libio_iop_flags_initialize(
     48      rtems_libio_iop_flags_set(
    4949        diop,
    50         rtems_libio_fcntl_flags( oflag )
     50        LIBIO_FLAGS_OPEN | rtems_libio_fcntl_flags( oflag )
    5151      );
    5252      rv = rtems_libio_iop_to_descriptor( diop );
  • cpukit/libcsupport/src/libio.c

    r2ff83634 rc2287ba2  
    135135)
    136136{
     137  size_t zero;
     138
    137139  rtems_filesystem_location_free( &iop->pathinfo );
    138140
    139141  rtems_libio_lock();
    140142
    141   iop = memset( iop, 0, sizeof( *iop ) );
     143  /*
     144   * Clear everything except the reference count part.  At this point in time
     145   * there may be still some holders of this file descriptor.
     146   */
     147  rtems_libio_iop_flags_clear( iop, LIBIO_FLAGS_REFERENCE_INC - 1U );
     148  zero = offsetof( rtems_libio_t, offset );
     149  memset( (char *) iop + zero, 0, sizeof( *iop ) - zero );
     150
     151  /*
     152   * Append it to the free list.  This increases the likelihood that a use
     153   * after close is detected.
     154   */
    142155  *rtems_libio_iop_free_tail = iop;
    143156  rtems_libio_iop_free_tail = &iop->data1;
  • cpukit/libcsupport/src/open.c

    r2ff83634 rc2287ba2  
    116116  rtems_filesystem_eval_path_cleanup( &ctx );
    117117
    118   _Atomic_Store_uint(
    119     &iop->flags,
    120     rtems_libio_fcntl_flags( oflag ),
    121     ATOMIC_ORDER_RELAXED
    122   );
     118  rtems_libio_iop_flags_set( iop, rtems_libio_fcntl_flags( oflag ) );
    123119
    124120  rv = (*iop->pathinfo.handlers->open_h)( iop, path, oflag, mode );
  • cpukit/libcsupport/src/sup_fs_deviceio.c

    r2ff83634 rc2287ba2  
    3535
    3636  args.iop = iop;
    37   args.flags = iop->flags;
     37  args.flags = rtems_libio_iop_flags( iop );
    3838  args.mode = mode;
    3939
     
    7676  args.buffer = buf;
    7777  args.count = nbyte;
    78   args.flags = iop->flags;
     78  args.flags = rtems_libio_iop_flags( iop );
    7979  args.bytes_moved = 0;
    8080
     
    104104  args.buffer = RTEMS_DECONST( void *, buf );
    105105  args.count = nbyte;
    106   args.flags = iop->flags;
     106  args.flags = rtems_libio_iop_flags( iop );
    107107  args.bytes_moved = 0;
    108108
  • cpukit/libcsupport/src/termios.c

    r2ff83634 rc2287ba2  
    21112111  memset (&args, 0, sizeof (args));
    21122112  args.iop = iop;
    2113   args.flags = iop->flags;
     2113  args.flags = rtems_libio_iop_flags (iop);
    21142114  args.mode = mode;
    21152115
     
    21632163    args.buffer = buffer;
    21642164    args.count = count;
    2165     args.flags = iop->flags;
     2165    args.flags = rtems_libio_iop_flags (iop);
    21662166
    21672167    sc = rtems_termios_linesw[tty->t_line].l_read (tty, &args);
     
    22032203    args.buffer = RTEMS_DECONST (void *, buffer);
    22042204    args.count = count;
    2205     args.flags = iop->flags;
     2205    args.flags = rtems_libio_iop_flags (iop);
    22062206
    22072207    sc = rtems_termios_linesw[tty->t_line].l_write (tty, &args);
  • cpukit/libnetworking/rtems/rtems_syscall.c

    r2ff83634 rc2287ba2  
    8888  iop->pathinfo.mt_entry = &rtems_filesystem_null_mt_entry;
    8989  rtems_filesystem_location_add_to_mt_entry(&iop->pathinfo);
    90   rtems_libio_iop_flags_initialize(iop, LIBIO_FLAGS_READ_WRITE);
     90  rtems_libio_iop_flags_set(iop, LIBIO_FLAGS_OPEN | LIBIO_FLAGS_READ_WRITE);
    9191  return fd;
    9292}
     
    740740so_ioctl (rtems_libio_t *iop, struct socket *so, uint32_t   command, void *buffer)
    741741{
     742        unsigned int nonblock;
     743
    742744        switch (command) {
    743745        case FIONBIO:
     746                nonblock = rtems_libio_fcntl_flags (O_NONBLOCK);
     747
    744748                if (*(int *)buffer) {
    745                         iop->flags |= O_NONBLOCK;
     749                        rtems_libio_iop_flags_set (iop, nonblock);
    746750                        so->so_state |= SS_NBIO;
    747751                }
    748752                else {
    749                         iop->flags &= ~O_NONBLOCK;
     753                        rtems_libio_iop_flags_clear (iop, nonblock);
    750754                        so->so_state &= ~SS_NBIO;
    751755                }
  • cpukit/posix/src/shmopen.c

    r2ff83634 rc2287ba2  
    287287  rtems_filesystem_location_add_to_mt_entry( &iop->pathinfo );
    288288
    289   flags = LIBIO_FLAGS_CLOSE_ON_EXEC;
     289  flags = LIBIO_FLAGS_OPEN | LIBIO_FLAGS_CLOSE_ON_EXEC;
    290290  if ( (oflag & O_ACCMODE) == O_RDONLY ) {
    291291    flags |= LIBIO_FLAGS_READ;
     
    294294  }
    295295
    296   rtems_libio_iop_flags_initialize( iop, flags );
     296  rtems_libio_iop_flags_set( iop, flags );
    297297
    298298  return fd;
  • testsuites/fstests/fsclose01/init.c

    r2ff83634 rc2287ba2  
    11/*
    2  * Copyright (c) 2012, 2018 embedded brains GmbH.  All rights reserved.
     2 * Copyright (C) 2012, 2020 embedded brains GmbH (http://www.embedded-brains.de)
    33 *
    4  *  embedded brains GmbH
    5  *  Dornierstr. 4
    6  *  82178 Puchheim
    7  *  Germany
    8  *  <rtems@embedded-brains.de>
     4 * Redistribution and use in source and binary forms, with or without
     5 * modification, are permitted provided that the following conditions
     6 * are met:
     7 * 1. Redistributions of source code must retain the above copyright
     8 *    notice, this list of conditions and the following disclaimer.
     9 * 2. Redistributions in binary form must reproduce the above copyright
     10 *    notice, this list of conditions and the following disclaimer in the
     11 *    documentation and/or other materials provided with the distribution.
    912 *
    10  * The license and distribution terms for this file may be
    11  * found in the file LICENSE in this distribution or at
    12  * http://www.rtems.org/license/LICENSE.
     13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     16 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
     17 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     23 * POSSIBILITY OF SUCH DAMAGE.
    1324 */
    1425
     
    3344
    3445typedef enum {
    35   ACTION_ClOSE,
     46  ACTION_CLOSE,
    3647  ACTION_FCNTL,
    3748  ACTION_FDATASYNC,
     
    329340
    330341    switch (ctx->action) {
    331       case ACTION_ClOSE:
     342      case ACTION_CLOSE:
    332343        ctx->wait_in_close = true;
    333344        rv = close(ctx->fd);
     
    461472  rtems_test_assert(sc == RTEMS_SUCCESSFUL);
    462473
    463   for (ac = ACTION_ClOSE; ac <= ACTION_WRITEV; ++ac) {
     474  for (ac = ACTION_CLOSE; ac <= ACTION_WRITEV; ++ac) {
     475    rtems_libio_t *iop;
     476    unsigned int flags;
     477    unsigned int expected_flags;
     478
    464479    ctx->action = ac;
    465480    ctx->fd = open(path, O_RDWR);
    466481    rtems_test_assert(ctx->fd >= 0);
     482    iop = rtems_libio_iop(ctx->fd);
    467483
    468484    wakeup_worker(ctx);
     
    470486    rtems_test_assert(rv == -1);
    471487
    472     if (ac == ACTION_ClOSE) {
     488    if (ac == ACTION_CLOSE) {
    473489      rtems_test_assert(errno == EBADF);
     490
     491      flags = rtems_libio_iop_hold(iop);
     492      expected_flags = LIBIO_FLAGS_READ_WRITE;
     493      rtems_test_assert(flags == expected_flags);
     494      flags = rtems_libio_iop_flags(iop);
     495      expected_flags = LIBIO_FLAGS_REFERENCE_INC | LIBIO_FLAGS_READ_WRITE;
     496      rtems_test_assert(flags == expected_flags);
    474497    } else {
    475498      rtems_test_assert(errno == EBUSY);
     
    477500
    478501    wakeup_worker(ctx);
     502
     503    if (ac == ACTION_CLOSE) {
     504      flags = rtems_libio_iop_flags(iop);
     505      expected_flags = LIBIO_FLAGS_REFERENCE_INC;
     506      rtems_test_assert(flags == expected_flags);
     507      rtems_libio_iop_drop(iop);
     508      flags = rtems_libio_iop_flags(iop);
     509      expected_flags = 0;
     510      rtems_test_assert(flags == expected_flags);
     511    }
     512
    479513    rv = close(ctx->fd);
    480514
    481     if (ac == ACTION_ClOSE) {
     515    if (ac == ACTION_CLOSE) {
    482516      rtems_test_assert(rv == -1);
    483517      rtems_test_assert(errno == EBADF);
Note: See TracChangeset for help on using the changeset viewer.