From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by passt.top (Postfix) with ESMTP id 53EFB5A032B for ; Fri, 10 May 2024 12:52:03 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1715338322; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=0EO+4zd3Jx2UQN9OJ8brK9K0k2QipwJOl+AR0gjZ+V4=; b=Sjs0hujy1mobZPBmRN3nKgMpUDEka5wCHciKtWXqn5gYjn9x6dm12p5TMTsrxfNpkl3rQw asFdjdFkk4PERX6dh/lUvsUPPVQNlVc/sTRQO6ChThYIUxmYJdV7bXwtV7lb4KKaBl2nPt UBIg1fv1qbYWEu7NNedBoW2uQtN1LiQ= Received: from mail-ed1-f69.google.com (mail-ed1-f69.google.com [209.85.208.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-46-L5w0SyJpNs690gp8y3OwLw-1; Fri, 10 May 2024 06:45:45 -0400 X-MC-Unique: L5w0SyJpNs690gp8y3OwLw-1 Received: by mail-ed1-f69.google.com with SMTP id 4fb4d7f45d1cf-57268a481bbso1131507a12.2 for ; Fri, 10 May 2024 03:45:45 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1715337943; x=1715942743; h=content-transfer-encoding:mime-version:organization:references :in-reply-to:message-id:subject:cc:to:from:date:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=0EO+4zd3Jx2UQN9OJ8brK9K0k2QipwJOl+AR0gjZ+V4=; b=qP9S9hO+paGzWen9sb8CbMRPkzYSmtXA2lIe4p+n/iAuTJsc9DAk/s+kshR3hsJ5H8 KMbq+bgfcUIzC6JBqimbxxtbK4ccsQeHJPJH2SMaKGhLwfyCLCFqQsNnUD2IKlLzFgvJ GH5ESmw+zxPHS2D4bddJ7BTSXrxwPpTdXtE6yGqTcSrPBCuqlF8y9oFOScl7WWbCt7g8 uFlDzqta/hT5cP9gUVi39m1z0yiIEjWk8IWlQYVeSOyHisH3iefJyz+WEKodFZDnKNUX Uk8rpH2VcVmQZm6zvEx8D31KLXZypZVeplNbEHglc/yeOLa8a21O+REMhoQ3RcI8W/C7 etRg== X-Gm-Message-State: AOJu0YzN6C+4MUYf94mWqzNw+l7MOTIt1D1IXgFdbFapzGXXL8GwMIOE xgqoonvVs3DSXJiKPFgNKl2T0OBd7bRxOsha5xR/U4l1r3KaYbidDfj0DDfcfldnPYm44sykabC NOHhfDyi/LnW5TspV9qxJC5piJcRkL/J4vY/NTgC11fqmB9cyxN140cA2/HEXqA== X-Received: by 2002:a50:955c:0:b0:572:a16f:294 with SMTP id 4fb4d7f45d1cf-5734d67f7edmr1545881a12.30.1715337943314; Fri, 10 May 2024 03:45:43 -0700 (PDT) X-Google-Smtp-Source: AGHT+IHw/KB74A023krqigUotnfsbHnOiK+FCgtQbk6Ab461dyirBtG8sLhONDqBmaeIft8P4AA7yA== X-Received: by 2002:a50:955c:0:b0:572:a16f:294 with SMTP id 4fb4d7f45d1cf-5734d67f7edmr1545849a12.30.1715337942363; Fri, 10 May 2024 03:45:42 -0700 (PDT) Received: from maya.cloud.tilaa.com (maya.cloud.tilaa.com. [164.138.29.33]) by smtp.gmail.com with ESMTPSA id 4fb4d7f45d1cf-5733bea6a36sm1677558a12.12.2024.05.10.03.45.41 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Fri, 10 May 2024 03:45:41 -0700 (PDT) Date: Fri, 10 May 2024 12:45:08 +0200 From: Stefano Brivio To: Kangjing Huang Subject: Re: Guest namespace can access host ports via secondary interface addresses Message-ID: <20240510124508.288d874d@elisabeth> In-Reply-To: References: Organization: Red Hat X-Mailer: Claws Mail 4.2.0 (GTK 3.24.36; x86_64-pc-linux-gnu) MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit Message-ID-Hash: ZVJBFF7NQZRNU7JCFLEVKABD7VL44DGX X-Message-ID-Hash: ZVJBFF7NQZRNU7JCFLEVKABD7VL44DGX X-MailFrom: sbrivio@redhat.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: passt-user@passt.top X-Mailman-Version: 3.3.8 Precedence: list List-Id: "For passt users: support, questions and answers" Archived-At: Archived-At: List-Archive: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Hi Chaser, Thanks for your report! See my answer inline, below. On Thu, 9 May 2024 23:13:09 -0400 Kangjing Huang wrote: > Hi there, > > I was tweaking around pasta and its usage with podman, and I realized > that from pasta guest namespaces it is possible to access host ports > through the address of secondary interfaces on the host. > > Say I have two interfaces on host, with eth0 connecting to a gateway > and eth1 connected to another LAN: > > > $ # On host > > $ ifconfig eth0 > > eth0: flags=4163 mtu 1500 > > inet 192.168.1.2 netmask 255.255.255.0 broadcast 192.168.1.255 > > ... > > $ ifconfig eth1 > > eth1: flags=4163 mtu 1500 > > inet 192.168.110.1 netmask 255.255.255.0 broadcast 192.168.110.255 > > ... > > $ ip route > > default via 192.168.1.1 dev eth0 proto dhcp src 192.168.1.2 metric 1024 > > 192.168.1.0/24 dev eth0 proto kernel scope link src 192.168.1.2 metric 1024 > > 192.168.1.1 dev eth0 proto dhcp scope link src 192.168.1.2 metric 1024 > > 192.168.110.0/24 dev eth1 proto kernel scope link src 192.168.110.1 > > If there is some service started on host: > > > $ python -m http.server > > Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ... This binds your server to "any" address, so this is expected, more below. > >From a pasta namespace, it is impossible to access the host ports by > the address of the main interface: > > > $ pasta --config-net > > $ # Now in pasta namespace > > $ curl 192.168.1.2:8000 > > curl: (7) Failed to connect to 192.168.1.2 port 8000 after 0 ms: Couldn't connect to server This fails simply because your container also has address 192.168.1.2, by default, see: https://passt.top/#addresses You can use the address of the default gateway from the container to use this connection path. By the way, with default options (implying '--tcp-ns auto'), you can actually connect to a loopback address to reach your server on the host: $ python3 -m http.server 8082 Serving HTTP on 0.0.0.0 port 8082 (http://0.0.0.0:8082/) ... [...] and from the container: # curl 127.0.0.1:8082 [...] this is also reflected in the man page: auto Dynamically forward ports bound in the namespace. The list of ports is periodically derived (every second) from listening sockets reported by /proc/net/tcp and /proc/net/tcp6, see proc(5). and later, for --tcp-ns: -T, --tcp-ns spec Configure TCP port forwarding from target namespace to init namespace. spec is as described above for TCP. Default is auto. note that this was instead considered an unexpected (hence insecure) behaviour for Podman, which passes the '--tcp-ns none' option by default, as well as '--no-map-gw'. See also this discussion, referring to Podman integration, at: https://lists.podman.io/archives/list/podman@lists.podman.io/message/OG5U6Y23X5HFYETKB67YG4E6D2G3BMFJ/ > However I found that it is possible to do so by the address of the > secondary interface: > > > $ # In same pasta environment as above > > $ curl 192.168.110.1:8000 > > > > > > ... > > Is this an expected behavior? Yes, it is, so much that we even test for it: https://passt.top/passt/tree/test/pasta/tcp?id=1ba76c9e8c14b21d8c2c7cb71abdaa85feb96605#n34 in those test cases, "via tap" means using the tap interface pasta creates in the namespace, which is the same path you use by specifying the address of a secondary interface such as in your example. Sure, the host is in a different namespace from pasta's namespace, but the host can route traffic between them, just like it can route traffic from external hosts. What difference would it make if the client in your namespace could connect to an external proxy, that connects back to the host using your secondary interface? The only relevant bit for pasta's job here is to maintain the correct source address: $ python3 -m http.server 8082 Serving HTTP on 0.0.0.0 port 8082 (http://0.0.0.0:8082/) ... 1.2.3.1 - - [10/May/2024 12:13:17] "GET / HTTP/1.1" 200 - and not make that connection appearing as if it comes from a loopback device, because that would trick access control performed by services running on the host, or even a specific address binding. If I do this: $ python3 -m http.server -b 127.0.0.1 8082 Serving HTTP on 127.0.0.1 port 8082 (http://127.0.0.1:8082/) ... I won't be able to connect from the container using the local address of a non-remote interface, as expected: # curl 1.2.3.1:8082 curl: (28) Failed to connect to 1.2.3.1 port 8082 after 129895 ms: Couldn't connect to server See CVE-2021-20199 for why this matters (even though that's the reverse case). > I believe this is a security escape in > the container context, since containerized services can gain access to > unintended resources. Note that pasta doesn't implement containerisation, it just detaches a user and network namespace (again, by default) for convenience, but the resulting shell will even have access to the host filesystem. Podman implements containers, though, so it needs to care about this, and it passes non-default options, such as '--no-map-gw'. If it didn't, we would actually have what you describe, a container being able to access unintended resources, such as a localhost-bound server. By the way, for the future, if you believe you found a security issue, even if it's just a suspicion, please use the passt-sec@passt.top list instead, so that we can implement responsible disclosure if needed: https://passt.top/#security-and-vulnerability-reports but in this case, I really don't see the need. -- Stefano