patch-2.4.25 linux-2.4.25/arch/ppc64/kernel/ioctl32.c

Next file: linux-2.4.25/arch/ppc64/kernel/irq.c
Previous file: linux-2.4.25/arch/ppc64/kernel/idle.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.24/arch/ppc64/kernel/ioctl32.c linux-2.4.25/arch/ppc64/kernel/ioctl32.c
@@ -566,11 +566,52 @@
 		goto out;
 	}
 	switch (ethcmd) {
-	case ETHTOOL_GDRVINFO:	len = sizeof(struct ethtool_drvinfo); break;
+	case ETHTOOL_GSTRINGS:	{
+		struct ethtool_gstrings *stringsaddr = (struct ethtool_gstrings *)A(data);
+		if (get_user(len, (u32 *)&stringsaddr->len)) {
+			err = -EFAULT;
+			goto out;
+		}
+		if (len > (PAGE_SIZE - sizeof(struct ethtool_gstrings))/ETH_GSTRING_LEN ) {
+			err = -EINVAL;
+			goto out;
+		}
+		len = (len*ETH_GSTRING_LEN) + sizeof(struct ethtool_gstrings);
+		break;
+	}
+	case ETHTOOL_GSTATS:	{
+		struct ethtool_stats *statsaddr = (struct ethtool_stats *)A(data);
+		if (get_user(len, (u32 *)&statsaddr->n_stats)) {
+			err = -EFAULT;
+			goto out;
+		}
+		if (len > (PAGE_SIZE - sizeof(struct ethtool_stats))/sizeof(u64) ) {
+			err = -EINVAL;
+			goto out;
+		}
+		len = (len*sizeof(u64)) + sizeof(struct ethtool_stats);
+		break;
+	}
+	case ETHTOOL_SWOL:
+	case ETHTOOL_GWOL:
+		len = sizeof(struct ethtool_wolinfo);
+		break;
+	case ETHTOOL_GDRVINFO:
+		len = sizeof(struct ethtool_drvinfo);
+		break;
 	case ETHTOOL_GMSGLVL:
 	case ETHTOOL_SMSGLVL:
 	case ETHTOOL_GLINK:
-	case ETHTOOL_NWAY_RST:	len = sizeof(struct ethtool_value); break;
+	case ETHTOOL_NWAY_RST:
+	case ETHTOOL_SSG:
+	case ETHTOOL_GSG:
+	case ETHTOOL_GTXCSUM:
+	case ETHTOOL_STXCSUM:
+	case ETHTOOL_GRXCSUM:
+	case ETHTOOL_SRXCSUM:
+	case ETHTOOL_PHYS_ID:
+		len = sizeof(struct ethtool_value);
+		break;
 	case ETHTOOL_GREGS: {
 		struct ethtool_regs *regaddr = (struct ethtool_regs *)A(data);
 		/* darned variable size arguments */
@@ -578,22 +619,44 @@
 			err = -EFAULT;
 			goto out;
 		}
+		if (len > PAGE_SIZE - sizeof(struct ethtool_regs)) {
+			err = -EINVAL;
+			goto out;
+		}
 		len += sizeof(struct ethtool_regs);
 		break;
 	}
-	case ETHTOOL_GEEPROM: 
-	case ETHTOOL_SEEPROM: { 
-		struct ethtool_eeprom *promaddr = (struct ethtool_eeprom *)A(data); 
-		/* darned variable size arguments */ 
-		if (get_user(len, (u32 *)&promaddr->len)) { 
-			err = -EFAULT; 
-			goto out; 
-		} 
-		len += sizeof(struct ethtool_eeprom); 
-		break; 
-	} 
+	case ETHTOOL_GEEPROM:
+	case ETHTOOL_SEEPROM: {
+		struct ethtool_eeprom *promaddr = (struct ethtool_eeprom *)A(data);
+		/* darned variable size arguments */
+		if (get_user(len, (u32 *)&promaddr->len)) {
+			err = -EFAULT;
+			goto out;
+		}
+		if (len > PAGE_SIZE - sizeof(struct ethtool_eeprom)) {
+			err = -EINVAL;
+			goto out;
+		}
+		len += sizeof(struct ethtool_eeprom);
+		break;
+	}
+	case ETHTOOL_GRINGPARAM:
+	case ETHTOOL_SRINGPARAM:
+		len = sizeof(struct ethtool_ringparam);
+		break;
+	case ETHTOOL_GPAUSEPARAM:
+	case ETHTOOL_SPAUSEPARAM:
+		len = sizeof(struct ethtool_pauseparam);
+		break;
+	case ETHTOOL_GCOALESCE:
+	case ETHTOOL_SCOALESCE:
+		len = sizeof(struct ethtool_coalesce);
+		break;
 	case ETHTOOL_GSET:
