lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <1386119012.2836.2.camel@buesod1.americas.hpqcorp.net>
Date:	Tue, 03 Dec 2013 17:03:32 -0800
From:	Davidlohr Bueso <davidlohr@...com>
To:	Petr Mladek <pmladek@...e.cz>
Cc:	Andrew Morton <akpm@...ux-foundation.org>,
	Manfred Spraul <manfred@...orfullife.com>,
	Jiri Kosina <jkosina@...e.cz>, linux-kernel@...r.kernel.org
Subject: Re: [PATCH] ipc: avoid overflow of semop undo (semadj) value

On Tue, 2013-12-03 at 10:44 +0100, Petr Mladek wrote:
> When trying to understand semop code, I found a small mistake in the check for
> semadj (undo) value overflow. The new undo value is not stored immediately
> and next potential checks are done against the old value.
> 
> The failing scenario is not much practical. One semop call has to do more
> operations on the same semaphore. Also semval and semadj must have different
> values, so there has to be some operations without SEM_UNDO flag. For example:
> 
> 	struct sembuf depositor_op[1];
> 	struct sembuf collector_op[2];
> 
> 	depositor_op[0].sem_num = 0;
> 	depositor_op[0].sem_op = 20000;
> 	depositor_op[0].sem_flg = 0;
> 
> 	collector_op[0].sem_num = 0;
> 	collector_op[0].sem_op = -10000;
> 	collector_op[0].sem_flg = SEM_UNDO;
> 	collector_op[1].sem_num = 0;
> 	collector_op[1].sem_op = -10000;
> 	collector_op[1].sem_flg = SEM_UNDO;
> 
> 	if (semop(semid, depositor_op, 1) == -1)
> 		{ perror("Failed to do 1st deposit"); return 1; }
> 
> 	if (semop(semid, collector_op, 2) == -1)
> 		{ perror("Failed to do 1st collect"); return 1; }
> 
> 	if (semop(semid, depositor_op, 1) == -1)
> 		{ perror("Failed to do 2nd deposit"); return 1; }
> 
> 	if (semop(semid, collector_op, 2) == -1)
> 		{ perror("Failed to do 2nd collect"); return 1; }
> 
> 	return 0;
> 
> It passes without error now but the semadj value has overflown in the
> 2nd collector operation.
> 
> Signed-off-by: Petr Mladek <pmladek@...e.cz>

Seems sane.

Acked-by: Davidlohr Bueso <davidlohr@...com>

> ---
>  ipc/sem.c | 22 ++++++++++++----------
>  1 file changed, 12 insertions(+), 10 deletions(-)
> 
> diff --git a/ipc/sem.c b/ipc/sem.c
> index db9d241af133..0d4375761449 100644
> --- a/ipc/sem.c
> +++ b/ipc/sem.c
> @@ -599,7 +599,7 @@ SYSCALL_DEFINE3(semget, key_t, key, int, nsems, int, semflg)
>  static int perform_atomic_semop(struct sem_array *sma, struct sembuf *sops,
>  			     int nsops, struct sem_undo *un, int pid)
>  {
> -	int result, sem_op;
> +	int result, undo, sem_op;
>  	struct sembuf *sop;
>  	struct sem * curr;
>  
> @@ -607,7 +607,7 @@ static int perform_atomic_semop(struct sem_array *sma, struct sembuf *sops,
>  		curr = sma->sem_base + sop->sem_num;
>  		sem_op = sop->sem_op;
>  		result = curr->semval;
> -  
> +
>  		if (!sem_op && result)
>  			goto would_block;
>  
> @@ -616,25 +616,24 @@ static int perform_atomic_semop(struct sem_array *sma, struct sembuf *sops,
>  			goto would_block;
>  		if (result > SEMVMX)
>  			goto out_of_range;
> +
>  		if (sop->sem_flg & SEM_UNDO) {
> -			int undo = un->semadj[sop->sem_num] - sem_op;
> -			/*
> -	 		 *	Exceeding the undo range is an error.
> -			 */
> +			undo = un->semadj[sop->sem_num] - sem_op;
> +			/* Exceeding the undo range is an error. */
>  			if (undo < (-SEMAEM - 1) || undo > SEMAEM)
>  				goto out_of_range;
> +			un->semadj[sop->sem_num] = undo;
>  		}
> +
>  		curr->semval = result;
>  	}
>  
>  	sop--;
>  	while (sop >= sops) {
>  		sma->sem_base[sop->sem_num].sempid = pid;
> -		if (sop->sem_flg & SEM_UNDO)
> -			un->semadj[sop->sem_num] -= sop->sem_op;
>  		sop--;
>  	}
> -	
> +
>  	return 0;
>  
>  out_of_range:
> @@ -650,7 +649,10 @@ would_block:
>  undo:
>  	sop--;
>  	while (sop >= sops) {
> -		sma->sem_base[sop->sem_num].semval -= sop->sem_op;
> +		sem_op = sop->sem_op;
> +		sma->sem_base[sop->sem_num].semval -= sem_op;
> +		if (sop->sem_flg & SEM_UNDO)
> +			un->semadj[sop->sem_num] += sem_op;
>  		sop--;
>  	}
>  


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