linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/2] airo: Fix possible info leak in AIROOLDIOCTL/SIOCDEVPRIVATE
@ 2020-01-22  4:07 Michael Ellerman
  2020-01-22  4:07 ` [PATCH 2/2] airo: Add missing CAP_NET_ADMIN check " Michael Ellerman
  2020-01-23 10:03 ` [PATCH 1/2] airo: Fix possible info leak " David Miller
  0 siblings, 2 replies; 4+ messages in thread
From: Michael Ellerman @ 2020-01-22  4:07 UTC (permalink / raw)
  To: netdev; +Cc: linux-wireless, kvalo, davem, linux-kernel, security, ivansprundel

The driver for Cisco Aironet 4500 and 4800 series cards (airo.c),
implements AIROOLDIOCTL/SIOCDEVPRIVATE in airo_ioctl().

The ioctl handler copies an aironet_ioctl struct from userspace, which
includes a command and a length. Some of the commands are handled in
readrids(), which kmalloc()'s a buffer of RIDSIZE (2048) bytes.

That buffer is then passed to PC4500_readrid(), which has two cases.
The else case does some setup and then reads up to RIDSIZE bytes from
the hardware into the kmalloc()'ed buffer.

Here len == RIDSIZE, pBuf is the kmalloc()'ed buffer:

	// read the rid length field
	bap_read(ai, pBuf, 2, BAP1);
	// length for remaining part of rid
	len = min(len, (int)le16_to_cpu(*(__le16*)pBuf)) - 2;
	...
	// read remainder of the rid
	rc = bap_read(ai, ((__le16*)pBuf)+1, len, BAP1);

PC4500_readrid() then returns to readrids() which does:

	len = comp->len;
	if (copy_to_user(comp->data, iobuf, min(len, (int)RIDSIZE))) {

Where comp->len is the user controlled length field.

So if the "rid length field" returned by the hardware is < 2048, and
the user requests 2048 bytes in comp->len, we will leak the previous
contents of the kmalloc()'ed buffer to userspace.

Fix it by kzalloc()'ing the buffer.

Found by Ilja by code inspection, not tested as I don't have the
required hardware.

Reported-by: Ilja Van Sprundel <ivansprundel@ioactive.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
---
 drivers/net/wireless/cisco/airo.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/cisco/airo.c b/drivers/net/wireless/cisco/airo.c
index f43c06569ea1..d69c2ee7e206 100644
--- a/drivers/net/wireless/cisco/airo.c
+++ b/drivers/net/wireless/cisco/airo.c
@@ -7813,7 +7813,7 @@ static int readrids(struct net_device *dev, aironet_ioctl *comp) {
 		return -EINVAL;
 	}
 
-	if ((iobuf = kmalloc(RIDSIZE, GFP_KERNEL)) == NULL)
+	if ((iobuf = kzalloc(RIDSIZE, GFP_KERNEL)) == NULL)
 		return -ENOMEM;
 
 	PC4500_readrid(ai,ridcode,iobuf,RIDSIZE, 1);
-- 
2.21.1


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH 2/2] airo: Add missing CAP_NET_ADMIN check in AIROOLDIOCTL/SIOCDEVPRIVATE
  2020-01-22  4:07 [PATCH 1/2] airo: Fix possible info leak in AIROOLDIOCTL/SIOCDEVPRIVATE Michael Ellerman
