Skip to content

FreeBSD ArgusSourceProcess: pthread_cond_timedwait() error EINVAL #20

@mdtancsa

Description

@mdtancsa

In ArgusSource.c around line 2235, inside the ArgusSourceProcess function, we see how it calculates the timeout:

gettimeofday (tvp, 0L);

         tts->tv_sec  = tvp->tv_sec + 0;
         tts->tv_nsec = (tvp->tv_usec * 1000) + 250000000;
         if (tts->tv_nsec > 1000000000) {
            tts->tv_sec++;
            tts->tv_nsec -= 1000000000;
         }

gettimeofday returns the current time in seconds and microseconds (tv_usec).

The code converts microseconds to nanoseconds (by multiplying by 1,000) and adds 250,000,000 nanoseconds (0.25 seconds) to set a future timeout.

The bug: If gettimeofday happens to fetch a time where the microsecond value is exactly 750000, the math evaluates to: (750000 * 1000) + 250000000 = 1,000,000,000.

The if statement checks if the result is strictly greater than > 1000000000. Since 1,000,000,000 is not greater than itself, it skips the rollover logic.

It then passes exactly 1,000,000,000 to pthread_cond_timedwait(), which violates the POSIX rule requiring nanoseconds to be strictly less than 1,000,000,000. The function immediately rejects it and returns EINVAL, crashing the thread.

The comparison should be
if (tts->tv_nsec >= 1000000000) {

a dtrace probe seems to confirm

#!/usr/sbin/dtrace -s

/* Watch for entry to capture the timespec pointer (arg2) */
pid$target::pthread_cond_timedwait:entry
{
    self->ts_ptr = arg2;
}
/* Watch for the return. If it returns 22 (EINVAL), trigger the output */
pid$target::pthread_cond_timedwait:return
/arg1 == 22/
{

    printf("\npthread_cond_timedwait returned EINVAL!\n");

    /* Attempt to read the timespec struct (tv_sec and tv_nsec) */
    this->ts = (struct timespec *)copyin(self->ts_ptr, sizeof(struct timespec));
    printf("tv_sec: %Y\n", this->ts->tv_sec);
    printf("tv_nsec: %d\n", this->ts->tv_nsec);

 }

# dtrace -s awatch.d -p 9585
dtrace: script 'awatch.d' matched 3 probes
dtrace: pid 9585 exited with status 1
CPU     ID                    FUNCTION:NAME
 21  87869    pthread_cond_timedwait:return 
pthread_cond_timedwait returned EINVAL!
tv_sec: 1969 Dec 31 19:00:01
tv_nsec: 1000000000

              libthr.so.3`pthread_cond_timedwait+0x20
              argus`0x2230cf
              libc.so.7`__libc_start1+0x150
              argus`0x221864
              `0x1b5d97a03008

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions