Linux Kernel SCTP模块拒绝服务漏洞

QQ空间 新浪微博 微信 QQ facebook twitter
漏洞ID 1185722 漏洞类型 其他
发布时间 2008-08-20 更新时间 2009-01-29
CVE编号 CVE-2008-3792 CNNVD-ID CNNVD-200809-034
漏洞平台 N/A CVSS评分 7.1
|漏洞来源
https://cxsecurity.com/issue/WLB-2008090087
http://www.cnnvd.org.cn/web/xxk/ldxqById.tag?CNNVD=CNNVD-200809-034
|漏洞详情
Linuxkernel是美国Linux基金会发布的开源操作系统Linux所使用的内核。NFSv4implementation是其中的一个分布式文件系统协议。LinuxKernel在实现SCTP协议时所使用的net/sctp/socket.c在继续SCTP-AUTHAPI函数之前没有验证是否启用了SCTP-AUTH扩展,这允许攻击者通过调用sctp_setsockopt_auth_chunk、sctp_setsockopt_hmac_ident、sctp_setsockopt_auth_key、sctp_setsockopt_active_key、sctp_setsockopt_del_key、sctp_getsockopt_maxburst、sctp_getsockopt_active_key、sctp_getsockopt_peer_auth_chunks或sctp_getsockopt_local_auth_chunks等方式触发空指针引用,导致拒绝服务。如果启用了SCTP-AUTH扩展的话,net/sctp/socket.c文件中的sctp_getsockopt_hmac_ident函数依赖于不可信任的长度值限制从内核内存所拷贝的数据,net/sctp/auth.c文件中的sctp_auth_ep_set_hmacs函数没有验证标识符索引处于SCTP_AUTH_HMAC_ID_MAX所创建的范围之内,这允许本地攻击者通过特制的SCTP_HMAC_IDENTIOCTL请求获取敏感信息。
|漏洞EXP
Andrew, David

This problem is not limited to only the reported socket
option.  Most of the AUTH socket options suffer the
same or similar issues.  Here is a patch that fixes
all the issues I saw the the API.  The new tests for
this API have been created and all of them have passed.

-vlad

sctp: fix potential panics in the SCTP-AUTH API.

All of the SCTP-AUTH socket options could cause a panic
if the extension is disabled and the API is envoked.

Additionally, there were some additional assumptions that
certain pointers would always be valid which may not
always be the case.

This patch hardens the API and address all of the crash
scenarios.

Signed-off-by: Vlad Yasevich <vladislav.yasevich@hp.com>
---
 net/sctp/endpointola.c |    4 +-
 net/sctp/socket.c      |   85 ++++++++++++++++++++++++++++++++++++-----------
 2 files changed, 67 insertions(+), 22 deletions(-)

diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c
index e39a0cd..466eb75 100644
--- a/net/sctp/endpointola.c
+++ b/net/sctp/endpointola.c
@@ -103,6 +103,7 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
 
 		/* Initialize the CHUNKS parameter */
 		auth_chunks->param_hdr.type = SCTP_PARAM_CHUNKS;
