为什么使用 memcpy 将数据复制到缓冲区会导致缓冲区溢出?
Why copying data into buffer using memcpy cause buffer to overflow?
我有这个函数,但有时它会在粗体行 memcpy(&(sin6->sin6_addr), &(inet->address[0] ), 16);
尝试在应用程序外部执行此功能,但从未引起问题。大家怎么看为什么应用程序会在这次调用时崩溃?
struct mariyo_inet {
uint8_t length; /* Generally 4 or 16- the length of the address, in bytes. */
uint8_t netmask; /* The number of significant bits in the address. */
uint8_t address[16]; /* The address itself. */
} __attribute__((packed));
void mariyo_inet_to_sockaddr(struct mariyo_inet *inet, struct sockaddr *sock, socklen_t *len, uint16_t port_ne)
{
if (inet->length == 16) {
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sock;
sin6->sin6_family = AF_INET6;
sin6->sin6_port = port_ne;
#ifndef __linux__
sin6->sin6_len = sizeof(*sin6);
#endif
if (len) *len = sizeof(*sin6);
**memcpy(&(sin6->sin6_addr), &(inet->address[0]), 16);**
} else if (inet->length == 4) {
struct sockaddr_in *sin = (struct sockaddr_in *) sock;
sin->sin_family = AF_INET;
sin->sin_port = port_ne;
#ifndef __linux__
sin->sin_len = sizeof (*sin);
#endif
if (len) *len = sizeof(*sin);
memcpy(&(sin->sin_addr),
&(inet->address[0]),
4);
}
}
这是应用程序堆栈跟踪,
#7 0x00000000007c94b9 in mariyo_inet_to_sockaddr (inet=inet@entry=0x7ff31a7da940, sock=sock@entry=0x7ff31a7da900, len=len@entry=0x7ff31a7da8f0, port_ne=port_ne@entry=0) at mariyo.c:4959
sin6 = 0x7ff31a7da900
#8 0x000000000062847a in enzyme_mconn_icmp_transmit_cb () at enzyme_mconn_icmp.c:522
ret = <optimized out>
mconn_icmp = <optimized out>
icmp_buf_len = <optimized out>
icmp_linear_buf = 0x61d000d6cec8 "E"
iph = 0x61d000d6cec8
iph_len = <optimized out>
icmp_hdr = <optimized out>
icmpreq_cookie = 0x604000845f68
icmpinfo = 0x619000355298
icmpfail_cookie = <optimized out>
ip_tlen = 1228
#9 0x0000000000603595 in enzyme_mconn_dequeue_data (mconn=mconn@entry=0x624010002b90, need_to_lock=0) at enzyme_mconn.c:547
ret = 0
tx_len = 1228
__FUNCTION__ = "enzyme_mconn_dequeue_data"
#10 0x0000000000608ee5 in enzyme_mconn_send_data_to_client (mconn=mconn@entry=0x624010002b90, buf=buf@entry=0x60e000188218, buf_len=buf_len@entry=1228, need_to_lock=need_to_lock@entry=1) at enzyme_mconn.c:668
res = 0
enq_len = <optimized out>
drop_len = <optimized out>
__FUNCTION__ = "enzyme_mconn_send_data_to_client"
#11 0x0000000000609b42 in enzyme_client_process_rx_data (mconn=mconn@entry=0x624010003148, buf=buf@entry=0x60e000188218, buf_len=buf_len@entry=1228) at enzyme_mconn.c:952
peer = 0x624010002b90
res = <optimized out>
__FUNCTION__ = "enzyme_client_process_rx_data"
ip_proto = <optimized out>
这是它对调用者的看法,
int mariyo_string_to_inet(const char *in_str, struct mariyo_inet *inet)
{
char tmp[51];
//
// filling tmp here from in_str
//
/* IPv4 + IPv6 in same address == bad */
if (saw_dot || saw_colon) {
if (saw_colon) {
/* IPv6 (Note: Supports IPv4 in IPv6) */
if (!inet_pton(AF_INET6, tmp, &(inet->address[0]))) {
//fprintf(stderr, "%s:%d: Could not parse IP address <%s>\n", __FILE__, __LINE__, tmp);
return 1;
}
if (!slash) netmask = 128;
if (netmask > 128) {
//fprintf(stderr, "%s:%d: Bad netmask > 128 on IP address <%s>\n", __FILE__, __LINE__, in_str);
return 1;
}
inet->length = 16;
}
return 0;
}
{
.....
socklen_t sock_len;
struct mariyo_inet inet_ip;
struct sockaddr sock_addr;
memset(&inet_ip, 0, sizeof(struct mariyo_inet));
mariyo_string_to_inet(icmpinfo->probe_info.dest_ip, &inet_ip);
memset(&sock_addr, 0, sizeof(struct sockaddr));
mariyo_inet_to_sockaddr(&inet_ip, &(sock_addr), &sock_len, 0);
....
}
struct sockaddr
不能保证足够大(而且通常不够大)以容纳 IPv6 地址。
改用struct sockaddr_storage
。
我有这个函数,但有时它会在粗体行 memcpy(&(sin6->sin6_addr), &(inet->address[0] ), 16); 尝试在应用程序外部执行此功能,但从未引起问题。大家怎么看为什么应用程序会在这次调用时崩溃?
struct mariyo_inet {
uint8_t length; /* Generally 4 or 16- the length of the address, in bytes. */
uint8_t netmask; /* The number of significant bits in the address. */
uint8_t address[16]; /* The address itself. */
} __attribute__((packed));
void mariyo_inet_to_sockaddr(struct mariyo_inet *inet, struct sockaddr *sock, socklen_t *len, uint16_t port_ne)
{
if (inet->length == 16) {
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) sock;
sin6->sin6_family = AF_INET6;
sin6->sin6_port = port_ne;
#ifndef __linux__
sin6->sin6_len = sizeof(*sin6);
#endif
if (len) *len = sizeof(*sin6);
**memcpy(&(sin6->sin6_addr), &(inet->address[0]), 16);**
} else if (inet->length == 4) {
struct sockaddr_in *sin = (struct sockaddr_in *) sock;
sin->sin_family = AF_INET;
sin->sin_port = port_ne;
#ifndef __linux__
sin->sin_len = sizeof (*sin);
#endif
if (len) *len = sizeof(*sin);
memcpy(&(sin->sin_addr),
&(inet->address[0]),
4);
}
}
这是应用程序堆栈跟踪,
#7 0x00000000007c94b9 in mariyo_inet_to_sockaddr (inet=inet@entry=0x7ff31a7da940, sock=sock@entry=0x7ff31a7da900, len=len@entry=0x7ff31a7da8f0, port_ne=port_ne@entry=0) at mariyo.c:4959
sin6 = 0x7ff31a7da900
#8 0x000000000062847a in enzyme_mconn_icmp_transmit_cb () at enzyme_mconn_icmp.c:522
ret = <optimized out>
mconn_icmp = <optimized out>
icmp_buf_len = <optimized out>
icmp_linear_buf = 0x61d000d6cec8 "E"
iph = 0x61d000d6cec8
iph_len = <optimized out>
icmp_hdr = <optimized out>
icmpreq_cookie = 0x604000845f68
icmpinfo = 0x619000355298
icmpfail_cookie = <optimized out>
ip_tlen = 1228
#9 0x0000000000603595 in enzyme_mconn_dequeue_data (mconn=mconn@entry=0x624010002b90, need_to_lock=0) at enzyme_mconn.c:547
ret = 0
tx_len = 1228
__FUNCTION__ = "enzyme_mconn_dequeue_data"
#10 0x0000000000608ee5 in enzyme_mconn_send_data_to_client (mconn=mconn@entry=0x624010002b90, buf=buf@entry=0x60e000188218, buf_len=buf_len@entry=1228, need_to_lock=need_to_lock@entry=1) at enzyme_mconn.c:668
res = 0
enq_len = <optimized out>
drop_len = <optimized out>
__FUNCTION__ = "enzyme_mconn_send_data_to_client"
#11 0x0000000000609b42 in enzyme_client_process_rx_data (mconn=mconn@entry=0x624010003148, buf=buf@entry=0x60e000188218, buf_len=buf_len@entry=1228) at enzyme_mconn.c:952
peer = 0x624010002b90
res = <optimized out>
__FUNCTION__ = "enzyme_client_process_rx_data"
ip_proto = <optimized out>
这是它对调用者的看法,
int mariyo_string_to_inet(const char *in_str, struct mariyo_inet *inet)
{
char tmp[51];
//
// filling tmp here from in_str
//
/* IPv4 + IPv6 in same address == bad */
if (saw_dot || saw_colon) {
if (saw_colon) {
/* IPv6 (Note: Supports IPv4 in IPv6) */
if (!inet_pton(AF_INET6, tmp, &(inet->address[0]))) {
//fprintf(stderr, "%s:%d: Could not parse IP address <%s>\n", __FILE__, __LINE__, tmp);
return 1;
}
if (!slash) netmask = 128;
if (netmask > 128) {
//fprintf(stderr, "%s:%d: Bad netmask > 128 on IP address <%s>\n", __FILE__, __LINE__, in_str);
return 1;
}
inet->length = 16;
}
return 0;
}
{
.....
socklen_t sock_len;
struct mariyo_inet inet_ip;
struct sockaddr sock_addr;
memset(&inet_ip, 0, sizeof(struct mariyo_inet));
mariyo_string_to_inet(icmpinfo->probe_info.dest_ip, &inet_ip);
memset(&sock_addr, 0, sizeof(struct sockaddr));
mariyo_inet_to_sockaddr(&inet_ip, &(sock_addr), &sock_len, 0);
....
}
struct sockaddr
不能保证足够大(而且通常不够大)以容纳 IPv6 地址。
改用struct sockaddr_storage
。