12

当 STREAM unix 域套接字的侦听积压已满时,connect(2)在大多数系统上使用 ECONNREFUSED 失败。它最好返回 EAGAIN。

原因在于,能够区分死套接字(文件系统中存在节点,但不再有进程监听)和完全积压的两种情况非常有用。我在移植一些 Linux 软件时遇到了这个问题,该软件有一些代码来清理死套接字,但如果代码可以通过向它们发送垃圾邮件来填充它们的积压工作而被欺骗来删除套接字,那么它就是一个安全漏洞。

只有 Linux 返回 EAGAIN;AIX、Solaris 和 Darwin 遵循 BSD 行为(仅在每个上进行了测试)。

POSIX 没有将 EAGAIN 列为 connect() ( link ) 的可能返回码,因此这里可能存在一些合规性问题。

让每个人都根据 Linux 进行更改的最佳途径是什么?我可以向 Oracle、Apple、FreeBSD PR 提交错误报告,然后在每个组织的邮件列表中解决它。还是我应该纠缠标准机构(奥斯汀集团)的某个人?即使优势很明显,尝试让每个人都在这里改变是否明智?

4

2 回答 2

2

无论您是否尝试更改标准,或更改供应商的实施方式connect(),我都认为从软件的角度来看,这不会有任何区别。ECONNREFUSED并且EAGAIN都应该被视为重试。

区分这两种情况可能允许您在客户端上编写更具体的诊断消息,但重试逻辑应该相同。即使侦听器当前不存在,它也可能最终存在,因此应尝试重试。

try_again:
    rc = connect(s, (void *)&addr, sizeof(addr));
    if (rc == 0) return connect_succeeded(s, &addr);
    switch (errno) {
    case EAGAIN:
    case ECONNREFUSED:
        if (should_try_again(retries++)) {
            goto try_again;
        }
        break;
    case EINTR:
        goto try_again;
    default:        
        break;
    }
    return connect_failed(s, errno);
于 2018-12-20T23:14:58.090 回答
0

与大多数事情一样,如果您可以说服消息来源采取行动,那么所有用户都必须遵守。因此,让 POSIX解决问题当然是最好的。然后所有的实现都必须遵守。

另一种解决方案是使用它工作的系统。即只使用 Linux 机器(在这种情况下)。同样在 Linux 中,您可以调整内核并使其以一种或另一种方式工作(这对于 BSD 也是可行的)。

现在,我对此事的看法,在我看来,这里的主要问题是一个恶意进程试图打开一个套接字来接收消息而不是预期的服务。我的问题是:这种情况多久发生一次?

如果您使用类似于 systemctl 的系统,您将运行一个且只有一个服务实例。如果您在服务中尝试打开AF_UNIX套接字,那么您确实是唯一尝试这样做的人。因此,删除文件不是问题。

如果您允许流氓软件在您的系统上运行(即它是公开的并且您有很多用户可以访问,就像过去人们会远程登录到服务器),那么您可能需要使用 TCP 或 UDP 连接。

最后,如果另一个软件能够打开该AF_UNIX套接字,我认为您无论如何都会遇到麻烦,因为您的服务可以在该流氓软件(1)删除您的套接字时运行,(2)bind()是新的,(3)您的新客户端现在正在与该流氓软件交谈,而不是您的服务,即使您仍在运行并侦听连接......在隐藏的文件套接字上。(请注意,旧客户端将继续与您的服务通信,任何重新连接的客户端都会与流氓软件通信)。

所以...你的问题在哪里?

于 2021-07-21T17:04:34.933 回答