mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-01-24 02:03:06 -05:00
026687816d
This small change simplifies the function a bit but also fixes a problem with it. Let's take an example to see this: Let's say we have a reserved range between 0xe0000 to 0xfffff (EBDA), then we want to map from the memory device (/dev/mem) the entire EBDA to a program. If a program tries to map more than 131072 bytes, the current logic will work - the start address is 0xe0000, and ofcourse it's below the limit, hence it passes the first two restrictions. Then, the third if statement will fail if we try to mmap more than the said allowed bytes. However, let's take another scenario, where we try to mmap from 0xf0000 - but we try to mmap less than 131072 - but more than 65536. In such case, we again pass the first two if statements, but the third one is passed two, because it doesn't take into account the offseted address from the start of the reserved range (0xe0000). In such case, a user can easily mmap 65535 bytes above 0x100000. This might seem negligible. However, it's still a severe bug that can theoretically be exploited into a info leak or tampering with important kernel structures.
67 lines
2.7 KiB
C++
67 lines
2.7 KiB
C++
/*
|
|
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <AK/Checked.h>
|
|
#include <AK/Format.h>
|
|
#include <AK/Types.h>
|
|
|
|
typedef u64 PhysicalPtr;
|
|
typedef u64 PhysicalSize;
|
|
|
|
class PhysicalAddress {
|
|
public:
|
|
ALWAYS_INLINE static PhysicalPtr physical_page_base(PhysicalPtr page_address) { return page_address & ~(PhysicalPtr)0xfff; }
|
|
ALWAYS_INLINE static size_t physical_page_index(PhysicalPtr page_address)
|
|
{
|
|
auto page_index = page_address >> 12;
|
|
if constexpr (sizeof(size_t) < sizeof(PhysicalPtr))
|
|
VERIFY(!(page_index & ~(PhysicalPtr)((size_t)-1)));
|
|
return (size_t)(page_index);
|
|
}
|
|
|
|
PhysicalAddress() = default;
|
|
explicit PhysicalAddress(PhysicalPtr address)
|
|
: m_address(address)
|
|
{
|
|
}
|
|
|
|
[[nodiscard]] PhysicalAddress offset(PhysicalPtr o) const { return PhysicalAddress(m_address + o); }
|
|
[[nodiscard]] bool offset_addition_would_overflow(PhysicalPtr o) const { return Checked<PhysicalPtr>::addition_would_overflow(m_address, o); }
|
|
[[nodiscard]] PhysicalPtr get() const { return m_address; }
|
|
void set(PhysicalPtr address) { m_address = address; }
|
|
void mask(PhysicalPtr m) { m_address &= m; }
|
|
|
|
[[nodiscard]] bool is_null() const { return m_address == 0; }
|
|
|
|
[[nodiscard]] u8* as_ptr() { return reinterpret_cast<u8*>(m_address); }
|
|
[[nodiscard]] const u8* as_ptr() const { return reinterpret_cast<const u8*>(m_address); }
|
|
|
|
[[nodiscard]] PhysicalAddress page_base() const { return PhysicalAddress(physical_page_base(m_address)); }
|
|
[[nodiscard]] PhysicalPtr offset_in_page() const { return PhysicalAddress(m_address & 0xfff).get(); }
|
|
|
|
bool operator==(const PhysicalAddress& other) const { return m_address == other.m_address; }
|
|
bool operator!=(const PhysicalAddress& other) const { return m_address != other.m_address; }
|
|
bool operator>(const PhysicalAddress& other) const { return m_address > other.m_address; }
|
|
bool operator>=(const PhysicalAddress& other) const { return m_address >= other.m_address; }
|
|
bool operator<(const PhysicalAddress& other) const { return m_address < other.m_address; }
|
|
bool operator<=(const PhysicalAddress& other) const { return m_address <= other.m_address; }
|
|
|
|
private:
|
|
PhysicalPtr m_address { 0 };
|
|
};
|
|
|
|
template<>
|
|
struct AK::Formatter<PhysicalAddress> : AK::Formatter<FormatString> {
|
|
void format(FormatBuilder& builder, PhysicalAddress value)
|
|
{
|
|
if constexpr (sizeof(PhysicalPtr) == sizeof(u64))
|
|
return AK::Formatter<FormatString>::format(builder, "P{:016x}", value.get());
|
|
else
|
|
return AK::Formatter<FormatString>::format(builder, "P{}", value.as_ptr());
|
|
}
|
|
};
|