1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 07:38:10 +00:00

Kernel: Fix subtle race condition in sys$write implementation

There is a slight race condition in our implementation of write().
We call File::can_write() before attempting to write to it (blocking if
it returns false). If it returns true, we assume that we can write to
the file, and our code assumes that File::write() cannot possibly fail
by being blocked. There is, however, the rare case where another process
writes to the file and prevents further writes in between the call to
Files::can_write() and File::write() in the first process. This would
result in the first process calling File::write() when it cannot be
written to.

We fix this by adding a mechanism for File::can_write() to signal that
it was blocked, making it the responsibilty of File::write() to check
whether it can write and then finally making sys$write() check if the
write failed due to it being blocked.
This commit is contained in:
Sahan Fernando 2021-05-18 21:49:34 +10:00 committed by Andreas Kling
parent 208cfcb0a5
commit d0f314b23c
3 changed files with 15 additions and 14 deletions

View file

@ -31,6 +31,7 @@ KResultOr<size_t> SerialDevice::read(FileDescription&, u64, UserOrKernelBuffer&
if (!size)
return 0;
ScopedSpinLock lock(m_serial_lock);
if (!(get_line_status() & DataReady))
return 0;
@ -46,13 +47,14 @@ bool SerialDevice::can_write(const FileDescription&, size_t) const
return (get_line_status() & EmptyTransmitterHoldingRegister) != 0;
}
KResultOr<size_t> SerialDevice::write(FileDescription&, u64, const UserOrKernelBuffer& buffer, size_t size)
KResultOr<size_t> SerialDevice::write(FileDescription& description, u64, const UserOrKernelBuffer& buffer, size_t size)
{
if (!size)
return 0;
if (!(get_line_status() & EmptyTransmitterHoldingRegister))
return 0;
ScopedSpinLock lock(m_serial_lock);
if (!can_write(description, size))
return EAGAIN;
return buffer.read_buffered<128>(size, [&](u8 const* data, size_t data_size) {
for (size_t i = 0; i < data_size; i++)