i386/123731: [patch][fix][sysvsem] System V semaphores cause unexpected hanging

Ivan Shcheklein shcheklein at gmail.com
Fri May 16 11:30:03 UTC 2008


>Number:         123731
>Category:       i386
>Synopsis:       [patch][fix][sysvsem] System V semaphores cause unexpected hanging
>Confidential:   no
>Severity:       critical
>Priority:       high
>Responsible:    freebsd-i386
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Fri May 16 11:30:02 UTC 2008
>Closed-Date:
>Last-Modified:
>Originator:     Ivan Shcheklein
>Release:        FREEBSD-6.2
>Organization:
ISPRAS
>Environment:
FreeBSD bs. 6.2-RELEASE FreeBSD 6.2-RELEASE #0: Fri Dec 14 20:38:20 MSK 2007     root at bsd.:/usr/obj/usr/src/sys/GENERIC  i386
>Description:
It seems that my previous PR (http://www.freebsd.org/cgi/query-pr.cgi?pr=118153) was too hard to understand. There is no any feedback for a long time and no one was assigned to consider the problem. Moreover it was tagged with [sysvshm] while [sysvsem] is quite better here.

I want to try once again since I suppose it is really critical bug.

The bug itself is the following:

in src/sys/kern/sysv_sem.c,v 1.78 2005/06/07 we have:

1. in line 1066 we get semptr through sem_base
  
    semptr = &semakptr->u.sem_base[sopptr->sem_num];  

2. in lines 1129-1333 we adjust counters using this semptr:

    if (sopptr->sem_op == 0)
        semptr->semzcnt++;
    else
        semptr->semncnt++;

3. in line 1135 we age going to sleep:

    error = msleep(semakptr, sema_mtxp, (PZERO - 4) | PCATCH, "semwait", 0);

4. in lines 1153-1156 after wake up we again adjust counters using the same semptr:

    if (sopptr->sem_op == 0)
         semptr->semzcnt--;
    else
         semptr->semncnt--;

During "msleep" in step 3 "sem_base" of the semaphore can be moved (if other process drops semaphore which was allocated before this one). Therefore, I believe, in step 4 "semptr" value can be invalid and MUST be renewed before use. 

As a circumstantial proof you can also consider the same Darwin's code:

----------------------------------------------------
		/*
		 * IMPORTANT: while we were asleep, the semaphore array might
		 * have been reallocated somewhere else (see grow_sema_array()).
		 * When we wake up, we have to re-lookup the semaphore 
		 * structures and re-validate them.
		 */

		suptr = NULL;	/* sem_undo may have been reallocated */
	 	semaptr = &sema[semid];	   /* sema may have been reallocated */
----------------------------------------------------

This bug can cause unexpected processes hanging in the multiprocess environment which extensively use System V semaphores.

What else do you need to consider this bug?


>How-To-Repeat:

>Fix:
Patch is attached which renew sempth after wakeup:

*** sysv_sem_old.c	Fri Dec 14 18:40:09 2007
--- sysv_sem.c	Fri Dec 14 18:23:46 2007
***************
*** 1145,1154 ****
--- 1145,1159 ----
  			error = EIDRM;
  			goto done2;
  		}
  
  		/*
+ 		 * Renew the semaphore's pointer after wakeup
+ 		 */
+ 		semptr = &semakptr->u.sem_base[sopptr->sem_num];
+ 
+ 		/*
  		 * The semaphore is still alive.  Readjust the count of
  		 * waiting processes.
  		 */
  		if (sopptr->sem_op == 0)
  			semptr->semzcnt--;

Note! Possibly some other strucutures should be also re-validates like in Darwin.

Patch attached with submission follows:

*** sysv_sem_old.c	Fri Dec 14 18:40:09 2007
--- sysv_sem.c	Fri Dec 14 18:23:46 2007
***************
*** 1145,1154 ****
--- 1145,1159 ----
  			error = EIDRM;
  			goto done2;
  		}
  
  		/*
+ 		 * Renew the semaphore's pointer after wakeup
+ 		 */
+ 		semptr = &semakptr->u.sem_base[sopptr->sem_num];
+ 
+ 		/*
  		 * The semaphore is still alive.  Readjust the count of
  		 * waiting processes.
  		 */
  		if (sopptr->sem_op == 0)
  			semptr->semzcnt--;


>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-i386 mailing list