Commit 17c7e7f4 authored by Arnd Bergmann's avatar Arnd Bergmann

compat_ioctl: handle PPPIOCGIDLE for 64-bit time_t

The ppp_idle structure is defined in terms of __kernel_time_t, which is
defined as 'long' on all architectures, and this usage is not affected
by the y2038 problem since it transports a time interval rather than an
absolute time.

However, the ppp user space defines the same structure as time_t, which
may be 64-bit wide on new libc versions even on 32-bit architectures.

It's easy enough to just handle both possible structure layouts on
all architectures, to deal with the possibility that a user space ppp
implementation comes with its own ppp_idle structure definition, as well
as to document the fact that the driver is y2038-safe.

Doing this also avoids the need for a special compat mode translation,
since 32-bit and 64-bit kernels now support the same interfaces.  The old
32-bit structure is also available on native 64-bit architectures now,
but this is harmless.

Cc: netdev@vger.kernel.org
Cc: linux-ppp@vger.kernel.org
Cc: Paul Mackerras <paulus@samba.org>
Cc: "David S. Miller" <davem@davemloft.net>
Signed-off-by: default avatarArnd Bergmann <arnd@arndb.de>
parent 5b6c02df
...@@ -378,6 +378,8 @@ an interface unit are: ...@@ -378,6 +378,8 @@ an interface unit are:
CONFIG_PPP_FILTER option is enabled, the set of packets which reset CONFIG_PPP_FILTER option is enabled, the set of packets which reset
the transmit and receive idle timers is restricted to those which the transmit and receive idle timers is restricted to those which
pass the `active' packet filter. pass the `active' packet filter.
Two versions of this command exist, to deal with user space
expecting times as either 32-bit or 64-bit time_t seconds.
* PPPIOCSMAXCID sets the maximum connection-ID parameter (and thus the * PPPIOCSMAXCID sets the maximum connection-ID parameter (and thus the
number of connection slots) for the TCP header compressor and number of connection slots) for the TCP header compressor and
......
...@@ -612,7 +612,8 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ...@@ -612,7 +612,8 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
struct ppp_file *pf; struct ppp_file *pf;
struct ppp *ppp; struct ppp *ppp;
int err = -EFAULT, val, val2, i; int err = -EFAULT, val, val2, i;
struct ppp_idle idle; struct ppp_idle32 idle32;
struct ppp_idle64 idle64;
struct npioctl npi; struct npioctl npi;
int unit, cflags; int unit, cflags;
struct slcompress *vj; struct slcompress *vj;
...@@ -735,10 +736,18 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ...@@ -735,10 +736,18 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
err = 0; err = 0;
break; break;
case PPPIOCGIDLE: case PPPIOCGIDLE32:
idle.xmit_idle = (jiffies - ppp->last_xmit) / HZ; idle32.xmit_idle = (jiffies - ppp->last_xmit) / HZ;
idle.recv_idle = (jiffies - ppp->last_recv) / HZ; idle32.recv_idle = (jiffies - ppp->last_recv) / HZ;
if (copy_to_user(argp, &idle, sizeof(idle))) if (copy_to_user(argp, &idle32, sizeof(idle32)))
break;
err = 0;
break;
case PPPIOCGIDLE64:
idle64.xmit_idle = (jiffies - ppp->last_xmit) / HZ;
idle64.recv_idle = (jiffies - ppp->last_recv) / HZ;
if (copy_to_user(argp, &idle64, sizeof(idle64)))
break; break;
err = 0; err = 0;
break; break;
......
...@@ -52,6 +52,7 @@ ...@@ -52,6 +52,7 @@
#include <linux/sort.h> #include <linux/sort.h>
#ifdef CONFIG_BLOCK
static int do_ioctl(struct file *file, unsigned int cmd, unsigned long arg) static int do_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{ {
int err; int err;
...@@ -63,7 +64,6 @@ static int do_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ...@@ -63,7 +64,6 @@ static int do_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
return vfs_ioctl(file, cmd, arg); return vfs_ioctl(file, cmd, arg);
} }
#ifdef CONFIG_BLOCK
struct compat_sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */ struct compat_sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */
char req_state; char req_state;
char orphan; char orphan;
...@@ -99,33 +99,6 @@ static int sg_grt_trans(struct file *file, ...@@ -99,33 +99,6 @@ static int sg_grt_trans(struct file *file,
} }
#endif /* CONFIG_BLOCK */ #endif /* CONFIG_BLOCK */
struct ppp_idle32 {
compat_time_t xmit_idle;
compat_time_t recv_idle;
};
#define PPPIOCGIDLE32 _IOR('t', 63, struct ppp_idle32)
static int ppp_gidle(struct file *file, unsigned int cmd,
struct ppp_idle32 __user *idle32)
{
struct ppp_idle __user *idle;
__kernel_time_t xmit, recv;
int err;
idle = compat_alloc_user_space(sizeof(*idle));
err = do_ioctl(file, PPPIOCGIDLE, (unsigned long) idle);
if (!err) {
if (get_user(xmit, &idle->xmit_idle) ||
get_user(recv, &idle->recv_idle) ||
put_user(xmit, &idle32->xmit_idle) ||
put_user(recv, &idle32->recv_idle))
err = -EFAULT;
}
return err;
}
/* /*
* simple reversible transform to make our table more evenly * simple reversible transform to make our table more evenly
* distributed after sorting. * distributed after sorting.
...@@ -192,7 +165,8 @@ COMPATIBLE_IOCTL(PPPIOCGDEBUG) ...@@ -192,7 +165,8 @@ COMPATIBLE_IOCTL(PPPIOCGDEBUG)
COMPATIBLE_IOCTL(PPPIOCSDEBUG) COMPATIBLE_IOCTL(PPPIOCSDEBUG)
/* PPPIOCSPASS is translated */ /* PPPIOCSPASS is translated */
/* PPPIOCSACTIVE is translated */ /* PPPIOCSACTIVE is translated */
/* PPPIOCGIDLE is translated */ COMPATIBLE_IOCTL(PPPIOCGIDLE32)
COMPATIBLE_IOCTL(PPPIOCGIDLE64)
COMPATIBLE_IOCTL(PPPIOCNEWUNIT) COMPATIBLE_IOCTL(PPPIOCNEWUNIT)
COMPATIBLE_IOCTL(PPPIOCATTACH) COMPATIBLE_IOCTL(PPPIOCATTACH)
COMPATIBLE_IOCTL(PPPIOCDETACH) COMPATIBLE_IOCTL(PPPIOCDETACH)
...@@ -214,16 +188,14 @@ COMPATIBLE_IOCTL(PPPIOCGL2TPSTATS) ...@@ -214,16 +188,14 @@ COMPATIBLE_IOCTL(PPPIOCGL2TPSTATS)
static long do_ioctl_trans(unsigned int cmd, static long do_ioctl_trans(unsigned int cmd,
unsigned long arg, struct file *file) unsigned long arg, struct file *file)
{ {
#ifdef CONFIG_BLOCK
void __user *argp = compat_ptr(arg); void __user *argp = compat_ptr(arg);
switch (cmd) { switch (cmd) {
case PPPIOCGIDLE32:
return ppp_gidle(file, cmd, argp);
#ifdef CONFIG_BLOCK
case SG_GET_REQUEST_TABLE: case SG_GET_REQUEST_TABLE:
return sg_grt_trans(file, cmd, argp); return sg_grt_trans(file, cmd, argp);
#endif
} }
#endif
return -ENOIOCTLCMD; return -ENOIOCTLCMD;
} }
......
...@@ -104,6 +104,8 @@ struct pppol2tp_ioc_stats { ...@@ -104,6 +104,8 @@ struct pppol2tp_ioc_stats {
#define PPPIOCGDEBUG _IOR('t', 65, int) /* Read debug level */ #define PPPIOCGDEBUG _IOR('t', 65, int) /* Read debug level */
#define PPPIOCSDEBUG _IOW('t', 64, int) /* Set debug level */ #define PPPIOCSDEBUG _IOW('t', 64, int) /* Set debug level */
#define PPPIOCGIDLE _IOR('t', 63, struct ppp_idle) /* get idle time */ #define PPPIOCGIDLE _IOR('t', 63, struct ppp_idle) /* get idle time */
#define PPPIOCGIDLE32 _IOR('t', 63, struct ppp_idle32) /* 32-bit times */
#define PPPIOCGIDLE64 _IOR('t', 63, struct ppp_idle64) /* 64-bit times */
#define PPPIOCNEWUNIT _IOWR('t', 62, int) /* create new ppp unit */ #define PPPIOCNEWUNIT _IOWR('t', 62, int) /* create new ppp unit */
#define PPPIOCATTACH _IOW('t', 61, int) /* attach to ppp unit */ #define PPPIOCATTACH _IOW('t', 61, int) /* attach to ppp unit */
#define PPPIOCDETACH _IOW('t', 60, int) /* obsolete, do not use */ #define PPPIOCDETACH _IOW('t', 60, int) /* obsolete, do not use */
......
...@@ -142,10 +142,24 @@ struct ppp_comp_stats { ...@@ -142,10 +142,24 @@ struct ppp_comp_stats {
/* /*
* The following structure records the time in seconds since * The following structure records the time in seconds since
* the last NP packet was sent or received. * the last NP packet was sent or received.
*
* Linux implements both 32-bit and 64-bit time_t versions
* for compatibility with user space that defines ppp_idle
* based on the libc time_t.
*/ */
struct ppp_idle { struct ppp_idle {
__kernel_time_t xmit_idle; /* time since last NP packet sent */ __kernel_time_t xmit_idle; /* time since last NP packet sent */
__kernel_time_t recv_idle; /* time since last NP packet received */ __kernel_time_t recv_idle; /* time since last NP packet received */
}; };
struct ppp_idle32 {
__s32 xmit_idle; /* time since last NP packet sent */
__s32 recv_idle; /* time since last NP packet received */
};
struct ppp_idle64 {
__s64 xmit_idle; /* time since last NP packet sent */
__s64 recv_idle; /* time since last NP packet received */
};
#endif /* _UAPI_PPP_DEFS_H_ */ #endif /* _UAPI_PPP_DEFS_H_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment