Skip to content

CAN driver: timestamp option corrupts can_id field in can_callback #367

@xn365

Description

@xn365

Description
When CONFIG_NET_TIMESTAMP is enabled and a CAN socket sets the CAN_RAW_TIMESTAMP option via setsockopt(), transmitted CAN frames occasionally have incorrect CAN IDs. The corrupted IDs show a linear growth pattern matching system timestamp values.
Symptoms

  1. CAN frames sent via SocketCAN interface have wrong CAN IDs on the bus
  2. Corrupted IDs increase linearly over time (e.g., 0x00000001, 0x00000002, ...)
  3. Issue occurs more frequently when sending multiple frames in rapid succession
  4. Problem appears in can_callback() but not in can_poll(), indicating data corruption during callback processing
    Environment
  • Platform: STM32H7 (STM32H743II)
  • Configuration: CONFIG_NET_TIMESTAMP=y, CONFIG_NET_CAN=y
  • Driver: stm32_fdcan_sock.c
    Steps to Reproduce
  1. Enable CONFIG_NET_TIMESTAMP in NuttX configuration
  2. Create a CAN raw socket:
    int sock = socket(PF_CAN, SOCK_RAW, CAN_RAW);
  3. Enable timestamp option:
    int enable = 1;
    setsockopt(sock, SOL_CAN_RAW, CAN_RAW_TIMESTAMP, &enable, sizeof(enable));
    4. Send CAN frames using sendmsg() or write()
  4. Monitor CAN bus - frames will have incorrect IDs matching timestamp values
    Root Cause
    In net/can/can_callback.c, lines 128-135:
#ifdef CONFIG_NET_TIMESTAMP
if (conn->sconn.s_timestamp)
{
    struct timespec *ts = (struct timespec *)&dev->d_appdata[dev->d_len];
    struct timeval *tv = (struct timeval *)&dev->d_appdata[dev->d_len];
    dev->d_len += sizeof(struct timeval);
    clock_systime_timespec(ts);
    tv->tv_usec = ts->tv_nsec / 1000;
}
#endif

Issues:

  1. Buffer overflow: When dev->d_len == 0 (e.g., during CAN_POLL events), timestamp is written to the start of d_appdata, which overlaps with d_buf containing the CAN frame
  2. Type confusion: ts and tv point to the same memory location but are treated as different types
  3. Missing bounds check: No validation that dev->d_len > 0 before writing timestamp
    The timestamp values (tv_sec and tv_usec) overwrite the can_id field in the CAN frame structure, causing transmission of frames with timestamp values as CAN IDs.
    Suggested Fix
#ifdef CONFIG_NET_TIMESTAMP
if (conn->sconn.s_timestamp && dev->d_len > 0)
{
    struct timeval *tv = (struct timeval *)&dev->d_appdata[dev->d_len];
    struct timespec ts;
    dev->d_len += sizeof(struct timeval);
    clock_systime_timespec(&ts);
    tv->tv_sec = ts.tv_sec;
    tv->tv_usec = ts.tv_nsec / 1000;
}
#endif

Changes:

  1. Add dev->d_len > 0 check to prevent writing to empty buffer
  2. Use local timespec variable to avoid type confusion
  3. Properly set both tv_sec and tv_usec fields
    Additional Considerations
  • The issue is more pronounced with multiple frame transmission due to increased probability of CAN_POLL events with d_len == 0
  • Similar code may exist in other network protocol callback functions
  • Buffer pointer synchronization between d_buf and d_appdata should be verified in the driver layer
    Workaround
    Temporarily disable CONFIG_NET_TIMESTAMP or avoid using CAN_RAW_TIMESTAMP socket option.
    References
  • File: nuttx/net/can/can_callback.c
  • Related: stm32_fdcan_sock.c buffer management
  • SocketCAN documentation on timestamp options

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions