You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 7 Next »

In threading, pthreads have the option of being set to cancel immediately or defer until a specific cancellation point. Canceling asynchronously (immediately) is dangerous, however, because most threads are in fact not safe to cancel immediately.

The IEEE standards page states that:

only functions that are cancel-safe may be called from a thread that is asynchronously cancelable.

Canceling asynchronously would follow the same route as passing a signal in to the thread to kill it, thus posing similarities to POS44-C. Do not use signals to terminate threads, which is strongly related to SIG02-C. Avoid using signals to implement normal functionality. These expand on the dangers of canceling a thread suddenly as this can create a data race condition.

Noncompliant Code Example

In this noncompliant code example the thread is doing something as simple as swapping a and b repeatedly. However, this thread is can potentially create a data race condition. Because an asynchronous cancel can happen at ANY time, it could cancel right before the last line (a = c) and thereby lose the old value of b.

volatile int a, b;
pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t mut_sig = PTHREAD_COND_INITIALIZER;

void main(void) {
  int j;

  pthread_mutex_lock(&mut);
  pthread_create(&thread_identifier,NULL,(void*)thread, NULL);

  /* wait until canceltype is set */
  pthread_cond_wait(&mut_sig, &mut);
  pthread_mutex_unlock(&mut);

  /* do stuff, like data input */
  j = getc(STDIN);
  /* since we don't know when the character is read in, the program could continue at any time */
  pthread_cancel(thread_identifier);

  printf("a: %i | b: %i", a, b);

  /* clean up */
  pthread_mutex_destroy(&mut);
  pthread_cond_destroy(&mut_sig);
}

void thread(void) {
  int i, c;

  /* set the cancelability flag during mutex. */
  /* this guarantees this block calls after pthread_cond_wait() and, more importantly, before pthread_cancel() */
  pthread_mutex_lock(&mut);
  pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,&i);
  pthread_cond_signal(&mut_sig);
  pthread_mutex_unlock(&mut);

  while (1) {
    c = b;
    b = a;
    a = c;
  }
}

Compliant Solution

From IEEE standards page:

The cancelability state and type of any newly created threads, including the thread in which main() was first invoked, shall be PTHREAD_CANCEL_ENABLE and PTHREAD_CANCEL_DEFERRED respectively.

Since the default condition according to the IEEE standards for POSIX is PTHREAD_CANCEL_DEFERRED, one would simply not set cancel type for the compliant solution.

However, since not all compilers are necessarily guaranteed to follow standards, one could also explicitly call pthread_setcanceltype with PTHREAD_CANCEL_DEFERRED.

volatile int a, b;
pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t mut_sig = PTHREAD_COND_INITIALIZER;

void main(void) {
  int j;

  pthread_mutex_lock(&mut);
  pthread_create(&thread_identifier,NULL,(void*)thread, NULL);

  /* wait until canceltype is set */
  pthread_cond_wait(&mut_sig, &mut);
  pthread_mutex_unlock(&mut);

  /* do stuff, like data input */
  j = getc(STDIN);
  /* since we don't know when the character is read in, the program could continue at any time */
  pthread_cancel(thread_identifier);

  /* pthread_join waits for the thread to finish up before continuing */
  pthread_join(thread_identifier, 0);

  printf("a: %i | b: %i", a, b);

  /* clean up */
  pthread_mutex_destroy(&mut);
  pthread_cond_destroy(&mut_sig);
}
void thread(void) {
  int i, c;

  /* set the cancelability flag during mutex. */
  /* this guarantees this block calls after pthread_cond_wait() and, more importantly, before pthread_cancel() */
  pthread_mutex_lock(&mut);
  pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,&i);
  pthread_cond_signal(&mut_sig);
  pthread_mutex_unlock(&mut);

  while (1) {
    c = b;
    b = a;
    a = c;
    /* now we're safe to cancel, creating cancel point */
    pthread_testcancel();
  }
}

Risk Assessment

Incorrectly using threads that asynchronously cancel may result in silent corruption and, in the worst case, unpredictable interactions.

Automated Detection

TODO

Related Vulnerabilities

Search for vulnerabilities resulting from the violation of this rule on the CERT website.

Other Languages

In Java, similar reasoning resulted in the deprecation of Thread.stop() and appears in the Java Secure Coding Standard as CON13-J. Do not use Thread.stop() to terminate threads .

References

[[MKS]] pthread_cancel() Man Page
[[Open Group 04]] Threads Overview

  • No labels