From: Andi Kleen While doing some compat_ioctl conversions I noticed a few issues in compat_sys_ioctl: - It is not completely compatible to old ->ioctl because the traditional common ioctls are not checked before it. I added a check for those. The main advantage is that the handler now works the same as a traditional handler even when it returns -EINVAL - The private socket ioctl check should only apply for sockets. - There was a security hook missing. Drawback is that it uses the same hook now, and the LSM module cannot distingush between 32bit and 64bit clients. But it'll have to live with that for now. Signed-off-by: Andi Kleen Signed-off-by: Andrew Morton --- 25-akpm/fs/compat.c | 51 ++++++++++++++++++++++++++++++++++++++++++--------- 25-akpm/fs/ioctl.c | 4 ++++ 2 files changed, 46 insertions(+), 9 deletions(-) diff -puN fs/compat.c~some-fixes-for-compat-ioctl fs/compat.c --- 25/fs/compat.c~some-fixes-for-compat-ioctl Tue Jan 18 15:40:13 2005 +++ 25-akpm/fs/compat.c Tue Jan 18 15:40:13 2005 @@ -25,6 +25,7 @@ #include #include #include +#include #include #include /* for SIOCDEVPRIVATE */ #include @@ -47,6 +48,7 @@ #include #include +#include /* * Not all architectures have sys_utime, so implement this in terms @@ -437,16 +439,41 @@ asmlinkage long compat_sys_ioctl(unsigne if (!filp) goto out; - if (filp->f_op && filp->f_op->compat_ioctl) { - error = filp->f_op->compat_ioctl(filp, cmd, arg); - if (error != -ENOIOCTLCMD) - goto out_fput; - } + /* + * To allow the compat_ioctl handlers to be self contained + * we need to check the common ioctls here first. + * Just handle them with the standard handlers below. + */ + switch (cmd) { + case FIOCLEX: + case FIONCLEX: + case FIONBIO: + case FIOASYNC: + case FIOQSIZE: + break; + + case FIBMAP: + case FIGETBSZ: + case FIONREAD: + if (S_ISREG(filp->f_dentry->d_inode->i_mode)) + break; + /*FALL THROUGH*/ + + default: + if (filp->f_op && filp->f_op->compat_ioctl) { + error = filp->f_op->compat_ioctl(filp, cmd, arg); + if (error != -ENOIOCTLCMD) + goto out_fput; + } - if (!filp->f_op || - (!filp->f_op->ioctl && !filp->f_op->unlocked_ioctl)) - goto do_ioctl; + if (!filp->f_op || + (!filp->f_op->ioctl && !filp->f_op->unlocked_ioctl)) + goto do_ioctl; + break; + } + /* When register_ioctl32_conversion is finally gone remove + this lock! -AK */ down_read(&ioctl32_sem); for (t = ioctl32_hash_table[ioctl32_hash(cmd)]; t; t = t->next) { if (t->cmd == cmd) @@ -454,7 +481,8 @@ asmlinkage long compat_sys_ioctl(unsigne } up_read(&ioctl32_sem); - if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) { + if (S_ISSOCK(filp->f_dentry->d_inode->i_mode) && + cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) { error = siocdevprivate_ioctl(fd, cmd, arg); } else { static int count; @@ -468,6 +496,11 @@ asmlinkage long compat_sys_ioctl(unsigne found_handler: if (t->handler) { + /* RED-PEN how should LSM module know it's handling 32bit? */ + error = security_file_ioctl(filp, cmd, arg); + if (error) + goto out_fput; + lock_kernel(); error = t->handler(fd, cmd, arg, filp); unlock_kernel(); diff -puN fs/ioctl.c~some-fixes-for-compat-ioctl fs/ioctl.c --- 25/fs/ioctl.c~some-fixes-for-compat-ioctl Tue Jan 18 15:40:13 2005 +++ 25-akpm/fs/ioctl.c Tue Jan 18 15:40:13 2005 @@ -78,6 +78,10 @@ static int file_ioctl(struct file *filp, } +/* + * When you add any new common ioctls to the switches above and below + * please update compat_sys_ioctl() too. + */ asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) { struct file * filp; _