Skip to contentSkip to conversation

more copy_{to,from}_user fixes

BKPATCH Arnaldo Carvalho de Melo 2 participants 3 messages Jun 3, 2002

Subsystems (4)
lore
Share & tools
lore
#0 lore raw

Linus, some more, please consider pulling from:

http://kernel-acme.bkbits.net:8080/copy_to_from_user-2.5

I stopped this (re)audit when 544 were still to be reviewed. Bedtime 8)

And there are some observations for the ones that know the code mentioned below...

And from a quick look ./arch/i386/kernel/vm86.c seems to have problems too, look at this:

struct pt_regs * save_v86_state(struct kernel_vm86_regs * regs) .
.
.

        tmp = copy_to_user(&current->thread.vm86_info->regs,regs, VM86_REGS_SIZE1);
        tmp += copy_to_user(&current->thread.vm86_info->regs.VM86_REGS_PART2,
                &regs->VM86_REGS_PART2, VM86_REGS_SIZE2);
        tmp += put_user(current->thread.screen_bitmap,&current->thread.vm86_info

Another one:

./arch/parisc/hpux/fs.c

static int filldir(void * __buf, const char * name, int namlen, loff_t offset, ino_t ino)

is not checking copy_{to,from}_user and {put,get}_user.

Haven't checked the call chain to see if this is OK

Also ./arch/ppc64/kernel/sys_ppc32.c seems to have problems, not checking returns, etc, haven't checked the call chain to see if this is OK

But for this ones, even if it is OK to call it without checking (uh) it could be __copy_{to,from}_user

Question in the show_regs functions (one per arch, I guess) is it ok not to check the return of these functions? (s390 for one doesn't checks)

Others that are possibly wrong:

./arch/sparc/kernel/sys_sunos.c - sunos_filldir (other _filldir routines also don't check the return).

- Arnaldo

# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas:
# ChangeSet 1.413 -> 1.414
# arch/alpha/kernel/osf_sys.c 1.12 -> 1.13
# arch/ppc/kernel/ppc_htab.c 1.7 -> 1.8
# arch/cris/drivers/sync_serial.c 1.3 -> 1.4
# drivers/cdrom/cdu31a.c 1.15 -> 1.16
# drivers/cdrom/sbpcd.c 1.18 -> 1.19
# drivers/cdrom/optcd.c 1.9 -> 1.10
# arch/ppc64/kernel/rtasd.c 1.3 -> 1.4
# arch/ia64/sn/io/ifconfig_net.c 1.1 -> 1.2
# drivers/cdrom/sonycd535.c 1.13 -> 1.14
# drivers/char/drm/i810_dma.c 1.12 -> 1.13
# arch/sparc64/solaris/timod.c 1.11 -> 1.12
# arch/ppc/iSeries/mf.c 1.1 -> 1.2
# arch/alpha/kernel/signal.c 1.7 -> 1.8
# arch/ia64/ia32/sys_ia32.c 1.14 -> 1.15
# drivers/cdrom/sjcd.c 1.9 -> 1.10
# arch/mips/kernel/sysirix.c 1.6 -> 1.7
# drivers/bluetooth/hci_vhci.c 1.6 -> 1.7
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 02/06/03 [email protected] 1.414
# arch/*
# drivers/cdrom/*
# drivers/char/*
#
# Fix some copy_{to,from}_user and {put,get}_user error handling,
# get rid of some verify_area, copy_{to,from}_user already checks for errors.
# --------------------------------------------
#

arch/alpha/kernel/osf_sys.c +13 -13
diff -Nru a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c
@@ -116,15 +116,17 @@
 	if (reclen > buf->count)
 		return -EINVAL;
 	if (buf->basep) {
-		put_user(offset, buf->basep);
+		if (put_user(offset, buf->basep))
+			return -EFAULT;
 		buf->basep = NULL;
 	}
 	dirent = buf->dirent;
 	put_user(ino, &dirent->d_ino);
 	put_user(namlen, &dirent->d_namlen);
 	put_user(reclen, &dirent->d_reclen);
-	copy_to_user(dirent->d_name, name, namlen);
-	put_user(0, dirent->d_name + namlen);
+	if (copy_to_user(dirent->d_name, name, namlen) ||
+	    put_user(0, dirent->d_name + namlen))
+		return -EFAULT;
 	((char *) dirent) += reclen;
 	buf->dirent = dirent;
 	buf->count -= reclen;
@@ -629,18 +631,16 @@
 			error = args->fset.nbytes;
 		break;
 	case PL_GET:
-		get_user(min_buf_size_ptr, &args->get.min_buf_size);
-		error = verify_area(VERIFY_WRITE, min_buf_size_ptr,
-				    sizeof(*min_buf_size_ptr));
-		if (!error)
-			put_user(0, min_buf_size_ptr);
+		error = get_user(min_buf_size_ptr, &args->get.min_buf_size);
+		if (error)
+			break;
+		error = put_user(0, min_buf_size_ptr);
 		break;
 	case PL_FGET:
-		get_user(min_buf_size_ptr, &args->fget.min_buf_size);
-		error = verify_area(VERIFY_WRITE, min_buf_size_ptr,
-				    sizeof(*min_buf_size_ptr));
-		if (!error)
-			put_user(0, min_buf_size_ptr);
+		error = get_user(min_buf_size_ptr, &args->fget.min_buf_size);
+		if (error)
+			break;
+		error = put_user(0, min_buf_size_ptr);
 		break;
 	case PL_DEL:
 	case PL_FDEL:
arch/alpha/kernel/signal.c +1 -2
diff -Nru a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c
@@ -253,9 +253,8 @@
 		   struct switch_stack *sw)
 {
 	unsigned long usp;
-	long i, err = 0;
+	long i, err = __get_user(regs->pc, &sc->sc_pc);
 
-	err |= __get_user(regs->pc, &sc->sc_pc);
 	sw->r26 = (unsigned long) ret_from_sys_call;
 
 	err |= __get_user(regs->r0, sc->sc_regs+0);
arch/cris/drivers/sync_serial.c +6 -3
diff -Nru a/arch/cris/drivers/sync_serial.c b/arch/cris/drivers/sync_serial.c
@@ -551,7 +551,8 @@
 	}
 
 	port = &ports[dev];
-	copy_from_user(port->out_buffer, buf, count);
+	if (copy_from_user(port->out_buffer, buf, count))
+		return -EFAULT;
 	port->outp = port->out_buffer;
 	port->out_count = count;
 	port->odd_output = 1;
@@ -597,7 +598,8 @@
 		return sync_serial_manual_write(file, buf, count, ppos); 
 	}
   
-	copy_from_user(port->out_buffer, buf, count);
+	if (copy_from_user(port->out_buffer, buf, count))
+		return -EFAULT;
 	add_wait_queue(&port->out_wait_q, &wait);
 	set_current_state(TASK_INTERRUPTIBLE);
 	start_dma(port, buf, count);
@@ -658,7 +660,8 @@
 		avail = port->in_buffer + IN_BUFFER_SIZE - start;
   
 	count = count > avail ? avail : count;
-	copy_to_user(buf, start, count);
+	if (copy_to_user(buf, start, count))
+		return -EFAULT;
 
 	/* Disable interrupts while updating readp */
 	save_flags(flags);
arch/ia64/ia32/sys_ia32.c +2 -1
diff -Nru a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c
@@ -278,7 +278,8 @@
 		return -ENOMEM;
 
 	if (old_prot)
-		copy_from_user(page, (void *) PAGE_START(start), PAGE_SIZE);
+		if (copy_from_user(page, (void *) PAGE_START(start), PAGE_SIZE))
+			return -EFAULT;
 
 	down_write(&current->mm->mmap_sem);
 	{
arch/ia64/sn/io/ifconfig_net.c +22 -8
diff -Nru a/arch/ia64/sn/io/ifconfig_net.c b/arch/ia64/sn/io/ifconfig_net.c
@@ -202,16 +202,30 @@
 	 * Read in the header and see how big of a buffer we really need to 
 	 * allocate.
 	 */
-	ifname_num = (struct ifname_num *) kmalloc(sizeof(struct ifname_num), 
-			GFP_KERNEL);
-	copy_from_user( ifname_num, (char *) arg, sizeof(struct ifname_num));
+	ifname_num = kmalloc(sizeof(struct ifname_num), GFP_KERNEL);
+	if (!ifname_num)
+		return -ENOMEM;
+	if (copy_from_user(ifname_num, (char *)arg,
+			   sizeof(struct ifname_num))) {
+		kfree(ifname_num);
+		return -EFAULT;
+	}
 	size = ifname_num->size;
 	kfree(ifname_num);
-	ifname_num = (struct ifname_num *) kmalloc(size, GFP_KERNEL);
+	ifname_num = kmalloc(size, GFP_KERNEL);
+	if (!ifname_num)
+		return -ENOMEM;
 	ifname_MAC = (struct ifname_MAC *) ((char *)ifname_num + (sizeof(struct ifname_num)) );
 
-	copy_from_user( ifname_num, (char *) arg, size);
+	if (copy_from_user(ifname_num, (char *)arg, size)) {
+		kfree(ifname_num);
+		return -EFAULT;
+	}
 	new_devices =  kmalloc(size - sizeof(struct ifname_num), GFP_KERNEL);
+	if (!new_devices) {
+		kfree(ifname_num);
+		return -EFAULT;
+	}
 	temp_new_devices = new_devices;
 
 	memset(new_devices, 0, size - sizeof(struct ifname_num));
@@ -257,9 +271,9 @@
 	/*
 	 * Copy back to the User Buffer area any new devices encountered.
 	 */
-	copy_to_user((char *)arg + (sizeof(struct ifname_num)), new_devices, 
-			size - sizeof(struct ifname_num));
-
+	if (copy_to_user((char *)arg + (sizeof(struct ifname_num)),
+			 new_devices, size - sizeof(struct ifname_num)))
+		return -EFAULT;
 	return(0);
 
 }
arch/mips/kernel/sysirix.c +1 -4
diff -Nru a/arch/mips/kernel/sysirix.c b/arch/mips/kernel/sysirix.c
@@ -1048,10 +1048,7 @@
 
 asmlinkage int irix_gettimeofday(struct timeval *tv)
 {
-	int retval;
-
-	retval = copy_to_user(tv, &xtime, sizeof(*tv)) ? -EFAULT : 0;
-	return retval;
+	return copy_to_user(tv, &xtime, sizeof(*tv)) ? -EFAULT : 0;
 }
 
 #define IRIX_MAP_AUTOGROW 0x40
arch/ppc/iSeries/mf.c +5 -2
diff -Nru a/arch/ppc/iSeries/mf.c b/arch/ppc/iSeries/mf.c
@@ -950,7 +950,10 @@
 	return -ENOMEM;
     }
 
