From: "Mickaël Salaün" <mic@digikod.net>
To: Matthieu Buffet <matthieu@buffet.re>
Cc: "Günther Noack" <gnoack@google.com>,
linux-security-module@vger.kernel.org,
"Mikhail Ivanov" <ivanov.mikhail1@huawei-partners.com>,
konstantin.meskhidze@huawei.com, "Tingmao Wang" <m@maowtm.org>,
netdev@vger.kernel.org
Subject: Re: [PATCH v4 2/7] landlock: Add UDP connect() access control
Date: Fri, 22 May 2026 23:18:06 +0200 [thread overview]
Message-ID: <20260522.AhMei2meelee@digikod.net> (raw)
In-Reply-To: <20260502124306.3975990-3-matthieu@buffet.re>
On Sat, May 02, 2026 at 02:43:01PM +0200, Matthieu Buffet wrote:
> Add support for a second fine-grained UDP access right.
> This first half of LANDLOCK_ACCESS_NET_CONNECT_SEND_UDP controls the
> ability to set the remote port of a socket (via connect()). It will be
> useful for applications that send datagrams, and for some servers too
> (those creating per-client sockets, which want to receive traffic only
> from a specific address).
>
> Similarly as for bind(), this access control is performed when
> configuring sockets, not in hot code paths.
>
> Include detection of when autobind is about to be required, and check if
> the process would be allowed to call bind(0) explicitly. Autobind can
> only be performed when sending a first datagram, when connect()ing, and
> in some splice() EOF edge case which, afaiu, can only happen after a
> remote peer has been set (which is already covered).
>
> Signed-off-by: Matthieu Buffet <matthieu@buffet.re>
> ---
> include/uapi/linux/landlock.h | 19 +++++
> security/landlock/audit.c | 2 +
> security/landlock/limits.h | 2 +-
> security/landlock/net.c | 79 +++++++++++++++++----
> tools/testing/selftests/landlock/net_test.c | 5 +-
> 5 files changed, 92 insertions(+), 15 deletions(-)
> diff --git a/security/landlock/net.c b/security/landlock/net.c
> index f9ccb52e7d45..045881f81295 100644
> --- a/security/landlock/net.c
> +++ b/security/landlock/net.c
> @@ -68,16 +68,17 @@ static int current_check_access_socket(struct socket *const sock,
>
> switch (address->sa_family) {
> case AF_UNSPEC:
> - if (access_request == LANDLOCK_ACCESS_NET_CONNECT_TCP) {
> + if (access_request == LANDLOCK_ACCESS_NET_CONNECT_TCP ||
> + access_request == LANDLOCK_ACCESS_NET_CONNECT_SEND_UDP) {
> /*
> * Connecting to an address with AF_UNSPEC dissolves
> - * the TCP association, which have the same effect as
> - * closing the connection while retaining the socket
> - * object (i.e., the file descriptor). As for dropping
> - * privileges, closing connections is always allowed.
> - *
> - * For a TCP access control system, this request is
> - * legitimate. Let the network stack handle potential
> + * the remote association while retaining the socket
> + * object (i.e., the file descriptor). For TCP, it has
> + * the same effect as closing the connection. For UDP,
> + * it removes any preset remote address. As for
> + * dropping privileges, these actions are always
> + * allowed.
> + * Let the network stack handle potential
> * inconsistencies and return -EINVAL if needed.
> */
> return 0;
> @@ -134,7 +135,8 @@ static int current_check_access_socket(struct socket *const sock,
> addr4 = (struct sockaddr_in *)address;
> port = addr4->sin_port;
>
> - if (access_request == LANDLOCK_ACCESS_NET_CONNECT_TCP) {
> + if (access_request == LANDLOCK_ACCESS_NET_CONNECT_TCP ||
> + access_request == LANDLOCK_ACCESS_NET_CONNECT_SEND_UDP) {
> audit_net.dport = port;
> audit_net.v4info.daddr = addr4->sin_addr.s_addr;
> } else if (access_request == LANDLOCK_ACCESS_NET_BIND_TCP ||
> @@ -157,7 +159,8 @@ static int current_check_access_socket(struct socket *const sock,
> addr6 = (struct sockaddr_in6 *)address;
> port = addr6->sin6_port;
>
> - if (access_request == LANDLOCK_ACCESS_NET_CONNECT_TCP) {
> + if (access_request == LANDLOCK_ACCESS_NET_CONNECT_TCP ||
> + access_request == LANDLOCK_ACCESS_NET_CONNECT_SEND_UDP) {
> audit_net.dport = port;
> audit_net.v6info.daddr = addr6->sin6_addr;
> } else if (access_request == LANDLOCK_ACCESS_NET_BIND_TCP ||
> @@ -213,6 +216,50 @@ static int current_check_access_socket(struct socket *const sock,
> return -EACCES;
> }
>
> +static int current_check_autobind_udp_socket(struct socket *const sock)
> +{
> + struct sockaddr_storage port0 = { 0 };
struct sockaddr_storage port0 = {};
> +
> + /*
> + * On UDP sockets, if a local port has not already been bound,
> + * calling connect() or sending a first datagram has the side
> + * effect of autobinding an ephemeral port: we also have to check
> + * that the process would have had the right to bind(0) explicitly.
> + * Note: socket is not locked, so another thread could do an
> + * explicit bind(!=0) on this socket, changing inet_num to non-zero
> + * after we read it, but this would only have us enforce an
> + * additional bind(0) access check and would not bypass policy.
> + */
> + if (inet_sk(sock->sk)->inet_num != 0)
> + return 0;
> +
> + /*
> + * Construct a struct sockaddr* with port 0 to pretend the
> + * process tried to bind() on that address.
> + */
> + port0.ss_family = sock->sk->__sk_common.skc_family;
> + switch (port0.ss_family) {
> + case AF_INET: {
> + ((struct sockaddr_in *)&port0)->sin_port = 0;
Why is this useful? The struct is already initialized to 0.
> + break;
> + }
> +
> +#if IS_ENABLED(CONFIG_IPV6)
> + case AF_INET6: {
> + ((struct sockaddr_in6 *)&port0)->sin6_port = 0;
Same question.
> + break;
> + }
> +#endif /* IS_ENABLED(CONFIG_IPV6) */
> +
> + default:
> + return 0;
> + }
> +
> + return current_check_access_socket(sock, (struct sockaddr *)&port0,
> + sizeof(port0),
> + LANDLOCK_ACCESS_NET_BIND_UDP);
> +}
next prev parent reply other threads:[~2026-05-22 21:18 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-02 12:42 [PATCH v4 0/7] landlock: Add UDP access control support Matthieu Buffet
2026-05-02 12:43 ` [PATCH v4 1/7] landlock: Add UDP bind() access control Matthieu Buffet
2026-05-02 12:43 ` [PATCH v4 2/7] landlock: Add UDP connect() " Matthieu Buffet
2026-05-22 21:10 ` Mickaël Salaün
2026-05-22 21:18 ` Mickaël Salaün [this message]
2026-05-02 12:43 ` [PATCH v4 3/7] landlock: Add UDP send " Matthieu Buffet
2026-05-22 21:10 ` Mickaël Salaün
2026-05-02 12:43 ` [PATCH v4 4/7] selftests/landlock: Add UDP bind/connect tests Matthieu Buffet
2026-05-02 12:43 ` [PATCH v4 5/7] selftests/landlock: Add tests for sendmsg() Matthieu Buffet
2026-05-02 12:43 ` [PATCH v4 6/7] samples/landlock: Add sandboxer UDP access control Matthieu Buffet
2026-05-02 12:43 ` [PATCH v4 7/7] landlock: Add documentation for UDP support Matthieu Buffet
2026-05-22 21:11 ` Mickaël Salaün
2026-05-06 15:33 ` [PATCH v4 0/7] landlock: Add UDP access control support Günther Noack
2026-05-07 22:11 ` Matthieu Buffet
2026-05-22 21:08 ` Mickaël Salaün
2026-05-25 20:28 ` Mickaël Salaün
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260522.AhMei2meelee@digikod.net \
--to=mic@digikod.net \
--cc=gnoack@google.com \
--cc=ivanov.mikhail1@huawei-partners.com \
--cc=konstantin.meskhidze@huawei.com \
--cc=linux-security-module@vger.kernel.org \
--cc=m@maowtm.org \
--cc=matthieu@buffet.re \
--cc=netdev@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.