nuttx/libs/libc/misc/lib_fdcheck.c
hujun5 08e6f56176 fdcheck: fix race condition in fdcheck
reason: ioctl will use the fl_lock file lock, causing context switching,
further leading to the failure of g_fdcheck_lock protection

Configuring NuttX and compile:
$ ./tools/configure.sh -l qemu-armv8a:nsh_smp
$ make
Running with qemu
$ qemu-system-aarch64 -cpu cortex-a53 -smp 4 -nographic \
   -machine virt,virtualization=on,gic-version=3 \
   -net none -chardev stdio,id=con,mux=on -serial chardev:con \
   -mon chardev=con,mode=readline -kernel ./nuttx

Signed-off-by: hujun5 <hujun5@xiaomi.com>
2024-08-18 10:27:03 -03:00

130 lines
3.5 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/****************************************************************************
* libs/libc/misc/lib_fdcheck.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/fdcheck.h>
#include <nuttx/lib/math32.h>
#include <nuttx/sched.h>
#include <nuttx/spinlock.h>
#include <sys/ioctl.h>
#include <debug.h>
#include <stdio.h>
#ifdef CONFIG_FDCHECK
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define TAG_SHIFT 0
#define TAG_BITS 8
#define TAG_MASK ((1 << TAG_BITS) - 1)
#define FD_SHIFT (TAG_SHIFT + TAG_BITS)
#define FD_BITS LOG2_CEIL(OPEN_MAX)
#define FD_MASK ((1 << FD_BITS) - 1)
static_assert(FD_BITS <= TAG_BITS, "FD_BITS is too long");
/****************************************************************************
* Private Data
****************************************************************************/
static spinlock_t g_fdcheck_lock = SP_UNLOCKED;
static uint8_t g_fdcheck_tag = 0;
/****************************************************************************
* Public Functions
****************************************************************************/
int fdcheck_restore(int val)
{
uint8_t tag_store;
int fd;
/* If val is a bare fd0~255, we should return it directly */
fd = (val >> FD_SHIFT) & FD_MASK;
if (fd == 0 || val < 0)
{
return val;
}
int ret = ioctl(fd, FIOC_GETTAG_FDCHECK, &tag_store);
if (ret >= 0)
{
uint8_t tag_expect = (val >> TAG_SHIFT) & TAG_MASK;
if (tag_expect != tag_store)
{
ferr("tag_expect 0x%x tag_store 0x%x\n",
tag_expect, tag_store);
PANIC();
}
}
return fd;
}
int fdcheck_protect(int fd)
{
int protect_fd;
uint8_t tag;
int ret;
if (fd <= 2)
{
return fd;
}
protect_fd = (fd & FD_MASK) << FD_SHIFT;
ret = ioctl(fd, FIOC_GETTAG_FDCHECK, &tag);
DEBUGASSERT(ret >= 0);
if (tag == 0)
{
uint8_t fdcheck_tag;
irqstate_t flags = spin_lock_irqsave(&g_fdcheck_lock);
if ((++g_fdcheck_tag & TAG_MASK) == 0)
{
++g_fdcheck_tag;
}
g_fdcheck_tag &= TAG_MASK;
protect_fd |= g_fdcheck_tag << TAG_SHIFT;
fdcheck_tag = g_fdcheck_tag;
spin_unlock_irqrestore(&g_fdcheck_lock, flags);
ret = ioctl(fd, FIOC_SETTAG_FDCHECK, &fdcheck_tag);
DEBUGASSERT(ret == 0);
}
else
{
protect_fd |= (tag & TAG_MASK) << TAG_SHIFT;
}
return protect_fd;
}
#endif