-    copy_from_user(page, buffer, size);
+    if (copy_from_user(page, buffer, size)) {
+	    rc = -EFAULT;
+	    goto out;
+    }
     memset(&myVspCmd, 0, sizeof(myVspCmd));
 
     myVspCmd.xCmd = 30;
@@ -973,7 +976,7 @@
 	    rc = -ENOMEM;
 	}
     }
-
+out:
     pci_free_consistent(NULL, size, page, dma_addr);
 
     return rc;
arch/ppc/kernel/ppc_htab.c +2 -1
diff -Nru a/arch/ppc/kernel/ppc_htab.c b/arch/ppc/kernel/ppc_htab.c
@@ -223,7 +223,8 @@
 		n = strlen(buffer) - *ppos;
 	if (n > count)
 		n = count;
-	copy_to_user(buf, buffer + *ppos, n);
+	if (copy_to_user(buf, buffer + *ppos, n))
+		return -EFAULT;
 	*ppos += n;
 	return n;
 }
arch/ppc64/kernel/rtasd.c +1 -3
diff -Nru a/arch/ppc64/kernel/rtasd.c b/arch/ppc64/kernel/rtasd.c
@@ -99,9 +99,7 @@
 	rtas_log_size -= 1;
 	spin_unlock(&rtas_log_lock);
 
