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

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
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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
+14 −5
Original line number Diff line number Diff line
@@ -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;
@@ -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;
+5 −33
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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.
@@ -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)
@@ -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;
}
+2 −0
Original line number Diff line number Diff line
@@ -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 */
+14 −0
Original line number Diff line number Diff line
@@ -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_ */