@ 2020-01-22  4:07 ` Michael Ellerman
  2020-01-23 10:03   ` David Miller
  2020-01-23 10:03 ` [PATCH 1/2] airo: Fix possible info leak " David Miller
  1 sibling, 1 reply; 4+ messages in thread
From: Michael Ellerman @ 2020-01-22  4:07 UTC (permalink / raw)
  To: netdev; +Cc: linux-wireless, kvalo, davem, linux-kernel, security, ivansprundel

The driver for Cisco Aironet 4500 and 4800 series cards (airo.c),
implements AIROOLDIOCTL/SIOCDEVPRIVATE in airo_ioctl().

The ioctl handler copies an aironet_ioctl struct from userspace, which
includes a command. Some of the commands are handled in readrids(),
where the user controlled command is converted into a driver-internal
value called "ridcode".

There are two command values, AIROGWEPKTMP and AIROGWEPKNV, which
correspond to ridcode values of RID_WEP_TEMP and RID_WEP_PERM
respectively. These commands both have checks that the user has
CAP_NET_ADMIN, with the comment that "Only super-user can read WEP
keys", otherwise they return -EPERM.

However there is another command value, AIRORRID, that lets the user
specify the ridcode value directly, with no other checks. This means
the user can bypass the CAP_NET_ADMIN check on AIROGWEPKTMP and
AIROGWEPKNV.

Fix it by moving the CAP_NET_ADMIN check out of the command handling
and instead do it later based on the ridcode. That way regardless of
whether the ridcode is set via AIROGWEPKTMP or AIROGWEPKNV, or passed
in using AIRORID, we always do the CAP_NET_ADMIN check.

Found by Ilja by code inspection, not tested as I don't have the
required hardware.

Reported-by: Ilja Van Sprundel <ivansprundel@ioactive.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
---
 drivers/net/wireless/cisco/airo.c | 18 ++++++++----------
 1 file changed, 8 insertions(+), 10 deletions(-)

diff --git a/drivers/net/wireless/cisco/airo.c b/drivers/net/wireless/cisco/airo.c
index d69c2ee7e206..c4c8f1b62e1e 100644
--- a/drivers/net/wireless/cisco/airo.c
+++ b/drivers/net/wireless/cisco/airo.c
@@ -7790,16 +7790,8 @@ static int readrids(struct net_device *dev, aironet_ioctl *comp) {
 	case AIROGVLIST:    ridcode = RID_APLIST;       break;
 	case AIROGDRVNAM:   ridcode = RID_DRVNAME;      break;
 	case AIROGEHTENC:   ridcode = RID_ETHERENCAP;   break;
-	case AIROGWEPKTMP:  ridcode = RID_WEP_TEMP;
-		/* Only super-user can read WEP keys */
-		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
-		break;
-	case AIROGWEPKNV:   ridcode = RID_WEP_PERM;
-		/* Only super-user can read WEP keys */
-		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
-		break;
+	case AIROGWEPKTMP:  ridcode = RID_WEP_TEMP;	break;
+	case AIROGWEPKNV:   ridcode = RID_WEP_PERM;	break;
 	case AIROGSTAT:     ridcode = RID_STATUS;       break;
 	case AIROGSTATSD32: ridcode = RID_STATSDELTA;   break;
 	case AIROGSTATSC32: ridcode = RID_STATS;        break;
@@ -7813,6 +7805,12 @@ static int readrids(struct net_device *dev, aironet_ioctl *comp) {
 		return -EINVAL;
 	}
 
+	if (ridcode == RID_WEP_TEMP || ridcode == RID_WEP_PERM) {
+		/* Only super-user can read WEP keys */
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+	}
+
 	if ((iobuf = kzalloc(RIDSIZE, GFP_KERNEL)) == NULL)
 		return -ENOMEM;
 
-- 
2.21.1


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* Re: [PATCH 1/2] airo: Fix possible info leak in AIROOLDIOCTL/SIOCDEVPRIVATE
  2020-01-22  4:07 [PATCH 1/2] airo: Fix possible info leak in AIROOLDIOCTL/SIOCDEVPRIVATE Michael Ellerman
  2020-01-22  4:07 ` [PATCH 2/2] airo: Add missing CAP_NET_ADMIN check " Michael Ellerman