-	copy_to_user(buf, tmp, count);
-	error = count;
-
+	error = copy_to_user(buf, tmp, count) ? -EFAULT : count;
 out:
 	kfree(tmp);
 	return error;
arch/sparc64/solaris/timod.c +9 -5
diff -Nru a/arch/sparc64/solaris/timod.c b/arch/sparc64/solaris/timod.c
@@ -820,14 +820,18 @@
 	if (error && ctl_maxlen > sizeof(udi) && sock->state == TS_IDLE) {
 		SOLD("generating udi");
 		udi.PRIM_type = T_UNITDATA_IND;
-		get_user(udi.SRC_length, ctl_len);
+		if (get_user(udi.SRC_length, ctl_len))
+			return -EFAULT;
 		udi.SRC_offset = sizeof(udi);
 		udi.OPT_length = udi.OPT_offset = 0;
-		copy_to_user(ctl_buf, &udi, sizeof(udi));
-		put_user(sizeof(udi)+udi.SRC_length, ctl_len);
+		if (copy_to_user(ctl_buf, &udi, sizeof(udi)) ||
+		    put_user(sizeof(udi)+udi.SRC_length, ctl_len))
+			return -EFAULT;
 		SOLD("udi done");
-	} else
-		put_user(0, ctl_len);
+	} else {
+		if (put_user(0, ctl_len))
+			return -EFAULT;
+	}
 	put_user(error, data_len);
 	SOLD("done");
 	return 0;
