^
ffff8801afa03a00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
ffff8801afa03a80: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
==================================================================
---
This bug is generated by a dumb bot. It may contain errors.
See https://goo.gl/tpsmEJ for details.
Direct all questions to syzkaller@googlegroups.com.
syzbot will keep track of this bug report.
If you forgot to add the Reported-by tag, once the fix for this bug is
merged
into any tree, please reply to this email with:
#syz fix: exact-commit-title
If you want to test a patch for this bug, please reply with:
#syz test: git://repo/address.git branch
and provide the patch inline or as an attachment.
To mark this as a duplicate of another syzbot report, please reply with:
#syz dup: exact-subject-of-another-report
If it's a one-off invalid bug report, please reply with:
#syz invalid
Note: if the crash happens again, it will cause creation of a new bug
report.
Note: all commands must start from beginning of the line in the email body.
This is a bug in ppp_generic.c; it still happens on Linus' tree and it's easily
reproducible, see program below. The bug is that the PPPIOCDETACH ioctl doesn't
consider that the file can still be attached to epoll instances even when
->f_count == 1. Also, the reproducer doesn't test this but I think ppp_poll(),
ppp_read(), and ppp_write() can all race with PPPIOCDETACH, causing
use-after-frees as well. Any chance that PPPIOCDETACH can simply be removed,
given that it's apparently been "deprecated" for 16 years? Does anyone use it?
#include <fcntl.h>
#include <linux/ppp-ioctl.h>
#include <sys/epoll.h>
#include <sys/ioctl.h>
int main()
{
int pppfd, epfd, unit = 0;
struct epoll_event event = { 0 };
pppfd = open("/dev/ppp", O_RDONLY);
ioctl(pppfd, PPPIOCNEWUNIT, &unit);
epfd = epoll_create(0x2000);
epoll_ctl(epfd, EPOLL_CTL_ADD, pppfd, &event);
ioctl(pppfd, PPPIOCDETACH, &unit);
}
- Eric
On Sun, May 13, 2018 at 11:11:55PM -0700, Eric Biggers wrote:
[+ppp list and maintainer]
This is a bug in ppp_generic.c; it still happens on Linus' tree and it's easily
reproducible, see program below. The bug is that the PPPIOCDETACH ioctl doesn't
consider that the file can still be attached to epoll instances even when
->f_count == 1.
Right. What would it take to remove the file for the epoll instances?
Sorry for the naive question, but I'm not familiar with VFS and didn't
find a helper function we could call.
Also, the reproducer doesn't test this but I think ppp_poll(),
ppp_read(), and ppp_write() can all race with PPPIOCDETACH, causing
use-after-frees as well.
I also believe so. ppp_release() resets ->private_data, and even though
functions like ppp_read() test ->private_data before executing, there's
no synchronisation mechanism to ensure that the update is visible
before the unit or channel is destroyed. Is that the kind of race you
had in mind?
Any chance that PPPIOCDETACH can simply be removed,
given that it's apparently been "deprecated" for 16 years?
Does anyone use it?
The only users I'm aware of are pppd versions older than ppp-2.4.2
(released in November 2003). But even at that time, there were issues
with PPPIOCDETACH as pppd didn't seem to react properly when this call
failed. An Internet search on the "PPPIOCDETACH file->f_count=" kernel
log string, or on the "Couldn't release PPP unit: Invalid argument"
error message of pppd, returns several related bug reports.
Originally, PPPIOCDETACH never failed, but testing ->f_count was
later introduced to fix crashes when the file descriptor had been
duplicated. It seems that this was motivated by polling issues too.
Long story short, it looks like PPPIOCDETACH never has worked well
and we have at least two more bugs to fix. Given how it has proven
fragile, I wouldn't be surprised if there were even more lurking
around. I'd say that it's probably safer to drop it than to add more
workarounds and playing wack-a-mole with those bugs.
From: Eric Biggers <hidden> Date: 2018-05-23 03:30:03
On Fri, May 18, 2018 at 06:02:23PM +0200, Guillaume Nault wrote:
On Sun, May 13, 2018 at 11:11:55PM -0700, Eric Biggers wrote:
quoted
[+ppp list and maintainer]
This is a bug in ppp_generic.c; it still happens on Linus' tree and it's easily
reproducible, see program below. The bug is that the PPPIOCDETACH ioctl doesn't
consider that the file can still be attached to epoll instances even when
->f_count == 1.
Right. What would it take to remove the file for the epoll instances?
Sorry for the naive question, but I'm not familiar with VFS and didn't
find a helper function we could call.
There is eventpoll_release_file(), but it's not exported to modules. It might
work to call it, but it seems like a hack.
quoted
Also, the reproducer doesn't test this but I think ppp_poll(),
ppp_read(), and ppp_write() can all race with PPPIOCDETACH, causing
use-after-frees as well.
I also believe so. ppp_release() resets ->private_data, and even though
functions like ppp_read() test ->private_data before executing, there's
no synchronisation mechanism to ensure that the update is visible
before the unit or channel is destroyed. Is that the kind of race you
had in mind?
Yes, though after looking into it more I *think* these additional races aren't
actually possible, due to the 'f_count < 2' check. These races could only
happen with a shared fd table, but in that case fdget() would increment f_count
for the duration of each operation, resulting in 'f_count >= 2' if both ioctl()
and something else is running on the same file concurrently.
Note that this also means PPPIOCDETACH doesn't work at all if called from a
multithreaded application...
quoted
Any chance that PPPIOCDETACH can simply be removed,
given that it's apparently been "deprecated" for 16 years?
Does anyone use it?
The only users I'm aware of are pppd versions older than ppp-2.4.2
(released in November 2003). But even at that time, there were issues
with PPPIOCDETACH as pppd didn't seem to react properly when this call
failed. An Internet search on the "PPPIOCDETACH file->f_count=" kernel
log string, or on the "Couldn't release PPP unit: Invalid argument"
error message of pppd, returns several related bug reports.
Originally, PPPIOCDETACH never failed, but testing ->f_count was
later introduced to fix crashes when the file descriptor had been
duplicated. It seems that this was motivated by polling issues too.
Long story short, it looks like PPPIOCDETACH never has worked well
and we have at least two more bugs to fix. Given how it has proven
fragile, I wouldn't be surprised if there were even more lurking
around. I'd say that it's probably safer to drop it than to add more
workarounds and playing wack-a-mole with those bugs.
IMO, if we can get away with removing it without any users noticing, that would
be much better than trying to fix it with a VFS-level hack, and probably missing
some cases. I'll send a patch to get things started...
- Eric
From: Eric Biggers <hidden> Date: 2018-05-23 04:01:48
From: Eric Biggers <redacted>
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.
Reported-by: syzbot+16363c99d4134717c05b@syzkaller.appspotmail.com
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Signed-off-by: Eric Biggers <redacted>
---
Documentation/networking/ppp_generic.txt | 6 -----
drivers/net/ppp/ppp_generic.c | 29 ------------------------
fs/compat_ioctl.c | 1 -
include/uapi/linux/ppp-ioctl.h | 1 -
4 files changed, 37 deletions(-)
@@ -300,12 +300,6 @@ unattached instance are: The ioctl calls available on an instance of /dev/ppp attached to a channel are:-* PPPIOCDETACH detaches the instance from the channel. This ioctl is- deprecated since the same effect can be achieved by closing the- instance. In order to prevent possible races this ioctl will fail- with an EINVAL error if more than one file descriptor refers to this- instance (i.e. as a result of dup(), dup2() or fork()).- * PPPIOCCONNECT connects this channel to a PPP interface. The argument should point to an int containing the interface unit number. It will return an EINVAL error if the channel is already
On Tue, May 22, 2018 at 08:29:58PM -0700, Eric Biggers wrote:
On Fri, May 18, 2018 at 06:02:23PM +0200, Guillaume Nault wrote:
quoted
On Sun, May 13, 2018 at 11:11:55PM -0700, Eric Biggers wrote:
quoted
[+ppp list and maintainer]
This is a bug in ppp_generic.c; it still happens on Linus' tree and it's easily
reproducible, see program below. The bug is that the PPPIOCDETACH ioctl doesn't
consider that the file can still be attached to epoll instances even when
->f_count == 1.
Right. What would it take to remove the file for the epoll instances?
Sorry for the naive question, but I'm not familiar with VFS and didn't
find a helper function we could call.
There is eventpoll_release_file(), but it's not exported to modules. It might
work to call it, but it seems like a hack.
quoted
quoted
Also, the reproducer doesn't test this but I think ppp_poll(),
ppp_read(), and ppp_write() can all race with PPPIOCDETACH, causing
use-after-frees as well.
I also believe so. ppp_release() resets ->private_data, and even though
functions like ppp_read() test ->private_data before executing, there's
no synchronisation mechanism to ensure that the update is visible
before the unit or channel is destroyed. Is that the kind of race you
had in mind?
Yes, though after looking into it more I *think* these additional races aren't
actually possible, due to the 'f_count < 2' check. These races could only
happen with a shared fd table, but in that case fdget() would increment f_count
for the duration of each operation, resulting in 'f_count >= 2' if both ioctl()
and something else is running on the same file concurrently.
Note that this also means PPPIOCDETACH doesn't work at all if called from a
multithreaded application...
quoted
quoted
Any chance that PPPIOCDETACH can simply be removed,
given that it's apparently been "deprecated" for 16 years?
Does anyone use it?
The only users I'm aware of are pppd versions older than ppp-2.4.2
(released in November 2003). But even at that time, there were issues
with PPPIOCDETACH as pppd didn't seem to react properly when this call
failed. An Internet search on the "PPPIOCDETACH file->f_count=" kernel
log string, or on the "Couldn't release PPP unit: Invalid argument"
error message of pppd, returns several related bug reports.
Originally, PPPIOCDETACH never failed, but testing ->f_count was
later introduced to fix crashes when the file descriptor had been
duplicated. It seems that this was motivated by polling issues too.
Long story short, it looks like PPPIOCDETACH never has worked well
and we have at least two more bugs to fix. Given how it has proven
fragile, I wouldn't be surprised if there were even more lurking
around. I'd say that it's probably safer to drop it than to add more
workarounds and playing wack-a-mole with those bugs.
IMO, if we can get away with removing it without any users noticing, that would
be much better than trying to fix it with a VFS-level hack, and probably missing
some cases. I'll send a patch to get things started...
Yes, I fully agree. That looks much safer, and given the track record
of this ioctl I very much doubt anyone would depend on it.
On Tue, May 22, 2018 at 08:59:52PM -0700, Eric Biggers wrote:
quoted hunk
From: Eric Biggers <redacted>
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.
Reported-by: syzbot+16363c99d4134717c05b@syzkaller.appspotmail.com
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Signed-off-by: Eric Biggers <redacted>
---
Documentation/networking/ppp_generic.txt | 6 -----
drivers/net/ppp/ppp_generic.c | 29 ------------------------
fs/compat_ioctl.c | 1 -
include/uapi/linux/ppp-ioctl.h | 1 -
4 files changed, 37 deletions(-)
@@ -300,12 +300,6 @@ unattached instance are: The ioctl calls available on an instance of /dev/ppp attached to a channel are:-* PPPIOCDETACH detaches the instance from the channel. This ioctl is- deprecated since the same effect can be achieved by closing the- instance. In order to prevent possible races this ioctl will fail- with an EINVAL error if more than one file descriptor refers to this- instance (i.e. as a result of dup(), dup2() or fork()).- * PPPIOCCONNECT connects this channel to a PPP interface. The argument should point to an int containing the interface unit number. It will return an EINVAL error if the channel is already
@@ -603,35 +603,6 @@ static long ppp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)gotoout;}-if(cmd==PPPIOCDETACH){-/*-*Wehavetobecarefulhere...ifthefiledescriptor-*hasbeendup'd,wecouldhaveanotherprocessinthe-*middleofapollusingthesamefile*,sowehad-*betternotfreetheinterfacedatastructures--*insteadwefailtheioctl.Eveninthiscase,we-*shutdowntheinterfaceifwearetheownerofit.-*Actually,weshouldgetridofPPPIOCDETACH,userland-*(i.e.pppd)couldachievethesameeffectbyclosing-*thisfdandreopening/dev/ppp.-*/-err=-EINVAL;-if(pf->kind==INTERFACE){-ppp=PF_TO_PPP(pf);-rtnl_lock();-if(file==ppp->owner)-unregister_netdevice(ppp->dev);-rtnl_unlock();-}-if(atomic_long_read(&file->f_count)<2){-ppp_release(NULL,file);-err=0;-}else-pr_warn("PPPIOCDETACH file->f_count=%ld\n",-atomic_long_read(&file->f_count));-gotoout;-}-
I'd rather add
+ if (cmd == PPPIOCDETACH) {
+ err = -EINVAL;
+ goto out;
+ }
Making PPPIOCDETACH unknown to ppp_generic means that the ioctl would
be handled by the underlying channel when pf->kind == CHANNEL (see the
chan->ops->ioctl() call further down). That shouldn't be a problem per
se, but even though PPPIOCDETACH is unsupported, I feel that it should
remain a ppp_generic thing. I don't really want its value to be reused
for other purposes in the future or have different behaviour depending
on the underlying channel.
Also PPPIOCDETACH can already fail with -EINVAL. Therefore, if ever
there really were programs out there using this call, they'd already
have to handle this case. Unconditionally returning -EINVAL would
further minimise possibilities for breakage.
I'd rather add
+ if (cmd == PPPIOCDETACH) {
+ err = -EINVAL;
+ goto out;
+ }
Making PPPIOCDETACH unknown to ppp_generic means that the ioctl would
be handled by the underlying channel when pf->kind == CHANNEL (see the
chan->ops->ioctl() call further down). That shouldn't be a problem per
se, but even though PPPIOCDETACH is unsupported, I feel that it should
remain a ppp_generic thing. I don't really want its value to be reused
for other purposes in the future or have different behaviour depending
on the underlying channel.
Also PPPIOCDETACH can already fail with -EINVAL. Therefore, if ever
there really were programs out there using this call, they'd already
have to handle this case. Unconditionally returning -EINVAL would
further minimise possibilities for breakage.
I'd rather add
+ if (cmd == PPPIOCDETACH) {
+ err = -EINVAL;
+ goto out;
+ }
Making PPPIOCDETACH unknown to ppp_generic means that the ioctl would
be handled by the underlying channel when pf->kind == CHANNEL (see the
chan->ops->ioctl() call further down). That shouldn't be a problem per
se, but even though PPPIOCDETACH is unsupported, I feel that it should
remain a ppp_generic thing. I don't really want its value to be reused
for other purposes in the future or have different behaviour depending
on the underlying channel.
Also PPPIOCDETACH can already fail with -EINVAL. Therefore, if ever
there really were programs out there using this call, they'd already
have to handle this case. Unconditionally returning -EINVAL would
further minimise possibilities for breakage.
I agree.
Okay, I'll do that and leave the ioctl number reserved.
I will add a pr_warn_once() too.
Thanks,
- Eric
From: Eric Biggers <hidden> Date: 2018-05-23 21:39:43
From: Eric Biggers <redacted>
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")
Cc: stable@vger.kernel.org
Signed-off-by: Eric Biggers <redacted>
---
v2: leave a stub in place, rather than removing the ioctl completely.
Documentation/networking/ppp_generic.txt | 6 ------
drivers/net/ppp/ppp_generic.c | 27 +++++-------------------
include/uapi/linux/ppp-ioctl.h | 2 +-
3 files changed, 6 insertions(+), 29 deletions(-)
@@ -300,12 +300,6 @@ unattached instance are: The ioctl calls available on an instance of /dev/ppp attached to a channel are:-* PPPIOCDETACH detaches the instance from the channel. This ioctl is- deprecated since the same effect can be achieved by closing the- instance. In order to prevent possible races this ioctl will fail- with an EINVAL error if more than one file descriptor refers to this- instance (i.e. as a result of dup(), dup2() or fork()).- * PPPIOCCONNECT connects this channel to a PPP interface. The argument should point to an int containing the interface unit number. It will return an EINVAL error if the channel is already
From: Paul Mackerras <hidden> Date: 2018-05-23 23:04:00
On Wed, May 23, 2018 at 02:37:38PM -0700, Eric Biggers wrote:
From: Eric Biggers <redacted>
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")
Cc: stable@vger.kernel.org
Signed-off-by: Eric Biggers <redacted>
On Wed, May 23, 2018 at 02:37:38PM -0700, Eric Biggers wrote:
From: Eric Biggers <redacted>
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")
Cc: stable@vger.kernel.org
Signed-off-by: Eric Biggers <redacted>
---
v2: leave a stub in place, rather than removing the ioctl completely.
Thanks a lot for your help on this matter.
BTW, netdev has its own rules wrt. stable backports. You didn't need to
CC: stable@. David handles -stable submissions himself.
Using a 'PATCH net' subject prefix would have made it clear that this
patch was fixing some released code and should be considered for -stable
backport.
Reviewed-by: Guillaume Nault <redacted>
Tested-by: Guillaume Nault <redacted>
From: David Miller <davem@davemloft.net> Date: 2018-05-25 02:55:25
From: Eric Biggers <redacted>
Date: Wed, 23 May 2018 14:37:38 -0700
From: Eric Biggers <redacted>
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 <redacted>
From: Walter Harms <hidden> Date: 2018-06-06 09:10:01
quoted hunk
Eric Biggers [off-list ref] hat am 23. Mai 2018 um 23:37 geschrieben:
From: Eric Biggers <redacted>
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")
Cc: stable@vger.kernel.org
Signed-off-by: Eric Biggers <redacted>
---
v2: leave a stub in place, rather than removing the ioctl completely.
Documentation/networking/ppp_generic.txt | 6 ------
drivers/net/ppp/ppp_generic.c | 27 +++++-------------------
include/uapi/linux/ppp-ioctl.h | 2 +-
3 files changed, 6 insertions(+), 29 deletions(-)
@@ -300,12 +300,6 @@ unattached instance are: The ioctl calls available on an instance of /dev/ppp attached to a channel are:-* PPPIOCDETACH detaches the instance from the channel. This ioctl is- deprecated since the same effect can be achieved by closing the- instance. In order to prevent possible races this ioctl will fail- with an EINVAL error if more than one file descriptor refers to this- instance (i.e. as a result of dup(), dup2() or fork()).- * PPPIOCCONNECT connects this channel to a PPP interface. The argument should point to an int containing the interface unit number. It will return an EINVAL error if the channel is already
@@ -605,30 +605,13 @@ static long ppp_ioctl(struct file *file, unsigned int
cmd, unsigned long arg)
if (cmd == PPPIOCDETACH) {
/*
- * We have to be careful here... if the file descriptor
- * has been dup'd, we could have another process in the
- * middle of a poll using the same file *, so we had
- * better not free the interface data structures -
- * instead we fail the ioctl. Even in this case, we
- * shut down the interface if we are the owner of it.
- * Actually, we should get rid of PPPIOCDETACH, userland
- * (i.e. pppd) could achieve the same effect by closing
- * this fd and reopening /dev/ppp.
+ * PPPIOCDETACH is no longer supported as it was heavily broken,
+ * and is only known to have been used by pppd older than
+ * ppp-2.4.2 (released November 2003).
*/
+ pr_warn_once("%s (%d) used obsolete PPPIOCDETACH ioctl\n",
+ current->comm, current->pid);
err = -EINVAL;
- if (pf->kind == INTERFACE) {
- ppp = PF_TO_PPP(pf);
- rtnl_lock();
- if (file == ppp->owner)
- unregister_netdevice(ppp->dev);
- rtnl_unlock();
- }
- if (atomic_long_read(&file->f_count) < 2) {
- ppp_release(NULL, file);
- err = 0;
- } else
- pr_warn("PPPIOCDETACH file->f_count=%ld\n",
- atomic_long_read(&file->f_count));
goto out;
}
@@ -106,7 +106,7 @@ struct pppol2tp_ioc_stats {#define PPPIOCGIDLE _IOR('t', 63, struct ppp_idle) /* get idle time */#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) /* detach from ppp unit/chan */+#define PPPIOCDETACH _IOW('t', 60, int) /* obsolete, do not use */
It's a bit late but ...
i would suggest a stronger wording here. like /* removed 2003 */
for me "obsolete" sounds like "maybe it will be removed in a distant future"
just my 2 cents,
re,
wh
#define PPPIOCSMRRU _IOW('t', 59, int) /* set multilink MRU */
#define PPPIOCCONNECT _IOW('t', 58, int) /* connect channel to unit */
#define PPPIOCDISCONN _IO('t', 57) /* disconnect channel */
--
2.17.0.441.gb46fe60e1d-goog
--
To unsubscribe from this list: send the line "unsubscribe linux-ppp" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html