2005-01-06 23:35:40 +00:00
|
|
|
/*-
|
1994-09-13 14:47:38 +00:00
|
|
|
* Implementation of SVID semaphores
|
|
|
|
*
|
|
|
|
* Author: Daniel Boulet
|
|
|
|
*
|
|
|
|
* This software is provided ``AS IS'' without any warranties of any kind.
|
|
|
|
*/
|
2005-01-22 19:04:17 +00:00
|
|
|
/*-
|
|
|
|
* Copyright (c) 2003-2005 McAfee, Inc.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* This software was developed for the FreeBSD Project in part by McAfee
|
|
|
|
* Research, the Security Research Division of McAfee, Inc under DARPA/SPAWAR
|
|
|
|
* contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS research
|
|
|
|
* program.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*/
|
1994-09-13 14:47:38 +00:00
|
|
|
|
2003-06-11 00:56:59 +00:00
|
|
|
#include <sys/cdefs.h>
|
|
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
|
2009-06-24 20:01:13 +00:00
|
|
|
#include "opt_compat.h"
|
2000-05-01 13:33:56 +00:00
|
|
|
#include "opt_sysvipc.h"
|
|
|
|
|
1994-09-13 14:47:38 +00:00
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/systm.h>
|
1995-10-21 19:50:00 +00:00
|
|
|
#include <sys/sysproto.h>
|
2003-03-24 21:15:35 +00:00
|
|
|
#include <sys/eventhandler.h>
|
1994-09-13 14:47:38 +00:00
|
|
|
#include <sys/kernel.h>
|
|
|
|
#include <sys/proc.h>
|
2001-08-31 00:02:18 +00:00
|
|
|
#include <sys/lock.h>
|
2004-05-30 20:34:58 +00:00
|
|
|
#include <sys/module.h>
|
2001-08-31 00:02:18 +00:00
|
|
|
#include <sys/mutex.h>
|
2011-04-06 18:11:24 +00:00
|
|
|
#include <sys/racct.h>
|
1994-09-13 14:47:38 +00:00
|
|
|
#include <sys/sem.h>
|
2000-12-01 08:57:47 +00:00
|
|
|
#include <sys/syscall.h>
|
2006-06-27 18:28:50 +00:00
|
|
|
#include <sys/syscallsubr.h>
|
1995-10-21 19:50:00 +00:00
|
|
|
#include <sys/sysent.h>
|
2000-05-01 13:33:56 +00:00
|
|
|
#include <sys/sysctl.h>
|
2006-06-27 18:28:50 +00:00
|
|
|
#include <sys/uio.h>
|
2000-05-01 13:33:56 +00:00
|
|
|
#include <sys/malloc.h>
|
2000-10-31 01:34:00 +00:00
|
|
|
#include <sys/jail.h>
|
2006-10-22 11:52:19 +00:00
|
|
|
|
|
|
|
#include <security/mac/mac_framework.h>
|
2000-05-01 13:33:56 +00:00
|
|
|
|
2011-02-25 10:11:01 +00:00
|
|
|
FEATURE(sysv_sem, "System V semaphores support");
|
|
|
|
|
2000-05-01 13:33:56 +00:00
|
|
|
static MALLOC_DEFINE(M_SEM, "sem", "SVID compatible semaphores");
|
1994-09-13 14:47:38 +00:00
|
|
|
|
2002-07-22 18:27:54 +00:00
|
|
|
#ifdef SEM_DEBUG
|
|
|
|
#define DPRINTF(a) printf a
|
|
|
|
#else
|
|
|
|
#define DPRINTF(a)
|
|
|
|
#endif
|
|
|
|
|
2010-03-19 11:04:42 +00:00
|
|
|
static int seminit(void);
|
2002-03-19 21:25:46 +00:00
|
|
|
static int sysvsem_modload(struct module *, int, void *);
|
|
|
|
static int semunload(void);
|
2003-03-24 21:15:35 +00:00
|
|
|
static void semexit_myhook(void *arg, struct proc *p);
|
2002-03-19 21:25:46 +00:00
|
|
|
static int sysctl_sema(SYSCTL_HANDLER_ARGS);
|
2004-11-12 13:23:47 +00:00
|
|
|
static int semvalid(int semid, struct semid_kernel *semakptr);
|
1995-08-28 09:19:25 +00:00
|
|
|
|
1995-12-15 05:00:31 +00:00
|
|
|
#ifndef _SYS_SYSPROTO_H_
|
|
|
|
struct __semctl_args;
|
2002-03-19 21:25:46 +00:00
|
|
|
int __semctl(struct thread *td, struct __semctl_args *uap);
|
1995-10-21 19:50:00 +00:00
|
|
|
struct semget_args;
|
2002-03-19 21:25:46 +00:00
|
|
|
int semget(struct thread *td, struct semget_args *uap);
|
1995-10-21 19:50:00 +00:00
|
|
|
struct semop_args;
|
2002-03-19 21:25:46 +00:00
|
|
|
int semop(struct thread *td, struct semop_args *uap);
|
1995-12-15 05:00:31 +00:00
|
|
|
#endif
|
1995-10-21 19:50:00 +00:00
|
|
|
|
2002-03-19 21:25:46 +00:00
|
|
|
static struct sem_undo *semu_alloc(struct thread *td);
|
2003-11-07 04:47:14 +00:00
|
|
|
static int semundo_adjust(struct thread *td, struct sem_undo **supptr,
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
int semid, int semseq, int semnum, int adjval);
|
2002-03-19 21:25:46 +00:00
|
|
|
static void semundo_clear(int semid, int semnum);
|
1995-10-21 19:50:00 +00:00
|
|
|
|
2002-08-13 08:47:17 +00:00
|
|
|
static struct mtx sem_mtx; /* semaphore global lock */
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
static struct mtx sem_undo_mtx;
|
1995-12-14 08:32:45 +00:00
|
|
|
static int semtot = 0;
|
2004-11-12 13:23:47 +00:00
|
|
|
static struct semid_kernel *sema; /* semaphore id pool */
|
2002-08-13 08:47:17 +00:00
|
|
|
static struct mtx *sema_mtx; /* semaphore id pool mutexes*/
|
2000-05-01 13:33:56 +00:00
|
|
|
static struct sem *sem; /* semaphore pool */
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
LIST_HEAD(, sem_undo) semu_list; /* list of active undo structures */
|
|
|
|
LIST_HEAD(, sem_undo) semu_free_list; /* list of free undo structures */
|
2000-05-01 13:33:56 +00:00
|
|
|
static int *semu; /* undo structure pool */
|
2003-03-24 21:15:35 +00:00
|
|
|
static eventhandler_tag semexit_tag;
|
2000-05-01 13:33:56 +00:00
|
|
|
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
#define SEMUNDO_MTX sem_undo_mtx
|
2002-08-13 08:47:17 +00:00
|
|
|
#define SEMUNDO_LOCK() mtx_lock(&SEMUNDO_MTX);
|
|
|
|
#define SEMUNDO_UNLOCK() mtx_unlock(&SEMUNDO_MTX);
|
|
|
|
#define SEMUNDO_LOCKASSERT(how) mtx_assert(&SEMUNDO_MTX, (how));
|
|
|
|
|
2000-05-01 13:33:56 +00:00
|
|
|
struct sem {
|
|
|
|
u_short semval; /* semaphore value */
|
|
|
|
pid_t sempid; /* pid of last operation */
|
|
|
|
u_short semncnt; /* # awaiting semval > cval */
|
|
|
|
u_short semzcnt; /* # awaiting semval = 0 */
|
|
|
|
};
|
1994-09-13 14:47:38 +00:00
|
|
|
|
2000-05-01 13:33:56 +00:00
|
|
|
/*
|
|
|
|
* Undo structure (one per process)
|
|
|
|
*/
|
|
|
|
struct sem_undo {
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
LIST_ENTRY(sem_undo) un_next; /* ptr to next active undo structure */
|
2000-05-01 13:33:56 +00:00
|
|
|
struct proc *un_proc; /* owner of this structure */
|
|
|
|
short un_cnt; /* # of active entries */
|
|
|
|
struct undo {
|
|
|
|
short un_adjval; /* adjust on exit values */
|
|
|
|
short un_num; /* semaphore # */
|
|
|
|
int un_id; /* semid */
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
unsigned short un_seq;
|
2000-05-01 13:33:56 +00:00
|
|
|
} un_ent[1]; /* undo entries */
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Configuration parameters
|
|
|
|
*/
|
|
|
|
#ifndef SEMMNI
|
2010-06-11 09:27:33 +00:00
|
|
|
#define SEMMNI 50 /* # of semaphore identifiers */
|
2000-05-01 13:33:56 +00:00
|
|
|
#endif
|
|
|
|
#ifndef SEMMNS
|
2010-06-11 09:27:33 +00:00
|
|
|
#define SEMMNS 340 /* # of semaphores in system */
|
2000-05-01 13:33:56 +00:00
|
|
|
#endif
|
|
|
|
#ifndef SEMUME
|
2010-06-11 09:27:33 +00:00
|
|
|
#define SEMUME 50 /* max # of undo entries per process */
|
2000-05-01 13:33:56 +00:00
|
|
|
#endif
|
|
|
|
#ifndef SEMMNU
|
2010-06-11 09:27:33 +00:00
|
|
|
#define SEMMNU 150 /* # of undo structures in system */
|
2000-05-01 13:33:56 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/* shouldn't need tuning */
|
|
|
|
#ifndef SEMMAP
|
|
|
|
#define SEMMAP 30 /* # of entries in semaphore map */
|
|
|
|
#endif
|
|
|
|
#ifndef SEMMSL
|
|
|
|
#define SEMMSL SEMMNS /* max # of semaphores per id */
|
|
|
|
#endif
|
|
|
|
#ifndef SEMOPM
|
|
|
|
#define SEMOPM 100 /* max # of operations per semop call */
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define SEMVMX 32767 /* semaphore maximum value */
|
|
|
|
#define SEMAEM 16384 /* adjust on exit max value */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Due to the way semaphore memory is allocated, we have to ensure that
|
|
|
|
* SEMUSZ is properly aligned.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define SEM_ALIGN(bytes) (((bytes) + (sizeof(long) - 1)) & ~(sizeof(long) - 1))
|
|
|
|
|
|
|
|
/* actual size of an undo structure */
|
|
|
|
#define SEMUSZ SEM_ALIGN(offsetof(struct sem_undo, un_ent[SEMUME]))
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Macro to find a particular sem_undo vector
|
|
|
|
*/
|
2002-08-05 05:16:09 +00:00
|
|
|
#define SEMU(ix) \
|
|
|
|
((struct sem_undo *)(((intptr_t)semu)+ix * seminfo.semusz))
|
2000-05-01 13:33:56 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* semaphore info struct
|
|
|
|
*/
|
|
|
|
struct seminfo seminfo = {
|
|
|
|
SEMMAP, /* # of entries in semaphore map */
|
|
|
|
SEMMNI, /* # of semaphore identifiers */
|
|
|
|
SEMMNS, /* # of semaphores in system */
|
|
|
|
SEMMNU, /* # of undo structures in system */
|
|
|
|
SEMMSL, /* max # of semaphores per id */
|
|
|
|
SEMOPM, /* max # of operations per semop call */
|
|
|
|
SEMUME, /* max # of undo entries per process */
|
|
|
|
SEMUSZ, /* size in bytes of undo structure */
|
|
|
|
SEMVMX, /* semaphore maximum value */
|
|
|
|
SEMAEM /* adjust on exit max value */
|
|
|
|
};
|
|
|
|
|
2005-02-12 01:22:39 +00:00
|
|
|
SYSCTL_INT(_kern_ipc, OID_AUTO, semmap, CTLFLAG_RW, &seminfo.semmap, 0,
|
|
|
|
"Number of entries in the semaphore map");
|
|
|
|
SYSCTL_INT(_kern_ipc, OID_AUTO, semmni, CTLFLAG_RDTUN, &seminfo.semmni, 0,
|
|
|
|
"Number of semaphore identifiers");
|
|
|
|
SYSCTL_INT(_kern_ipc, OID_AUTO, semmns, CTLFLAG_RDTUN, &seminfo.semmns, 0,
|
|
|
|
"Maximum number of semaphores in the system");
|
|
|
|
SYSCTL_INT(_kern_ipc, OID_AUTO, semmnu, CTLFLAG_RDTUN, &seminfo.semmnu, 0,
|
|
|
|
"Maximum number of undo structures in the system");
|
|
|
|
SYSCTL_INT(_kern_ipc, OID_AUTO, semmsl, CTLFLAG_RW, &seminfo.semmsl, 0,
|
|
|
|
"Max semaphores per id");
|
|
|
|
SYSCTL_INT(_kern_ipc, OID_AUTO, semopm, CTLFLAG_RDTUN, &seminfo.semopm, 0,
|
|
|
|
"Max operations per semop call");
|
|
|
|
SYSCTL_INT(_kern_ipc, OID_AUTO, semume, CTLFLAG_RDTUN, &seminfo.semume, 0,
|
|
|
|
"Max undo entries per process");
|
|
|
|
SYSCTL_INT(_kern_ipc, OID_AUTO, semusz, CTLFLAG_RDTUN, &seminfo.semusz, 0,
|
|
|
|
"Size in bytes of undo structure");
|
|
|
|
SYSCTL_INT(_kern_ipc, OID_AUTO, semvmx, CTLFLAG_RW, &seminfo.semvmx, 0,
|
|
|
|
"Semaphore maximum value");
|
|
|
|
SYSCTL_INT(_kern_ipc, OID_AUTO, semaem, CTLFLAG_RW, &seminfo.semaem, 0,
|
|
|
|
"Adjust on exit max value");
|
2011-01-18 21:14:18 +00:00
|
|
|
SYSCTL_PROC(_kern_ipc, OID_AUTO, sema, CTLTYPE_OPAQUE | CTLFLAG_RD,
|
2010-11-14 06:09:50 +00:00
|
|
|
NULL, 0, sysctl_sema, "", "Semaphore id pool");
|
2000-05-01 13:33:56 +00:00
|
|
|
|
2010-03-19 11:04:42 +00:00
|
|
|
static struct syscall_helper_data sem_syscalls[] = {
|
|
|
|
SYSCALL_INIT_HELPER(__semctl),
|
|
|
|
SYSCALL_INIT_HELPER(semget),
|
|
|
|
SYSCALL_INIT_HELPER(semop),
|
|
|
|
#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
|
|
|
|
defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
|
|
|
|
SYSCALL_INIT_HELPER(semsys),
|
|
|
|
SYSCALL_INIT_HELPER(freebsd7___semctl),
|
|
|
|
#endif
|
|
|
|
SYSCALL_INIT_LAST
|
|
|
|
};
|
|
|
|
|
|
|
|
#ifdef COMPAT_FREEBSD32
|
|
|
|
#include <compat/freebsd32/freebsd32.h>
|
|
|
|
#include <compat/freebsd32/freebsd32_ipc.h>
|
|
|
|
#include <compat/freebsd32/freebsd32_proto.h>
|
|
|
|
#include <compat/freebsd32/freebsd32_signal.h>
|
|
|
|
#include <compat/freebsd32/freebsd32_syscall.h>
|
|
|
|
#include <compat/freebsd32/freebsd32_util.h>
|
|
|
|
|
|
|
|
static struct syscall_helper_data sem32_syscalls[] = {
|
|
|
|
SYSCALL32_INIT_HELPER(freebsd32_semctl),
|
|
|
|
SYSCALL32_INIT_HELPER(semget),
|
|
|
|
SYSCALL32_INIT_HELPER(semop),
|
|
|
|
SYSCALL32_INIT_HELPER(freebsd32_semsys),
|
|
|
|
#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
|
|
|
|
defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
|
|
|
|
SYSCALL32_INIT_HELPER(freebsd7_freebsd32_semctl),
|
|
|
|
#endif
|
|
|
|
SYSCALL_INIT_LAST
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static int
|
2000-12-01 08:57:47 +00:00
|
|
|
seminit(void)
|
1994-09-13 14:47:38 +00:00
|
|
|
{
|
2010-03-19 11:04:42 +00:00
|
|
|
int i, error;
|
1994-09-13 14:47:38 +00:00
|
|
|
|
2001-09-13 20:20:09 +00:00
|
|
|
TUNABLE_INT_FETCH("kern.ipc.semmap", &seminfo.semmap);
|
|
|
|
TUNABLE_INT_FETCH("kern.ipc.semmni", &seminfo.semmni);
|
|
|
|
TUNABLE_INT_FETCH("kern.ipc.semmns", &seminfo.semmns);
|
|
|
|
TUNABLE_INT_FETCH("kern.ipc.semmnu", &seminfo.semmnu);
|
|
|
|
TUNABLE_INT_FETCH("kern.ipc.semmsl", &seminfo.semmsl);
|
|
|
|
TUNABLE_INT_FETCH("kern.ipc.semopm", &seminfo.semopm);
|
|
|
|
TUNABLE_INT_FETCH("kern.ipc.semume", &seminfo.semume);
|
|
|
|
TUNABLE_INT_FETCH("kern.ipc.semusz", &seminfo.semusz);
|
|
|
|
TUNABLE_INT_FETCH("kern.ipc.semvmx", &seminfo.semvmx);
|
|
|
|
TUNABLE_INT_FETCH("kern.ipc.semaem", &seminfo.semaem);
|
|
|
|
|
2003-02-19 05:47:46 +00:00
|
|
|
sem = malloc(sizeof(struct sem) * seminfo.semmns, M_SEM, M_WAITOK);
|
2004-11-12 13:23:47 +00:00
|
|
|
sema = malloc(sizeof(struct semid_kernel) * seminfo.semmni, M_SEM,
|
2003-02-19 05:47:46 +00:00
|
|
|
M_WAITOK);
|
2002-08-13 08:47:17 +00:00
|
|
|
sema_mtx = malloc(sizeof(struct mtx) * seminfo.semmni, M_SEM,
|
2003-02-19 05:47:46 +00:00
|
|
|
M_WAITOK | M_ZERO);
|
|
|
|
semu = malloc(seminfo.semmnu * seminfo.semusz, M_SEM, M_WAITOK);
|
1994-09-13 14:47:38 +00:00
|
|
|
|
|
|
|
for (i = 0; i < seminfo.semmni; i++) {
|
2004-11-12 13:23:47 +00:00
|
|
|
sema[i].u.sem_base = 0;
|
|
|
|
sema[i].u.sem_perm.mode = 0;
|
|
|
|
sema[i].u.sem_perm.seq = 0;
|
2005-01-22 19:04:17 +00:00
|
|
|
#ifdef MAC
|
2007-10-24 19:04:04 +00:00
|
|
|
mac_sysvsem_init(&sema[i]);
|
2005-01-22 19:04:17 +00:00
|
|
|
#endif
|
1994-09-13 14:47:38 +00:00
|
|
|
}
|
2002-08-13 08:47:17 +00:00
|
|
|
for (i = 0; i < seminfo.semmni; i++)
|
|
|
|
mtx_init(&sema_mtx[i], "semid", NULL, MTX_DEF);
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
LIST_INIT(&semu_free_list);
|
1994-09-13 14:47:38 +00:00
|
|
|
for (i = 0; i < seminfo.semmnu; i++) {
|
2002-08-05 05:16:09 +00:00
|
|
|
struct sem_undo *suptr = SEMU(i);
|
1994-09-13 14:47:38 +00:00
|
|
|
suptr->un_proc = NULL;
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
LIST_INSERT_HEAD(&semu_free_list, suptr, un_next);
|
1994-09-13 14:47:38 +00:00
|
|
|
}
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
LIST_INIT(&semu_list);
|
2002-08-13 08:47:17 +00:00
|
|
|
mtx_init(&sem_mtx, "sem", NULL, MTX_DEF);
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
mtx_init(&sem_undo_mtx, "semu", NULL, MTX_DEF);
|
2003-03-24 21:15:35 +00:00
|
|
|
semexit_tag = EVENTHANDLER_REGISTER(process_exit, semexit_myhook, NULL,
|
|
|
|
EVENTHANDLER_PRI_ANY);
|
2010-03-19 11:04:42 +00:00
|
|
|
|
|
|
|
error = syscall_helper_register(sem_syscalls);
|
|
|
|
if (error != 0)
|
|
|
|
return (error);
|
|
|
|
#ifdef COMPAT_FREEBSD32
|
|
|
|
error = syscall32_helper_register(sem32_syscalls);
|
|
|
|
if (error != 0)
|
|
|
|
return (error);
|
|
|
|
#endif
|
|
|
|
return (0);
|
1994-09-13 14:47:38 +00:00
|
|
|
}
|
2000-12-01 08:57:47 +00:00
|
|
|
|
|
|
|
static int
|
|
|
|
semunload(void)
|
|
|
|
{
|
2002-08-13 08:47:17 +00:00
|
|
|
int i;
|
2000-12-01 08:57:47 +00:00
|
|
|
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
/* XXXKIB */
|
2000-12-01 08:57:47 +00:00
|
|
|
if (semtot != 0)
|
|
|
|
return (EBUSY);
|
|
|
|
|
2010-03-19 11:04:42 +00:00
|
|
|
#ifdef COMPAT_FREEBSD32
|
|
|
|
syscall32_helper_unregister(sem32_syscalls);
|
|
|
|
#endif
|
|
|
|
syscall_helper_unregister(sem_syscalls);
|
2003-03-24 21:15:35 +00:00
|
|
|
EVENTHANDLER_DEREGISTER(process_exit, semexit_tag);
|
2005-01-22 19:04:17 +00:00
|
|
|
#ifdef MAC
|
|
|
|
for (i = 0; i < seminfo.semmni; i++)
|
2007-10-24 19:04:04 +00:00
|
|
|
mac_sysvsem_destroy(&sema[i]);
|
2005-01-22 19:04:17 +00:00
|
|
|
#endif
|
2000-12-01 08:57:47 +00:00
|
|
|
free(sem, M_SEM);
|
|
|
|
free(sema, M_SEM);
|
|
|
|
free(semu, M_SEM);
|
2002-08-13 08:47:17 +00:00
|
|
|
for (i = 0; i < seminfo.semmni; i++)
|
|
|
|
mtx_destroy(&sema_mtx[i]);
|
2009-03-30 15:01:29 +00:00
|
|
|
free(sema_mtx, M_SEM);
|
2002-08-13 08:47:17 +00:00
|
|
|
mtx_destroy(&sem_mtx);
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
mtx_destroy(&sem_undo_mtx);
|
2000-12-01 08:57:47 +00:00
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
sysvsem_modload(struct module *module, int cmd, void *arg)
|
|
|
|
{
|
|
|
|
int error = 0;
|
|
|
|
|
|
|
|
switch (cmd) {
|
|
|
|
case MOD_LOAD:
|
2010-03-19 11:04:42 +00:00
|
|
|
error = seminit();
|
|
|
|
if (error != 0)
|
|
|
|
semunload();
|
2000-12-01 08:57:47 +00:00
|
|
|
break;
|
|
|
|
case MOD_UNLOAD:
|
|
|
|
error = semunload();
|
|
|
|
break;
|
|
|
|
case MOD_SHUTDOWN:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
error = EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
2001-01-14 18:04:30 +00:00
|
|
|
static moduledata_t sysvsem_mod = {
|
|
|
|
"sysvsem",
|
2000-12-01 08:57:47 +00:00
|
|
|
&sysvsem_modload,
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
2009-06-24 13:35:38 +00:00
|
|
|
DECLARE_MODULE(sysvsem, sysvsem_mod, SI_SUB_SYSV_SEM, SI_ORDER_FIRST);
|
2001-01-14 18:04:30 +00:00
|
|
|
MODULE_VERSION(sysvsem, 1);
|
1994-09-13 14:47:38 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Allocate a new sem_undo structure for a process
|
|
|
|
* (returns ptr to structure or NULL if no more room)
|
|
|
|
*/
|
|
|
|
|
1995-12-14 08:32:45 +00:00
|
|
|
static struct sem_undo *
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
semu_alloc(struct thread *td)
|
1994-09-13 14:47:38 +00:00
|
|
|
{
|
2002-08-05 05:16:09 +00:00
|
|
|
struct sem_undo *suptr;
|
1994-09-13 14:47:38 +00:00
|
|
|
|
2002-08-13 08:47:17 +00:00
|
|
|
SEMUNDO_LOCKASSERT(MA_OWNED);
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
if ((suptr = LIST_FIRST(&semu_free_list)) == NULL)
|
|
|
|
return (NULL);
|
|
|
|
LIST_REMOVE(suptr, un_next);
|
|
|
|
LIST_INSERT_HEAD(&semu_list, suptr, un_next);
|
|
|
|
suptr->un_cnt = 0;
|
|
|
|
suptr->un_proc = td->td_proc;
|
|
|
|
return (suptr);
|
|
|
|
}
|
1994-09-13 14:47:38 +00:00
|
|
|
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
static int
|
|
|
|
semu_try_free(struct sem_undo *suptr)
|
|
|
|
{
|
1994-09-13 14:47:38 +00:00
|
|
|
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
SEMUNDO_LOCKASSERT(MA_OWNED);
|
1994-09-13 14:47:38 +00:00
|
|
|
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
if (suptr->un_cnt != 0)
|
|
|
|
return (0);
|
|
|
|
LIST_REMOVE(suptr, un_next);
|
|
|
|
LIST_INSERT_HEAD(&semu_free_list, suptr, un_next);
|
|
|
|
return (1);
|
1994-09-13 14:47:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Adjust a particular entry for a particular proc
|
|
|
|
*/
|
|
|
|
|
1995-12-14 08:32:45 +00:00
|
|
|
static int
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
semundo_adjust(struct thread *td, struct sem_undo **supptr, int semid,
|
|
|
|
int semseq, int semnum, int adjval)
|
1994-09-13 14:47:38 +00:00
|
|
|
{
|
2001-09-12 08:38:13 +00:00
|
|
|
struct proc *p = td->td_proc;
|
2002-08-05 05:16:09 +00:00
|
|
|
struct sem_undo *suptr;
|
|
|
|
struct undo *sunptr;
|
1994-09-13 14:47:38 +00:00
|
|
|
int i;
|
|
|
|
|
2002-08-13 08:47:17 +00:00
|
|
|
SEMUNDO_LOCKASSERT(MA_OWNED);
|
1994-09-13 14:47:38 +00:00
|
|
|
/* Look for and remember the sem_undo if the caller doesn't provide
|
|
|
|
it */
|
|
|
|
|
|
|
|
suptr = *supptr;
|
|
|
|
if (suptr == NULL) {
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
LIST_FOREACH(suptr, &semu_list, un_next) {
|
1994-09-13 14:47:38 +00:00
|
|
|
if (suptr->un_proc == p) {
|
|
|
|
*supptr = suptr;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (suptr == NULL) {
|
|
|
|
if (adjval == 0)
|
|
|
|
return(0);
|
2001-09-12 08:38:13 +00:00
|
|
|
suptr = semu_alloc(td);
|
1994-09-13 14:47:38 +00:00
|
|
|
if (suptr == NULL)
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
return (ENOSPC);
|
1994-09-13 14:47:38 +00:00
|
|
|
*supptr = suptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Look for the requested entry and adjust it (delete if adjval becomes
|
|
|
|
* 0).
|
|
|
|
*/
|
|
|
|
sunptr = &suptr->un_ent[0];
|
|
|
|
for (i = 0; i < suptr->un_cnt; i++, sunptr++) {
|
|
|
|
if (sunptr->un_id != semid || sunptr->un_num != semnum)
|
|
|
|
continue;
|
2001-10-11 08:15:14 +00:00
|
|
|
if (adjval != 0) {
|
|
|
|
adjval += sunptr->un_adjval;
|
|
|
|
if (adjval > seminfo.semaem || adjval < -seminfo.semaem)
|
|
|
|
return (ERANGE);
|
|
|
|
}
|
|
|
|
sunptr->un_adjval = adjval;
|
1994-09-13 14:47:38 +00:00
|
|
|
if (sunptr->un_adjval == 0) {
|
|
|
|
suptr->un_cnt--;
|
|
|
|
if (i < suptr->un_cnt)
|
|
|
|
suptr->un_ent[i] =
|
|
|
|
suptr->un_ent[suptr->un_cnt];
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
if (suptr->un_cnt == 0)
|
|
|
|
semu_try_free(suptr);
|
1994-09-13 14:47:38 +00:00
|
|
|
}
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
return (0);
|
1994-09-13 14:47:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Didn't find the right entry - create it */
|
|
|
|
if (adjval == 0)
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
return (0);
|
2001-10-11 08:15:14 +00:00
|
|
|
if (adjval > seminfo.semaem || adjval < -seminfo.semaem)
|
|
|
|
return (ERANGE);
|
1998-12-14 08:34:55 +00:00
|
|
|
if (suptr->un_cnt != seminfo.semume) {
|
1994-09-13 14:47:38 +00:00
|
|
|
sunptr = &suptr->un_ent[suptr->un_cnt];
|
|
|
|
suptr->un_cnt++;
|
|
|
|
sunptr->un_adjval = adjval;
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
sunptr->un_id = semid;
|
|
|
|
sunptr->un_num = semnum;
|
|
|
|
sunptr->un_seq = semseq;
|
1994-09-13 14:47:38 +00:00
|
|
|
} else
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
return (EINVAL);
|
|
|
|
return (0);
|
1994-09-13 14:47:38 +00:00
|
|
|
}
|
|
|
|
|
1995-12-14 08:32:45 +00:00
|
|
|
static void
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
semundo_clear(int semid, int semnum)
|
1994-09-13 14:47:38 +00:00
|
|
|
{
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
struct sem_undo *suptr, *suptr1;
|
|
|
|
struct undo *sunptr;
|
|
|
|
int i;
|
1994-09-13 14:47:38 +00:00
|
|
|
|
2002-08-13 08:47:17 +00:00
|
|
|
SEMUNDO_LOCKASSERT(MA_OWNED);
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
LIST_FOREACH_SAFE(suptr, &semu_list, un_next, suptr1) {
|
|
|
|
sunptr = &suptr->un_ent[0];
|
|
|
|
for (i = 0; i < suptr->un_cnt; i++, sunptr++) {
|
|
|
|
if (sunptr->un_id != semid)
|
|
|
|
continue;
|
|
|
|
if (semnum == -1 || sunptr->un_num == semnum) {
|
|
|
|
suptr->un_cnt--;
|
|
|
|
if (i < suptr->un_cnt) {
|
|
|
|
suptr->un_ent[i] =
|
|
|
|
suptr->un_ent[suptr->un_cnt];
|
|
|
|
continue;
|
1994-09-13 14:47:38 +00:00
|
|
|
}
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
semu_try_free(suptr);
|
1994-09-13 14:47:38 +00:00
|
|
|
}
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
if (semnum != -1)
|
|
|
|
break;
|
1994-09-13 14:47:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-08-13 08:47:17 +00:00
|
|
|
static int
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
semvalid(int semid, struct semid_kernel *semakptr)
|
2002-08-13 08:47:17 +00:00
|
|
|
{
|
|
|
|
|
2004-11-12 13:23:47 +00:00
|
|
|
return ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0 ||
|
|
|
|
semakptr->u.sem_perm.seq != IPCID_TO_SEQ(semid) ? EINVAL : 0);
|
2002-08-13 08:47:17 +00:00
|
|
|
}
|
|
|
|
|
1995-12-15 05:00:31 +00:00
|
|
|
/*
|
2007-03-04 22:36:48 +00:00
|
|
|
* Note that the user-mode half of this passes a union, not a pointer.
|
1995-12-15 05:00:31 +00:00
|
|
|
*/
|
|
|
|
#ifndef _SYS_SYSPROTO_H_
|
|
|
|
struct __semctl_args {
|
1994-09-13 14:47:38 +00:00
|
|
|
int semid;
|
|
|
|
int semnum;
|
|
|
|
int cmd;
|
|
|
|
union semun *arg;
|
|
|
|
};
|
1995-12-15 05:00:31 +00:00
|
|
|
#endif
|
|
|
|
int
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
__semctl(struct thread *td, struct __semctl_args *uap)
|
1994-09-13 14:47:38 +00:00
|
|
|
{
|
2006-07-08 19:51:38 +00:00
|
|
|
struct semid_ds dsbuf;
|
|
|
|
union semun arg, semun;
|
|
|
|
register_t rval;
|
2006-06-27 18:28:50 +00:00
|
|
|
int error;
|
|
|
|
|
|
|
|
switch (uap->cmd) {
|
|
|
|
case SEM_STAT:
|
|
|
|
case IPC_SET:
|
|
|
|
case IPC_STAT:
|
|
|
|
case GETALL:
|
|
|
|
case SETVAL:
|
|
|
|
case SETALL:
|
2006-07-08 19:51:38 +00:00
|
|
|
error = copyin(uap->arg, &arg, sizeof(arg));
|
2006-06-27 18:28:50 +00:00
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
break;
|
2006-07-08 19:51:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
switch (uap->cmd) {
|
|
|
|
case SEM_STAT:
|
|
|
|
case IPC_STAT:
|
|
|
|
semun.buf = &dsbuf;
|
|
|
|
break;
|
|
|
|
case IPC_SET:
|
|
|
|
error = copyin(arg.buf, &dsbuf, sizeof(dsbuf));
|
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
semun.buf = &dsbuf;
|
|
|
|
break;
|
|
|
|
case GETALL:
|
|
|
|
case SETALL:
|
|
|
|
semun.array = arg.array;
|
|
|
|
break;
|
|
|
|
case SETVAL:
|
|
|
|
semun.val = arg.val;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
error = kern_semctl(td, uap->semid, uap->semnum, uap->cmd, &semun,
|
|
|
|
&rval);
|
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
|
|
|
|
switch (uap->cmd) {
|
|
|
|
case SEM_STAT:
|
|
|
|
case IPC_STAT:
|
|
|
|
error = copyout(&dsbuf, arg.buf, sizeof(dsbuf));
|
2006-06-27 18:28:50 +00:00
|
|
|
break;
|
|
|
|
}
|
2006-07-08 19:51:38 +00:00
|
|
|
|
|
|
|
if (error == 0)
|
|
|
|
td->td_retval[0] = rval;
|
|
|
|
return (error);
|
2006-06-27 18:28:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2006-07-08 19:51:38 +00:00
|
|
|
kern_semctl(struct thread *td, int semid, int semnum, int cmd,
|
|
|
|
union semun *arg, register_t *rval)
|
2006-06-27 18:28:50 +00:00
|
|
|
{
|
|
|
|
u_short *array;
|
2002-02-27 18:32:23 +00:00
|
|
|
struct ucred *cred = td->td_ucred;
|
2006-07-08 19:51:38 +00:00
|
|
|
int i, error;
|
|
|
|
struct semid_ds *sbuf;
|
2004-11-12 13:23:47 +00:00
|
|
|
struct semid_kernel *semakptr;
|
2002-08-13 08:47:17 +00:00
|
|
|
struct mtx *sema_mtxp;
|
|
|
|
u_short usval, count;
|
2006-06-29 13:58:36 +00:00
|
|
|
int semidx;
|
1994-09-13 14:47:38 +00:00
|
|
|
|
2006-07-12 11:41:53 +00:00
|
|
|
DPRINTF(("call to semctl(%d, %d, %d, 0x%p)\n",
|
2002-07-22 18:27:54 +00:00
|
|
|
semid, semnum, cmd, arg));
|
2009-05-27 14:11:23 +00:00
|
|
|
if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC))
|
2002-03-05 18:57:36 +00:00
|
|
|
return (ENOSYS);
|
2000-10-31 01:34:00 +00:00
|
|
|
|
2002-08-13 08:47:17 +00:00
|
|
|
array = NULL;
|
|
|
|
|
2001-09-13 21:06:41 +00:00
|
|
|
switch(cmd) {
|
|
|
|
case SEM_STAT:
|
2006-06-29 13:58:36 +00:00
|
|
|
/*
|
|
|
|
* For this command we assume semid is an array index
|
|
|
|
* rather than an IPC id.
|
|
|
|
*/
|
2002-03-06 12:28:51 +00:00
|
|
|
if (semid < 0 || semid >= seminfo.semmni)
|
2002-08-13 08:47:17 +00:00
|
|
|
return (EINVAL);
|
2004-11-12 13:23:47 +00:00
|
|
|
semakptr = &sema[semid];
|
2002-08-13 08:47:17 +00:00
|
|
|
sema_mtxp = &sema_mtx[semid];
|
|
|
|
mtx_lock(sema_mtxp);
|
2004-11-12 13:23:47 +00:00
|
|
|
if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0) {
|
2002-08-13 08:47:17 +00:00
|
|
|
error = EINVAL;
|
|
|
|
goto done2;
|
|
|
|
}
|
2004-11-12 13:23:47 +00:00
|
|
|
if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R)))
|
2002-08-13 08:47:17 +00:00
|
|
|
goto done2;
|
2005-01-22 19:04:17 +00:00
|
|
|
#ifdef MAC
|
2007-10-24 19:04:04 +00:00
|
|
|
error = mac_sysvsem_check_semctl(cred, semakptr, cmd);
|
2006-09-20 13:40:00 +00:00
|
|
|
if (error != 0)
|
2005-01-22 19:04:17 +00:00
|
|
|
goto done2;
|
|
|
|
#endif
|
2006-07-08 19:51:38 +00:00
|
|
|
bcopy(&semakptr->u, arg->buf, sizeof(struct semid_ds));
|
|
|
|
*rval = IXSEQ_TO_IPCID(semid, semakptr->u.sem_perm);
|
2002-08-13 08:47:17 +00:00
|
|
|
mtx_unlock(sema_mtxp);
|
2006-07-08 19:51:38 +00:00
|
|
|
return (0);
|
2001-09-13 21:06:41 +00:00
|
|
|
}
|
|
|
|
|
2006-06-29 13:58:36 +00:00
|
|
|
semidx = IPCID_TO_IX(semid);
|
|
|
|
if (semidx < 0 || semidx >= seminfo.semmni)
|
2002-08-13 08:47:17 +00:00
|
|
|
return (EINVAL);
|
1994-09-13 14:47:38 +00:00
|
|
|
|
2006-06-29 13:58:36 +00:00
|
|
|
semakptr = &sema[semidx];
|
|
|
|
sema_mtxp = &sema_mtx[semidx];
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
if (cmd == IPC_RMID)
|
|
|
|
mtx_lock(&sem_mtx);
|
2005-01-22 19:04:17 +00:00
|
|
|
mtx_lock(sema_mtxp);
|
2006-07-08 19:51:38 +00:00
|
|
|
#ifdef MAC
|
2007-10-24 19:04:04 +00:00
|
|
|
error = mac_sysvsem_check_semctl(cred, semakptr, cmd);
|
2006-09-20 13:40:00 +00:00
|
|
|
if (error != 0)
|
2006-07-08 19:51:38 +00:00
|
|
|
goto done2;
|
2005-01-22 19:04:17 +00:00
|
|
|
#endif
|
2005-04-18 11:51:10 +00:00
|
|
|
|
2001-08-31 00:02:18 +00:00
|
|
|
error = 0;
|
2006-07-08 19:51:38 +00:00
|
|
|
*rval = 0;
|
1994-09-13 14:47:38 +00:00
|
|
|
|
|
|
|
switch (cmd) {
|
|
|
|
case IPC_RMID:
|
2006-06-27 18:28:50 +00:00
|
|
|
if ((error = semvalid(semid, semakptr)) != 0)
|
2002-08-13 08:47:17 +00:00
|
|
|
goto done2;
|
2004-11-12 13:23:47 +00:00
|
|
|
if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_M)))
|
2001-08-31 00:02:18 +00:00
|
|
|
goto done2;
|
2004-11-12 13:23:47 +00:00
|
|
|
semakptr->u.sem_perm.cuid = cred->cr_uid;
|
|
|
|
semakptr->u.sem_perm.uid = cred->cr_uid;
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
semakptr->u.sem_perm.mode = 0;
|
2011-04-06 18:11:24 +00:00
|
|
|
racct_sub_cred(semakptr->cred, RACCT_NSEM, semakptr->u.sem_nsems);
|
2011-04-06 16:59:54 +00:00
|
|
|
crfree(semakptr->cred);
|
|
|
|
semakptr->cred = NULL;
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
SEMUNDO_LOCK();
|
|
|
|
semundo_clear(semidx, -1);
|
|
|
|
SEMUNDO_UNLOCK();
|
|
|
|
#ifdef MAC
|
|
|
|
mac_sysvsem_cleanup(semakptr);
|
|
|
|
#endif
|
|
|
|
wakeup(semakptr);
|
|
|
|
for (i = 0; i < seminfo.semmni; i++) {
|
|
|
|
if ((sema[i].u.sem_perm.mode & SEM_ALLOC) &&
|
|
|
|
sema[i].u.sem_base > semakptr->u.sem_base)
|
|
|
|
mtx_lock_flags(&sema_mtx[i], LOP_DUPOK);
|
|
|
|
}
|
2004-11-12 13:23:47 +00:00
|
|
|
for (i = semakptr->u.sem_base - sem; i < semtot; i++)
|
|
|
|
sem[i] = sem[i + semakptr->u.sem_nsems];
|
1994-09-13 14:47:38 +00:00
|
|
|
for (i = 0; i < seminfo.semmni; i++) {
|
2004-11-12 13:23:47 +00:00
|
|
|
if ((sema[i].u.sem_perm.mode & SEM_ALLOC) &&
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
sema[i].u.sem_base > semakptr->u.sem_base) {
|
2004-11-12 13:23:47 +00:00
|
|
|
sema[i].u.sem_base -= semakptr->u.sem_nsems;
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
mtx_unlock(&sema_mtx[i]);
|
|
|
|
}
|
1994-09-13 14:47:38 +00:00
|
|
|
}
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
semtot -= semakptr->u.sem_nsems;
|
1994-09-13 14:47:38 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case IPC_SET:
|
2006-06-27 18:28:50 +00:00
|
|
|
if ((error = semvalid(semid, semakptr)) != 0)
|
2002-08-13 08:47:17 +00:00
|
|
|
goto done2;
|
2004-11-12 13:23:47 +00:00
|
|
|
if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_M)))
|
2001-08-31 00:02:18 +00:00
|
|
|
goto done2;
|
2006-07-08 19:51:38 +00:00
|
|
|
sbuf = arg->buf;
|
|
|
|
semakptr->u.sem_perm.uid = sbuf->sem_perm.uid;
|
|
|
|
semakptr->u.sem_perm.gid = sbuf->sem_perm.gid;
|
2004-11-12 13:23:47 +00:00
|
|
|
semakptr->u.sem_perm.mode = (semakptr->u.sem_perm.mode &
|
2006-07-08 19:51:38 +00:00
|
|
|
~0777) | (sbuf->sem_perm.mode & 0777);
|
2004-11-12 13:23:47 +00:00
|
|
|
semakptr->u.sem_ctime = time_second;
|
1994-09-13 14:47:38 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case IPC_STAT:
|
2006-06-27 18:28:50 +00:00
|
|
|
if ((error = semvalid(semid, semakptr)) != 0)
|
2002-08-13 08:47:17 +00:00
|
|
|
goto done2;
|
2004-11-12 13:23:47 +00:00
|
|
|
if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R)))
|
2002-08-13 08:47:17 +00:00
|
|
|
goto done2;
|
2006-07-08 19:51:38 +00:00
|
|
|
bcopy(&semakptr->u, arg->buf, sizeof(struct semid_ds));
|
1994-09-13 14:47:38 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case GETNCNT:
|
2006-06-27 18:28:50 +00:00
|
|
|
if ((error = semvalid(semid, semakptr)) != 0)
|
2002-08-13 08:47:17 +00:00
|
|
|
goto done2;
|
2004-11-12 13:23:47 +00:00
|
|
|
if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R)))
|
2001-08-31 00:02:18 +00:00
|
|
|
goto done2;
|
2004-11-12 13:23:47 +00:00
|
|
|
if (semnum < 0 || semnum >= semakptr->u.sem_nsems) {
|
2001-08-31 00:02:18 +00:00
|
|
|
error = EINVAL;
|
|
|
|
goto done2;
|
|
|
|
}
|
2006-07-08 19:51:38 +00:00
|
|
|
*rval = semakptr->u.sem_base[semnum].semncnt;
|
1994-09-13 14:47:38 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case GETPID:
|
2006-06-27 18:28:50 +00:00
|
|
|
if ((error = semvalid(semid, semakptr)) != 0)
|
2002-08-13 08:47:17 +00:00
|
|
|
goto done2;
|
2004-11-12 13:23:47 +00:00
|
|
|
if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R)))
|
2001-08-31 00:02:18 +00:00
|
|
|
goto done2;
|
2004-11-12 13:23:47 +00:00
|
|
|
if (semnum < 0 || semnum >= semakptr->u.sem_nsems) {
|
2001-08-31 00:02:18 +00:00
|
|
|
error = EINVAL;
|
|
|
|
goto done2;
|
|
|
|
}
|
2006-07-08 19:51:38 +00:00
|
|
|
*rval = semakptr->u.sem_base[semnum].sempid;
|
1994-09-13 14:47:38 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case GETVAL:
|
2006-06-27 18:28:50 +00:00
|
|
|
if ((error = semvalid(semid, semakptr)) != 0)
|
2002-08-13 08:47:17 +00:00
|
|
|
goto done2;
|
2004-11-12 13:23:47 +00:00
|
|
|
if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R)))
|
2001-08-31 00:02:18 +00:00
|
|
|
goto done2;
|
2004-11-12 13:23:47 +00:00
|
|
|
if (semnum < 0 || semnum >= semakptr->u.sem_nsems) {
|
2001-08-31 00:02:18 +00:00
|
|
|
error = EINVAL;
|
|
|
|
goto done2;
|
|
|
|
}
|
2006-07-08 19:51:38 +00:00
|
|
|
*rval = semakptr->u.sem_base[semnum].semval;
|
1994-09-13 14:47:38 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case GETALL:
|
2006-06-27 18:28:50 +00:00
|
|
|
/*
|
2006-07-08 19:51:38 +00:00
|
|
|
* Unfortunately, callers of this function don't know
|
|
|
|
* in advance how many semaphores are in this set.
|
|
|
|
* While we could just allocate the maximum size array
|
|
|
|
* and pass the actual size back to the caller, that
|
|
|
|
* won't work for SETALL since we can't copyin() more
|
|
|
|
* data than the user specified as we may return a
|
|
|
|
* spurious EFAULT.
|
|
|
|
*
|
|
|
|
* Note that the number of semaphores in a set is
|
|
|
|
* fixed for the life of that set. The only way that
|
|
|
|
* the 'count' could change while are blocked in
|
|
|
|
* malloc() is if this semaphore set were destroyed
|
|
|
|
* and a new one created with the same index.
|
|
|
|
* However, semvalid() will catch that due to the
|
|
|
|
* sequence number unless exactly 0x8000 (or a
|
|
|
|
* multiple thereof) semaphore sets for the same index
|
|
|
|
* are created and destroyed while we are in malloc!
|
|
|
|
*
|
2006-06-27 18:28:50 +00:00
|
|
|
*/
|
2006-07-08 19:51:38 +00:00
|
|
|
count = semakptr->u.sem_nsems;
|
|
|
|
mtx_unlock(sema_mtxp);
|
|
|
|
array = malloc(sizeof(*array) * count, M_TEMP, M_WAITOK);
|
2002-08-13 08:47:17 +00:00
|
|
|
mtx_lock(sema_mtxp);
|
2006-06-27 18:28:50 +00:00
|
|
|
if ((error = semvalid(semid, semakptr)) != 0)
|
2002-08-13 08:47:17 +00:00
|
|
|
goto done2;
|
2006-07-08 19:51:38 +00:00
|
|
|
KASSERT(count == semakptr->u.sem_nsems, ("nsems changed"));
|
2004-11-12 13:23:47 +00:00
|
|
|
if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R)))
|
2002-08-13 08:47:17 +00:00
|
|
|
goto done2;
|
2004-11-12 13:23:47 +00:00
|
|
|
for (i = 0; i < semakptr->u.sem_nsems; i++)
|
|
|
|
array[i] = semakptr->u.sem_base[i].semval;
|
2002-08-13 08:47:17 +00:00
|
|
|
mtx_unlock(sema_mtxp);
|
2006-07-08 19:51:38 +00:00
|
|
|
error = copyout(array, arg->array, count * sizeof(*array));
|
|
|
|
mtx_lock(sema_mtxp);
|
1994-09-13 14:47:38 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case GETZCNT:
|
2006-06-27 18:28:50 +00:00
|
|
|
if ((error = semvalid(semid, semakptr)) != 0)
|
2002-08-13 08:47:17 +00:00
|
|
|
goto done2;
|
2004-11-12 13:23:47 +00:00
|
|
|
if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_R)))
|
2001-08-31 00:02:18 +00:00
|
|
|
goto done2;
|
2004-11-12 13:23:47 +00:00
|
|
|
if (semnum < 0 || semnum >= semakptr->u.sem_nsems) {
|
2001-08-31 00:02:18 +00:00
|
|
|
error = EINVAL;
|
|
|
|
goto done2;
|
|
|
|
}
|
2006-07-08 19:51:38 +00:00
|
|
|
*rval = semakptr->u.sem_base[semnum].semzcnt;
|
1994-09-13 14:47:38 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case SETVAL:
|
2006-06-27 18:28:50 +00:00
|
|
|
if ((error = semvalid(semid, semakptr)) != 0)
|
2002-08-13 08:47:17 +00:00
|
|
|
goto done2;
|
2004-11-12 13:23:47 +00:00
|
|
|
if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_W)))
|
2001-08-31 00:02:18 +00:00
|
|
|
goto done2;
|
2004-11-12 13:23:47 +00:00
|
|
|
if (semnum < 0 || semnum >= semakptr->u.sem_nsems) {
|
2001-08-31 00:02:18 +00:00
|
|
|
error = EINVAL;
|
|
|
|
goto done2;
|
|
|
|
}
|
2006-06-27 18:28:50 +00:00
|
|
|
if (arg->val < 0 || arg->val > seminfo.semvmx) {
|
2001-10-11 08:15:14 +00:00
|
|
|
error = ERANGE;
|
|
|
|
goto done2;
|
|
|
|
}
|
2006-06-27 18:28:50 +00:00
|
|
|
semakptr->u.sem_base[semnum].semval = arg->val;
|
2002-08-13 08:47:17 +00:00
|
|
|
SEMUNDO_LOCK();
|
2006-06-29 13:58:36 +00:00
|
|
|
semundo_clear(semidx, semnum);
|
2002-08-13 08:47:17 +00:00
|
|
|
SEMUNDO_UNLOCK();
|
2004-11-12 13:23:47 +00:00
|
|
|
wakeup(semakptr);
|
1994-09-13 14:47:38 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case SETALL:
|
2006-06-27 18:28:50 +00:00
|
|
|
/*
|
2006-07-08 19:51:38 +00:00
|
|
|
* See comment on GETALL for why 'count' shouldn't change
|
|
|
|
* and why we require a userland buffer.
|
2006-06-27 18:28:50 +00:00
|
|
|
*/
|
2004-11-12 13:23:47 +00:00
|
|
|
count = semakptr->u.sem_nsems;
|
2006-07-08 19:51:38 +00:00
|
|
|
mtx_unlock(sema_mtxp);
|
2003-02-19 05:47:46 +00:00
|
|
|
array = malloc(sizeof(*array) * count, M_TEMP, M_WAITOK);
|
2006-06-27 18:28:50 +00:00
|
|
|
error = copyin(arg->array, array, count * sizeof(*array));
|
2007-07-03 15:58:47 +00:00
|
|
|
mtx_lock(sema_mtxp);
|
2002-08-13 08:47:17 +00:00
|
|
|
if (error)
|
|
|
|
break;
|
2006-06-27 18:28:50 +00:00
|
|
|
if ((error = semvalid(semid, semakptr)) != 0)
|
2002-08-13 08:47:17 +00:00
|
|
|
goto done2;
|
2006-07-08 19:51:38 +00:00
|
|
|
KASSERT(count == semakptr->u.sem_nsems, ("nsems changed"));
|
2004-11-12 13:23:47 +00:00
|
|
|
if ((error = ipcperm(td, &semakptr->u.sem_perm, IPC_W)))
|
2002-08-13 08:47:17 +00:00
|
|
|
goto done2;
|
2004-11-12 13:23:47 +00:00
|
|
|
for (i = 0; i < semakptr->u.sem_nsems; i++) {
|
2002-08-13 08:47:17 +00:00
|
|
|
usval = array[i];
|
2001-10-11 08:15:14 +00:00
|
|
|
if (usval > seminfo.semvmx) {
|
|
|
|
error = ERANGE;
|
|
|
|
break;
|
|
|
|
}
|
2004-11-12 13:23:47 +00:00
|
|
|
semakptr->u.sem_base[i].semval = usval;
|
1994-09-13 14:47:38 +00:00
|
|
|
}
|
2002-08-13 08:47:17 +00:00
|
|
|
SEMUNDO_LOCK();
|
2006-06-29 13:58:36 +00:00
|
|
|
semundo_clear(semidx, -1);
|
2002-08-13 08:47:17 +00:00
|
|
|
SEMUNDO_UNLOCK();
|
2004-11-12 13:23:47 +00:00
|
|
|
wakeup(semakptr);
|
1994-09-13 14:47:38 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2001-08-31 00:02:18 +00:00
|
|
|
error = EINVAL;
|
|
|
|
break;
|
1994-09-13 14:47:38 +00:00
|
|
|
}
|
|
|
|
|
2001-08-31 00:02:18 +00:00
|
|
|
done2:
|
2006-07-08 19:51:38 +00:00
|
|
|
mtx_unlock(sema_mtxp);
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
if (cmd == IPC_RMID)
|
|
|
|
mtx_unlock(&sem_mtx);
|
2002-08-13 08:47:17 +00:00
|
|
|
if (array != NULL)
|
|
|
|
free(array, M_TEMP);
|
2001-08-31 00:02:18 +00:00
|
|
|
return(error);
|
1994-09-13 14:47:38 +00:00
|
|
|
}
|
|
|
|
|
1995-12-15 05:00:31 +00:00
|
|
|
#ifndef _SYS_SYSPROTO_H_
|
1994-09-13 14:47:38 +00:00
|
|
|
struct semget_args {
|
|
|
|
key_t key;
|
|
|
|
int nsems;
|
|
|
|
int semflg;
|
|
|
|
};
|
1995-12-15 05:00:31 +00:00
|
|
|
#endif
|
|
|
|
int
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
semget(struct thread *td, struct semget_args *uap)
|
1994-09-13 14:47:38 +00:00
|
|
|
{
|
2001-08-31 00:02:18 +00:00
|
|
|
int semid, error = 0;
|
1994-09-13 14:47:38 +00:00
|
|
|
int key = uap->key;
|
|
|
|
int nsems = uap->nsems;
|
|
|
|
int semflg = uap->semflg;
|
2002-03-05 18:57:36 +00:00
|
|
|
struct ucred *cred = td->td_ucred;
|
1994-09-13 14:47:38 +00:00
|
|
|
|
2002-07-22 18:27:54 +00:00
|
|
|
DPRINTF(("semget(0x%x, %d, 0%o)\n", key, nsems, semflg));
|
2009-05-27 14:11:23 +00:00
|
|
|
if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC))
|
2002-03-05 18:57:36 +00:00
|
|
|
return (ENOSYS);
|
2000-10-31 01:34:00 +00:00
|
|
|
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
mtx_lock(&sem_mtx);
|
1994-09-13 14:47:38 +00:00
|
|
|
if (key != IPC_PRIVATE) {
|
|
|
|
for (semid = 0; semid < seminfo.semmni; semid++) {
|
2004-11-12 13:23:47 +00:00
|
|
|
if ((sema[semid].u.sem_perm.mode & SEM_ALLOC) &&
|
|
|
|
sema[semid].u.sem_perm.key == key)
|
1994-09-13 14:47:38 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (semid < seminfo.semmni) {
|
2002-07-22 18:27:54 +00:00
|
|
|
DPRINTF(("found public key\n"));
|
2004-11-12 13:23:47 +00:00
|
|
|
if ((error = ipcperm(td, &sema[semid].u.sem_perm,
|
2001-08-31 00:02:18 +00:00
|
|
|
semflg & 0700))) {
|
|
|
|
goto done2;
|
|
|
|
}
|
2004-11-12 13:23:47 +00:00
|
|
|
if (nsems > 0 && sema[semid].u.sem_nsems < nsems) {
|
2002-07-22 18:27:54 +00:00
|
|
|
DPRINTF(("too small\n"));
|
2001-08-31 00:02:18 +00:00
|
|
|
error = EINVAL;
|
|
|
|
goto done2;
|
1994-09-13 14:47:38 +00:00
|
|
|
}
|
|
|
|
if ((semflg & IPC_CREAT) && (semflg & IPC_EXCL)) {
|
2002-07-22 18:27:54 +00:00
|
|
|
DPRINTF(("not exclusive\n"));
|
2001-08-31 00:02:18 +00:00
|
|
|
error = EEXIST;
|
|
|
|
goto done2;
|
1994-09-13 14:47:38 +00:00
|
|
|
}
|
2005-01-22 19:04:17 +00:00
|
|
|
#ifdef MAC
|
2007-10-24 19:04:04 +00:00
|
|
|
error = mac_sysvsem_check_semget(cred, &sema[semid]);
|
2006-09-20 13:40:00 +00:00
|
|
|
if (error != 0)
|
2005-01-22 19:04:17 +00:00
|
|
|
goto done2;
|
|
|
|
#endif
|
1994-09-13 14:47:38 +00:00
|
|
|
goto found;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-11-12 13:23:47 +00:00
|
|
|
DPRINTF(("need to allocate the semid_kernel\n"));
|
1994-09-13 14:47:38 +00:00
|
|
|
if (key == IPC_PRIVATE || (semflg & IPC_CREAT)) {
|
|
|
|
if (nsems <= 0 || nsems > seminfo.semmsl) {
|
2002-07-22 18:27:54 +00:00
|
|
|
DPRINTF(("nsems out of range (0<%d<=%d)\n", nsems,
|
|
|
|
seminfo.semmsl));
|
2001-08-31 00:02:18 +00:00
|
|
|
error = EINVAL;
|
|
|
|
goto done2;
|
1994-09-13 14:47:38 +00:00
|
|
|
}
|
|
|
|
if (nsems > seminfo.semmns - semtot) {
|
2002-07-22 18:27:54 +00:00
|
|
|
DPRINTF((
|
|
|
|
"not enough semaphores left (need %d, got %d)\n",
|
|
|
|
nsems, seminfo.semmns - semtot));
|
2001-08-31 00:02:18 +00:00
|
|
|
error = ENOSPC;
|
|
|
|
goto done2;
|
1994-09-13 14:47:38 +00:00
|
|
|
}
|
|
|
|
for (semid = 0; semid < seminfo.semmni; semid++) {
|
2004-11-12 13:23:47 +00:00
|
|
|
if ((sema[semid].u.sem_perm.mode & SEM_ALLOC) == 0)
|
1994-09-13 14:47:38 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (semid == seminfo.semmni) {
|
2004-11-12 13:23:47 +00:00
|
|
|
DPRINTF(("no more semid_kernel's available\n"));
|
2001-08-31 00:02:18 +00:00
|
|
|
error = ENOSPC;
|
|
|
|
goto done2;
|
1994-09-13 14:47:38 +00:00
|
|
|
}
|
2011-04-06 18:11:24 +00:00
|
|
|
PROC_LOCK(td->td_proc);
|
|
|
|
error = racct_add(td->td_proc, RACCT_NSEM, nsems);
|
|
|
|
PROC_UNLOCK(td->td_proc);
|
|
|
|
if (error != 0) {
|
|
|
|
error = ENOSPC;
|
|
|
|
goto done2;
|
|
|
|
}
|
2002-07-22 18:27:54 +00:00
|
|
|
DPRINTF(("semid %d is available\n", semid));
|
2009-01-15 12:15:46 +00:00
|
|
|
mtx_lock(&sema_mtx[semid]);
|
|
|
|
KASSERT((sema[semid].u.sem_perm.mode & SEM_ALLOC) == 0,
|
|
|
|
("Lost semaphore %d", semid));
|
2004-11-12 13:23:47 +00:00
|
|
|
sema[semid].u.sem_perm.key = key;
|
|
|
|
sema[semid].u.sem_perm.cuid = cred->cr_uid;
|
|
|
|
sema[semid].u.sem_perm.uid = cred->cr_uid;
|
|
|
|
sema[semid].u.sem_perm.cgid = cred->cr_gid;
|
|
|
|
sema[semid].u.sem_perm.gid = cred->cr_gid;
|
|
|
|
sema[semid].u.sem_perm.mode = (semflg & 0777) | SEM_ALLOC;
|
2011-04-06 19:08:50 +00:00
|
|
|
sema[semid].cred = crhold(cred);
|
2004-11-12 13:23:47 +00:00
|
|
|
sema[semid].u.sem_perm.seq =
|
|
|
|
(sema[semid].u.sem_perm.seq + 1) & 0x7fff;
|
|
|
|
sema[semid].u.sem_nsems = nsems;
|
|
|
|
sema[semid].u.sem_otime = 0;
|
|
|
|
sema[semid].u.sem_ctime = time_second;
|
|
|
|
sema[semid].u.sem_base = &sem[semtot];
|
1994-09-13 14:47:38 +00:00
|
|
|
semtot += nsems;
|
2004-11-12 13:23:47 +00:00
|
|
|
bzero(sema[semid].u.sem_base,
|
|
|
|
sizeof(sema[semid].u.sem_base[0])*nsems);
|
2005-01-22 19:04:17 +00:00
|
|
|
#ifdef MAC
|
2007-10-24 19:04:04 +00:00
|
|
|
mac_sysvsem_create(cred, &sema[semid]);
|
2005-01-22 19:04:17 +00:00
|
|
|
#endif
|
2009-01-15 12:15:46 +00:00
|
|
|
mtx_unlock(&sema_mtx[semid]);
|
2006-07-12 11:41:53 +00:00
|
|
|
DPRINTF(("sembase = %p, next = %p\n",
|
2004-11-12 13:23:47 +00:00
|
|
|
sema[semid].u.sem_base, &sem[semtot]));
|
1994-09-13 14:47:38 +00:00
|
|
|
} else {
|
2002-07-22 18:27:54 +00:00
|
|
|
DPRINTF(("didn't find it and wasn't asked to create it\n"));
|
2001-08-31 00:02:18 +00:00
|
|
|
error = ENOENT;
|
|
|
|
goto done2;
|
1994-09-13 14:47:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
found:
|
2004-11-12 13:23:47 +00:00
|
|
|
td->td_retval[0] = IXSEQ_TO_IPCID(semid, sema[semid].u.sem_perm);
|
2001-08-31 00:02:18 +00:00
|
|
|
done2:
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
mtx_unlock(&sem_mtx);
|
2001-08-31 00:02:18 +00:00
|
|
|
return (error);
|
1994-09-13 14:47:38 +00:00
|
|
|
}
|
|
|
|
|
1995-12-15 05:00:31 +00:00
|
|
|
#ifndef _SYS_SYSPROTO_H_
|
1994-09-13 14:47:38 +00:00
|
|
|
struct semop_args {
|
|
|
|
int semid;
|
|
|
|
struct sembuf *sops;
|
2003-01-25 21:27:37 +00:00
|
|
|
size_t nsops;
|
1994-09-13 14:47:38 +00:00
|
|
|
};
|
1995-12-15 05:00:31 +00:00
|
|
|
#endif
|
|
|
|
int
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
semop(struct thread *td, struct semop_args *uap)
|
1994-09-13 14:47:38 +00:00
|
|
|
{
|
2003-12-19 13:07:17 +00:00
|
|
|
#define SMALL_SOPS 8
|
|
|
|
struct sembuf small_sops[SMALL_SOPS];
|
1994-09-13 14:47:38 +00:00
|
|
|
int semid = uap->semid;
|
2003-01-25 21:27:37 +00:00
|
|
|
size_t nsops = uap->nsops;
|
2002-10-19 02:07:35 +00:00
|
|
|
struct sembuf *sops;
|
2004-11-12 13:23:47 +00:00
|
|
|
struct semid_kernel *semakptr;
|
2002-08-05 05:16:09 +00:00
|
|
|
struct sembuf *sopptr = 0;
|
|
|
|
struct sem *semptr = 0;
|
2001-10-11 08:15:14 +00:00
|
|
|
struct sem_undo *suptr;
|
2002-08-13 08:47:17 +00:00
|
|
|
struct mtx *sema_mtxp;
|
2003-01-29 12:30:59 +00:00
|
|
|
size_t i, j, k;
|
2003-01-25 21:27:37 +00:00
|
|
|
int error;
|
1994-10-02 17:35:40 +00:00
|
|
|
int do_wakeup, do_undos;
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
unsigned short seq;
|
1994-09-13 14:47:38 +00:00
|
|
|
|
2006-07-12 11:41:53 +00:00
|
|
|
#ifdef SEM_DEBUG
|
|
|
|
sops = NULL;
|
|
|
|
#endif
|
|
|
|
DPRINTF(("call to semop(%d, %p, %u)\n", semid, sops, nsops));
|
1994-09-13 14:47:38 +00:00
|
|
|
|
2009-05-27 14:11:23 +00:00
|
|
|
if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC))
|
2002-03-05 18:57:36 +00:00
|
|
|
return (ENOSYS);
|
2000-10-31 01:34:00 +00:00
|
|
|
|
1994-09-13 14:47:38 +00:00
|
|
|
semid = IPCID_TO_IX(semid); /* Convert back to zero origin */
|
|
|
|
|
2002-08-13 08:47:17 +00:00
|
|
|
if (semid < 0 || semid >= seminfo.semmni)
|
2004-11-13 08:06:40 +00:00
|
|
|
return (EINVAL);
|
1994-09-13 14:47:38 +00:00
|
|
|
|
2002-08-13 08:47:17 +00:00
|
|
|
/* Allocate memory for sem_ops */
|
2003-12-19 13:07:17 +00:00
|
|
|
if (nsops <= SMALL_SOPS)
|
|
|
|
sops = small_sops;
|
2011-04-06 18:11:24 +00:00
|
|
|
else if (nsops > seminfo.semopm) {
|
2002-07-22 18:27:54 +00:00
|
|
|
DPRINTF(("too many sops (max=%d, nsops=%d)\n", seminfo.semopm,
|
|
|
|
nsops));
|
2002-08-13 08:47:17 +00:00
|
|
|
return (E2BIG);
|
2011-04-06 18:11:24 +00:00
|
|
|
} else {
|
|
|
|
PROC_LOCK(td->td_proc);
|
|
|
|
if (nsops > racct_get_available(td->td_proc, RACCT_NSEMOP)) {
|
|
|
|
PROC_UNLOCK(td->td_proc);
|
|
|
|
return (E2BIG);
|
|
|
|
}
|
|
|
|
PROC_UNLOCK(td->td_proc);
|
|
|
|
|
|
|
|
sops = malloc(nsops * sizeof(*sops), M_TEMP, M_WAITOK);
|
1994-09-13 14:47:38 +00:00
|
|
|
}
|
2001-10-11 08:15:14 +00:00
|
|
|
if ((error = copyin(uap->sops, sops, nsops * sizeof(sops[0]))) != 0) {
|
2006-07-12 11:41:53 +00:00
|
|
|
DPRINTF(("error = %d from copyin(%p, %p, %d)\n", error,
|
2002-07-22 18:27:54 +00:00
|
|
|
uap->sops, sops, nsops * sizeof(sops[0])));
|
2003-12-19 13:07:17 +00:00
|
|
|
if (sops != small_sops)
|
|
|
|
free(sops, M_SEM);
|
2002-08-13 08:47:17 +00:00
|
|
|
return (error);
|
1994-09-13 14:47:38 +00:00
|
|
|
}
|
|
|
|
|
2004-11-12 13:23:47 +00:00
|
|
|
semakptr = &sema[semid];
|
2002-08-13 08:47:17 +00:00
|
|
|
sema_mtxp = &sema_mtx[semid];
|
|
|
|
mtx_lock(sema_mtxp);
|
2004-11-12 13:23:47 +00:00
|
|
|
if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0) {
|
2002-08-13 08:47:17 +00:00
|
|
|
error = EINVAL;
|
|
|
|
goto done2;
|
|
|
|
}
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
seq = semakptr->u.sem_perm.seq;
|
|
|
|
if (seq != IPCID_TO_SEQ(uap->semid)) {
|
2002-08-13 08:47:17 +00:00
|
|
|
error = EINVAL;
|
|
|
|
goto done2;
|
|
|
|
}
|
2001-10-11 08:15:14 +00:00
|
|
|
/*
|
|
|
|
* Initial pass thru sops to see what permissions are needed.
|
|
|
|
* Also perform any checks that don't need repeating on each
|
|
|
|
* attempt to satisfy the request vector.
|
|
|
|
*/
|
|
|
|
j = 0; /* permission needed */
|
|
|
|
do_undos = 0;
|
|
|
|
for (i = 0; i < nsops; i++) {
|
|
|
|
sopptr = &sops[i];
|
2004-11-12 13:23:47 +00:00
|
|
|
if (sopptr->sem_num >= semakptr->u.sem_nsems) {
|
2001-10-11 08:15:14 +00:00
|
|
|
error = EFBIG;
|
|
|
|
goto done2;
|
|
|
|
}
|
|
|
|
if (sopptr->sem_flg & SEM_UNDO && sopptr->sem_op != 0)
|
|
|
|
do_undos = 1;
|
|
|
|
j |= (sopptr->sem_op == 0) ? SEM_R : SEM_A;
|
|
|
|
}
|
|
|
|
|
2004-11-12 13:23:47 +00:00
|
|
|
if ((error = ipcperm(td, &semakptr->u.sem_perm, j))) {
|
2002-07-22 18:27:54 +00:00
|
|
|
DPRINTF(("error = %d from ipaccess\n", error));
|
2001-08-31 00:02:18 +00:00
|
|
|
goto done2;
|
1994-09-13 14:47:38 +00:00
|
|
|
}
|
2005-01-22 19:04:17 +00:00
|
|
|
#ifdef MAC
|
2007-10-24 19:04:04 +00:00
|
|
|
error = mac_sysvsem_check_semop(td->td_ucred, semakptr, j);
|
2006-09-20 13:40:00 +00:00
|
|
|
if (error != 0)
|
2005-01-22 19:04:17 +00:00
|
|
|
goto done2;
|
|
|
|
#endif
|
1994-09-13 14:47:38 +00:00
|
|
|
|
1995-05-30 08:16:23 +00:00
|
|
|
/*
|
1994-09-13 14:47:38 +00:00
|
|
|
* Loop trying to satisfy the vector of requests.
|
|
|
|
* If we reach a point where we must wait, any requests already
|
|
|
|
* performed are rolled back and we go to sleep until some other
|
|
|
|
* process wakes us up. At this point, we start all over again.
|
|
|
|
*
|
|
|
|
* This ensures that from the perspective of other tasks, a set
|
|
|
|
* of requests is atomic (never partially satisfied).
|
|
|
|
*/
|
|
|
|
for (;;) {
|
|
|
|
do_wakeup = 0;
|
2001-10-11 08:15:14 +00:00
|
|
|
error = 0; /* error return if necessary */
|
1994-09-13 14:47:38 +00:00
|
|
|
|
|
|
|
for (i = 0; i < nsops; i++) {
|
|
|
|
sopptr = &sops[i];
|
2004-11-12 13:23:47 +00:00
|
|
|
semptr = &semakptr->u.sem_base[sopptr->sem_num];
|
1994-09-13 14:47:38 +00:00
|
|
|
|
2002-07-22 18:27:54 +00:00
|
|
|
DPRINTF((
|
2006-07-12 11:41:53 +00:00
|
|
|
"semop: semakptr=%p, sem_base=%p, "
|
|
|
|
"semptr=%p, sem[%d]=%d : op=%d, flag=%s\n",
|
2004-11-12 13:23:47 +00:00
|
|
|
semakptr, semakptr->u.sem_base, semptr,
|
1994-09-13 14:47:38 +00:00
|
|
|
sopptr->sem_num, semptr->semval, sopptr->sem_op,
|
2002-07-22 18:27:54 +00:00
|
|
|
(sopptr->sem_flg & IPC_NOWAIT) ?
|
|
|
|
"nowait" : "wait"));
|
1994-09-13 14:47:38 +00:00
|
|
|
|
|
|
|
if (sopptr->sem_op < 0) {
|
|
|
|
if (semptr->semval + sopptr->sem_op < 0) {
|
2002-07-22 18:27:54 +00:00
|
|
|
DPRINTF(("semop: can't do it now\n"));
|
1994-09-13 14:47:38 +00:00
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
semptr->semval += sopptr->sem_op;
|
|
|
|
if (semptr->semval == 0 &&
|
|
|
|
semptr->semzcnt > 0)
|
|
|
|
do_wakeup = 1;
|
|
|
|
}
|
|
|
|
} else if (sopptr->sem_op == 0) {
|
2001-10-11 08:15:14 +00:00
|
|
|
if (semptr->semval != 0) {
|
2002-07-22 18:27:54 +00:00
|
|
|
DPRINTF(("semop: not zero now\n"));
|
1994-09-13 14:47:38 +00:00
|
|
|
break;
|
|
|
|
}
|
2001-10-11 08:15:14 +00:00
|
|
|
} else if (semptr->semval + sopptr->sem_op >
|
|
|
|
seminfo.semvmx) {
|
|
|
|
error = ERANGE;
|
|
|
|
break;
|
1994-09-13 14:47:38 +00:00
|
|
|
} else {
|
|
|
|
if (semptr->semncnt > 0)
|
|
|
|
do_wakeup = 1;
|
|
|
|
semptr->semval += sopptr->sem_op;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Did we get through the entire vector?
|
|
|
|
*/
|
|
|
|
if (i >= nsops)
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* No ... rollback anything that we've already done
|
|
|
|
*/
|
2002-07-22 18:27:54 +00:00
|
|
|
DPRINTF(("semop: rollback 0 through %d\n", i-1));
|
1994-09-13 14:47:38 +00:00
|
|
|
for (j = 0; j < i; j++)
|
2004-11-12 13:23:47 +00:00
|
|
|
semakptr->u.sem_base[sops[j].sem_num].semval -=
|
1994-09-13 14:47:38 +00:00
|
|
|
sops[j].sem_op;
|
|
|
|
|
2001-10-11 08:15:14 +00:00
|
|
|
/* If we detected an error, return it */
|
|
|
|
if (error != 0)
|
|
|
|
goto done2;
|
|
|
|
|
1994-09-13 14:47:38 +00:00
|
|
|
/*
|
|
|
|
* If the request that we couldn't satisfy has the
|
|
|
|
* NOWAIT flag set then return with EAGAIN.
|
|
|
|
*/
|
2001-08-31 00:02:18 +00:00
|
|
|
if (sopptr->sem_flg & IPC_NOWAIT) {
|
|
|
|
error = EAGAIN;
|
|
|
|
goto done2;
|
|
|
|
}
|
1994-09-13 14:47:38 +00:00
|
|
|
|
|
|
|
if (sopptr->sem_op == 0)
|
|
|
|
semptr->semzcnt++;
|
|
|
|
else
|
|
|
|
semptr->semncnt++;
|
|
|
|
|
2002-07-22 18:27:54 +00:00
|
|
|
DPRINTF(("semop: good night!\n"));
|
2004-11-12 13:23:47 +00:00
|
|
|
error = msleep(semakptr, sema_mtxp, (PZERO - 4) | PCATCH,
|
2002-08-13 08:47:17 +00:00
|
|
|
"semwait", 0);
|
2002-07-22 18:27:54 +00:00
|
|
|
DPRINTF(("semop: good morning (error=%d)!\n", error));
|
2004-03-17 09:37:13 +00:00
|
|
|
/* return code is checked below, after sem[nz]cnt-- */
|
1994-09-13 14:47:38 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Make sure that the semaphore still exists
|
|
|
|
*/
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
seq = semakptr->u.sem_perm.seq;
|
2004-11-12 13:23:47 +00:00
|
|
|
if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0 ||
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
seq != IPCID_TO_SEQ(uap->semid)) {
|
2001-08-31 00:02:18 +00:00
|
|
|
error = EIDRM;
|
|
|
|
goto done2;
|
|
|
|
}
|
1994-09-13 14:47:38 +00:00
|
|
|
|
2008-06-19 18:08:42 +00:00
|
|
|
/*
|
|
|
|
* Renew the semaphore's pointer after wakeup since
|
|
|
|
* during msleep sem_base may have been modified and semptr
|
|
|
|
* is not valid any more
|
|
|
|
*/
|
|
|
|
semptr = &semakptr->u.sem_base[sopptr->sem_num];
|
|
|
|
|
1994-09-13 14:47:38 +00:00
|
|
|
/*
|
|
|
|
* The semaphore is still alive. Readjust the count of
|
|
|
|
* waiting processes.
|
|
|
|
*/
|
|
|
|
if (sopptr->sem_op == 0)
|
|
|
|
semptr->semzcnt--;
|
|
|
|
else
|
|
|
|
semptr->semncnt--;
|
2004-03-17 09:37:13 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Is it really morning, or was our sleep interrupted?
|
|
|
|
* (Delayed check of msleep() return code because we
|
|
|
|
* need to decrement sem[nz]cnt either way.)
|
|
|
|
*/
|
|
|
|
if (error != 0) {
|
|
|
|
error = EINTR;
|
|
|
|
goto done2;
|
|
|
|
}
|
|
|
|
DPRINTF(("semop: good morning!\n"));
|
1994-09-13 14:47:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
done:
|
|
|
|
/*
|
|
|
|
* Process any SEM_UNDO requests.
|
|
|
|
*/
|
|
|
|
if (do_undos) {
|
2002-08-13 08:47:17 +00:00
|
|
|
SEMUNDO_LOCK();
|
2001-10-11 08:15:14 +00:00
|
|
|
suptr = NULL;
|
1994-09-13 14:47:38 +00:00
|
|
|
for (i = 0; i < nsops; i++) {
|
|
|
|
/*
|
|
|
|
* We only need to deal with SEM_UNDO's for non-zero
|
|
|
|
* op's.
|
|
|
|
*/
|
|
|
|
int adjval;
|
|
|
|
|
|
|
|
if ((sops[i].sem_flg & SEM_UNDO) == 0)
|
|
|
|
continue;
|
|
|
|
adjval = sops[i].sem_op;
|
|
|
|
if (adjval == 0)
|
|
|
|
continue;
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
error = semundo_adjust(td, &suptr, semid, seq,
|
1994-09-13 14:47:38 +00:00
|
|
|
sops[i].sem_num, -adjval);
|
2001-08-31 00:02:18 +00:00
|
|
|
if (error == 0)
|
1994-09-13 14:47:38 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Oh-Oh! We ran out of either sem_undo's or undo's.
|
|
|
|
* Rollback the adjustments to this point and then
|
|
|
|
* rollback the semaphore ups and down so we can return
|
|
|
|
* with an error with all structures restored. We
|
|
|
|
* rollback the undo's in the exact reverse order that
|
|
|
|
* we applied them. This guarantees that we won't run
|
|
|
|
* out of space as we roll things back out.
|
|
|
|
*/
|
2003-01-29 12:30:59 +00:00
|
|
|
for (j = 0; j < i; j++) {
|
|
|
|
k = i - j - 1;
|
|
|
|
if ((sops[k].sem_flg & SEM_UNDO) == 0)
|
1994-09-13 14:47:38 +00:00
|
|
|
continue;
|
2003-01-29 12:30:59 +00:00
|
|
|
adjval = sops[k].sem_op;
|
1994-09-13 14:47:38 +00:00
|
|
|
if (adjval == 0)
|
|
|
|
continue;
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
if (semundo_adjust(td, &suptr, semid, seq,
|
2003-01-29 12:30:59 +00:00
|
|
|
sops[k].sem_num, adjval) != 0)
|
1994-09-13 14:47:38 +00:00
|
|
|
panic("semop - can't undo undos");
|
|
|
|
}
|
|
|
|
|
|
|
|
for (j = 0; j < nsops; j++)
|
2004-11-12 13:23:47 +00:00
|
|
|
semakptr->u.sem_base[sops[j].sem_num].semval -=
|
1994-09-13 14:47:38 +00:00
|
|
|
sops[j].sem_op;
|
|
|
|
|
2002-07-22 18:27:54 +00:00
|
|
|
DPRINTF(("error = %d from semundo_adjust\n", error));
|
2002-08-13 08:47:17 +00:00
|
|
|
SEMUNDO_UNLOCK();
|
2001-08-31 00:02:18 +00:00
|
|
|
goto done2;
|
1994-09-13 14:47:38 +00:00
|
|
|
} /* loop through the sops */
|
2002-08-13 08:47:17 +00:00
|
|
|
SEMUNDO_UNLOCK();
|
1994-09-13 14:47:38 +00:00
|
|
|
} /* if (do_undos) */
|
|
|
|
|
2001-10-11 08:15:14 +00:00
|
|
|
/* We're definitely done - set the sempid's and time */
|
1994-09-13 14:47:38 +00:00
|
|
|
for (i = 0; i < nsops; i++) {
|
|
|
|
sopptr = &sops[i];
|
2004-11-12 13:23:47 +00:00
|
|
|
semptr = &semakptr->u.sem_base[sopptr->sem_num];
|
2001-09-12 08:38:13 +00:00
|
|
|
semptr->sempid = td->td_proc->p_pid;
|
1994-09-13 14:47:38 +00:00
|
|
|
}
|
2004-11-12 13:23:47 +00:00
|
|
|
semakptr->u.sem_otime = time_second;
|
1994-09-13 14:47:38 +00:00
|
|
|
|
2001-10-11 08:15:14 +00:00
|
|
|
/*
|
|
|
|
* Do a wakeup if any semaphore was up'd whilst something was
|
|
|
|
* sleeping on it.
|
|
|
|
*/
|
1994-09-13 14:47:38 +00:00
|
|
|
if (do_wakeup) {
|
2002-07-22 18:27:54 +00:00
|
|
|
DPRINTF(("semop: doing wakeup\n"));
|
2004-11-12 13:23:47 +00:00
|
|
|
wakeup(semakptr);
|
2002-07-22 18:27:54 +00:00
|
|
|
DPRINTF(("semop: back from wakeup\n"));
|
1994-09-13 14:47:38 +00:00
|
|
|
}
|
2002-07-22 18:27:54 +00:00
|
|
|
DPRINTF(("semop: done\n"));
|
2001-09-12 08:38:13 +00:00
|
|
|
td->td_retval[0] = 0;
|
2001-08-31 00:02:18 +00:00
|
|
|
done2:
|
2002-08-13 08:47:17 +00:00
|
|
|
mtx_unlock(sema_mtxp);
|
2003-12-19 13:07:17 +00:00
|
|
|
if (sops != small_sops)
|
|
|
|
free(sops, M_SEM);
|
2001-08-31 00:02:18 +00:00
|
|
|
return (error);
|
1994-09-13 14:47:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Go through the undo structures for this process and apply the adjustments to
|
|
|
|
* semaphores.
|
|
|
|
*/
|
2000-12-01 08:57:47 +00:00
|
|
|
static void
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
semexit_myhook(void *arg, struct proc *p)
|
1994-09-13 14:47:38 +00:00
|
|
|
{
|
2002-08-05 05:16:09 +00:00
|
|
|
struct sem_undo *suptr;
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
struct semid_kernel *semakptr;
|
|
|
|
struct mtx *sema_mtxp;
|
|
|
|
int semid, semnum, adjval, ix;
|
|
|
|
unsigned short seq;
|
1994-09-13 14:47:38 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Go through the chain of undo vectors looking for one
|
|
|
|
* associated with this process.
|
|
|
|
*/
|
2002-08-13 08:47:17 +00:00
|
|
|
SEMUNDO_LOCK();
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
LIST_FOREACH(suptr, &semu_list, un_next) {
|
|
|
|
if (suptr->un_proc == p)
|
1994-09-13 14:47:38 +00:00
|
|
|
break;
|
|
|
|
}
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
if (suptr == NULL) {
|
|
|
|
SEMUNDO_UNLOCK();
|
2000-05-01 11:13:41 +00:00
|
|
|
return;
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
}
|
|
|
|
LIST_REMOVE(suptr, un_next);
|
1994-09-13 14:47:38 +00:00
|
|
|
|
2006-07-12 11:41:53 +00:00
|
|
|
DPRINTF(("proc @%p has undo structure with %d entries\n", p,
|
2002-07-22 18:27:54 +00:00
|
|
|
suptr->un_cnt));
|
1994-09-13 14:47:38 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If there are any active undo elements then process them.
|
|
|
|
*/
|
|
|
|
if (suptr->un_cnt > 0) {
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
SEMUNDO_UNLOCK();
|
1994-09-13 14:47:38 +00:00
|
|
|
for (ix = 0; ix < suptr->un_cnt; ix++) {
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
semid = suptr->un_ent[ix].un_id;
|
|
|
|
semnum = suptr->un_ent[ix].un_num;
|
|
|
|
adjval = suptr->un_ent[ix].un_adjval;
|
|
|
|
seq = suptr->un_ent[ix].un_seq;
|
2004-11-12 13:23:47 +00:00
|
|
|
semakptr = &sema[semid];
|
2002-08-13 08:47:17 +00:00
|
|
|
sema_mtxp = &sema_mtx[semid];
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
|
2002-08-13 08:47:17 +00:00
|
|
|
mtx_lock(sema_mtxp);
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0 ||
|
|
|
|
(semakptr->u.sem_perm.seq != seq)) {
|
|
|
|
mtx_unlock(sema_mtxp);
|
|
|
|
continue;
|
|
|
|
}
|
2004-11-12 13:23:47 +00:00
|
|
|
if (semnum >= semakptr->u.sem_nsems)
|
1994-09-13 14:47:38 +00:00
|
|
|
panic("semexit - semnum out of range");
|
|
|
|
|
2002-07-22 18:27:54 +00:00
|
|
|
DPRINTF((
|
2006-07-12 11:41:53 +00:00
|
|
|
"semexit: %p id=%d num=%d(adj=%d) ; sem=%d\n",
|
1994-09-13 14:47:38 +00:00
|
|
|
suptr->un_proc, suptr->un_ent[ix].un_id,
|
|
|
|
suptr->un_ent[ix].un_num,
|
|
|
|
suptr->un_ent[ix].un_adjval,
|
2004-11-12 13:23:47 +00:00
|
|
|
semakptr->u.sem_base[semnum].semval));
|
1994-09-13 14:47:38 +00:00
|
|
|
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
if (adjval < 0 && semakptr->u.sem_base[semnum].semval <
|
|
|
|
-adjval)
|
|
|
|
semakptr->u.sem_base[semnum].semval = 0;
|
|
|
|
else
|
2004-11-12 13:23:47 +00:00
|
|
|
semakptr->u.sem_base[semnum].semval += adjval;
|
1994-09-13 14:47:38 +00:00
|
|
|
|
2004-11-12 13:23:47 +00:00
|
|
|
wakeup(semakptr);
|
2002-07-22 18:27:54 +00:00
|
|
|
DPRINTF(("semexit: back from wakeup\n"));
|
2002-08-13 08:47:17 +00:00
|
|
|
mtx_unlock(sema_mtxp);
|
1994-09-13 14:47:38 +00:00
|
|
|
}
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
SEMUNDO_LOCK();
|
1994-09-13 14:47:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Deallocate the undo vector.
|
|
|
|
*/
|
2002-07-22 18:27:54 +00:00
|
|
|
DPRINTF(("removing vector\n"));
|
1994-09-13 14:47:38 +00:00
|
|
|
suptr->un_proc = NULL;
|
It seems that there are at least three issues with IPC_RMID operation
on SysV semaphores.
The squeeze of the semaphore array in the kern_semctl() modifies
sem_base for the semaphores with sem_base greater then sem_base of
the removed semaphore, as well as the values of the semaphores,
without locking their mutex. This can lead to (killable) hangs or
unexpected behaviour of the processes performing any sem operations
while other process does IPC_RMID.
The semexit_myhook() eventhandler unlocks SEMUNDO_LOCK() while
accessing *suptr. This allows for IPC_RMID for the sem id to be
performed in parallel with undo hook referenced by the current undo
structure. This leads to the panic("semexit - semid not allocated") [1].
The semaphore creation is protected by Giant, while IPC_RMID is done
while only semaphore mutex is held. This seems to result in invalid
values for semtot, causing random ENOSPC error returns [2].
Redo the locking of the semaphores lifetime cycle. Delegate the
sem_mtx to the sole purpose of protecting semget() and
semctl(IPC_RMID). Introduce new sem_undo_mtx to protect SEM_UNDO
handling. Remove the Giant remnants from the code.
Note that mac_sysvsem_check_semget() and mac_sysvsem_create() are
now called while sem_mtx is held, as well as mac_sysvsem_cleanup() [3].
When semaphore is removed, acquire semaphore locks for all semaphores
with sem_base that is going to be changed by squeeze of the sema
array. The lock order is not important there, because the region is
protected by sem_mtx.
Organize both used and free sem_undo structures into the lists,
protected by sem_undo_mtx. In semexit_myhook(), remove sem_undo
structure that is being processed, from used list, without putting it
onto the free to prevent modifications by other threads. This allows
for sem_undo_lock to be dropped to acquire individial semaphore locks
without violating lock order. Since IPC_RMID may no longer find this
sem_undo, do tolerate references to unallocated semaphores in undo
structure, and check sequential number to not undo unrelated semaphore
with the same id.
While there, convert functions definitions to ANSI C and fix small
style(9) glitches.
Reported by: Omer Faruk Sen <omerfsen gmail com> [1], pho [2]
Reviewed by: rwatson [3]
Tested by: pho
MFC after: 1 month
2009-01-14 15:20:13 +00:00
|
|
|
suptr->un_cnt = 0;
|
|
|
|
LIST_INSERT_HEAD(&semu_free_list, suptr, un_next);
|
2007-03-26 17:41:14 +00:00
|
|
|
SEMUNDO_UNLOCK();
|
1994-09-13 14:47:38 +00:00
|
|
|
}
|
2001-05-30 03:28:59 +00:00
|
|
|
|
|
|
|
static int
|
|
|
|
sysctl_sema(SYSCTL_HANDLER_ARGS)
|
|
|
|
{
|
|
|
|
|
|
|
|
return (SYSCTL_OUT(req, sema,
|
2004-11-12 13:23:47 +00:00
|
|
|
sizeof(struct semid_kernel) * seminfo.semmni));
|
2001-05-30 03:28:59 +00:00
|
|
|
}
|
2009-06-24 20:01:13 +00:00
|
|
|
|
|
|
|
#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
|
|
|
|
defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
|
|
|
|
|
|
|
|
/* XXX casting to (sy_call_t *) is bogus, as usual. */
|
|
|
|
static sy_call_t *semcalls[] = {
|
2009-06-24 21:10:52 +00:00
|
|
|
(sy_call_t *)freebsd7___semctl, (sy_call_t *)semget,
|
2009-06-24 20:01:13 +00:00
|
|
|
(sy_call_t *)semop
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Entry point for all SEM calls.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
semsys(td, uap)
|
|
|
|
struct thread *td;
|
|
|
|
/* XXX actually varargs. */
|
|
|
|
struct semsys_args /* {
|
|
|
|
int which;
|
|
|
|
int a2;
|
|
|
|
int a3;
|
|
|
|
int a4;
|
|
|
|
int a5;
|
|
|
|
} */ *uap;
|
|
|
|
{
|
|
|
|
int error;
|
|
|
|
|
|
|
|
if (!prison_allow(td->td_ucred, PR_ALLOW_SYSVIPC))
|
|
|
|
return (ENOSYS);
|
|
|
|
if (uap->which < 0 ||
|
|
|
|
uap->which >= sizeof(semcalls)/sizeof(semcalls[0]))
|
|
|
|
return (EINVAL);
|
|
|
|
error = (*semcalls[uap->which])(td, &uap->a2);
|
|
|
|
return (error);
|
|
|
|
}
|
2009-06-24 21:10:52 +00:00
|
|
|
|
2010-03-19 11:04:42 +00:00
|
|
|
#ifndef CP
|
2009-06-24 21:10:52 +00:00
|
|
|
#define CP(src, dst, fld) do { (dst).fld = (src).fld; } while (0)
|
2010-03-19 11:04:42 +00:00
|
|
|
#endif
|
2009-06-24 21:10:52 +00:00
|
|
|
|
|
|
|
#ifndef _SYS_SYSPROTO_H_
|
|
|
|
struct freebsd7___semctl_args {
|
|
|
|
int semid;
|
|
|
|
int semnum;
|
|
|
|
int cmd;
|
|
|
|
union semun_old *arg;
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
int
|
|
|
|
freebsd7___semctl(struct thread *td, struct freebsd7___semctl_args *uap)
|
|
|
|
{
|
|
|
|
struct semid_ds_old dsold;
|
|
|
|
struct semid_ds dsbuf;
|
|
|
|
union semun_old arg;
|
|
|
|
union semun semun;
|
|
|
|
register_t rval;
|
|
|
|
int error;
|
|
|
|
|
|
|
|
switch (uap->cmd) {
|
|
|
|
case SEM_STAT:
|
|
|
|
case IPC_SET:
|
|
|
|
case IPC_STAT:
|
|
|
|
case GETALL:
|
|
|
|
case SETVAL:
|
|
|
|
case SETALL:
|
|
|
|
error = copyin(uap->arg, &arg, sizeof(arg));
|
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (uap->cmd) {
|
|
|
|
case SEM_STAT:
|
|
|
|
case IPC_STAT:
|
|
|
|
semun.buf = &dsbuf;
|
|
|
|
break;
|
|
|
|
case IPC_SET:
|
|
|
|
error = copyin(arg.buf, &dsold, sizeof(dsold));
|
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
ipcperm_old2new(&dsold.sem_perm, &dsbuf.sem_perm);
|
|
|
|
CP(dsold, dsbuf, sem_base);
|
|
|
|
CP(dsold, dsbuf, sem_nsems);
|
|
|
|
CP(dsold, dsbuf, sem_otime);
|
|
|
|
CP(dsold, dsbuf, sem_ctime);
|
|
|
|
semun.buf = &dsbuf;
|
|
|
|
break;
|
|
|
|
case GETALL:
|
|
|
|
case SETALL:
|
|
|
|
semun.array = arg.array;
|
|
|
|
break;
|
|
|
|
case SETVAL:
|
|
|
|
semun.val = arg.val;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
error = kern_semctl(td, uap->semid, uap->semnum, uap->cmd, &semun,
|
|
|
|
&rval);
|
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
|
|
|
|
switch (uap->cmd) {
|
|
|
|
case SEM_STAT:
|
|
|
|
case IPC_STAT:
|
|
|
|
bzero(&dsold, sizeof(dsold));
|
|
|
|
ipcperm_new2old(&dsbuf.sem_perm, &dsold.sem_perm);
|
|
|
|
CP(dsbuf, dsold, sem_base);
|
|
|
|
CP(dsbuf, dsold, sem_nsems);
|
|
|
|
CP(dsbuf, dsold, sem_otime);
|
|
|
|
CP(dsbuf, dsold, sem_ctime);
|
|
|
|
error = copyout(&dsold, arg.buf, sizeof(dsold));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (error == 0)
|
|
|
|
td->td_retval[0] = rval;
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
2010-03-19 11:04:42 +00:00
|
|
|
#endif /* COMPAT_FREEBSD{4,5,6,7} */
|
|
|
|
|
|
|
|
#ifdef COMPAT_FREEBSD32
|
|
|
|
|
|
|
|
int
|
|
|
|
freebsd32_semsys(struct thread *td, struct freebsd32_semsys_args *uap)
|
|
|
|
{
|
|
|
|
|
|
|
|
#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
|
|
|
|
defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
|
|
|
|
switch (uap->which) {
|
|
|
|
case 0:
|
|
|
|
return (freebsd7_freebsd32_semctl(td,
|
|
|
|
(struct freebsd7_freebsd32_semctl_args *)&uap->a2));
|
|
|
|
default:
|
|
|
|
return (semsys(td, (struct semsys_args *)uap));
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
return (nosys(td, NULL));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(COMPAT_FREEBSD4) || defined(COMPAT_FREEBSD5) || \
|
|
|
|
defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD7)
|
|
|
|
int
|
|
|
|
freebsd7_freebsd32_semctl(struct thread *td,
|
|
|
|
struct freebsd7_freebsd32_semctl_args *uap)
|
|
|
|
{
|
|
|
|
struct semid_ds32_old dsbuf32;
|
|
|
|
struct semid_ds dsbuf;
|
|
|
|
union semun semun;
|
|
|
|
union semun32 arg;
|
|
|
|
register_t rval;
|
|
|
|
int error;
|
|
|
|
|
|
|
|
switch (uap->cmd) {
|
|
|
|
case SEM_STAT:
|
|
|
|
case IPC_SET:
|
|
|
|
case IPC_STAT:
|
|
|
|
case GETALL:
|
|
|
|
case SETVAL:
|
|
|
|
case SETALL:
|
|
|
|
error = copyin(uap->arg, &arg, sizeof(arg));
|
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (uap->cmd) {
|
|
|
|
case SEM_STAT:
|
|
|
|
case IPC_STAT:
|
|
|
|
semun.buf = &dsbuf;
|
|
|
|
break;
|
|
|
|
case IPC_SET:
|
|
|
|
error = copyin(PTRIN(arg.buf), &dsbuf32, sizeof(dsbuf32));
|
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
freebsd32_ipcperm_old_in(&dsbuf32.sem_perm, &dsbuf.sem_perm);
|
|
|
|
PTRIN_CP(dsbuf32, dsbuf, sem_base);
|
|
|
|
CP(dsbuf32, dsbuf, sem_nsems);
|
|
|
|
CP(dsbuf32, dsbuf, sem_otime);
|
|
|
|
CP(dsbuf32, dsbuf, sem_ctime);
|
|
|
|
semun.buf = &dsbuf;
|
|
|
|
break;
|
|
|
|
case GETALL:
|
|
|
|
case SETALL:
|
|
|
|
semun.array = PTRIN(arg.array);
|
|
|
|
break;
|
|
|
|
case SETVAL:
|
|
|
|
semun.val = arg.val;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
error = kern_semctl(td, uap->semid, uap->semnum, uap->cmd, &semun,
|
|
|
|
&rval);
|
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
|
|
|
|
switch (uap->cmd) {
|
|
|
|
case SEM_STAT:
|
|
|
|
case IPC_STAT:
|
|
|
|
bzero(&dsbuf32, sizeof(dsbuf32));
|
|
|
|
freebsd32_ipcperm_old_out(&dsbuf.sem_perm, &dsbuf32.sem_perm);
|
|
|
|
PTROUT_CP(dsbuf, dsbuf32, sem_base);
|
|
|
|
CP(dsbuf, dsbuf32, sem_nsems);
|
|
|
|
CP(dsbuf, dsbuf32, sem_otime);
|
|
|
|
CP(dsbuf, dsbuf32, sem_ctime);
|
|
|
|
error = copyout(&dsbuf32, PTRIN(arg.buf), sizeof(dsbuf32));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (error == 0)
|
|
|
|
td->td_retval[0] = rval;
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
int
|
|
|
|
freebsd32_semctl(struct thread *td, struct freebsd32_semctl_args *uap)
|
|
|
|
{
|
|
|
|
struct semid_ds32 dsbuf32;
|
|
|
|
struct semid_ds dsbuf;
|
|
|
|
union semun semun;
|
|
|
|
union semun32 arg;
|
|
|
|
register_t rval;
|
|
|
|
int error;
|
|
|
|
|
|
|
|
switch (uap->cmd) {
|
|
|
|
case SEM_STAT:
|
|
|
|
case IPC_SET:
|
|
|
|
case IPC_STAT:
|
|
|
|
case GETALL:
|
|
|
|
case SETVAL:
|
|
|
|
case SETALL:
|
|
|
|
error = copyin(uap->arg, &arg, sizeof(arg));
|
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (uap->cmd) {
|
|
|
|
case SEM_STAT:
|
|
|
|
case IPC_STAT:
|
|
|
|
semun.buf = &dsbuf;
|
|
|
|
break;
|
|
|
|
case IPC_SET:
|
|
|
|
error = copyin(PTRIN(arg.buf), &dsbuf32, sizeof(dsbuf32));
|
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
freebsd32_ipcperm_in(&dsbuf32.sem_perm, &dsbuf.sem_perm);
|
|
|
|
PTRIN_CP(dsbuf32, dsbuf, sem_base);
|
|
|
|
CP(dsbuf32, dsbuf, sem_nsems);
|
|
|
|
CP(dsbuf32, dsbuf, sem_otime);
|
|
|
|
CP(dsbuf32, dsbuf, sem_ctime);
|
|
|
|
semun.buf = &dsbuf;
|
|
|
|
break;
|
|
|
|
case GETALL:
|
|
|
|
case SETALL:
|
|
|
|
semun.array = PTRIN(arg.array);
|
|
|
|
break;
|
|
|
|
case SETVAL:
|
|
|
|
semun.val = arg.val;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
error = kern_semctl(td, uap->semid, uap->semnum, uap->cmd, &semun,
|
|
|
|
&rval);
|
|
|
|
if (error)
|
|
|
|
return (error);
|
|
|
|
|
|
|
|
switch (uap->cmd) {
|
|
|
|
case SEM_STAT:
|
|
|
|
case IPC_STAT:
|
|
|
|
bzero(&dsbuf32, sizeof(dsbuf32));
|
|
|
|
freebsd32_ipcperm_out(&dsbuf.sem_perm, &dsbuf32.sem_perm);
|
|
|
|
PTROUT_CP(dsbuf, dsbuf32, sem_base);
|
|
|
|
CP(dsbuf, dsbuf32, sem_nsems);
|
|
|
|
CP(dsbuf, dsbuf32, sem_otime);
|
|
|
|
CP(dsbuf, dsbuf32, sem_ctime);
|
|
|
|
error = copyout(&dsbuf32, PTRIN(arg.buf), sizeof(dsbuf32));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (error == 0)
|
|
|
|
td->td_retval[0] = rval;
|
|
|
|
return (error);
|
|
|
|
}
|
2009-06-24 21:10:52 +00:00
|
|
|
|
2010-03-19 11:04:42 +00:00
|
|
|
#endif /* COMPAT_FREEBSD32 */
|