@ 2020-01-23 10:03 ` David Miller
  1 sibling, 0 replies; 4+ messages in thread
From: David Miller @ 2020-01-23 10:03 UTC (permalink / raw)
  To: mpe; +Cc: netdev, linux-wireless, kvalo, linux-kernel, security, ivansprundel

From: Michael Ellerman <mpe@ellerman.id.au>
Date: Wed, 22 Jan 2020 15:07:27 +1100

> The driver for Cisco Aironet 4500 and 4800 series cards (airo.c),
> implements AIROOLDIOCTL/SIOCDEVPRIVATE in airo_ioctl().
> 
> The ioctl handler copies an aironet_ioctl struct from userspace, which
> includes a command and a length. Some of the commands are handled in
> readrids(), which kmalloc()'s a buffer of RIDSIZE (2048) bytes.
> 
> That buffer is then passed to PC4500_readrid(), which has two cases.
> The else case does some setup and then reads up to RIDSIZE bytes from
> the hardware into the kmalloc()'ed buffer.
> 
> Here len == RIDSIZE, pBuf is the kmalloc()'ed buffer:
> 
> 	// read the rid length field
> 	bap_read(ai, pBuf, 2, BAP1);
> 	// length for remaining part of rid
> 	len = min(len, (int)le16_to_cpu(*(__le16*)pBuf)) - 2;
> 	...
> 	// read remainder of the rid
> 	rc = bap_read(ai, ((__le16*)pBuf)+1, len, BAP1);
> 
> PC4500_readrid() then returns to readrids() which does:
> 
> 	len = comp->len;
> 	if (copy_to_user(comp->data, iobuf, min(len, (int)RIDSIZE))) {
> 
> Where comp->len is the user controlled length field.
> 
> So if the "rid length field" returned by the hardware is < 2048, and
> the user requests 2048 bytes in comp->len, we will leak the previous
> contents of the kmalloc()'ed buffer to userspace.
> 
> Fix it by kzalloc()'ing the buffer.
> 
> Found by Ilja by code inspection, not tested as I don't have the
> required hardware.
> 
> Reported-by: Ilja Van Sprundel <ivansprundel@ioactive.com>
> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>

Applied and queued up for -stable.

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH 2/2] airo: Add missing CAP_NET_ADMIN check in AIROOLDIOCTL/SIOCDEVPRIVATE
  2020-01-22  4:07 ` [PATCH 2/2] airo: Add missing CAP_NET_ADMIN check " Michael Ellerman
@ 2020-01-23 10:03   ` David Miller
  0 siblings, 0 replies; 4+ messages in thread
From: David Miller @ 2020-01-23 10:03 UTC (permalink / raw)
  To: mpe; +Cc: netdev, linux-wireless, kvalo, linux-kernel, security, ivansprundel

From: Michael Ellerman <mpe@ellerman.id.au>
Date: Wed, 22 Jan 2020 15:07:28 +1100

> The driver for Cisco Aironet 4500 and 4800 series cards (airo.c),
> implements AIROOLDIOCTL/SIOCDEVPRIVATE in airo_ioctl().
> 
> The ioctl handler copies an aironet_ioctl struct from userspace, which
> includes a command. Some of the commands are handled in readrids(),
> where the user controlled command is converted into a driver-internal
> value called "ridcode".
> 
> There are two command values, AIROGWEPKTMP and AIROGWEPKNV, which
> correspond to ridcode values of RID_WEP_TEMP and RID_WEP_PERM
> respectively. These commands both have checks that the user has
> CAP_NET_ADMIN, with the comment that "Only super-user can read WEP
> keys", otherwise they return -EPERM.
> 
> However there is another command value, AIRORRID, that lets the user
> specify the ridcode value directly, with no other checks. This means
> the user can bypass the CAP_NET_ADMIN check on AIROGWEPKTMP and
> AIROGWEPKNV.
> 
> Fix it by moving the CAP_NET_ADMIN check out of the command handling
> and instead do it later based on the ridcode. That way regardless of
> whether the ridcode is set via AIROGWEPKTMP or AIROGWEPKNV, or passed
> in using AIRORID, we always do the CAP_NET_ADMIN check.
> 
> Found by Ilja by code inspection, not tested as I don't have the
> required hardware.
> 
> Reported-by: Ilja Van Sprundel <ivansprundel@ioactive.com>
> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>

Applied and queued up for -stable.

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2020-01-23 10:04 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-01-22  4:07 [PATCH 1/2] airo: Fix possible info leak in AIROOLDIOCTL/SIOCDEVPRIVATE Michael Ellerman
2020-01-22  4:07 ` [PATCH 2/2] airo: Add missing CAP_NET_ADMIN check " Michael Ellerman
2020-01-23 10:03   ` David Miller
2020-01-23 10:03 ` [PATCH 1/2] airo: Fix possible info leak " David Miller

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).