Skip to content

Commit

Permalink
compat_ioctl: handle PPPIOCGIDLE for 64-bit time_t
Browse files Browse the repository at this point in the history
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: Arnd Bergmann <arnd@arndb.de>
  • Loading branch information
Arnd Bergmann committed Oct 23, 2019
1 parent 5b6c02d commit 17c7e7f
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 38 deletions.
2 changes: 2 additions & 0 deletions Documentation/networking/ppp_generic.txt
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,8 @@ an interface unit are:
CONFIG_PPP_FILTER option is enabled, the set of packets which reset
the transmit and receive idle timers is restricted to those which
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
number of connection slots) for the TCP header compressor and
Expand Down
19 changes: 14 additions & 5 deletions drivers/net/ppp/ppp_generic.c
Original file line number Diff line number Diff line change
Expand Up @@ -612,7 +612,8 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
struct ppp_file *pf;
struct ppp *ppp;
int err = -EFAULT, val, val2, i;
struct ppp_idle idle;
struct ppp_idle32 idle32;
struct ppp_idle64 idle64;
struct npioctl npi;
int unit, cflags;
struct slcompress *vj;
Expand Down Expand Up @@ -735,10 +736,18 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
err = 0;
break;

case PPPIOCGIDLE:
idle.xmit_idle = (jiffies - ppp->last_xmit) / HZ;
idle.recv_idle = (jiffies - ppp->last_recv) / HZ;
if (copy_to_user(argp, &idle, sizeof(idle)))
case PPPIOCGIDLE32:
idle32.xmit_idle = (jiffies - ppp->last_xmit) / HZ;
idle32.recv_idle = (jiffies - ppp->last_recv) / HZ;
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;
err = 0;
break;
Expand Down
38 changes: 5 additions & 33 deletions fs/compat_ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@

#include <linux/sort.h>

#ifdef CONFIG_BLOCK
static int do_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int err;
Expand All @@ -63,7 +64,6 @@ static int do_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
return vfs_ioctl(file, cmd, arg);
}

#ifdef CONFIG_BLOCK
struct compat_sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */
char req_state;
char orphan;
Expand Down Expand Up @@ -99,33 +99,6 @@ static int sg_grt_trans(struct file *file,
}
#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
* distributed after sorting.
Expand Down Expand Up @@ -192,7 +165,8 @@ COMPATIBLE_IOCTL(PPPIOCGDEBUG)
COMPATIBLE_IOCTL(PPPIOCSDEBUG)
/* PPPIOCSPASS is translated */
/* PPPIOCSACTIVE is translated */
/* PPPIOCGIDLE is translated */
COMPATIBLE_IOCTL(PPPIOCGIDLE32)
COMPATIBLE_IOCTL(PPPIOCGIDLE64)
COMPATIBLE_IOCTL(PPPIOCNEWUNIT)
COMPATIBLE_IOCTL(PPPIOCATTACH)
COMPATIBLE_IOCTL(PPPIOCDETACH)
Expand All @@ -214,16 +188,14 @@ COMPATIBLE_IOCTL(PPPIOCGL2TPSTATS)
static long do_ioctl_trans(unsigned int cmd,
unsigned long arg, struct file *file)
{
#ifdef CONFIG_BLOCK
void __user *argp = compat_ptr(arg);

switch (cmd) {
case PPPIOCGIDLE32:
return ppp_gidle(file, cmd, argp);
#ifdef CONFIG_BLOCK
case SG_GET_REQUEST_TABLE:
return sg_grt_trans(file, cmd, argp);
#endif
}
#endif

return -ENOIOCTLCMD;
}
Expand Down
2 changes: 2 additions & 0 deletions include/uapi/linux/ppp-ioctl.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ struct pppol2tp_ioc_stats {
#define PPPIOCGDEBUG _IOR('t', 65, int) /* Read debug level */
#define PPPIOCSDEBUG _IOW('t', 64, int) /* Set debug level */
#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 PPPIOCATTACH _IOW('t', 61, int) /* attach to ppp unit */
#define PPPIOCDETACH _IOW('t', 60, int) /* obsolete, do not use */
Expand Down
14 changes: 14 additions & 0 deletions include/uapi/linux/ppp_defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,10 +142,24 @@ struct ppp_comp_stats {
/*
* The following structure records the time in seconds since
* 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 {
__kernel_time_t xmit_idle; /* time since last NP packet sent */
__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_ */

0 comments on commit 17c7e7f

Please sign in to comment.