oss-sec mailing list archives
Linux kernel: net/x25: a couple of overflows
From: kiyin(尹亮) <kiyin () tencent com>
Date: Sun, 15 Nov 2020 12:40:08 +0000
Hi, The .x25_addr[] address comes from the user and is not necessarily NUL terminated. This leads to a couple problems. 1) x25_bind read overflow https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/net/x25/af_x25.c?h=v5.9.3#n677 677 static int x25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) 678 { 679 struct sock *sk = sock->sk; 680 struct sockaddr_x25 *addr = (struct sockaddr_x25 *)uaddr; 681 int len, i, rc = 0; 682 683 if (addr_len != sizeof(struct sockaddr_x25) || 684 addr->sx25_family != AF_X25) { 685 rc = -EINVAL; 686 goto out; 687 } 688 689 /* check for the null_x25_address */ 690 if (strcmp(addr->sx25_addr.x25_addr, null_x25_address.x25_addr)) { 691 692 len = strlen(addr->sx25_addr.x25_addr); <----------------------- there is no check whether the addr->sx25_addr.x25_addr is null-terminated. if not, strlen will read out of sockaddr_x25 struct. 693 for (i = 0; i < len; i++) { 694 if (!isdigit(addr->sx25_addr.x25_addr[i])) { 695 rc = -EINVAL; 696 goto out; 697 } 698 } 699 } ...................................................................................................................................................................................................................... 713 } affected Linux kernel versions: 2.6.34~5.9.8 2) x25_addr_aton write overflow The call tree is: x25_connect() --> x25_write_internal() --> x25_addr_aton() https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/net/x25/af_x25.c?h=v5.9.3#n154 154 int x25_addr_aton(unsigned char *p, struct x25_address *called_addr, 155 struct x25_address *calling_addr) 156 { 157 unsigned int called_len, calling_len; 158 char *called, *calling; 159 int i; 160 161 called = called_addr->x25_addr; <----------------------- there is no check of x25->dest_addr, x25->source_addr in these three functions. 162 calling = calling_addr->x25_addr; 163 164 called_len = strlen(called); 165 calling_len = strlen(calling); <----------------------- the strlen in x25_addr_aton() will lead to write overflow the "addresses" buffer from x25_write_internal() 166 167 *p++ = (calling_len << 4) | (called_len << 0); 168 169 for (i = 0; i < (called_len + calling_len); i++) { 170 if (i < called_len) { 171 if (i % 2 != 0) { 172 *p |= (*called++ - '0') << 0; <----------------------- write overflow the "addresses" buffer from x25_write_internal() 173 p++; 174 } else { 175 *p = 0x00; 176 *p |= (*called++ - '0') << 4; 177 } 178 } else { 179 if (i % 2 != 0) { 180 *p |= (*calling++ - '0') << 0; 181 p++; 182 } else { 183 *p = 0x00; 184 *p |= (*calling++ - '0') << 4; 185 } 186 } 187 } 188 189 return 1 + (called_len + calling_len + 1) / 2; 190 } this security bug has been existed for 24 years since X.25 Project added first in Linux kernel 2.1.16. affected Linux kernel versions: 2.1.16~5.9.8 patch: The x25 protocol only allows 15 character addresses so putting a NUL terminator as the 16th character is safe. diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index 0bbb283f23c9..3180f15942fe 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c @@ -686,6 +686,8 @@ static int x25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) goto out; } + addr->sx25_addr.x25_addr[X25_ADDR_LEN - 1] = '\0'; + /* check for the null_x25_address */ if (strcmp(addr->sx25_addr.x25_addr, null_x25_address.x25_addr)) { @@ -779,6 +781,7 @@ static int x25_connect(struct socket *sock, struct sockaddr *uaddr, goto out; rc = -ENETUNREACH; + addr->sx25_addr.x25_addr[X25_ADDR_LEN - 1] = '\0'; rt = x25_get_route(&addr->sx25_addr); if (!rt) goto out; Regards, kiyin.
Current thread:
- Linux kernel: net/x25: a couple of overflows 尹亮 (Nov 15)