+		auth_chunks->param_hdr.length = htons(sizeof(sctp_paramhdr_t));
 
 		/* If the Add-IP functionality is enabled, we must
 		 * authenticate, ASCONF and ASCONF-ACK chunks
@@ -110,8 +111,7 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
 		if (sctp_addip_enable) {
 			auth_chunks->chunks<A NAME="-0"></A>[0] = SCTP_CID_ASCONF;
 			auth_chunks->chunks<A NAME="-1"></A>[1] = SCTP_CID_ASCONF_ACK;
-			auth_chunks->param_hdr.length =
-					htons(sizeof(sctp_paramhdr_t) + 2);
+			auth_chunks->param_hdr.length += htons(2);
 		}
 	}
 
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index dbb79ad..bb5c9ef 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -3055,6 +3055,9 @@ static int sctp_setsockopt_auth_chunk(struct sock *sk,
 {
 	struct sctp_authchunk val;
 
+	if (!sctp_auth_enable)
+		return -EACCES;
+
 	if (optlen != sizeof(struct sctp_authchunk))
 		return -EINVAL;
 	if (copy_from_user(&val, optval, optlen))
@@ -3085,6 +3088,9 @@ static int sctp_setsockopt_hmac_ident(struct sock *sk,
 	struct sctp_hmacalgo *hmacs;
 	int err;
 
+	if (!sctp_auth_enable)
+		return -EACCES;
+
 	if (optlen < sizeof(struct sctp_hmacalgo))
 		return -EINVAL;
 
@@ -3123,6 +3129,9 @@ static int sctp_setsockopt_auth_key(struct sock *sk,
 	struct sctp_association *asoc;
 	int ret;
 
+	if (!sctp_auth_enable)
+		return -EACCES;
+
 	if (optlen <= sizeof(struct sctp_authkey))
 		return -EINVAL;
 
@@ -3160,6 +3169,9 @@ static int sctp_setsockopt_active_key(struct sock *sk,
 	struct sctp_authkeyid val;
 	struct sctp_association *asoc;
 
+	if (!sctp_auth_enable)
+		return -EACCES;
+
 	if (optlen != sizeof(struct sctp_authkeyid))
 		return -EINVAL;
 	if (copy_from_user(&val, optval, optlen))
@@ -3185,6 +3197,9 @@ static int sctp_setsockopt_del_key(struct sock *sk,
 	struct sctp_authkeyid val;
 	struct sctp_association *asoc;
 
+	if (!sctp_auth_enable)
+		return -EACCES;
+
 	if (optlen != sizeof(struct sctp_authkeyid))
 		return -EINVAL;
 	if (copy_from_user(&val, optval, optlen))
@@ -5197,19 +5212,29 @@ static int sctp_getsockopt_maxburst(struct sock *sk, int len,
 static int sctp_getsockopt_hmac_ident(struct sock *sk, int len,
 				    char __user *optval, int __user *optlen)
 {
+	struct sctp_hmacalgo  __user *p = (void __user *)optval;
 	struct sctp_hmac_algo_param *hmacs;
-	__u16 param_len;
+	__u16 data_len = 0;
+	u32 num_idents;
+
+	if (!sctp_auth_enable)
+		return -EACCES;
 
 	hmacs = sctp_sk(sk)->ep->auth_hmacs_list;
-	param_len = ntohs(hmacs->param_hdr.length);
+	data_len = ntohs(hmacs->param_hdr.length) - sizeof(sctp_paramhdr_t);
 
-	if (len < param_len)
+	if (len < sizeof(struct sctp_hmacalgo) + data_len)
 		return -EINVAL;
+
+	len = sizeof(struct sctp_hmacalgo) + data_len;
+	num_idents = data_len / sizeof(u16);
+
 	if (put_user(len, optlen))
 		return -EFAULT;
-	if (copy_to_user(optval, hmacs->hmac_ids, len))
+	if (put_user(num_idents, &p->shmac_num_idents))
+		return -EFAULT;
+	if (copy_to_user(p->shmac_idents, hmacs->hmac_ids, data_len))
 		return -EFAULT;
-
 	return 0;
 }
 
@@ -5219,6 +5244,9 @@ static int sctp_getsockopt_active_key(struct sock *sk, int len,
 	struct sctp_authkeyid val;
 	struct sctp_association *asoc;
 
+	if (!sctp_auth_enable)
+		return -EACCES;
+
 	if (len < sizeof(struct sctp_authkeyid))
 		return -EINVAL;
 	if (copy_from_user(&val, optval, sizeof(struct sctp_authkeyid)))
@@ -5233,6 +5261,12 @@ static int sctp_getsockopt_active_key(struct sock *sk, int len,
 	else
 		val.scact_keynumber = sctp_sk(sk)->ep->active_key_id;
 
+	len = sizeof(struct sctp_authkeyid);
+	if (put_user(len, optlen))
+		return -EFAULT;
+	if (copy_to_user(optval, &val, len))
+		return -EFAULT;
+
 	return 0;
 }
 
@@ -5243,13 +5277,16 @@ static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len,
 	struct sctp_authchunks val;
 	struct sctp_association *asoc;
 	struct sctp_chunks_param *ch;
-	u32    num_chunks;
+	u32    num_chunks = 0;
 	char __user *to;
 
-	if (len <= sizeof(struct sctp_authchunks))
+	if (!sctp_auth_enable)
+		return -EACCES;
+
+	if (len < sizeof(struct sctp_authchunks))
 		return -EINVAL;
 
-	if (copy_from_user(&val, p, sizeof(struct sctp_authchunks)))
+	if (copy_from_user(&val, optval, sizeof(struct sctp_authchunks)))
 		return -EFAULT;
 
 	to = p->gauth_chunks;
@@ -5258,20 +5295,21 @@ static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len,
 		return -EINVAL;
 
 	ch = asoc->peer.peer_chunks;
+	if (!ch)
+		goto num;
 
 	/* See if the user provided enough room for all the data */
 	num_chunks = ntohs(ch->param_hdr.length) - sizeof(sctp_paramhdr_t);
 	if (len < num_chunks)
 		return -EINVAL;
 
