-
Notifications
You must be signed in to change notification settings - Fork 9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
TCP listen control #15
Comments
The problem is that (TCP) client is unable to use ports that are restricted for server, right? |
Yes, a client would not be allowed to bind to a specific port (for a newly initiated outgoing connection) if its domain handles |
For example, a use case where some kind of server process forks the client and the client 's available ports are limited due to the parent ruleset, right? |
If a new process is spawned per client connection, then the new process doesn't need any specific right to reply on the opened socket/file descriptor. Indeed, in this case, there is no call to A use case where a client process does an explicit Another use case is to use a specific network interface or IP address. |
But why in this case client's domain might need to handle |
They shouldn't unless we can specify a port range (#16). What would make more sense is to use |
@BoardzMaster, do you still want to work on this or should we let this open for others? |
Hi @l0kod. @sm1ling-knight he is my colleague and he works on this now. I will give him a hand. |
|
I guess you meant that when I wrote a test and this indeed works, whereas it should not. Could you please send a patch to the LSM mailing list (with me in CC), to explain the issue and propose a fix for Landlock. I guess this should mainly add a |
Ok, i'll do it.
I thought about adding another security plug function that would be called by the ip layer at the end of the listen() handler execution.
What do you mean by that? Binding on 0 port is also seems to be an issue, maybe we should add one more hook for |
Well, it might be seen as an LSM issue, so yes, it would be nice to add
Binding on port 0 translates to binding to an ephemeral port, see the This should be a fix of |
So, we have to make following things for managing actions with ephemeral ports, right?
|
Explicit binding on port 0 is OK. It was discussed with @BoardzMaster, it reflects the However, binding on an ephemeral port with The |
Thanks, got it) |
Hello, @l0kod ! Here you added this check in net.c: /*
* For compatibility reason, accept AF_UNSPEC for bind
* accesses (mapped to AF_INET) only if the address is
* INADDR_ANY (cf. __inet_bind). Checking the address is
* required to not wrongfully return -EACCES instead of
* -EAFNOSUPPORT.
*/
if (access_request == LANDLOCK_ACCESS_NET_BIND_TCP) {
const struct sockaddr_in *const sockaddr =
(struct sockaddr_in *)address;
if (sockaddr->sin_addr.s_addr != htonl(INADDR_ANY))
return -EAFNOSUPPORT;
} I didn't understand, why Landlock design requires to make this network stack level check (why return of |
Because network LSM hooks are called before any check on the network request (e.g. legitimate address or protocol), hooks implementations first need to check that the provided data is complete to avoid introducing bugs, and they should also return the appropriate error code (e.g. |
Am I correct in understanding that this only applies to not-socket argument checking? (e.g. E.g. inet stack restricts calling to We don't want to provide appropriate check in hook, because it's not related to TEST_F(port_specific, listen_bind)
{
int bind_fd, ret;
int port0, port1;
port0 = 1024;
port1 = 1025;
/* Adds a rule layer with bind and connect actions. */
if (variant->sandbox == TCP_SANDBOX) {
const struct landlock_ruleset_attr ruleset_attr = {
.handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP
};
const struct landlock_net_port_attr tcp_bind_port0 = {
.allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP,
.port = port0,
};
const struct landlock_net_port_attr tcp_bind_0 = {
.allowed_access = LANDLOCK_ACCESS_NET_BIND_TCP,
.port = 0,
};
int ruleset_fd;
ruleset_fd = landlock_create_ruleset(&ruleset_attr,
sizeof(ruleset_attr), 0);
ASSERT_LE(0, ruleset_fd);
/* Allow calling to listen(2) without explicit binding. */
EXPECT_EQ(0,
landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT,
&tcp_bind_0, 0));
EXPECT_EQ(0,
landlock_add_rule(ruleset_fd, LANDLOCK_RULE_NET_PORT,
&tcp_bind_port0, 0));
enforce_ruleset(_metadata, ruleset_fd);
EXPECT_EQ(0, close(ruleset_fd));
}
bind_fd = socket_variant(&self->srv0);
ASSERT_LE(0, bind_fd);
/* Port for bind_fd is chosen randomly by kernel. */
ret = listen(bind_fd, backlog);
EXPECT_EQ(0, ret);
set_port(&self->srv0, port1);
ret = bind_variant(bind_fd, &self->srv0);
EXPECT_EQ(-EINVAL, ret);
EXPECT_EQ(0, close(bind_fd));
} |
I think error codes should be consistent. In this case, we (and probably other LSMs) forgot to check socket's state and I think we should (if the additional check is not too complex, which should not be the case). Please, send a fix, we'll continue the discussion on the mailing list. I have two patches that should improve the current state for all LSMs. I'll refresh them and send them. Feel free to pick them or reply with your own checks. |
https://lore.kernel.org/r/20240327120036.233641-1-mic@digikod.net |
Hello, @l0kod !
|
Sure! Feel free to get inspiration or even copy some parts of these discussions as long as authors are in Cc. You should also use this tag for a related patch: |
LANDLOCK_ACCESS_NET_BIND_TCP
is useful to limit the scope of "bindable" ports to forbid a malicious sandboxed process to impersonate a legitimate server process. However,bind(2)
might be used by (TCP) clients to set the source port to a (legitimate) value. This use case is an issue because we cannot allow a whole range of ports (e.g., >= 1024).A
LANDLOCK_ACCESS_NET_LISTEN_TCP
would make more sense to control incoming connections to a specific port.Being able to restrict
listen(2)
may lead to a cover channel where the sandboxed process can infer some properties (e.g. port) from the socket file descriptior (e.g. if it was passed from another process). This doesn't seem to be a security issue though.Controlling accept(2) might not be worth it because:
See thread: https://lore.kernel.org/all/b4440d19-93b9-e234-007b-4fc4f987550b@digikod.net/
Related to #6
Cc @BoardzMaster
The text was updated successfully, but these errors were encountered: