diff options
Diffstat (limited to 'ipc/sem.c')
-rw-r--r-- | ipc/sem.c | 24 |
1 files changed, 13 insertions, 11 deletions
@@ -875,6 +875,11 @@ static inline unsigned long copy_semid_from_user(struct sem_setbuf *out, void __ | |||
875 | } | 875 | } |
876 | } | 876 | } |
877 | 877 | ||
878 | /* | ||
879 | * This function handles some semctl commands which require the rw_mutex | ||
880 | * to be held in write mode. | ||
881 | * NOTE: no locks must be held, the rw_mutex is taken inside this function. | ||
882 | */ | ||
878 | static int semctl_down(struct ipc_namespace *ns, int semid, int semnum, | 883 | static int semctl_down(struct ipc_namespace *ns, int semid, int semnum, |
879 | int cmd, int version, union semun arg) | 884 | int cmd, int version, union semun arg) |
880 | { | 885 | { |
@@ -887,9 +892,12 @@ static int semctl_down(struct ipc_namespace *ns, int semid, int semnum, | |||
887 | if(copy_semid_from_user (&setbuf, arg.buf, version)) | 892 | if(copy_semid_from_user (&setbuf, arg.buf, version)) |
888 | return -EFAULT; | 893 | return -EFAULT; |
889 | } | 894 | } |
895 | down_write(&sem_ids(ns).rw_mutex); | ||
890 | sma = sem_lock_check_down(ns, semid); | 896 | sma = sem_lock_check_down(ns, semid); |
891 | if (IS_ERR(sma)) | 897 | if (IS_ERR(sma)) { |
892 | return PTR_ERR(sma); | 898 | err = PTR_ERR(sma); |
899 | goto out_up; | ||
900 | } | ||
893 | 901 | ||
894 | ipcp = &sma->sem_perm; | 902 | ipcp = &sma->sem_perm; |
895 | 903 | ||
@@ -915,26 +923,22 @@ static int semctl_down(struct ipc_namespace *ns, int semid, int semnum, | |||
915 | switch(cmd){ | 923 | switch(cmd){ |
916 | case IPC_RMID: | 924 | case IPC_RMID: |
917 | freeary(ns, ipcp); | 925 | freeary(ns, ipcp); |
918 | err = 0; | 926 | goto out_up; |
919 | break; | ||
920 | case IPC_SET: | 927 | case IPC_SET: |
921 | ipcp->uid = setbuf.uid; | 928 | ipcp->uid = setbuf.uid; |
922 | ipcp->gid = setbuf.gid; | 929 | ipcp->gid = setbuf.gid; |
923 | ipcp->mode = (ipcp->mode & ~S_IRWXUGO) | 930 | ipcp->mode = (ipcp->mode & ~S_IRWXUGO) |
924 | | (setbuf.mode & S_IRWXUGO); | 931 | | (setbuf.mode & S_IRWXUGO); |
925 | sma->sem_ctime = get_seconds(); | 932 | sma->sem_ctime = get_seconds(); |
926 | sem_unlock(sma); | ||
927 | err = 0; | ||
928 | break; | 933 | break; |
929 | default: | 934 | default: |
930 | sem_unlock(sma); | ||
931 | err = -EINVAL; | 935 | err = -EINVAL; |
932 | break; | ||
933 | } | 936 | } |
934 | return err; | ||
935 | 937 | ||
936 | out_unlock: | 938 | out_unlock: |
937 | sem_unlock(sma); | 939 | sem_unlock(sma); |
940 | out_up: | ||
941 | up_write(&sem_ids(ns).rw_mutex); | ||
938 | return err; | 942 | return err; |
939 | } | 943 | } |
940 | 944 | ||
@@ -968,9 +972,7 @@ asmlinkage long sys_semctl (int semid, int semnum, int cmd, union semun arg) | |||
968 | return err; | 972 | return err; |
969 | case IPC_RMID: | 973 | case IPC_RMID: |
970 | case IPC_SET: | 974 | case IPC_SET: |
971 | down_write(&sem_ids(ns).rw_mutex); | ||
972 | err = semctl_down(ns,semid,semnum,cmd,version,arg); | 975 | err = semctl_down(ns,semid,semnum,cmd,version,arg); |
973 | up_write(&sem_ids(ns).rw_mutex); | ||
974 | return err; | 976 | return err; |
975 | default: | 977 | default: |
976 | return -EINVAL; | 978 | return -EINVAL; |