Page MenuHomeFreeBSD

capsicum: Limit socket operations in capability mode
ClosedPublic

Authored by markj on Mar 25 2021, 4:57 PM.

Details

Summary

Plain socket(2) is permitted in capability mode. The reasoning seems to
be that unconnected, unbound sockets do not represent capabilities.
However, this is false is a few cases:

  • raw sockets can be used to receive data without being connected
  • routing sockets are automatically connected and provide access to routing tables
  • network interfaces are configured with ioctl() on a socket of any type

The system's interface list and routing tables are global namespaces
that should not be accessible to processes in capability mode, even if
they are privileged.

This change plugs these holes. In particular, protocols must now opt in
to allowing creation of a socket in capability mode. This is signaled
by setting PR_CAPATTACH in the protocol switch. Local and internet
sockets are permitted. The former because one may legitimately create
and bind a local socket to a relative path using bindat(2). The latter
because some existing code (e.g., capsicum tests) depends on this
ability.

ioctl() is handled by disallowing calls to ifioctl(), in_control() and
in6_control() from capability model. It may be useful at some point to
enable specific ioctls like we do for sysctls. Some testing with
capsicumized programs in the base system hasn't yet revealed any such
ioctls.

Test Plan
  • capsicum test suite
  • manual testing of some sandboxed programs, including dhclient, tcpdump and rtsold

Diff Detail

Repository
rG FreeBSD src repository
Lint
Automatic diff as part of commit; lint not applicable.
Unit
Automatic diff as part of commit; unit tests not applicable.

Event Timeline

markj requested review of this revision.Mar 25 2021, 4:57 PM
markj added a reviewer: capsicum.

@arichardson has done a bunch of recent work on capsicum-test, so CC for "... internet sockets are permitted ... because some existing code (e.g., capsicum tests) depends on this ability."

If this is only supported for the sake of tests (i.e., there is no actual use case for creating a PF_INET socket in a real capability mode sandbox) I'd rather we change the test.

@arichardson has done a bunch of recent work on capsicum-test, so CC for "... internet sockets are permitted ... because some existing code (e.g., capsicum tests) depends on this ability."

If this is only supported for the sake of tests (i.e., there is no actual use case for creating a PF_INET socket in a real capability mode sandbox) I'd rather we change the test.

I'm kind of on the fence about it. I don't think it creates much additional attack surface, and if it does, it could well be an issue regardless of whether socket creation is permitted or not. My reasoning is basically that unconnected, unbound PF_INET sockets shouldn't really represent capabilities. And the fact that software in the base system is affected gives me pause, even though so far it's just the test suite, so I took a more conservative approach.

Ping? I would like to commit this early next week if possible.

Some minor notes.
Thank you for working on this.

sys/kern/uipc_socket.c
529

Shouldn't we do this check as early as we can?

530

Should we return ECAPMODE ?

sys/net/if.c
2977

ECAPMODE?

sys/netinet/in.c
240

Shouldn't w do this check eariler?

markj marked 2 inline comments as done.

ENOTCAPABLE -> ECAPMODE

Sorry, uploaded a diff but didn't submit comments. :(

sys/kern/uipc_socket.c
529

I can reorder this with the preceding check, but that's it. Why is that preferable? Is to try and avoid providing information about protocol support in the kernel?

530

Oh, probably. I forgot about ECAPMODE.

sys/netinet/in.c
240

Assuming you mean reordering with the ifp == NULL check, sure, but again I don't really understand why.

LGTM.
I prefer this approach then forbidding whole socket syscall.

This revision is now accepted and ready to land.Apr 6 2021, 8:20 AM

This broke dhcpcd >_< We need some way of having a network configuration capability, not necessarily per-interface, but at least just some flag like SOCK_CONFIG (that can be only set on creation, outside of capability mode) that would allow ifioctls to work.

This broke dhcpcd >_< We need some way of having a network configuration capability, not necessarily per-interface, but at least just some flag like SOCK_CONFIG (that can be only set on creation, outside of capability mode) that would allow ifioctls to work.

Ok, I will revert part of the change for now I think. rtsold has a similar problem, but that is much easier to patch.

It looks like dhcpcd uses a global socket for all network configuration ioctls. I was thinking of using __specialfd to create a new kind of descriptor which permits network ioctls, but scoped to a specific interface.

One mitigation which I think doesn't require changes to dhcpcd would be to disallow network ioctls on sockets created by a process that has entered capability mode.

One mitigation which I think doesn't require changes to dhcpcd would be to disallow network ioctls on sockets created by a process that has entered capability mode.

This approach seems to work at least for basic usages of dhcpcd. Anyway, I will commit the revert shortly. Sorry for the breakage.