【问题标题】:Why copying data into buffer using memcpy cause buffer to overflow?为什么使用 memcpy 将数据复制到缓冲区会导致缓冲区溢出?
【发布时间】:2022-02-04 11:39:11
【问题描述】:

我有这个函数,偶尔它会在粗体行中导致缓冲区溢出错误,即 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);
    ....
}

【问题讨论】:

  • inet-&gt;length == 16 为真时,sock 保证 是否指向sockaddr_in6 结构?你怎么称呼这个mariyo_inet_to_sockaddr函数?
  • 编辑了问题以添加函数调用者的外观。
  • 嗯,当您使用memcpy 时,您是在复制到缓冲区,对吗?这就是目的?那么问题来了,为什么复制到缓冲区会导致缓冲区溢出呢?也许......因为它对复制的内容不够大?这似乎不是您的实际问题;请尝试更清楚地传达它。
  • 明白了。谢谢!

标签: c memory buffer-overflow


【解决方案1】:

struct sockaddr 不能保证足够大(通常不会)来容纳 IPv6 地址。

请改用struct sockaddr_storage

【讨论】:

  • 可爱。谢谢!
猜你喜欢
  • 1970-01-01
  • 2013-02-17
  • 2021-06-15
  • 1970-01-01
  • 1970-01-01
  • 2010-10-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多