SIGSEGV instead of EINVAL with invalid timer id in timer_delete() glibc 2.33

Bug #1940296 reported by Colin Ian King
10
This bug affects 2 people
Affects Status Importance Assigned to Milestone
GLibC
Unknown
Medium
glibc (Ubuntu)
Confirmed
High
Unassigned

Bug Description

The timer_delete(2) man page states:

RETURN VALUE
       On success, timer_delete() returns 0. On failure, -1 is returned,
       and errno is set to indicate the error.

ERRORS
       EINVAL timerid is not a valid timer ID.

The following shows that this is not strictly true:

$ cat t.c

#include <time.h>
#include <stdlib.h>

int main(void)
{
        timer_t t = (timer_t)0xe236f38802c65008ULL;

        return timer_delete(t);
}

$ gcc t.c -lrt -g
./a.out
Segmentation fault (core dumped)

$ valgrind ./a.out
==30195== Memcheck, a memory error detector
==30195== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==30195== Using Valgrind-3.17.0 and LibVEX; rerun with -h for copyright info
==30195== Command: ./a.out
==30195==
==30195== Invalid read of size 4
==30195== at 0x487FBF7: timerid_to_kernel_timer (kernel-posix-timers.h:94)
==30195== by 0x487FBF7: timer_delete@@GLIBC_2.3.3 (timer_delete.c:35)
==30195== by 0x10916E: main (t.c:8)
==30195== Address 0xc46de710058ca010 is not stack'd, malloc'd or (recently) free'd
==30195==
==30195==
==30195== Process terminating with default action of signal 11 (SIGSEGV)
==30195== General Protection Fault
==30195== at 0x487FBF7: timerid_to_kernel_timer (kernel-posix-timers.h:94)
==30195== by 0x487FBF7: timer_delete@@GLIBC_2.3.3 (timer_delete.c:35)
==30195== by 0x10916E: main (t.c:8)
==30195==
==30195== HEAP SUMMARY:
==30195== in use at exit: 0 bytes in 0 blocks
==30195== total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==30195==
==30195== All heap blocks were freed -- no leaks are possible
==30195==
==30195== For lists of detected and suppressed errors, rerun with: -s
==30195== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Segmentation fault (core dumped)

Changed in glibc (Ubuntu):
importance: Undecided → High
description: updated
description: updated
Revision history for this message
Michael Hudson-Doyle (mwhudson) wrote :

This still happens with 2.34 fwiw. Do you want to report this at https://sourceware.org/bugzilla/ or do you want me to do that?

Revision history for this message
Colin Ian King (colin-king) wrote :

Hi Michael, do you mind following that up with the bugzilla report for me?

Revision history for this message
Colin Ian King (colin-king) wrote :

Same issue with timer_gettime():

int main(void)
{
        timer_t t = (timer_t)0xe236f38802c65008ULL;
        struct itimerspec v;

        return timer_gettime(t, &v);
}

..should return -EINVAL but instead segfaults.

Revision history for this message
Colin Ian King (colin-king) wrote :

And timer_settime():

#include <time.h>
#include <stdlib.h>

int main(void)
{
        timer_t t = (timer_t)0xe236f38802c65008ULL;
        struct itimerspec new, old;

        return timer_settime(t, 0, &new, &old);
}

Revision history for this message
In , Michael Hudson-Doyle (mwhudson) wrote :

Forwarding from https://bugs.launchpad.net/ubuntu/+source/glibc/+bug/1940296:

The timer_delete(2) man page states:

RETURN VALUE
       On success, timer_delete() returns 0. On failure, -1 is returned,
       and errno is set to indicate the error.

ERRORS
       EINVAL timerid is not a valid timer ID.

The following shows that this is not strictly true:

$ cat t.c

#include <time.h>
#include <stdlib.h>

int main(void)
{
        timer_t t = (timer_t)0xe236f38802c65008ULL;

        return timer_delete(t);
}

$ gcc t.c -lrt -g
./a.out
Segmentation fault (core dumped)

$ valgrind ./a.out
==30195== Memcheck, a memory error detector
==30195== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==30195== Using Valgrind-3.17.0 and LibVEX; rerun with -h for copyright info
==30195== Command: ./a.out
==30195==
==30195== Invalid read of size 4
==30195== at 0x487FBF7: timerid_to_kernel_timer (kernel-posix-timers.h:94)
==30195== by 0x487FBF7: timer_delete@@GLIBC_2.3.3 (timer_delete.c:35)
==30195== by 0x10916E: main (t.c:8)
==30195== Address 0xc46de710058ca010 is not stack'd, malloc'd or (recently) free'd
==30195==
==30195==
==30195== Process terminating with default action of signal 11 (SIGSEGV)
==30195== General Protection Fault
==30195== at 0x487FBF7: timerid_to_kernel_timer (kernel-posix-timers.h:94)
==30195== by 0x487FBF7: timer_delete@@GLIBC_2.3.3 (timer_delete.c:35)
==30195== by 0x10916E: main (t.c:8)
==30195==
==30195== HEAP SUMMARY:
==30195== in use at exit: 0 bytes in 0 blocks
==30195== total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==30195==
==30195== All heap blocks were freed -- no leaks are possible
==30195==
==30195== For lists of detected and suppressed errors, rerun with: -s
==30195== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Segmentation fault (core dumped)

Similar things happen with timer_gettime and timer_settime.

Revision history for this message
Michael Hudson-Doyle (mwhudson) wrote :
Revision history for this message
In , Florian Weimer (fweimer) wrote :

Please report this to the man-pages project if the manual page is unclear.

POSIX clearly describes what the program is doing as undefined behavior:


The behavior is undefined if the value specified by the timerid argument to timer_delete() does not correspond to a timer ID returned by timer_create() but not yet deleted by timer_delete().

Revision history for this message
Dimitri John Ledkov (xnox) wrote :

/* Check whether timer is valid; global mutex must be held. */
static inline int
timer_valid (struct timer_node *timer)
{
  return timer && timer->inuse == TIMER_INUSE;
}

if some memory, casted to a timer_node struct, happens to have inuse field match the value of TIMER_INUSE the validation check passes, and it is attempted to be used.

What could be done is check if the passed in timer, is actually in __timer_array, such that we only try to operate on the valid ones.

Not sure what glibc prior to 2.33 did to check/detect it.

Changed in glibc:
importance: Unknown → Medium
Revision history for this message
Launchpad Janitor (janitor) wrote :

Status changed to 'Confirmed' because the bug affects multiple users.

Changed in glibc (Ubuntu):
status: New → Confirmed
To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.