1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-20 14:15:07 +00:00

Kernel: Utilize AK::Userspace<T> in the ioctl interface

It's easy to forget the responsibility of validating and safely copying
kernel parameters in code that is far away from syscalls. ioctl's are
one such example, and bugs there are just as dangerous as at the root
syscall level.

To avoid this case, utilize the AK::Userspace<T> template in the ioctl
kernel interface so that implementors have no choice but to properly
validate and copy ioctl pointer arguments.
This commit is contained in:
Brian Gianforcaro 2021-07-26 02:47:00 -07:00 committed by Ali Mohammad Pur
parent 0bb3d83a48
commit 9a04f53a0f
16 changed files with 99 additions and 93 deletions

View file

@ -568,13 +568,14 @@ KResult IPv4Socket::getsockopt(FileDescription& description, int level, int opti
}
}
int IPv4Socket::ioctl(FileDescription&, unsigned request, FlatPtr arg)
int IPv4Socket::ioctl(FileDescription&, unsigned request, Userspace<void*> arg)
{
REQUIRE_PROMISE(inet);
auto ioctl_route = [request, arg]() {
auto user_route = static_ptr_cast<rtentry*>(arg);
rtentry route;
if (!copy_from_user(&route, (rtentry*)arg))
if (!copy_from_user(&route, user_route))
return -EFAULT;
auto copied_ifname = copy_string_from_user(route.rt_dev, IFNAMSIZ);
@ -605,8 +606,9 @@ int IPv4Socket::ioctl(FileDescription&, unsigned request, FlatPtr arg)
};
auto ioctl_arp = [request, arg]() {
auto user_req = static_ptr_cast<arpreq*>(arg);
arpreq arp_req;
if (!copy_from_user(&arp_req, (arpreq*)arg))
if (!copy_from_user(&arp_req, user_req))
return -EFAULT;
switch (request) {
@ -631,7 +633,7 @@ int IPv4Socket::ioctl(FileDescription&, unsigned request, FlatPtr arg)
};
auto ioctl_interface = [request, arg]() {
ifreq* user_ifr = (ifreq*)arg;
auto user_ifr = static_ptr_cast<ifreq*>(arg);
ifreq ifr;
if (!copy_from_user(&ifr, user_ifr))
return -EFAULT;
@ -662,72 +664,65 @@ int IPv4Socket::ioctl(FileDescription&, unsigned request, FlatPtr arg)
return 0;
case SIOCGIFADDR: {
u16 sa_family = AF_INET;
if (!copy_to_user(&user_ifr->ifr_addr.sa_family, &sa_family))
return -EFAULT;
auto ip4_addr = adapter->ipv4_address().to_u32();
if (!copy_to_user(&((sockaddr_in&)user_ifr->ifr_addr).sin_addr.s_addr, &ip4_addr, sizeof(ip4_addr)))
auto& socket_address_in = reinterpret_cast<sockaddr_in&>(ifr.ifr_addr);
socket_address_in.sin_family = AF_INET;
socket_address_in.sin_addr.s_addr = ip4_addr;
if (!copy_to_user(user_ifr, &ifr))
return -EFAULT;
return 0;
}
case SIOCGIFNETMASK: {
u16 sa_family = AF_INET;
if (!copy_to_user(&user_ifr->ifr_addr.sa_family, &sa_family))
return -EFAULT;
auto ip4_netmask = adapter->ipv4_netmask().to_u32();
auto& socket_address_in = reinterpret_cast<sockaddr_in&>(ifr.ifr_addr);
socket_address_in.sin_family = AF_INET;
// NOTE: NOT ifr_netmask.
if (!copy_to_user(&((sockaddr_in&)user_ifr->ifr_addr).sin_addr.s_addr, &ip4_netmask, sizeof(ip4_netmask)))
socket_address_in.sin_addr.s_addr = ip4_netmask;
if (!copy_to_user(user_ifr, &ifr))
return -EFAULT;
return 0;
}
case SIOCGIFHWADDR: {
u16 sa_family = AF_INET;
if (!copy_to_user(&user_ifr->ifr_hwaddr.sa_family, &sa_family))
return -EFAULT;
auto mac_address = adapter->mac_address();
if (!copy_to_user(ifr.ifr_hwaddr.sa_data, &mac_address, sizeof(MACAddress)))
ifr.ifr_hwaddr.sa_family = AF_INET;
mac_address.copy_to(Bytes { ifr.ifr_hwaddr.sa_data, sizeof(ifr.ifr_hwaddr.sa_data) });
if (!copy_to_user(user_ifr, &ifr))
return -EFAULT;
return 0;
}
case SIOCGIFBRDADDR: {
u16 sa_family = AF_INET;
if (!copy_to_user(&user_ifr->ifr_addr.sa_family, &sa_family))
return -EFAULT;
// Broadcast address is basically the reverse of the netmask, i.e.
// instead of zeroing out the end, you OR with 1 instead.
auto ip4_netmask = adapter->ipv4_netmask().to_u32();
auto broadcast_addr = adapter->ipv4_address().to_u32() | ~ip4_netmask;
if (!copy_to_user(&((sockaddr_in&)user_ifr->ifr_addr).sin_addr.s_addr, &broadcast_addr, sizeof(broadcast_addr)))
auto& socket_address_in = reinterpret_cast<sockaddr_in&>(ifr.ifr_addr);
socket_address_in.sin_family = AF_INET;
socket_address_in.sin_addr.s_addr = broadcast_addr;
if (!copy_to_user(user_ifr, &ifr))
return -EFAULT;
return 0;
}
case SIOCGIFMTU: {
u16 sa_family = AF_INET;
if (!copy_to_user(&user_ifr->ifr_addr.sa_family, &sa_family))
return -EFAULT;
auto ip4_metric = adapter->mtu();
if (!copy_to_user(&user_ifr->ifr_metric, &ip4_metric, sizeof(ip4_metric)))
ifr.ifr_addr.sa_family = AF_INET;
ifr.ifr_metric = ip4_metric;
if (!copy_to_user(user_ifr, &ifr))
return -EFAULT;
return 0;
}
case SIOCGIFFLAGS: {
u16 sa_family = AF_INET;
if (!copy_to_user(&user_ifr->ifr_addr.sa_family, &sa_family))
return -EFAULT;
// FIXME: stub!
short flags = 1;
if (!copy_to_user(&user_ifr->ifr_flags, &flags, sizeof(flags)))
constexpr short flags = 1;
ifr.ifr_addr.sa_family = AF_INET;
ifr.ifr_flags = flags;
if (!copy_to_user(user_ifr, &ifr))
return -EFAULT;
return 0;
}