Skip to content

Commit af8d3c7

Browse files
ebiggersdavem330
authored andcommitted
ppp: remove the PPPIOCDETACH ioctl
The PPPIOCDETACH ioctl effectively tries to "close" the given ppp file before f_count has reached 0, which is fundamentally a bad idea. It does check 'f_count < 2', which excludes concurrent operations on the file since they would only be possible with a shared fd table, in which case each fdget() would take a file reference. However, it fails to account for the fact that even with 'f_count == 1' the file can still be linked into epoll instances. As reported by syzbot, this can trivially be used to cause a use-after-free. Yet, the only known user of PPPIOCDETACH is pppd versions older than ppp-2.4.2, which was released almost 15 years ago (November 2003). Also, PPPIOCDETACH apparently stopped working reliably at around the same time, when the f_count check was added to the kernel, e.g. see https://lkml.org/lkml/2002/12/31/83. Also, the current 'f_count < 2' check makes PPPIOCDETACH only work in single-threaded applications; it always fails if called from a multithreaded application. All pppd versions released in the last 15 years just close() the file descriptor instead. Therefore, instead of hacking around this bug by exporting epoll internals to modules, and probably missing other related bugs, just remove the PPPIOCDETACH ioctl and see if anyone actually notices. Leave a stub in place that prints a one-time warning and returns EINVAL. Reported-by: syzbot+16363c99d4134717c05b@syzkaller.appspotmail.com Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Signed-off-by: Eric Biggers <ebiggers@google.com> Acked-by: Paul Mackerras <paulus@ozlabs.org> Reviewed-by: Guillaume Nault <g.nault@alphalink.fr> Tested-by: Guillaume Nault <g.nault@alphalink.fr> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 730c54d commit af8d3c7

File tree

3 files changed

+6
-29
lines changed

3 files changed

+6
-29
lines changed

Documentation/networking/ppp_generic.txt

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -300,12 +300,6 @@ unattached instance are:
300300
The ioctl calls available on an instance of /dev/ppp attached to a
301301
channel are:
302302

303-
* PPPIOCDETACH detaches the instance from the channel. This ioctl is
304-
deprecated since the same effect can be achieved by closing the
305-
instance. In order to prevent possible races this ioctl will fail
306-
with an EINVAL error if more than one file descriptor refers to this
307-
instance (i.e. as a result of dup(), dup2() or fork()).
308-
309303
* PPPIOCCONNECT connects this channel to a PPP interface. The
310304
argument should point to an int containing the interface unit
311305
number. It will return an EINVAL error if the channel is already

drivers/net/ppp/ppp_generic.c

Lines changed: 5 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -605,30 +605,13 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
605605

606606
if (cmd == PPPIOCDETACH) {
607607
/*
608-
* We have to be careful here... if the file descriptor
609-
* has been dup'd, we could have another process in the
610-
* middle of a poll using the same file *, so we had
611-
* better not free the interface data structures -
612-
* instead we fail the ioctl. Even in this case, we
613-
* shut down the interface if we are the owner of it.
614-
* Actually, we should get rid of PPPIOCDETACH, userland
615-
* (i.e. pppd) could achieve the same effect by closing
616-
* this fd and reopening /dev/ppp.
608+
* PPPIOCDETACH is no longer supported as it was heavily broken,
609+
* and is only known to have been used by pppd older than
610+
* ppp-2.4.2 (released November 2003).
617611
*/
612+
pr_warn_once("%s (%d) used obsolete PPPIOCDETACH ioctl\n",
613+
current->comm, current->pid);
618614
err = -EINVAL;
619-
if (pf->kind == INTERFACE) {
620-
ppp = PF_TO_PPP(pf);
621-
rtnl_lock();
622-
if (file == ppp->owner)
623-
unregister_netdevice(ppp->dev);
624-
rtnl_unlock();
625-
}
626-
if (atomic_long_read(&file->f_count) < 2) {
627-
ppp_release(NULL, file);
628-
err = 0;
629-
} else
630-
pr_warn("PPPIOCDETACH file->f_count=%ld\n",
631-
atomic_long_read(&file->f_count));
632615
goto out;
633616
}
634617

include/uapi/linux/ppp-ioctl.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ struct pppol2tp_ioc_stats {
106106
#define PPPIOCGIDLE _IOR('t', 63, struct ppp_idle) /* get idle time */
107107
#define PPPIOCNEWUNIT _IOWR('t', 62, int) /* create new ppp unit */
108108
#define PPPIOCATTACH _IOW('t', 61, int) /* attach to ppp unit */
109-
#define PPPIOCDETACH _IOW('t', 60, int) /* detach from ppp unit/chan */
109+
#define PPPIOCDETACH _IOW('t', 60, int) /* obsolete, do not use */
110110
#define PPPIOCSMRRU _IOW('t', 59, int) /* set multilink MRU */
111111
#define PPPIOCCONNECT _IOW('t', 58, int) /* connect channel to unit */
112112
#define PPPIOCDISCONN _IO('t', 57) /* disconnect channel */

0 commit comments

Comments
 (0)