From: Vincenzo Frascino vincenzo.frascino@arm.com
With the introduction of capabilities, the PCuABI expects a capability when dealing with the user pointers.
When the TUN driver is enabled in a PCuABI compatible kernel, the compiler reports the error below:
drivers/net/tun.c:3502:20: error: incompatible function pointer types initializing 'long (*)(struct file *, unsigned int, user_uintptr_t)' (aka 'long (*)(struct file *, unsigned int, unsigned __intcap)') with an expression of type 'long (struct file *, unsigned int, unsigned long)' [-Werror,-Wincompatible-function-pointer-types] .unlocked_ioctl = tun_chr_ioctl, ^~~~~~~~~~~~~ 1 error generated.
Address the issue using the proper type to represent user pointers (user_uintptr_t). Also make sure to always create a valid user pointer in tun_chr_compat_ioctl() by using compat_ptr(); this was only done for a small and very incomplete list of requests that expect a pointer.
Tested-by: David Horton david.horton@cyberhive.com Signed-off-by: Vincenzo Frascino vincenzo.frascino@arm.com Co-developed-by: Kevin Brodsky kevin.brodsky@arm.com Signed-off-by: Kevin Brodsky kevin.brodsky@arm.com --- drivers/net/tun.c | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-)
diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 24001112c323..63242f93704c 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -3042,7 +3042,7 @@ static unsigned char tun_get_addr_len(unsigned short type) }
static long __tun_chr_ioctl(struct file *file, unsigned int cmd, - unsigned long arg, int ifreq_len) + user_uintptr_t arg, int ifreq_len) { struct tun_file *tfile = file->private_data; struct net *net = sock_net(&tfile->sk); @@ -3373,7 +3373,7 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd, }
static long tun_chr_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) + unsigned int cmd, user_uintptr_t arg) { return __tun_chr_ioctl(file, cmd, arg, sizeof (struct ifreq)); } @@ -3382,28 +3382,14 @@ static long tun_chr_ioctl(struct file *file, static long tun_chr_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - switch (cmd) { - case TUNSETIFF: - case TUNGETIFF: - case TUNSETTXFILTER: - case TUNGETSNDBUF: - case TUNSETSNDBUF: - case SIOCGIFHWADDR: - case SIOCSIFHWADDR: - arg = (unsigned long)compat_ptr(arg); - break; - default: - arg = (compat_ulong_t)arg; - break; - } - /* * compat_ifreq is shorter than ifreq, so we must not access beyond * the end of that structure. All fields that are used in this * driver are compatible though, we don't need to convert the * contents. */ - return __tun_chr_ioctl(file, cmd, arg, sizeof(struct compat_ifreq)); + return __tun_chr_ioctl(file, cmd, (user_uintptr_t)compat_ptr(arg), + sizeof(struct compat_ifreq)); } #endif /* CONFIG_COMPAT */