ioctl32 fix for bond_ioctl
PATCH 1/1 ioctl32 fix for bond_ioctl
Problem: These four ioctls use ifreq32.ifr_ifru.ifru_data.
case SIOCBONDENSLAVE:
case SIOCBONDRELEASE:
case SIOCBONDSETHWADDR:
case SIOCBONDCHANGEACTIVE:
Whereas these use ifreq32.ifr_ifru.ifru_slave:
case SIOCBONDSLAVEINFOQUERY:
case SIOCBONDINFOQUERY:
The current code assumes ifru_data for all 6 ioctls. This fails with EFAULT for the last two. The attached patch fixes the problem and has been tested on ia64.
-Arun
fs/compat_ioctl.c +26 -35
@@ -576,54 +576,45 @@static int bond_ioctl (unsigned long fd,unsigned int cmd,unsigned long arg) { -struct ifreq ifr; +struct ifreq kifr; +struct ifreq *uifr; +struct ifreq32 *ifr32 = (struct ifreq32 *) arg;mm_segment_t old_fs; -int err, len; +int err;u32 data; - -if (copy_from_user (&ifr, (struct ifreq32 *)arg,sizeof (struct ifreq32 ))) -return -EFAULT ; - ifr.ifr_data = (__kernel_caddr_t )get_zeroed_page (GFP_KERNEL ); -if (!ifr.ifr_data) -return -EAGAIN ; +void *datap;switch (cmd) {case SIOCBONDENSLAVE :case SIOCBONDRELEASE :case SIOCBONDSETHWADDR :case SIOCBONDCHANGEACTIVE : - len =IFNAMSIZ *sizeof (char ); -break ; +if (copy_from_user (&kifr, ifr32,sizeof (struct ifreq32 ))) +return -EFAULT ; + + old_fs =get_fs (); +set_fs (KERNEL_DS ); + err =sys_ioctl (fd, cmd, (unsigned long )&kifr); +set_fs (old_fs); + +return err;case SIOCBONDSLAVEINFOQUERY : - len =sizeof (struct ifslave ); -break ;case SIOCBONDINFOQUERY : - len =sizeof (struct ifbond ); -break ; -default : - err = -EINVAL ; - goto out; - }; + uifr =compat_alloc_user_space (sizeof (*uifr)); +if (copy_in_user (&uifr->ifr_name, &ifr32->ifr_name,IFNAMSIZ )) +return -EFAULT ; -__get_user (data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data)); -if (copy_from_user (ifr.ifr_data,compat_ptr (data), len)) { - err = -EFAULT ; - goto out; - } +if (get_user (data, &ifr32->ifr_ifru.ifru_data)) +return -EFAULT ; - old_fs =get_fs (); -set_fs (KERNEL_DS ); - err =sys_ioctl (fd, cmd, (unsigned long )&ifr); -set_fs (old_fs); -if (!err) { - len =copy_to_user (compat_ptr (data), ifr.ifr_data, len); -if (len) - err = -EFAULT ; - } + datap =compat_ptr (data); +if (put_user (datap, &uifr->ifr_ifru.ifru_data)) +return -EFAULT ; -out: -free_page ((unsigned long )ifr.ifr_data); -return err; +return sys_ioctl (fd, cmd, (unsigned long )uifr); +default : +return -EINVAL ; + }; }int siocdevprivate_ioctl (unsigned int fd,unsigned int cmd,unsigned long arg)