Skip to content
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

Call to bind(sock, addr) on core:sys/linux with a Sock_Addr_In always returns EINVAL #4612

Closed
fnknda opened this issue Dec 22, 2024 · 0 comments · Fixed by #4613
Closed

Call to bind(sock, addr) on core:sys/linux with a Sock_Addr_In always returns EINVAL #4612

fnknda opened this issue Dec 22, 2024 · 0 comments · Fixed by #4613

Comments

@fnknda
Copy link
Contributor

fnknda commented Dec 22, 2024

Context

When trying to call bind(sock, addr), defined in the package core:sys/linux, using a Sock_Addr_In as an address, the syscall to bind always returns EINVAL. This is because the Sock_Addr_In structure is not properly defined.

On Linux's source code, the sockaddr_in structure (defined here) have a sin_zero field that pads the size of the structure to be, at least, the size of struct sockaddr (defined here), which turns out to be 16 bytes (a short integer + an array of 14 bytes).

On an IPv4 bind, Linux expects the address to be, at least, the size of the previously defined sockaddr_in (here). If it doesn't have the minimum size (16 bytes), the code fails.

Sock_Addr_In (here) currently have a size of 8 bytes (2 short integers + an array of 4 bytes), so it will always fail this check.

The core:net's calls to linux.bind on the functions _bind (here) and _listen_tcp (here) get around this because of the way they unwrap the address structure from the endpoint. The _unwrap_os_addr (here) always returns a type Sock_Addr_Any, which has a size of 110 bytes, due to being a union with a Sock_Addr_Un.

Given that the bind syscall only checks for an addr_len smaller than sockaddr_in, not bigger, these calls to bind won't fail.

Thus, Sock_Addr_In needs to have the sin_zero padding.

Expected Behavior

The bind syscall returning successfully

Current Behavior

As seen with the snippet bellow, the current call to bind always returns an EINVAL error.

Failure Information (for bugs)

Steps to Reproduce

Compile the following code with odin build test.odin -file, then run using strace (strace test).

package main

import "core:sys/linux"

main :: proc()
{
	using linux

	sock, errno := socket(Address_Family.INET, Socket_Type.STREAM, {}, Protocol.TCP)
	if errno != Errno.NONE do panic("linux.socket")
	defer close(sock)

	addr := Sock_Addr_In{ sin_family=Address_Family.INET }
	errno = bind(sock, &addr)                              // Fails here
	if errno != Errno.NONE do panic("linux.bind")          // Then panics here
}

Failure Logs

Snippet of strace's output

socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) = 3
bind(3, {sa_family=AF_INET, sa_data="\0\0\0\0\0\0"}, 8) = -1 EINVAL (Invalid argument)
write(2, "/home/fukuda/tmp/test.odin", 26/home/fukuda/tmp/test.odin) = 26
write(2, "(", 1()                        = 1
write(2, "15", 215)                       = 2
write(2, ":", 1:)                        = 1
write(2, "28", 228)                       = 2
write(2, ")", 1))                        = 1
write(2, " ", 1 )                        = 1
write(2, "panic", 5panic)                    = 5
write(2, ": ", 2: )                       = 2
write(2, "linux.bind", 10linux.bind)              = 10
write(2, "\n", 1
)                       = 1
--- SIGILL {si_signo=SIGILL, si_code=ILL_ILLOPN, si_addr=0x403e05} ---
+++ killed by SIGILL (core dumped) +++
Illegal instruction (core dumped)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant