Состояние гонки в надежных мьютексах glibc/NPTL/Linux? - программирование

Состояние гонки в надежных мьютексах glibc/NPTL/Linux?

В комментарии по вопросу Автоматически выпускать мьютексы при сбоях в Unix еще в 2010 году, заявила Джилл:

glibc надежные мьютексы настолько быстры, потому что glibc принимает опасные ярлыки. Нет гарантии, что мьютекс все еще существует, когда ядро ​​отмечает его как "вызывает EOWNERDEAD". Если мьютекс был уничтожен, а память заменена файлом с отображением памяти, в котором содержится последний идентификатор потока прав в нужном месте, а последний собственный поток заканчивается сразу после записи слова блокировки (но до полного удаления мьютекса из его списка принадлежащие мьютексам), файл поврежден. Устойчивые мьютексы Solaris и will-be-FreeBSD9 медленнее, потому что они не хотят этого риска.

Я не могу понять смысл претензии, так как уничтожение мьютекса не является законным, если оно не разблокировано (и, следовательно, не в каком-либо потоковом списке). Я также не могу найти ссылки на такие ошибки/проблемы. Была ли претензия просто ошибочной?

Причина, по которой я спрашиваю и что меня интересует, заключается в том, что это имеет отношение к правильности моей собственной реализации, основанной на одном и том же примитиве Linux-надежного мьютекса.

4b9b3361

Ответ 1

Описание гонки от разработчика FreeBSD pthread David Xu: http://lists.freebsd.org/pipermail/svn-src-user/2010-November/003668.html

Я не думаю, что цикл munmap/mmap строго необходим для гонки. Часть разделяемой памяти может быть использована и для другого использования. Это редко, но действительно.

Как упоминалось в этом сообщении, более "забавное" происходит, если потоки с различной привилегией имеют доступ к общему надежному мьютексу. Поскольку node для списка принадлежащих надежным мьютексам находится в самом мьютексе, поток с низкой привилегией может испортить список потоков высоких прав. Это может быть легко использовано для предотвращения сбоя потока высоких прав и в редких случаях это может привести к повреждению памяти потоков с высокими правами. По-видимому, надежные мьютексы Linux предназначены только для использования потоками с теми же привилегиями. Этого можно было бы избежать легко, создав массив надежных списков массива полностью в памяти потоков вместо связанного списка.

Ответ 2

Думаю, я нашел гонку, и это действительно очень уродливо. Это происходит следующим образом:

В потоке A был сохранен надежный мьютекс и разблокирован. Основная процедура:

  • Поместите его в "ожидающий" слот заголовка заголовка потока.
  • Удалите его из связанного списка надежных мьютексов, удерживаемых текущим потоком.
  • Разблокируйте мьютексы.
  • Очистите "ожидающий" слот заголовка заголовка потока.

Проблема заключается в том, что между шагами 3 и 4 другой поток в том же самом процессе мог получить мьютекс, затем разблокировать его и (по правде), считая себя конечным пользователем мьютекса, уничтожить и освободить /munmap его. После этого, если какой-либо поток процесса создает совместное сопоставление файла, устройства или общей памяти, и, как выясняется, ему присваивается один и тот же адрес, а значение в этом месте совпадает с pid потока, который все еще находится между шагами 3 и 4 разблокировки, у вас есть ситуация, при которой, если процесс будет убит, ядро ​​испортит отображаемый файл, установив высокий бит 32-разрядного целого, который, по его мнению, является идентификатором владельца мьютекса.

Решение состоит в том, чтобы удерживать глобальную блокировку на mmap/munmap между шагами 2 и 4 выше, точно так же, как в моем решении проблемы с барьером, описанной в моем ответе на этот вопрос:

Может ли реализованный корректный отказоустойчивый процесс-общий барьер в Linux?