| From a12006354213203bf7fc2114286df9cbe848e234 Mon Sep 17 00:00:00 2001 |
| From: Vlad Yasevich <vladislav.yasevich@hp.com> |
| Date: Wed, 27 Aug 2008 22:41:00 -0700 |
| Subject: sctp: fix potential panics in the SCTP-AUTH API. |
| |
| From: Vlad Yasevich <vladislav.yasevich@hp.com> |
| |
| [ Upstream commit 5e739d1752aca4e8f3e794d431503bfca3162df4 ] |
| |
| 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> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| |
| --- |
| net/sctp/endpointola.c | 4 +- |
| net/sctp/socket.c | 85 +++++++++++++++++++++++++++++++++++++------------ |
| 2 files changed, 67 insertions(+), 22 deletions(-) |
| |
| --- a/net/sctp/endpointola.c |
| +++ b/net/sctp/endpointola.c |
| @@ -103,6 +103,7 @@ static struct sctp_endpoint *sctp_endpoi |
| |
| /* 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_endpoi |
| if (sctp_addip_enable) { |
| auth_chunks->chunks[0] = SCTP_CID_ASCONF; |
| auth_chunks->chunks[1] = SCTP_CID_ASCONF_ACK; |
| - auth_chunks->param_hdr.length = |
| - htons(sizeof(sctp_paramhdr_t) + 2); |
| + auth_chunks->param_hdr.length += htons(2); |
| } |
| } |
| |
| --- a/net/sctp/socket.c |
| +++ b/net/sctp/socket.c |
| @@ -2983,6 +2983,9 @@ static int sctp_setsockopt_auth_chunk(st |
| { |
| 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)) |
| @@ -3013,6 +3016,9 @@ static int sctp_setsockopt_hmac_ident(st |
| struct sctp_hmacalgo *hmacs; |
| int err; |
| |
| + if (!sctp_auth_enable) |
| + return -EACCES; |
| + |
| if (optlen < sizeof(struct sctp_hmacalgo)) |
| return -EINVAL; |
| |
| @@ -3051,6 +3057,9 @@ static int sctp_setsockopt_auth_key(stru |
| struct sctp_association *asoc; |
| int ret; |
| |
| + if (!sctp_auth_enable) |
| + return -EACCES; |
| + |
| if (optlen <= sizeof(struct sctp_authkey)) |
| return -EINVAL; |
| |
| @@ -3088,6 +3097,9 @@ static int sctp_setsockopt_active_key(st |
| 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)) |
| @@ -3113,6 +3125,9 @@ static int sctp_setsockopt_del_key(struc |
| 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)) |
| @@ -5073,19 +5088,29 @@ static int sctp_getsockopt_maxburst(stru |
| 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; |
| } |
| |
| @@ -5095,6 +5120,9 @@ static int sctp_getsockopt_active_key(st |
| 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))) |
| @@ -5109,6 +5137,12 @@ static int sctp_getsockopt_active_key(st |
| 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; |
| } |
| |
| @@ -5119,13 +5153,16 @@ static int sctp_getsockopt_peer_auth_chu |
| 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; |
| @@ -5134,20 +5171,21 @@ static int sctp_getsockopt_peer_auth_chu |
| 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; |
| } |
| |
| @@ -5158,13 +5196,16 @@ static int sctp_getsockopt_local_auth_ch |
| 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; |
| @@ -5177,17 +5218,21 @@ static int sctp_getsockopt_local_auth_ch |
| 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; |
| } |