1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-14 11:44:58 +00:00

Kernel/Net: Iron out the locking mechanism across the subsystem

There is a big mix of LockRefPtrs all over the Networking subsystem, as
well as lots of room for improvements with our locking patterns, which
this commit will not pursue, but will give a good start for such work.

To deal with this situation, we change the following things:
- Creating instances of NetworkAdapter should always yield a non-locking
  NonnullRefPtr. Acquiring an instance from the NetworkingManagement
  should give a simple RefPtr,as giving LockRefPtr does not really
  protect from concurrency problems in such case.
- Since NetworkingManagement works with normal RefPtrs we should
  protect all instances of RefPtr<NetworkAdapter> with SpinlockProtected
  to ensure references are gone unexpectedly.
- Protect the so_error class member with a proper spinlock. This happens
  to be important because the clear_so_error() method lacked any proper
  locking measures. It also helps preventing a possible TOCTOU when we
  might do a more fine-grained locking in the Socket code, so this could
  be definitely a start for this.
- Change unnecessary LockRefPtr<PacketWithTimestamp> in the structure
  of OutgoingPacket to a simple RefPtr<PacketWithTimestamp> as the whole
  list should be MutexProtected.
This commit is contained in:
Liav A 2023-04-11 03:50:15 +03:00 committed by Linus Groh
parent bd7d4513bf
commit 7c1f645e27
13 changed files with 93 additions and 83 deletions

View file

@ -100,7 +100,9 @@ ErrorOr<void> Socket::setsockopt(int level, int option, Userspace<void const*> u
auto device = NetworkingManagement::the().lookup_by_name(ifname->view());
if (!device)
return ENODEV;
m_bound_interface = move(device);
m_bound_interface.with([&device](auto& bound_device) {
bound_device = move(device);
});
return {};
}
case SO_DEBUG:
@ -169,31 +171,35 @@ ErrorOr<void> Socket::getsockopt(OpenFileDescription&, int level, int option, Us
case SO_ERROR: {
if (size < sizeof(int))
return EINVAL;
int errno = 0;
if (auto const& error = so_error(); error.has_value())
errno = error.value();
TRY(copy_to_user(static_ptr_cast<int*>(value), &errno));
size = sizeof(int);
TRY(copy_to_user(value_size, &size));
clear_so_error();
return {};
return so_error().with([&size, value, value_size](auto& error) -> ErrorOr<void> {
int errno = 0;
if (error.has_value())
errno = error.value();
TRY(copy_to_user(static_ptr_cast<int*>(value), &errno));
size = sizeof(int);
TRY(copy_to_user(value_size, &size));
error = {};
return {};
});
}
case SO_BINDTODEVICE:
if (size < IFNAMSIZ)
return EINVAL;
if (m_bound_interface) {
auto name = m_bound_interface->name();
auto length = name.length() + 1;
auto characters = name.characters_without_null_termination();
TRY(copy_to_user(static_ptr_cast<char*>(value), characters, length));
size = length;
return copy_to_user(value_size, &size);
} else {
size = 0;
TRY(copy_to_user(value_size, &size));
// FIXME: This return value looks suspicious.
return EFAULT;
}
return m_bound_interface.with([&](auto& bound_device) -> ErrorOr<void> {
if (bound_device) {
auto name = bound_device->name();
auto length = name.length() + 1;
auto characters = name.characters_without_null_termination();
TRY(copy_to_user(static_ptr_cast<char*>(value), characters, length));
size = length;
return copy_to_user(value_size, &size);
} else {
size = 0;
TRY(copy_to_user(value_size, &size));
// FIXME: This return value looks suspicious.
return EFAULT;
}
});
case SO_TIMESTAMP:
if (size < sizeof(int))
return EINVAL;