-	case ETHTOOL_SSET:	len = sizeof(struct ethtool_cmd); break;
+	case ETHTOOL_SSET:
+		len = sizeof(struct ethtool_cmd);
+		break;
 	default:
 		err = -EOPNOTSUPP;
 		goto out;
@@ -1238,12 +1301,16 @@
 	u32 iov_len;
 } sg_iovec32_t;
 
+#define EMU_SG_MAX 128
+
 static int alloc_sg_iovec(sg_io_hdr_t *sgp, u32 uptr32)
 {
 	sg_iovec32_t *uiov = (sg_iovec32_t *) A(uptr32);
 	sg_iovec_t *kiov;
 	int i;
 
+	if (sgp->iovec_count > EMU_SG_MAX)
+		return -EINVAL;
 	sgp->dxferp = kmalloc(sgp->iovec_count *
 			      sizeof(sg_iovec_t), GFP_KERNEL);
 	if (!sgp->dxferp)
@@ -1257,39 +1324,9 @@
 		if (__get_user(iov_base32, &uiov->iov_base) ||
 		    __get_user(kiov->iov_len, &uiov->iov_len))
 			return -EFAULT;
-
-		kiov->iov_base = kmalloc(kiov->iov_len, GFP_KERNEL);
-		if (!kiov->iov_base)
-			return -ENOMEM;
-		if (copy_from_user(kiov->iov_base,
-				   (void *) A(iov_base32),
-				   kiov->iov_len))
+		if (verify_area(VERIFY_WRITE, (void *)A(iov_base32), kiov->iov_len))
 			return -EFAULT;
-
-		uiov++;
-		kiov++;
-	}
-
-	return 0;
-}
-
-static int copy_back_sg_iovec(sg_io_hdr_t *sgp, u32 uptr32)
-{
-	sg_iovec32_t *uiov = (sg_iovec32_t *) A(uptr32);
-	sg_iovec_t *kiov = (sg_iovec_t *) sgp->dxferp;
-	int i;
-
-	for (i = 0; i < sgp->iovec_count; i++) {
-		u32 iov_base32;
-
-		if (__get_user(iov_base32, &uiov->iov_base))
-			return -EFAULT;
-
-		if (copy_to_user((void *) A(iov_base32),
-				 kiov->iov_base,
-				 kiov->iov_len))
-			return -EFAULT;
-
+		kiov->iov_base = (void *)A(iov_base32);
 		uiov++;
 		kiov++;
 	}
@@ -1299,16 +1336,6 @@
 
 static void free_sg_iovec(sg_io_hdr_t *sgp)
 {
-	sg_iovec_t *kiov = (sg_iovec_t *) sgp->dxferp;
-	int i;
-
-	for (i = 0; i < sgp->iovec_count; i++) {
-		if (kiov->iov_base) {
-			kfree(kiov->iov_base);
-			kiov->iov_base = NULL;
-		}
-		kiov++;
-	}
 	kfree(sgp->dxferp);
 	sgp->dxferp = NULL;
 }
@@ -1337,6 +1364,10 @@
 	sg_io64.sbp = NULL;
 
 	err |= __get_user(cmdp32, &sg_io32->cmdp);
+	if (sg_io64.cmd_len > 4*PAGE_SIZE || sg_io64.mx_sb_len > 4*PAGE_SIZE) {
+		err = -EINVAL;
+		goto out;
+	}
 	sg_io64.cmdp = kmalloc(sg_io64.cmd_len, GFP_KERNEL);
 	if (!sg_io64.cmdp) {
 		err = -ENOMEM;
@@ -1371,6 +1402,10 @@
 			goto out;
 		}
 	} else {
+		if (sg_io64.dxfer_len > 4*PAGE_SIZE) {
+			err = -EINVAL;
+			goto out;
+		}
 		sg_io64.dxferp = kmalloc(sg_io64.dxfer_len, GFP_KERNEL);
 		if (!sg_io64.dxferp) {
 			err = -ENOMEM;
@@ -1411,7 +1446,7 @@
 	err |= copy_to_user((void *)A(sbp32), sg_io64.sbp, sg_io64.mx_sb_len);
 	if (sg_io64.dxferp) {
 		if (sg_io64.iovec_count)
-			err |= copy_back_sg_iovec(&sg_io64, dxferp32);
+			;
 		else
 			err |= copy_to_user((void *)A(dxferp32),
 					    sg_io64.dxferp,
@@ -1467,6 +1502,8 @@
 	case PPPIOCSCOMPRESS32:
 		if (copy_from_user(&data32, (struct ppp_option_data32 *)arg, sizeof(struct ppp_option_data32)))
 			return -EFAULT;
+		if (data32.length > PAGE_SIZE)
+			return -EINVAL;
 		data.ptr = kmalloc (data32.length, GFP_KERNEL);
 		if (!data.ptr)
 			return -ENOMEM;
@@ -1669,10 +1706,9 @@
 		err |= __get_user(addr, &((struct cdrom_read_audio32 *)arg)->buf);
 		if (err)
 			return -EFAULT;
-		data = kmalloc(cdreadaudio.nframes * 2352, GFP_KERNEL);
-		if (!data)
-			return -ENOMEM;
-		cdreadaudio.buf = data;
+		if (verify_area(VERIFY_WRITE, (void *)A(addr), cdreadaudio.nframes*2352))
+			return -EFAULT;
+		cdreadaudio.buf = (void *)A(addr);
 		break;
 	case CDROM_SEND_PACKET:
 		karg = &cgc;
@@ -1681,9 +1717,9 @@
 		err |= __get_user(cgc.buflen, &((struct cdrom_generic_command32 *)arg)->buflen);
 		if (err)
 			return -EFAULT;
-		if ((data = kmalloc(cgc.buflen, GFP_KERNEL)) == NULL)
-			return -ENOMEM;
-		cgc.buffer = data;
+		if (verify_area(VERIFY_WRITE, (void *)A(addr), cgc.buflen))
+			return -EFAULT;
+		cgc.buffer = (void *)A(addr);
 		break;
 	default:
 		do {
@@ -1698,18 +1734,6 @@
 	set_fs (KERNEL_DS);
 	err = sys_ioctl (fd, cmd, (unsigned long)karg);
 	set_fs (old_fs);
-	if (err)
-		goto out;
-	switch (cmd) {
-	case CDROMREADAUDIO:
-		err = copy_to_user((char *)A(addr), data, cdreadaudio.nframes * 2352);
-		break;
-	case CDROM_SEND_PACKET:
-		err = copy_to_user((char *)A(addr), data, cgc.buflen);
-		break;
-	default:
-		break;
-	}
 out:	if (data)
 		kfree(data);
 	return err ? -EFAULT : 0;
@@ -2126,37 +2150,16 @@
 	if (iobuf32.buffer == (__kernel_caddr_t32) NULL || iobuf32.length == 0) {
 		iobuf.buffer = (void*)(unsigned long)iobuf32.buffer;
 	} else {
-		iobuf.buffer = kmalloc(iobuf.length, GFP_KERNEL);
-		if (iobuf.buffer == NULL) {
-			err = -ENOMEM;
-			goto out;
-		}
-
-		err = copy_from_user(iobuf.buffer, (void *)A(iobuf32.buffer), iobuf.length);
-		if (err) {
-			err = -EFAULT;
-			goto out;
-		}
+		iobuf.buffer = A(iobuf32.buffer);
+		if (verify_area(VERIFY_WRITE, iobuf.buffer, iobuf.length))
+			return -EINVAL;
 	}
 
 	old_fs = get_fs(); set_fs (KERNEL_DS);
-	err = sys_ioctl (fd, cmd, (unsigned long)&iobuf);      
+	err = sys_ioctl (fd, cmd, (unsigned long)&iobuf);
 	set_fs (old_fs);
-        if (err)
-		goto out;
-
-        if (iobuf.buffer && iobuf.length > 0) {
-		err = copy_to_user((void *)A(iobuf32.buffer), iobuf.buffer, iobuf.length);
-		if (err) {
-			err = -EFAULT;
-			goto out;
-		}
-	}
-	err = __put_user(iobuf.length, &(((struct atm_iobuf32*)arg)->length));
-
- out:
-        if (iobuf32.buffer && iobuf32.length > 0)
-		kfree(iobuf.buffer);
+	if (!err)
+		err = __put_user(iobuf.length, &(((struct atm_iobuf32*)arg)->length));
 
 	return err;
 }
@@ -2179,40 +2182,19 @@
         
 	if (sioc32.arg == (__kernel_caddr_t32) NULL || sioc32.length == 0) {
 		sioc.arg = (void*)(unsigned long)sioc32.arg;
-        } else {
-                sioc.arg = kmalloc(sioc.length, GFP_KERNEL);
-                if (sioc.arg == NULL) {
-                        err = -ENOMEM;
-			goto out;
-		}
-                
-                err = copy_from_user(sioc.arg, (void *)A(sioc32.arg), sioc32.length);
-                if (err) {
-                        err = -EFAULT;
-                        goto out;
-                }
-        }
-        
-        old_fs = get_fs(); set_fs (KERNEL_DS);
-        err = sys_ioctl (fd, cmd, (unsigned long)&sioc);	
-        set_fs (old_fs);
-        if (err) {
-                goto out;
+	} else {
+		sioc.arg = A(sioc32.arg);
+		if (verify_area(VERIFY_WRITE, sioc.arg, sioc32.length))
+			return -EFAULT;
 	}
-        
-        if (sioc.arg && sioc.length > 0) {
-                err = copy_to_user((void *)A(sioc32.arg), sioc.arg, sioc.length);
-                if (err) {
-                        err = -EFAULT;
-                        goto out;
-                }
-        }
-        err = __put_user(sioc.length, &(((struct atmif_sioc32*)arg)->length));
-        
- out:
-        if (sioc32.arg && sioc32.length > 0)
-		kfree(sioc.arg);
-        
+
+	old_fs = get_fs(); set_fs (KERNEL_DS);
+	err = sys_ioctl (fd, cmd, (unsigned long)&sioc);
+	set_fs (old_fs);
+
+	if (!err)
+		err = __put_user(sioc.length, &(((struct atmif_sioc32*)arg)->length));
+
 	return err;
 }
 
@@ -2428,12 +2410,24 @@
 		return NULL;
 	}
 	if (ptr1) {
+		if (l->lv_allocated_le > 2*PAGE_SIZE/sizeof(pe_t)) {
+			kfree(l);
+			*errp = -EINVAL;
+			return NULL;
+		}
 		size = l->lv_allocated_le * sizeof(pe_t);
 		l->lv_current_pe = vmalloc(size);
 		if (l->lv_current_pe)
 			err = copy_from_user(l->lv_current_pe, (void *)A(ptr1), size);
 	}
 	if (!err && ptr2) {
+		/* small limit */
+		/* just verify area it? */
+		if (l->lv_remap_end > 256*PAGE_SIZE/sizeof(lv_block_exception_t)) {
+			put_lv_t(l);
+			*errp = -EINVAL;
+			return NULL;
+		}
 		size = l->lv_remap_end * sizeof(lv_block_exception_t);
 		l->lv_block_exception = lbe = vmalloc(size);
 		if (l->lv_block_exception) {
@@ -3597,17 +3591,11 @@
 		goto out;
 	uptr = (void *) A(udata);
 
-	err = -ENOMEM;
 	buflen = kurb->buffer_length;
-	kptr = kmalloc(buflen, GFP_KERNEL);
-	if (!kptr)
-		goto out;
-
-	kurb->buffer = kptr;
 
-	err = -EFAULT;
-	if (copy_from_user(kptr, uptr, buflen))
-		goto out_kptr;
+	err = verify_area(VERIFY_WRITE, uptr, buflen);
+	if (err)
+		goto out;
 
 	old_fs = get_fs();
 	set_fs(KERNEL_DS);
@@ -3618,15 +3606,9 @@
 		/* XXX Shit, this doesn't work for async URBs :-( XXX */
 		if (put_urb32(kurb, uurb)) {
 			err = -EFAULT;
-		} else if ((kurb->endpoint & USB_DIR_IN) != 0) {
-			if (copy_to_user(uptr, kptr, buflen))
-				err = -EFAULT;
 		}
 	}
 
-out_kptr:
-	kfree(kptr);
-
 out:
 	kfree(kurb);
 	return err;
@@ -3698,14 +3680,13 @@
 #define MEMWRITEOOB32 	_IOWR('M',3,struct mtd_oob_buf32)
 #define MEMREADOOB32 	_IOWR('M',4,struct mtd_oob_buf32)
 
-static inline int 
+static inline int
 mtd_rw_oob(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
 	mm_segment_t 			old_fs 	= get_fs();
 	struct mtd_oob_buf32	*uarg 	= (struct mtd_oob_buf32 *)arg;
 	struct mtd_oob_buf		karg;
 	u32 tmp;
-	char *ptr;
 	int ret;
 
 	if (get_user(karg.start, &uarg->start) 		||
@@ -3713,21 +3694,12 @@
 	    get_user(tmp, &uarg->ptr))
 		return -EFAULT;
 
-	ptr = (char *)A(tmp);
-	if (0 >= karg.length) 
-		return -EINVAL;
-
-	karg.ptr = kmalloc(karg.length, GFP_KERNEL);
-	if (NULL == karg.ptr)
-		return -ENOMEM;
-
-	if (copy_from_user(karg.ptr, ptr, karg.length)) {
-		kfree(karg.ptr);
+	karg.ptr = A(tmp);
+	if (verify_area(VERIFY_WRITE, karg.ptr, karg.length))
 		return -EFAULT;
-	}
 
 	set_fs(KERNEL_DS);
-	if (MEMREADOOB32 == cmd) 
+	if (MEMREADOOB32 == cmd)
 		ret = sys_ioctl(fd, MEMREADOOB, (unsigned long)&karg);
 	else if (MEMWRITEOOB32 == cmd)
 		ret = sys_ioctl(fd, MEMWRITEOOB, (unsigned long)&karg);
@@ -3736,14 +3708,12 @@
 	set_fs(old_fs);
 
 	if (0 == ret && cmd == MEMREADOOB32) {
-		ret = copy_to_user(ptr, karg.ptr, karg.length);
-		ret |= put_user(karg.start, &uarg->start);
+		ret = put_user(karg.start, &uarg->start);
 		ret |= put_user(karg.length, &uarg->length);
 	}
 
-	kfree(karg.ptr);
-	return ((0 == ret) ? 0 : -EFAULT);
-}	
+	return ret;
+}
 
 /* Fix sizeof(sizeof()) breakage */
 #define BLKELVGET_32	_IOR(0x12,106,int)
@@ -3801,6 +3771,7 @@
 COMPATIBLE_IOCTL(TCSETAW),
 COMPATIBLE_IOCTL(TCSETAF),
 COMPATIBLE_IOCTL(TCSBRK),
+COMPATIBLE_IOCTL(TCSBRKP),
 COMPATIBLE_IOCTL(TCXONC),
 COMPATIBLE_IOCTL(TCFLSH),
 COMPATIBLE_IOCTL(TCGETS),
@@ -3836,6 +3807,8 @@
 COMPATIBLE_IOCTL(TIOCSSERIAL),
 COMPATIBLE_IOCTL(TIOCSERGETLSR),
 COMPATIBLE_IOCTL(TIOCSLTC),
+COMPATIBLE_IOCTL(TIOCMIWAIT),
+COMPATIBLE_IOCTL(TIOCGICOUNT),
 /* Big F */
 COMPATIBLE_IOCTL(FBIOGET_VSCREENINFO),
 COMPATIBLE_IOCTL(FBIOPUT_VSCREENINFO),

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)