mirror of
https://github.com/RGBCube/serenity
synced 2025-05-30 22:08:12 +00:00
Kernel: Use Userspace<T> for the getsockopt syscall and Socket interface
The way getsockopt is implemented for socket types requires us to push down Userspace<T> using into those interfaces. This change does so, and utilizes proper copy implementations instead of the kind of haphazard pointer dereferencing that was occurring there before.
This commit is contained in:
parent
6920d5f423
commit
30b2c0dc85
9 changed files with 69 additions and 43 deletions
|
@ -306,8 +306,8 @@ struct SC_getsockopt_params {
|
||||||
int sockfd;
|
int sockfd;
|
||||||
int level;
|
int level;
|
||||||
int option;
|
int option;
|
||||||
void* value;
|
Userspace<void*> value;
|
||||||
socklen_t* value_size;
|
Userspace<socklen_t*> value_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SC_setsockopt_params {
|
struct SC_setsockopt_params {
|
||||||
|
|
|
@ -451,16 +451,22 @@ KResult IPv4Socket::setsockopt(int level, int option, Userspace<const void*> use
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
KResult IPv4Socket::getsockopt(FileDescription& description, int level, int option, void* value, socklen_t* value_size)
|
KResult IPv4Socket::getsockopt(FileDescription& description, int level, int option, Userspace<void*> value, Userspace<socklen_t*> value_size)
|
||||||
{
|
{
|
||||||
if (level != IPPROTO_IP)
|
if (level != IPPROTO_IP)
|
||||||
return Socket::getsockopt(description, level, option, value, value_size);
|
return Socket::getsockopt(description, level, option, value, value_size);
|
||||||
|
|
||||||
|
socklen_t size;
|
||||||
|
if (!Process::current()->validate_read_and_copy_typed(&size, value_size))
|
||||||
|
return KResult(-EFAULT);
|
||||||
|
|
||||||
switch (option) {
|
switch (option) {
|
||||||
case IP_TTL:
|
case IP_TTL:
|
||||||
if (*value_size < sizeof(int))
|
if (size < sizeof(int))
|
||||||
return KResult(-EINVAL);
|
return KResult(-EINVAL);
|
||||||
*(int*)value = m_ttl;
|
copy_to_user(static_ptr_cast<int*>(value), (int*)&m_ttl);
|
||||||
|
size = sizeof(int);
|
||||||
|
copy_to_user(value_size, &size);
|
||||||
return KSuccess;
|
return KSuccess;
|
||||||
default:
|
default:
|
||||||
return KResult(-ENOPROTOOPT);
|
return KResult(-ENOPROTOOPT);
|
||||||
|
|
|
@ -61,7 +61,7 @@ public:
|
||||||
virtual KResultOr<size_t> sendto(FileDescription&, const void*, size_t, int, const sockaddr*, socklen_t) override;
|
virtual KResultOr<size_t> sendto(FileDescription&, const void*, size_t, int, const sockaddr*, socklen_t) override;
|
||||||
virtual KResultOr<size_t> recvfrom(FileDescription&, void*, size_t, int flags, sockaddr*, socklen_t*) override;
|
virtual KResultOr<size_t> recvfrom(FileDescription&, void*, size_t, int flags, sockaddr*, socklen_t*) override;
|
||||||
virtual KResult setsockopt(int level, int option, Userspace<const void*>, socklen_t) override;
|
virtual KResult setsockopt(int level, int option, Userspace<const void*>, socklen_t) override;
|
||||||
virtual KResult getsockopt(FileDescription&, int level, int option, void*, socklen_t*) override;
|
virtual KResult getsockopt(FileDescription&, int level, int option, Userspace<void*>, Userspace<socklen_t*>) override;
|
||||||
|
|
||||||
virtual int ioctl(FileDescription&, unsigned request, FlatPtr arg) override;
|
virtual int ioctl(FileDescription&, unsigned request, FlatPtr arg) override;
|
||||||
|
|
||||||
|
|
|
@ -344,24 +344,30 @@ String LocalSocket::absolute_path(const FileDescription& description) const
|
||||||
return builder.to_string();
|
return builder.to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
KResult LocalSocket::getsockopt(FileDescription& description, int level, int option, void* value, socklen_t* value_size)
|
KResult LocalSocket::getsockopt(FileDescription& description, int level, int option, Userspace<void*> value, Userspace<socklen_t*> value_size)
|
||||||
{
|
{
|
||||||
if (level != SOL_SOCKET)
|
if (level != SOL_SOCKET)
|
||||||
return Socket::getsockopt(description, level, option, value, value_size);
|
return Socket::getsockopt(description, level, option, value, value_size);
|
||||||
|
|
||||||
|
|
||||||
|
socklen_t size;
|
||||||
|
if (!Process::current()->validate_read_and_copy_typed(&size, value_size))
|
||||||
|
return KResult(-EFAULT);
|
||||||
|
|
||||||
switch (option) {
|
switch (option) {
|
||||||
case SO_PEERCRED: {
|
case SO_PEERCRED: {
|
||||||
if (*value_size < sizeof(ucred))
|
if (size < sizeof(ucred))
|
||||||
return KResult(-EINVAL);
|
return KResult(-EINVAL);
|
||||||
auto& creds = *(ucred*)value;
|
|
||||||
switch (role(description)) {
|
switch (role(description)) {
|
||||||
case Role::Accepted:
|
case Role::Accepted:
|
||||||
creds = m_origin;
|
copy_to_user(static_ptr_cast<ucred*>(value), &m_origin);
|
||||||
*value_size = sizeof(ucred);
|
size = sizeof(ucred);
|
||||||
|
copy_to_user(value_size, &size);
|
||||||
return KSuccess;
|
return KSuccess;
|
||||||
case Role::Connected:
|
case Role::Connected:
|
||||||
creds = m_acceptor;
|
copy_to_user(static_ptr_cast<ucred*>(value), &m_acceptor);
|
||||||
*value_size = sizeof(ucred);
|
size = sizeof(ucred);
|
||||||
|
copy_to_user(value_size, &size);
|
||||||
return KSuccess;
|
return KSuccess;
|
||||||
case Role::Connecting:
|
case Role::Connecting:
|
||||||
return KResult(-ENOTCONN);
|
return KResult(-ENOTCONN);
|
||||||
|
|
|
@ -62,7 +62,7 @@ public:
|
||||||
virtual bool can_write(const FileDescription&, size_t) const override;
|
virtual bool can_write(const FileDescription&, size_t) const override;
|
||||||
virtual KResultOr<size_t> sendto(FileDescription&, const void*, size_t, int, const sockaddr*, socklen_t) override;
|
virtual KResultOr<size_t> sendto(FileDescription&, const void*, size_t, int, const sockaddr*, socklen_t) override;
|
||||||
virtual KResultOr<size_t> recvfrom(FileDescription&, void*, size_t, int flags, sockaddr*, socklen_t*) override;
|
virtual KResultOr<size_t> recvfrom(FileDescription&, void*, size_t, int flags, sockaddr*, socklen_t*) override;
|
||||||
virtual KResult getsockopt(FileDescription&, int level, int option, void*, socklen_t*) override;
|
virtual KResult getsockopt(FileDescription&, int level, int option, Userspace<void*>, Userspace<socklen_t*>) override;
|
||||||
virtual KResult chown(FileDescription&, uid_t, gid_t) override;
|
virtual KResult chown(FileDescription&, uid_t, gid_t) override;
|
||||||
virtual KResult chmod(FileDescription&, mode_t) override;
|
virtual KResult chmod(FileDescription&, mode_t) override;
|
||||||
|
|
||||||
|
|
|
@ -137,40 +137,52 @@ KResult Socket::setsockopt(int level, int option, Userspace<const void*> user_va
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
KResult Socket::getsockopt(FileDescription&, int level, int option, void* value, socklen_t* value_size)
|
KResult Socket::getsockopt(FileDescription&, int level, int option, Userspace<void*> value, Userspace<socklen_t*> value_size)
|
||||||
{
|
{
|
||||||
|
socklen_t size;
|
||||||
|
if (!Process::current()->validate_read_and_copy_typed(&size, value_size))
|
||||||
|
return KResult(-EFAULT);
|
||||||
|
|
||||||
ASSERT(level == SOL_SOCKET);
|
ASSERT(level == SOL_SOCKET);
|
||||||
switch (option) {
|
switch (option) {
|
||||||
case SO_SNDTIMEO:
|
case SO_SNDTIMEO:
|
||||||
if (*value_size < sizeof(timeval))
|
if (size < sizeof(timeval))
|
||||||
return KResult(-EINVAL);
|
return KResult(-EINVAL);
|
||||||
*(timeval*)value = m_send_timeout;
|
copy_to_user(static_ptr_cast<timeval*>(value), &m_send_timeout);
|
||||||
*value_size = sizeof(timeval);
|
size = sizeof(timeval);
|
||||||
|
copy_to_user(value_size, &size);
|
||||||
return KSuccess;
|
return KSuccess;
|
||||||
case SO_RCVTIMEO:
|
case SO_RCVTIMEO:
|
||||||
if (*value_size < sizeof(timeval))
|
if (size < sizeof(timeval))
|
||||||
return KResult(-EINVAL);
|
return KResult(-EINVAL);
|
||||||
*(timeval*)value = m_receive_timeout;
|
copy_to_user(static_ptr_cast<timeval*>(value), &m_receive_timeout);
|
||||||
*value_size = sizeof(timeval);
|
size = sizeof(timeval);
|
||||||
|
copy_to_user(value_size, &size);
|
||||||
return KSuccess;
|
return KSuccess;
|
||||||
case SO_ERROR:
|
case SO_ERROR: {
|
||||||
if (*value_size < sizeof(int))
|
if (size < sizeof(int))
|
||||||
return KResult(-EINVAL);
|
return KResult(-EINVAL);
|
||||||
dbg() << "getsockopt(SO_ERROR): FIXME!";
|
dbg() << "getsockopt(SO_ERROR): FIXME!";
|
||||||
*(int*)value = 0;
|
int errno = 0;
|
||||||
*value_size = sizeof(int);
|
copy_to_user(static_ptr_cast<int*>(value), &errno);
|
||||||
|
size = sizeof(int);
|
||||||
|
copy_to_user(value_size, &size);
|
||||||
return KSuccess;
|
return KSuccess;
|
||||||
|
}
|
||||||
case SO_BINDTODEVICE:
|
case SO_BINDTODEVICE:
|
||||||
if (*value_size < IFNAMSIZ)
|
if (size < IFNAMSIZ)
|
||||||
return KResult(-EINVAL);
|
return KResult(-EINVAL);
|
||||||
if (m_bound_interface) {
|
if (m_bound_interface) {
|
||||||
const auto& name = m_bound_interface->name();
|
const auto& name = m_bound_interface->name();
|
||||||
auto length = name.length() + 1;
|
auto length = name.length() + 1;
|
||||||
memcpy(value, name.characters(), length);
|
copy_to_user(static_ptr_cast<char*>(value), name.characters(), length);
|
||||||
*value_size = length;
|
size = length;
|
||||||
|
copy_to_user(value_size, &size);
|
||||||
return KSuccess;
|
return KSuccess;
|
||||||
} else {
|
} else {
|
||||||
*value_size = 0;
|
size = 0;
|
||||||
|
copy_to_user(value_size, &size);
|
||||||
|
|
||||||
return KResult(-EFAULT);
|
return KResult(-EFAULT);
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -111,7 +111,7 @@ public:
|
||||||
virtual KResultOr<size_t> recvfrom(FileDescription&, void*, size_t, int flags, sockaddr*, socklen_t*) = 0;
|
virtual KResultOr<size_t> recvfrom(FileDescription&, void*, size_t, int flags, sockaddr*, socklen_t*) = 0;
|
||||||
|
|
||||||
virtual KResult setsockopt(int level, int option, Userspace<const void*>, socklen_t);
|
virtual KResult setsockopt(int level, int option, Userspace<const void*>, socklen_t);
|
||||||
virtual KResult getsockopt(FileDescription&, int level, int option, void*, socklen_t*);
|
virtual KResult getsockopt(FileDescription&, int level, int option, Userspace<void*>, Userspace<socklen_t*>);
|
||||||
|
|
||||||
pid_t origin_pid() const { return m_origin.pid; }
|
pid_t origin_pid() const { return m_origin.pid; }
|
||||||
uid_t origin_uid() const { return m_origin.uid; }
|
uid_t origin_uid() const { return m_origin.uid; }
|
||||||
|
|
|
@ -295,7 +295,7 @@ public:
|
||||||
int sys$shutdown(int sockfd, int how);
|
int sys$shutdown(int sockfd, int how);
|
||||||
ssize_t sys$sendto(const Syscall::SC_sendto_params*);
|
ssize_t sys$sendto(const Syscall::SC_sendto_params*);
|
||||||
ssize_t sys$recvfrom(const Syscall::SC_recvfrom_params*);
|
ssize_t sys$recvfrom(const Syscall::SC_recvfrom_params*);
|
||||||
int sys$getsockopt(const Syscall::SC_getsockopt_params*);
|
int sys$getsockopt(Userspace<const Syscall::SC_getsockopt_params*>);
|
||||||
int sys$setsockopt(Userspace<const Syscall::SC_setsockopt_params*>);
|
int sys$setsockopt(Userspace<const Syscall::SC_setsockopt_params*>);
|
||||||
int sys$getsockname(Userspace<const Syscall::SC_getsockname_params*>);
|
int sys$getsockname(Userspace<const Syscall::SC_getsockname_params*>);
|
||||||
int sys$getpeername(Userspace<const Syscall::SC_getpeername_params*>);
|
int sys$getpeername(Userspace<const Syscall::SC_getpeername_params*>);
|
||||||
|
|
|
@ -316,22 +316,24 @@ int Process::sys$getpeername(Userspace<const Syscall::SC_getpeername_params*> us
|
||||||
return get_sock_or_peer_name<false>(params);
|
return get_sock_or_peer_name<false>(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Process::sys$getsockopt(const Syscall::SC_getsockopt_params* params)
|
int Process::sys$getsockopt(Userspace<const Syscall::SC_getsockopt_params*> user_params)
|
||||||
{
|
{
|
||||||
if (!validate_read_typed(params))
|
Syscall::SC_getsockopt_params params;
|
||||||
|
if (!validate_read_and_copy_typed(¶ms, user_params))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
|
|
||||||
SmapDisabler disabler;
|
int sockfd = params.sockfd;
|
||||||
|
int level = params.level;
|
||||||
|
int option = params.option;
|
||||||
|
Userspace<void*> user_value = params.value;
|
||||||
|
Userspace<socklen_t*> user_value_size = params.value_size;
|
||||||
|
|
||||||
int sockfd = params->sockfd;
|
if (!validate_write_typed(user_value_size))
|
||||||
int level = params->level;
|
|
||||||
int option = params->option;
|
|
||||||
void* value = params->value;
|
|
||||||
socklen_t* value_size = params->value_size;
|
|
||||||
|
|
||||||
if (!validate_write_typed(value_size))
|
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
if (!validate_write(value, *value_size))
|
socklen_t value_size;
|
||||||
|
if (!validate_read_and_copy_typed(&value_size, user_value_size))
|
||||||
|
return -EFAULT;
|
||||||
|
if (!validate_write(user_value, value_size))
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
auto description = file_description(sockfd);
|
auto description = file_description(sockfd);
|
||||||
if (!description)
|
if (!description)
|
||||||
|
@ -345,7 +347,7 @@ int Process::sys$getsockopt(const Syscall::SC_getsockopt_params* params)
|
||||||
} else {
|
} else {
|
||||||
REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(socket.domain());
|
REQUIRE_PROMISE_FOR_SOCKET_DOMAIN(socket.domain());
|
||||||
}
|
}
|
||||||
return socket.getsockopt(*description, level, option, value, value_size);
|
return socket.getsockopt(*description, level, option, user_value, user_value_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Process::sys$setsockopt(Userspace<const Syscall::SC_setsockopt_params*> user_params)
|
int Process::sys$setsockopt(Userspace<const Syscall::SC_setsockopt_params*> user_params)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue