Record validated encrypted attachment ownership fix and remaining audit scope

This commit is contained in:
evgeny committed 2026-10-24 14:59:12 +02:00
1 parent 4862a52684
commit 1227027c2f
3 files changed
+54 -10

No files matched your search

+42 -6
View File
@@ -1,6 +1,6 @@
Аудит media_async / media_delivery — 2026-10-24
Статус: частичный; остановлен на подтверждённом дефекте по AGENTS.md.
Код модулей не изменён. Сборка Linux и 20 профильных тестов прошли.
Статус: подтверждённый дефект исправлен; полный аудит двух каталогов ещё не завершён.
Ниже сохранены исходное воспроизведение и согласованный проект; результаты исправления — в конце.
Подтверждённый дефект: исходник уничтожается через другое имя того же файла
@@ -29,7 +29,7 @@ source/destination. Разные строки могут обозначать о
- /tmp/media-encrypted-alias-lvVS77/ — сохранённые входы и результаты опыта.
Проектные .c/.h для воспроизведения не менялись.
Архитектурно уточнённый фикс — проект, код ещё не изменён
Согласованная архитектура исправления
Одной проверки file_io_paths перед fopen(wb) недостаточно для полного исправления
контракта владения. Сейчас encrypted_file удаляет destination при ошибке, а
@@ -151,8 +151,8 @@ DM не вызывает encrypted_file_write/read: он использует me
- Профильные 20 тестов, ASAN/UBSan/LSan и полный набор. Изменение file_io требует
также проверки его прежних пользователей: copy, video и media blocks/download.
Это архитектурный проект. Уточнённый фикс ещё не реализован и не тестировался;
успешные 20 тестов ниже относятся к текущей реализации до исправления.
Этот проект реализован. Успешные 20 тестов ниже относятся к исходной реализации;
проверки исправленного кода приведены в конце.
Что проверено и что осталось
@@ -172,4 +172,40 @@ media_delivery_chat, dm_media, dm_worker, services.
/tmp/media-doc-audit-logs/. Штатный test_encrypted_file не покрывает alias.
Старые сбои encrypted_attachment/media_delivery_chat в этом прогоне не воспроизвелись;
один PASS не закрывает задачи о нестабильности.
Полный check.sh и новые sanitizer-прогоны в этом аудите не запускались.
На исходном этапе полный check.sh и новые sanitizer-прогоны не запускались.
Результаты исправления — 2026-10-24
- file_io_temp получил единый FILE_IO_DURABLE: sync открытого fd при finish,
write-through rename на Windows и directory sync после rename на POSIX.
После rename temporary пуст, включая отказ directory sync; discard не удаляет результат.
Общие sync/publish функции перенесены в file_io; DM вызывает их напрямую.
- Write/read готовят отдельный закрытый temp. Source/target не открываются с усечением;
совпадающая строка, /./, hardlink и конечная ссылка отклоняются до создания выхода.
Read выдаёт info/type только после успешного закрытия/сохранения проверенного результата.
- ak_file хранит один output, учитывает подготовленный plaintext snapshot и выполненный rename.
Worker публикует один раз; completion очищает только собственные артефакты.
Кеш использует реестр владельцев; recovery очищает строгие temp в media и decrypted.
Построение путей и SQL recovery используют одну каноническую media_base.
- test_encrypted_file: прежние шесть размеров, восемь alias-сценариев обоих API,
активный output, alias перед publish и 23 отказа I/O с контролем fd/temp/метаданных.
До rename прежний target сохраняется; после отказа directory sync новый файл установлен.
- test_media_primitives: durable и обычный режим, sync failure до rename, failure после
rename, относительный/корневой каталог, защита активного temp в worker и после close.
- test_attachment_send детерминированно ждёт настоящего crypto rename без обработки
completion, затем останавливает сервис: нет сообщения/ключа/оставшихся файлов/temp.
- test_encrypted_attachment при каждом startup/restart проверяет оба дерева:
stale temp удалены; открытый/закрытый активные owners, конечные файлы и чужие имена сохранены.
- Профильный Linux-набор: 21/21 PASS, включая video/no_ffmpeg, DM, services и media delivery.
Основной make check: 185/185 PASS. TUN в отдельном network namespace с тем же бинарником:
proxy9/9, burst1/1, load8/8 PASS; 134217728 проверенных байт.
- ASAN/UBSan/LSan: 21/21 PASS с detect_leaks=1. Все встроенные зависимости собраны
с sanitizer-флагами в /tmp/utun-media-fix-sanitizers; обычные объекты проекта не смешивались.
Windows/FreeBSD build/runtime не проверялись.
Логи: /tmp/media-fix-profile-results.log, /tmp/media-fix-full-check.log,
/tmp/media-fix-network-check.log, /tmp/media-fix-sanitizer-results.log,
/tmp/media-fix-cancel-after-rename.log, /tmp/media-fix-encrypted-file.log.
Проверка реализации не выявила противоречий владения в перечисленных сценариях.
Частичные отметки остальных файлов аудита сохраняются; этот фикс не означает полного
завершения проверки media_async/media_delivery или закрытия старых нестабильных тестов.
+8 -4
View File
@@ -4,19 +4,23 @@
## Текущие задачи
[ ] **media_async encrypted_file: не уничтожать source через alias назначения** — подтверждено 24.10.2026.
[+] **media_async encrypted_file: не уничтожать source через alias назначения** — исправлено 24.10.2026.
write/read отвергают только одинаковые строки; /./ и hardlink обходят проверку одного файла.
write возвращает0, заменяя исходные30 байт контейнером пустого файла; read возвращает0,
заменяя входной ciphertext182 байта plaintext30 байт. Проверены реальные функции, inode и SHA256.
Архитектурный фикс: один file_io_temp в ak_file; codec готовит закрытый проверенный temp,
Реализован один file_io_temp в ak_file; codec готовит закрытый проверенный temp,
worker публикует его одним rename. Target не открывается с усечением; alias проверяется до work и перед publish.
Durability задаётся на весь срок temp; ошибка directory sync после rename не считается откатом.
Cleanup удаляет только собственные артефакты; crash recovery учитывает temp в media и decrypted.
DM не вызывает codec: сохранить его контракт общих sync/publish helpers при изменениях file_io.
Детали, проверка архитектуры исправления и незавершённый аудит: [media_async_audit_findings.txt](media_async_audit_findings.txt).
Воспроизведение: /tmp/media-encrypted-alias-repro.c, /tmp/media-encrypted-alias-repro.log.
Linux-сборка и20/20 профильных тестов PASS; штатный test_encrypted_file не проверяет alias.
/tmp/media-doc-audit-results.log. Код модулей не изменён; дальнейший аудит остановлен по AGENTS.md.
Добавлены восемь alias-сценариев, 23 отказа I/O с контролем fd/temp/метаданных,
отмена настоящего worker после rename до completion, startup/restart обоих деревьев.
Профильные21/21 и основной make check185/185 PASS; proxy9/9, burst1/1, load8/8 PASS
в отдельном network namespace,134217728 проверенных байт. ASAN/UBSan/LSan21/21 PASS, detect_leaks=1.
Логи: /tmp/media-fix-full-check.log, /tmp/media-fix-network-check.log, /tmp/media-fix-sanitizer-results.log.
Полный аудит остальных контрактов media_async/media_delivery ещё не завершён; Windows/FreeBSD не проверялись.
[+] **Proxy: исправить HUP/backpressure, владение и rollback** — завершено 24.10.2026.
Согласованный проект, причины и результаты: [doc/proxy_fix_plan.txt](proxy_fix_plan.txt).
+4
View File
@@ -18,7 +18,9 @@ static FILE *input_file, *output_file;
FILE* __real_fopen(const char*, const char*);
FILE* __real_fdopen(int, const char*);
size_t __real_fread(void*, size_t, size_t, FILE*), __real_fwrite(const void*, size_t, size_t, FILE*);
#ifdef __GLIBC__
size_t __real___fread_chk(void*, size_t, size_t, size_t, FILE*);
#endif
int __real_ferror(FILE*), __real_fflush(FILE*), __real_fclose(FILE*), __real_fsync(int);
int __real_fseeko(FILE*, off_t, int), __real_rename(const char*, const char*);
int __real_random_bytes(uint8_t*, size_t);
@@ -40,10 +42,12 @@ size_t __wrap_fread(void* data, size_t size, size_t count, FILE* file) {
if (file == input_file && inject(F_READ)) { read_failed = 1; return 0; }
return __real_fread(data, size, count, file);
}
#ifdef __GLIBC__
size_t __wrap___fread_chk(void* data, size_t cap, size_t size, size_t count, FILE* file) {
if (file == input_file && inject(F_READ)) { read_failed = 1; return 0; }
return __real___fread_chk(data, cap, size, count, file);
}
#endif
int __wrap_ferror(FILE* file) { return file == input_file && read_failed ? 1 : __real_ferror(file); }
size_t __wrap_fwrite(const void* data, size_t size, size_t count, FILE* file) {
return file == output_file && inject(F_WRITE) ? 0 : __real_fwrite(data, size, count, file);