diff options
| -rw-r--r-- | ipc/sem.c | 18 | 
1 files changed, 14 insertions, 4 deletions
diff --git a/ipc/sem.c b/ipc/sem.c index 59a3cd1d3252..5af1943ad782 100644 --- a/ipc/sem.c +++ b/ipc/sem.c @@ -85,6 +85,7 @@  #include <linux/nsproxy.h>  #include <linux/ipc_namespace.h>  #include <linux/sched/wake_q.h> +#include <linux/nospec.h>  #include <linux/uaccess.h>  #include "util.h" @@ -368,6 +369,7 @@ static inline int sem_lock(struct sem_array *sma, struct sembuf *sops,  			      int nsops)  {  	struct sem *sem; +	int idx;  	if (nsops != 1) {  		/* Complex operation - acquire a full lock */ @@ -385,7 +387,8 @@ static inline int sem_lock(struct sem_array *sma, struct sembuf *sops,  	 *  	 * Both facts are tracked by use_global_mode.  	 */ -	sem = &sma->sems[sops->sem_num]; +	idx = array_index_nospec(sops->sem_num, sma->sem_nsems); +	sem = &sma->sems[idx];  	/*  	 * Initial check for use_global_lock. Just an optimization, @@ -638,7 +641,8 @@ static int perform_atomic_semop_slow(struct sem_array *sma, struct sem_queue *q)  	un = q->undo;  	for (sop = sops; sop < sops + nsops; sop++) { -		curr = &sma->sems[sop->sem_num]; +		int idx = array_index_nospec(sop->sem_num, sma->sem_nsems); +		curr = &sma->sems[idx];  		sem_op = sop->sem_op;  		result = curr->semval; @@ -718,7 +722,9 @@ static int perform_atomic_semop(struct sem_array *sma, struct sem_queue *q)  	 * until the operations can go through.  	 */  	for (sop = sops; sop < sops + nsops; sop++) { -		curr = &sma->sems[sop->sem_num]; +		int idx = array_index_nospec(sop->sem_num, sma->sem_nsems); + +		curr = &sma->sems[idx];  		sem_op = sop->sem_op;  		result = curr->semval; @@ -1356,6 +1362,7 @@ static int semctl_setval(struct ipc_namespace *ns, int semid, int semnum,  		return -EIDRM;  	} +	semnum = array_index_nospec(semnum, sma->sem_nsems);  	curr = &sma->sems[semnum];  	ipc_assert_locked_object(&sma->sem_perm); @@ -1509,6 +1516,8 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,  		err = -EIDRM;  		goto out_unlock;  	} + +	semnum = array_index_nospec(semnum, nsems);  	curr = &sma->sems[semnum];  	switch (cmd) { @@ -2081,7 +2090,8 @@ static long do_semtimedop(int semid, struct sembuf __user *tsops,  	 */  	if (nsops == 1) {  		struct sem *curr; -		curr = &sma->sems[sops->sem_num]; +		int idx = array_index_nospec(sops->sem_num, sma->sem_nsems); +		curr = &sma->sems[idx];  		if (alter) {  			if (sma->complex_count) {  | 
