[lvc-project] [PATCH] tty: Fix possible deadlock in tty_buffer_flush
Vasiliy Kovalev
kovalev at altlinux.org
Thu May 9 13:32:43 MSK 2024
09.05.2024 09:41, Jiri Slaby wrote:
> On 08. 05. 24, 11:30, kovalev at altlinux.org wrote:
>> From: Vasiliy Kovalev <kovalev at altlinux.org>
>>
>> A possible scenario in which a deadlock may occur is as follows:
>>
>> flush_to_ldisc() {
>>
>> mutex_lock(&buf->lock);
>>
>> tty_port_default_receive_buf() {
>> tty_ldisc_receive_buf() {
>> n_tty_receive_buf2() {
>> n_tty_receive_buf_common() {
>> n_tty_receive_char_special() {
>> isig() {
>> tty_driver_flush_buffer() {
>> pty_flush_buffer() {
>> tty_buffer_flush() {
>>
>> mutex_lock(&buf->lock); (DEADLOCK)
>>
>> flush_to_ldisc() and tty_buffer_flush() functions they use the same mutex
>> (&buf->lock), but not necessarily the same struct tty_bufhead object.
>
> "not necessarily" -- so does it mean that it actually can happen (and we
> should fix it) or not at all (and we should annotate the mutex)?
During debugging, when running the reproducer multiple times, I failed
to catch a situation where these mutexes have the same address in memory
in the above call scenario, so I'm not sure that such a situation is
possible. But earlier, a thread is triggered that accesses the same
structure (and mutex), so LOCKDEP tools throw a warning:
thread 0:
flush_to_ldisc() {
mutex_lock(&buf->lock) // Address mutex == 0xA
n_tty_receive_buf_common();
mutex_unlock(&buf->lock) // Address mutex == 0xA
}
thread 1:
flush_to_ldisc() {
mutex_lock(&buf->lock) // Address mutex == 0xB
n_tty_receive_buf_common() {
isig() {
tty_driver_flush_buffer() {
pty_flush_buffer() {
tty_buffer_flush() {
mutex_lock(&buf->lock) // Address mutex == 0xA ->
throw Warning
// successful continuation
...
}
>> However, you should probably use a separate mutex for the
>> tty_buffer_flush() function to exclude such a situation.
> ...
>
>> Cc: stable at vger.kernel.org
>
> What commit does this fix?
I will assume that the commit of introducing mutexes in these functions:
e9975fdec013 ("tty: Ensure single-threaded flip buffer consumer with mutex")
>> --- a/drivers/tty/tty_buffer.c
>> +++ b/drivers/tty/tty_buffer.c
>> @@ -226,7 +226,7 @@ void tty_buffer_flush(struct tty_struct *tty,
>> struct tty_ldisc *ld)
>> atomic_inc(&buf->priority);
>> - mutex_lock(&buf->lock);
>> + mutex_lock(&buf->flush_mtx);
>
> Hmm, how does this protect against concurrent buf pickup. We free it
> here and the racing thread can start using it, or?
Yes, assuming that such a scenario is possible..
Otherwise, if such a scenario is not possible and the patch is
inappropriate, then you need to mark this mutex in some way to tell
lockdep tools to ignore this place..
>> /* paired w/ release in __tty_buffer_request_room; ensures there
>> are
>> * no pending memory accesses to the freed buffer
>> */
>
> thanks,
--
Regards,
Vasiliy Kovalev
More information about the lvc-project
mailing list