security/landlock/net.c

Source file repositories/reference/linux-study-clean/security/landlock/net.c

File Facts

System
Linux kernel
Corpus path
security/landlock/net.c
Extension
.c
Size
11084 bytes
Lines
380
Domain
Core OS
Bucket
Security And Isolation
Inferred role
Core OS: implementation source
Status
source implementation candidate

Why This File Exists

Core operating-system implementation surface: boot, tasks, memory, VFS, syscall-facing interfaces, synchronization, credentials, and isolation.

Dependency Surface

Detected Declarations

Annotated Snippet

if (sock_family == AF_INET6) {
				/*
				 * We cannot allow sending UDP datagrams to an
				 * explicit AF_UNSPEC address on IPv6 sockets,
				 * even if AF_UNSPEC is treated as "no address"
				 * on such sockets (so it should always be
				 * allowed).  That's because the socket's family
				 * can change under our feet (if another thread
				 * calls setsockopt(IPV6_ADDRFORM)) to IPv4,
				 * which would then treat AF_UNSPEC as AF_INET.
				 */
				audit_net.family = AF_UNSPEC;
				audit_net.sk = sock->sk;
				landlock_init_layer_masks(
					subject->domain, access_request,
					&layer_masks, LANDLOCK_KEY_NET_PORT);
				landlock_log_denial(
					subject,
					&(struct landlock_request){
						.type = LANDLOCK_REQUEST_NET_ACCESS,
						.audit.type =
							LSM_AUDIT_DATA_NET,
						.audit.u.net = &audit_net,
						.access = access_request,
						.layer_masks = &layer_masks,
					});
				return -EACCES;
			}
		} else if (access_request == LANDLOCK_ACCESS_NET_BIND_TCP ||
			   access_request == LANDLOCK_ACCESS_NET_BIND_UDP) {
			/*
			 * Binding to an AF_UNSPEC address is treated
			 * differently by IPv4 and IPv6 sockets. The socket's
			 * family may change under our feet due to
			 * setsockopt(IPV6_ADDRFORM), but that's ok: we either
			 * reject entirely for IPv6 or require
			 * %LANDLOCK_ACCESS_NET_BIND_TCP or
			 * %LANDLOCK_ACCESS_NET_BIND_UDP for IPv4, so it cannot
			 * be used to bypass the policy.
			 *
			 * IPv4 sockets map AF_UNSPEC to AF_INET for
			 * retrocompatibility for bind accesses, only if the
			 * address is INADDR_ANY (cf. __inet_bind). IPv6
			 * sockets always reject it.
			 *
			 * Checking the address is required to not wrongfully
			 * return -EACCES instead of -EAFNOSUPPORT or -EINVAL.
			 * We could return 0 and let the network stack handle
			 * these checks, but it is safer to return a proper
			 * error and test consistency thanks to kselftest.
			 */
			if (sock_family == AF_INET) {
				const struct sockaddr_in *const sockaddr =
					(struct sockaddr_in *)address;

				if (addrlen < sizeof(struct sockaddr_in))
					return -EINVAL;

				if (sockaddr->sin_addr.s_addr !=
				    htonl(INADDR_ANY))
					return -EAFNOSUPPORT;
			} else {
				if (addrlen < SIN6_LEN_RFC2133)
					return -EINVAL;
				else
					return -EAFNOSUPPORT;
			}
		} else {
			WARN_ON_ONCE(1);
		}
		/*
		 * AF_UNSPEC is treated as AF_INET only in
		 * bind(AF_UNSPEC+INADDR_ANY) on IPv4 sockets and when sending
		 * to AF_UNSPEC addresses on IPv4 sockets.
		 */
		fallthrough;
	case AF_INET: {
		const struct sockaddr_in *addr4;

		if (addrlen < sizeof(struct sockaddr_in))
			return -EINVAL;

		addr4 = (struct sockaddr_in *)address;
		port = addr4->sin_port;

		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 ||

Annotation

Implementation Notes