drivers/bluetooth/hci_vhci.c +6 -2
diff -Nru a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c
@@ -139,7 +139,10 @@
 	if (!(skb = bluez_skb_alloc(count, GFP_KERNEL)))
 		return -ENOMEM;
 	
-	copy_from_user(skb_put(skb, count), buf, count); 
+	if (copy_from_user(skb_put(skb, count), buf, count)) {
+		kfree_skb(skb);
+		return -EFAULT;
+	}
 
 	skb->dev = (void *) &hci_vhci->hdev;
 	skb->pkt_type = *((__u8 *) skb->data);
@@ -170,7 +173,8 @@
 	char *ptr = buf;
 
 	len = MIN(skb->len, len); 
-	copy_to_user(ptr, skb->data, len); 
+	if (copy_to_user(ptr, skb->data, len))
+		return -EFAULT;
 	total += len;
 
 	hci_vhci->hdev.stat.byte_tx += len;
drivers/cdrom/cdu31a.c +12 -11
diff -Nru a/drivers/cdrom/cdu31a.c b/drivers/cdrom/cdu31a.c
@@ -2619,13 +2619,14 @@
 						retval = -EIO;
 						goto exit_read_audio;
 					}
-				} else {
-					copy_to_user((char *) (ra->buf +
+				} else if (copy_to_user((char *)(ra->buf +
 							       (CD_FRAMESIZE_RAW
 								* cframe)),
-						     (char *)
-						     readahead_buffer,
-						     CD_FRAMESIZE_RAW);
+							(char *)
+							       readahead_buffer,
+							CD_FRAMESIZE_RAW)) {
+					retval = -EFAULT;
+					goto exit_read_audio;
 				}
 			} else {
 				printk
@@ -2635,12 +2636,12 @@
 				retval = -EIO;
 				goto exit_read_audio;
 			}
-		} else {
-			copy_to_user((char *) (ra->buf +
-					       (CD_FRAMESIZE_RAW *
-						cframe)),
-				     (char *) readahead_buffer,
-				     CD_FRAMESIZE_RAW);
+		} else if (copy_to_user((char *)(ra->buf + (CD_FRAMESIZE_RAW *
+							    cframe)),
+					(char *)readahead_buffer,
+					CD_FRAMESIZE_RAW)) {
+			retval = -EFAULT;
+			goto exit_read_audio;
 		}
 
 		cframe++;
drivers/cdrom/optcd.c +23 -45