-	len = num_chunks;
-	if (put_user(len, optlen))
+	if (copy_to_user(to, ch->chunks, num_chunks))
 		return -EFAULT;
+num:
+	len = sizeof(struct sctp_authchunks) + num_chunks;
+	if (put_user(len, optlen)) return -EFAULT;
 	if (put_user(num_chunks, &p->gauth_number_of_chunks))
 		return -EFAULT;
-	if (copy_to_user(to, ch->chunks, len))
-		return -EFAULT;
-
 	return 0;
 }
 
@@ -5282,13 +5320,16 @@ static int sctp_getsockopt_local_auth_chunks(struct sock *sk, int len,
 	struct sctp_authchunks val;
 	struct sctp_association *asoc;
 	struct sctp_chunks_param *ch;
-	u32    num_chunks;
+	u32    num_chunks = 0;
 	char __user *to;
 
-	if (len <= sizeof(struct sctp_authchunks))
+	if (!sctp_auth_enable)
+		return -EACCES;
+
+	if (len < sizeof(struct sctp_authchunks))
 		return -EINVAL;
 
-	if (copy_from_user(&val, p, sizeof(struct sctp_authchunks)))
+	if (copy_from_user(&val, optval, sizeof(struct sctp_authchunks)))
 		return -EFAULT;
 
 	to = p->gauth_chunks;
@@ -5301,17 +5342,21 @@ static int sctp_getsockopt_local_auth_chunks(struct sock *sk, int len,
 	else
 		ch = sctp_sk(sk)->ep->auth_chunk_list;
 
+	if (!ch)
+		goto num;
+
 	num_chunks = ntohs(ch->param_hdr.length) - sizeof(sctp_paramhdr_t);
-	if (len < num_chunks)
+	if (len < sizeof(struct sctp_authchunks) + num_chunks)
 		return -EINVAL;
 
-	len = num_chunks;
+	if (copy_to_user(to, ch->chunks, num_chunks))
+		return -EFAULT;
+num:
+	len = sizeof(struct sctp_authchunks) + num_chunks;
 	if (put_user(len, optlen))
 		return -EFAULT;
 	if (put_user(num_chunks, &p->gauth_number_of_chunks))
 		return -EFAULT;
-	if (copy_to_user(to, ch->chunks, len))
-		return -EFAULT;
 
 	return 0;
 }
-- 
1.5.2.5

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
<b>[prev in list] [next in list] [<font color="#c0c0c0">prev in thread</font>] [next in thread] </b>
</pre>
  </pre><br><center>
    Configure | 

    About |
    News |
    Donate |
    Add a list |
    Sponsors: 10East, KoreLogic, Terra-International, Chakpak.com
</center>
</body>
</html>
|参考资料

来源:BID
名称:31121
链接:http://www.securityfocus.com/bid/31121
来源:DEBIAN
名称:DSA-1636
链接:http://www.debian.org/security/2008/dsa-1636
来源:XF
名称:linux-kernel-sctpauthapi-dos(45189)
链接:http://xforce.iss.net/xforce/xfdb/45189
来源:UBUNTU
名称:USN-659-1
链接:http://www.ubuntu.com/usn/usn-659-1
来源:MISC
链接:http://www.trapkit.de/advisories/TKADV2008-007.txt
来源:SECTRACK
名称:1020854
链接:http://www.securitytracker.com/id?1020854
来源:BUGTRAQ
名称:20080911[TKADV2008-007]LinuxKernelSCTP-AUTHAPIInformationDisclosureVulnerabilityandNULLPointerDereferences
链接:http://www.securityfocus.com/archive/1/archive/1/496256/100/0/threaded
来源:REDHAT
名称:RHSA-2008:0857
链接:http://www.redhat.com/support/errata/RHSA-2008-0857.html
来源:MLIST
名称:[oss-security]20080926Re:CVE-2008-4113update:kernel:sctp:fixrandommemorydereferencewithSCTP_HMAC_IDENToption
链接:http://www.openwall.com/lists/oss-security/2008/09/26/6
来源:MLIST
名称:[oss-security]20080826Re:CVErequest:kernel:sctp:fixpotentialpanicsintheSCTP-AUTHAPI
链接:http://www.openwall.com/lists