Skip to content

[BUG REPORT] TCP socket listen/close 方法存在资源泄露问题 #1520

@yilin0518

Description

@yilin0518

描述错误
在kernel/src/net/socket/inet/stream/inner.rs中,enum Initlistenclose 两个方法可能存在资源泄露问题。
listen方法中通过一个for循环来创建新的BoundInner,并将socket绑定到self中存储的IP地址上,BoundInner::bind会把socket添加到对应的iface中。

//kernel/src/net/socket/inet/stream/inner.rs: 143
        if let Err(err) = || -> Result<(), SystemError> {
            for _ in 0..(backlog - 1) {
                // -1 because the first one is already bound
                let new_listen = socket::inet::BoundInner::bind(
                    new_listen_smoltcp_socket(listen_addr),
                    listen_addr
                        .addr
                        .as_ref()
                        .unwrap_or(&smoltcp::wire::IpAddress::from(
                            smoltcp::wire::Ipv4Address::UNSPECIFIED,
                        )),
                    inner.netns(),
                )?;
                inners.push(new_listen);
            }
            Ok(())
        }() {
            return Err((Init::Bound((inner, local)), err));
        }

        if let Err(err) = inner.with_mut::<smoltcp::socket::tcp::Socket, _, _>(|socket| {
            socket
                .listen(listen_addr)
                .map_err(|_| SystemError::ECONNREFUSED)
        }) {
            return Err((Init::Bound((inner, local)), err));
        }

如果循环中途(或闭包末尾)返回 Err:

已经成功 bind的那些 BoundInner 都在 inners 里,接着直接被 drop,但由于 BoundInner 没有 Drop 释放逻辑,不会调用BoundInner::release将这些socket释放到
结果:这些 socket handle 永久残留在 IfaceCommon.sockets中。

同样,后面这段也存在同类问题:

if let Err(err) = inner.with_mut::<tcp::Socket, _, _>(|socket| {
    socket.listen(listen_addr).map_err(|_| SystemError::ECONNREFUSED)
}) {
    return Err((Init::Bound((inner, local)), err));
}

如果直接return Err((Init::Bound((inner, local)), err)),此时 inners 里可能已经存了多个 BoundInner,仍然会被丢弃并泄露。

另外,在Init::close的Bound 分支不 release,导致“关闭也清不掉”。
TcpSocket::do_close()Inner::Init(init) 分支会调用 init.close()

// kernel/src/net/socket/inet/stream/mod.rs:482
inner::Inner::Init(init) => {
    init.close();
}

但是在Init::close没有对self.inners中的每个inner调用inner.close(),可能导致资源没有被释放。

  • DragonOS版本(哈希值):a68030ea174daa4bbbdeca2994502185bc57930e

Metadata

Metadata

Assignees

No one assigned

    Labels

    bug-report这是一个bug报告(如果确认是一个bug,请管理人员添加`bug` label)

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions