diff options
author | Daniel Axtens <dja@axtens.net> | 2021-09-20 01:12:24 +1000 |
---|---|---|
committer | Julian Andres Klode <julian.klode@canonical.com> | 2022-06-08 12:41:03 +0200 |
commit | e7573be61b3cf005cdf0a068652153437daca4b3 (patch) | |
tree | 936e8da9337a490eb462101dccfd3a1b2657a785 /include | |
parent | 968febf3a4de5df0f91cc13bc6b6053fc22575e1 (diff) |
net/tftp: Prevent a UAF and double-free from a failed seek
A malicious tftp server can cause UAFs and a double free.
An attempt to read from a network file is handled by grub_net_fs_read(). If
the read is at an offset other than the current offset, grub_net_seek_real()
is invoked.
In grub_net_seek_real(), if a backwards seek cannot be satisfied from the
currently received packets, and the underlying transport does not provide
a seek method, then grub_net_seek_real() will close and reopen the network
protocol layer.
For tftp, the ->close() call goes to tftp_close() and frees the tftp_data_t
file->data. The file->data pointer is not nulled out after the free.
If the ->open() call fails, the file->data will not be reallocated and will
continue point to a freed memory block. This could happen from a server
refusing to send the requisite ack to the new tftp request, for example.
The seek and the read will then fail, but the grub_file continues to exist:
the failed seek does not necessarily cause the entire file to be thrown
away (e.g. where the file is checked to see if it is gzipped/lzio/xz/etc.,
a read failure is interpreted as a decompressor passing on the file, not as
an invalidation of the entire grub_file_t structure).
This means subsequent attempts to read or seek the file will use the old
file->data after free. Eventually, the file will be close()d again and
file->data will be freed again.
Mark a net_fs file that doesn't reopen as broken. Do not permit read() or
close() on a broken file (seek is not exposed directly to the file API -
it is only called as part of read, so this blocks seeks as well).
As an additional defence, null out the ->data pointer if tftp_open() fails.
That would have lead to a simple null pointer dereference rather than
a mess of UAFs.
This may affect other protocols, I haven't checked.
Signed-off-by: Daniel Axtens <dja@axtens.net>
Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
Diffstat (limited to 'include')
-rw-r--r-- | include/grub/net.h | 1 |
1 files changed, 1 insertions, 0 deletions
diff --git a/include/grub/net.h b/include/grub/net.h index cbcae79b1..8d71ca6cc 100644 --- a/include/grub/net.h +++ b/include/grub/net.h @@ -277,6 +277,7 @@ typedef struct grub_net grub_fs_t fs; int eof; int stall; + int broken; } *grub_net_t; extern grub_net_t (*EXPORT_VAR (grub_net_open)) (const char *name); |