Change xxx by xxx on 2012/05/01 09:57:30 - add locking to the Linux procfs binary write path. Bug xxx: Potential heap overflow due to write \ race in /proc/driver/nvidia/registry Reviewed by: xxx DVS_BASIC_SANITY Linux Affected files ... ... //xxx/unix/Linux/nv-linux.h#xxx edit ... //xxx/unix/Linux/nv-procfs.c#xxx edit Differences ... ==== //xxx/unix/Linux/nv-linux.h#xxx (text) ==== @@ -1613,6 +1613,7 @@ { NV_FOPS_STACK_INDEX_MMAP, NV_FOPS_STACK_INDEX_IOCTL, + NV_FOPS_STACK_INDEX_PROCFS, NV_FOPS_STACK_INDEX_COUNT } nvidia_entry_point_index_t; @@ -1621,7 +1622,6 @@ // TODO: merge this sp variable into the sp_other array. nv_stack_t *sp; - // Use the nvidia_entry_point_index_t enum, to index into sp and sp_lock. nv_stack_t *fops_sp[NV_FOPS_STACK_INDEX_COUNT]; struct semaphore fops_sp_lock[NV_FOPS_STACK_INDEX_COUNT]; ==== //xxx/unix/Linux/nv-procfs.c#xxx (text) ==== @@ -450,7 +450,6 @@ } NV_SET_FILE_PRIVATE(file, nvfp); - nvfp->sp = sp; if (RM_OK != os_alloc_mem((void **)&nvfp->data, NV_PROC_WRITE_BUFFER_SIZE)) { @@ -459,7 +458,9 @@ NV_SET_FILE_PRIVATE(file, NULL); return -ENOMEM; } + os_mem_set((void *)nvfp->data, 0, NV_PROC_WRITE_BUFFER_SIZE); + nvfp->fops_sp[NV_FOPS_STACK_INDEX_PROCFS] = sp; return 0; } @@ -484,7 +485,7 @@ if (nvfp == NULL) return 0; - sp = nvfp->sp; + sp = nvfp->fops_sp[NV_FOPS_STACK_INDEX_PROCFS]; if (0 != nvfp->off) { @@ -607,30 +608,43 @@ void *data ) { + int status = 0; nv_file_private_t *nvfp = NV_GET_FILE_PRIVATE(file); char *proc_buffer; unsigned long bytes_left; + down(&nvfp->fops_sp_lock[NV_FOPS_STACK_INDEX_PROCFS]); + bytes_left = (NV_PROC_WRITE_BUFFER_SIZE - nvfp->off - 1); if (count == 0) - return -EINVAL; + { + status = -EINVAL; + goto done; + } else if ((bytes_left == 0) || (count > bytes_left)) - return -ENOSPC; + { + status = -ENOSPC; + goto done; + } proc_buffer = &((char *)nvfp->data)[nvfp->off]; if (copy_from_user(proc_buffer, buffer, count)) { - nv_printf(NV_DBG_ERRORS, - "NVRM: failed to copyin proc data!\n"); - return -EFAULT; + nv_printf(NV_DBG_ERRORS, "NVRM: failed to copy in proc data!\n"); + status = -EFAULT; + } + else + { + nvfp->proc_data = data; + nvfp->off += count; } - nvfp->proc_data = data; - nvfp->off += count; +done: + up(&nvfp->fops_sp_lock[NV_FOPS_STACK_INDEX_PROCFS]); - return count; + return ((status < 0) ? status : (int)count); } static int