149 lines not on this page · raw message

drivers/cdrom/sbpcd.c +7 -6
diff -Nru a/drivers/cdrom/sbpcd.c b/drivers/cdrom/sbpcd.c
@@ -4255,9 +4255,9 @@
 		if (D_S[d].has_data>1) RETURN_UP(-EBUSY);
 #endif /* SAFE_MIXED */ 
 		if (D_S[d].aud_buf==NULL) RETURN_UP(-EINVAL);
-		i=verify_area(VERIFY_READ, (void *) arg, sizeof(struct cdrom_read_audio));
-		if (i) RETURN_UP(i);
-		copy_from_user(&read_audio, (void *) arg, sizeof(struct cdrom_read_audio));
+		if (copy_from_user(&read_audio, (void *)arg,
+				   sizeof(struct cdrom_read_audio)))
+			RETURN_UP(-EFAULT);
 		if (read_audio.nframes < 0 || read_audio.nframes>D_S[d].sbp_audsiz) RETURN_UP(-EINVAL);
 		i=verify_area(VERIFY_WRITE, read_audio.buf,
 			      read_audio.nframes*CD_FRAMESIZE_RAW);
@@ -4454,9 +4454,10 @@
 				msg(DBG_AUD,"read_audio: cc_ReadError was necessary after read: %02X\n",i);
 				continue;
 			}
-			copy_to_user((u_char *) read_audio.buf,
-				    (u_char *) D_S[d].aud_buf,
-				    read_audio.nframes*CD_FRAMESIZE_RAW);
+			if (copy_to_user((u_char *)read_audio.buf,
+					 (u_char *) D_S[d].aud_buf,
+					 read_audio.nframes * CD_FRAMESIZE_RAW))
+				RETURN_UP(-EFAULT);
 			msg(DBG_AUD,"read_audio: copy_to_user done.\n");
 			break;
 		}
drivers/cdrom/sjcd.c +19 -28

86 lines not on this page · raw message

drivers/cdrom/sonycd535.c +16 -26

94 lines not on this page · raw message

drivers/char/drm/i810_dma.c +2 -1
diff -Nru a/drivers/char/drm/i810_dma.c b/drivers/char/drm/i810_dma.c
@@ -1209,7 +1209,8 @@
 
 	data.offset = dev_priv->overlay_offset;
 	data.physical = dev_priv->overlay_physical;
-	copy_to_user((drm_i810_overlay_t *)arg,&data,sizeof(data));
+	if (copy_to_user((drm_i810_overlay_t *)arg,&data,sizeof(data)))
+		return -EFAULT;
 	return 0;
 }
 
#1 lore raw

In message <[email protected]> you write:

Quoted 5 lines

Linus, some more, please consider pulling from:

http://kernel-acme.bkbits.net:8080/copy_to_from_user-2.5

I stopped this (re)audit when 544 were still to be reviewed. Bedtime 8)

Heh... Was this on 2.5.20? If so, you're fast 8)

I didn't bother to check for anything other than "I use the return value in a non-binary way": that's enough to keep me busy and frustrated.

Not checking at all can keep code much simpler sometimes, too. (And more codepaths, more bugs.)

Rusty.
--
Anyone who quotes me in their sig is an idiot. -- Rusty Russell.

#2 lore raw
In reply to Arnaldo Carvalho de Melo

Em Mon, Jun 03, 2002 at 06:07:09PM +1000, Rusty Russell escreveu:

Quoted 8 lines

In message <[email protected]> you write:

Quoted 5 lines

Linus, some more, please consider pulling from:

http://kernel-acme.bkbits.net:8080/copy_to_from_user-2.5

I stopped this (re)audit when 544 were still to be reviewed. Bedtime 8)

Heh... Was this on 2.5.20? If so, you're fast 8)

yes 8)

Quoted 6 lines

I didn't bother to check for anything other than "I use the return value in a non-binary way": that's enough to keep me busy and frustrated.

Not checking at all can keep code much simpler sometimes, too. (And more codepaths, more bugs.)

humm, but if it can fail...

- Arnaldo