diff options
author | Dan Carpenter <error27@gmail.com> | 2010-10-19 01:57:04 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-11-09 16:30:48 -0500 |
commit | bc704e31edc723a84c2469f26aa0279e1ddb948e (patch) | |
tree | 47d9c1b9675f303be6203beb46d533af288baa26 /drivers/staging | |
parent | 3b97eed201376db6c4487fc846022eb4ffa7e1f9 (diff) |
Staging: sst: more dereferencing user pointers
This is another patch about making a copy of the data into kernel space
before using it. It is easy to trigger a kernel oops in the original
code. If you passed a NULL to SNDRV_SST_SET_TARGET_DEVICE then it
called BUG_ON(). And SNDRV_SST_DRIVER_INFO would let you write the
information to arbitrary memory locations which is a security violation.
Signed-off-by: Dan Carpenter <error27@gmail.com>
Acked-by: Vinod Koul <vinod.koul@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/staging')
-rw-r--r-- | drivers/staging/intel_sst/intel_sst_app_interface.c | 75 |
1 files changed, 46 insertions, 29 deletions
diff --git a/drivers/staging/intel_sst/intel_sst_app_interface.c b/drivers/staging/intel_sst/intel_sst_app_interface.c index a0d13ee190e5..8390aa793b7b 100644 --- a/drivers/staging/intel_sst/intel_sst_app_interface.c +++ b/drivers/staging/intel_sst/intel_sst_app_interface.c | |||
@@ -838,7 +838,7 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg) | |||
838 | break; | 838 | break; |
839 | 839 | ||
840 | case _IOC_NR(SNDRV_SST_STREAM_SET_PARAMS): { | 840 | case _IOC_NR(SNDRV_SST_STREAM_SET_PARAMS): { |
841 | struct snd_sst_params *str_param = (struct snd_sst_params *)arg; | 841 | struct snd_sst_params str_param; |
842 | 842 | ||
843 | pr_debug("sst: IOCTL_SET_PARAMS recieved!\n"); | 843 | pr_debug("sst: IOCTL_SET_PARAMS recieved!\n"); |
844 | if (minor != STREAM_MODULE) { | 844 | if (minor != STREAM_MODULE) { |
@@ -846,17 +846,25 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg) | |||
846 | break; | 846 | break; |
847 | } | 847 | } |
848 | 848 | ||
849 | if (copy_from_user(&str_param, (void __user *)arg, | ||
850 | sizeof(str_param))) { | ||
851 | retval = -EFAULT; | ||
852 | break; | ||
853 | } | ||
854 | |||
849 | if (!str_id) { | 855 | if (!str_id) { |
850 | 856 | ||
851 | retval = sst_get_stream(str_param); | 857 | retval = sst_get_stream(&str_param); |
852 | if (retval > 0) { | 858 | if (retval > 0) { |
853 | struct stream_info *str_info; | 859 | struct stream_info *str_info; |
860 | char __user *dest; | ||
861 | |||
854 | sst_drv_ctx->stream_cnt++; | 862 | sst_drv_ctx->stream_cnt++; |
855 | data->str_id = retval; | 863 | data->str_id = retval; |
856 | str_info = &sst_drv_ctx->streams[retval]; | 864 | str_info = &sst_drv_ctx->streams[retval]; |
857 | str_info->src = SST_DRV; | 865 | str_info->src = SST_DRV; |
858 | retval = copy_to_user(&str_param->stream_id, | 866 | dest = (char *)arg + offsetof(struct snd_sst_params, stream_id); |
859 | &retval, sizeof(__u32)); | 867 | retval = copy_to_user(dest, &retval, sizeof(__u32)); |
860 | if (retval) | 868 | if (retval) |
861 | retval = -EFAULT; | 869 | retval = -EFAULT; |
862 | } else { | 870 | } else { |
@@ -866,16 +874,14 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg) | |||
866 | } else { | 874 | } else { |
867 | pr_debug("sst: SET_STREAM_PARAMS recieved!\n"); | 875 | pr_debug("sst: SET_STREAM_PARAMS recieved!\n"); |
868 | /* allocated set params only */ | 876 | /* allocated set params only */ |
869 | retval = sst_set_stream_param(str_id, str_param); | 877 | retval = sst_set_stream_param(str_id, &str_param); |
870 | /* Block the call for reply */ | 878 | /* Block the call for reply */ |
871 | if (!retval) { | 879 | if (!retval) { |
872 | int sfreq = 0, word_size = 0, num_channel = 0; | 880 | int sfreq = 0, word_size = 0, num_channel = 0; |
873 | sfreq = str_param->sparams.uc.pcm_params.sfreq; | 881 | sfreq = str_param.sparams.uc.pcm_params.sfreq; |
874 | word_size = str_param->sparams. | 882 | word_size = str_param.sparams.uc.pcm_params.pcm_wd_sz; |
875 | uc.pcm_params.pcm_wd_sz; | 883 | num_channel = str_param.sparams.uc.pcm_params.num_chan; |
876 | num_channel = str_param-> | 884 | if (str_param.ops == STREAM_OPS_CAPTURE) { |
877 | sparams.uc.pcm_params.num_chan; | ||
878 | if (str_param->ops == STREAM_OPS_CAPTURE) { | ||
879 | sst_drv_ctx->scard_ops->\ | 885 | sst_drv_ctx->scard_ops->\ |
880 | set_pcm_audio_params(sfreq, | 886 | set_pcm_audio_params(sfreq, |
881 | word_size, num_channel); | 887 | word_size, num_channel); |
@@ -976,16 +982,22 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg) | |||
976 | } | 982 | } |
977 | 983 | ||
978 | case _IOC_NR(SNDRV_SST_MMAP_PLAY): | 984 | case _IOC_NR(SNDRV_SST_MMAP_PLAY): |
979 | case _IOC_NR(SNDRV_SST_MMAP_CAPTURE): | 985 | case _IOC_NR(SNDRV_SST_MMAP_CAPTURE): { |
986 | struct snd_sst_mmap_buffs mmap_buf; | ||
987 | |||
980 | pr_debug("sst: SNDRV_SST_MMAP_PLAY/CAPTURE recieved!\n"); | 988 | pr_debug("sst: SNDRV_SST_MMAP_PLAY/CAPTURE recieved!\n"); |
981 | if (minor != STREAM_MODULE) { | 989 | if (minor != STREAM_MODULE) { |
982 | retval = -EBADRQC; | 990 | retval = -EBADRQC; |
983 | break; | 991 | break; |
984 | } | 992 | } |
985 | retval = intel_sst_mmap_play_capture(str_id, | 993 | if (copy_from_user(&mmap_buf, (void __user *)arg, |
986 | (struct snd_sst_mmap_buffs *)arg); | 994 | sizeof(mmap_buf))) { |
995 | retval = -EFAULT; | ||
996 | break; | ||
997 | } | ||
998 | retval = intel_sst_mmap_play_capture(str_id, &mmap_buf); | ||
987 | break; | 999 | break; |
988 | 1000 | } | |
989 | case _IOC_NR(SNDRV_SST_STREAM_DROP): | 1001 | case _IOC_NR(SNDRV_SST_STREAM_DROP): |
990 | pr_debug("sst: SNDRV_SST_IOCTL_DROP recieved!\n"); | 1002 | pr_debug("sst: SNDRV_SST_IOCTL_DROP recieved!\n"); |
991 | if (minor != STREAM_MODULE) { | 1003 | if (minor != STREAM_MODULE) { |
@@ -996,7 +1008,6 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg) | |||
996 | break; | 1008 | break; |
997 | 1009 | ||
998 | case _IOC_NR(SNDRV_SST_STREAM_GET_TSTAMP): { | 1010 | case _IOC_NR(SNDRV_SST_STREAM_GET_TSTAMP): { |
999 | unsigned long long *ms = (unsigned long long *)arg; | ||
1000 | struct snd_sst_tstamp tstamp = {0}; | 1011 | struct snd_sst_tstamp tstamp = {0}; |
1001 | unsigned long long time, freq, mod; | 1012 | unsigned long long time, freq, mod; |
1002 | 1013 | ||
@@ -1013,7 +1024,8 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg) | |||
1013 | freq = (unsigned long long) tstamp.sampling_frequency; | 1024 | freq = (unsigned long long) tstamp.sampling_frequency; |
1014 | time = time * 1000; /* converting it to ms */ | 1025 | time = time * 1000; /* converting it to ms */ |
1015 | mod = do_div(time, freq); | 1026 | mod = do_div(time, freq); |
1016 | if (copy_to_user(ms, &time, sizeof(*ms))) | 1027 | if (copy_to_user((void __user *)arg, &time, |
1028 | sizeof(unsigned long long))) | ||
1017 | retval = -EFAULT; | 1029 | retval = -EFAULT; |
1018 | break; | 1030 | break; |
1019 | } | 1031 | } |
@@ -1058,32 +1070,37 @@ long intel_sst_ioctl(struct file *file_ptr, unsigned int cmd, unsigned long arg) | |||
1058 | } | 1070 | } |
1059 | 1071 | ||
1060 | case _IOC_NR(SNDRV_SST_SET_TARGET_DEVICE): { | 1072 | case _IOC_NR(SNDRV_SST_SET_TARGET_DEVICE): { |
1061 | struct snd_sst_target_device *target_device; | 1073 | struct snd_sst_target_device target_device; |
1062 | 1074 | ||
1063 | pr_debug("sst: SET_TARGET_DEVICE recieved!\n"); | 1075 | pr_debug("sst: SET_TARGET_DEVICE recieved!\n"); |
1064 | target_device = (struct snd_sst_target_device *)arg; | 1076 | if (copy_from_user(&target_device, (void __user *)arg, |
1065 | BUG_ON(!target_device); | 1077 | sizeof(target_device))) { |
1078 | retval = -EFAULT; | ||
1079 | break; | ||
1080 | } | ||
1066 | if (minor != AM_MODULE) { | 1081 | if (minor != AM_MODULE) { |
1067 | retval = -EBADRQC; | 1082 | retval = -EBADRQC; |
1068 | break; | 1083 | break; |
1069 | } | 1084 | } |
1070 | retval = sst_target_device_select(target_device); | 1085 | retval = sst_target_device_select(&target_device); |
1071 | break; | 1086 | break; |
1072 | } | 1087 | } |
1073 | 1088 | ||
1074 | case _IOC_NR(SNDRV_SST_DRIVER_INFO): { | 1089 | case _IOC_NR(SNDRV_SST_DRIVER_INFO): { |
1075 | struct snd_sst_driver_info *info = | 1090 | struct snd_sst_driver_info info; |
1076 | (struct snd_sst_driver_info *)arg; | ||
1077 | 1091 | ||
1078 | pr_debug("sst: SNDRV_SST_DRIVER_INFO recived\n"); | 1092 | pr_debug("sst: SNDRV_SST_DRIVER_INFO recived\n"); |
1079 | info->version = SST_VERSION_NUM; | 1093 | info.version = SST_VERSION_NUM; |
1080 | /* hard coding, shud get sumhow later */ | 1094 | /* hard coding, shud get sumhow later */ |
1081 | info->active_pcm_streams = sst_drv_ctx->stream_cnt - | 1095 | info.active_pcm_streams = sst_drv_ctx->stream_cnt - |
1082 | sst_drv_ctx->encoded_cnt; | 1096 | sst_drv_ctx->encoded_cnt; |
1083 | info->active_enc_streams = sst_drv_ctx->encoded_cnt; | 1097 | info.active_enc_streams = sst_drv_ctx->encoded_cnt; |
1084 | info->max_pcm_streams = MAX_ACTIVE_STREAM - MAX_ENC_STREAM; | 1098 | info.max_pcm_streams = MAX_ACTIVE_STREAM - MAX_ENC_STREAM; |
1085 | info->max_enc_streams = MAX_ENC_STREAM; | 1099 | info.max_enc_streams = MAX_ENC_STREAM; |
1086 | info->buf_per_stream = sst_drv_ctx->mmap_len; | 1100 | info.buf_per_stream = sst_drv_ctx->mmap_len; |
1101 | if (copy_to_user((void __user *)arg, &info, | ||
1102 | sizeof(info))) | ||
1103 | retval = -EFAULT; | ||
1087 | break; | 1104 | break; |
1088 | } | 1105 | } |
1089 | 1106 | ||