Может ли программа исправить себя (переменные)? (критическая с точки зрения безопасности среда)
Я только начал писать отказоустойчивый код C с высокой степенью целостности, и я хотел бы знать, могут ли программы «исправить себя», если переменная по какой-либо причине повреждена (например, космическими лучами). Я знаю, что есть определенное оборудование, такое как ECC ram, которое может противостоять этому, но если предположить, что оборудование, которое я буду использовать, не имеет исправления ошибок, есть ли какие-либо способы, которыми программа может проверить себя на ошибки и исправить себя? Я знаю, что мог бы регистрировать каждое изменение переменной где-нибудь и проверять каждую переменную перед использованием, если она была каким-то образом изменена, но это значительно замедлило бы программу из-за скорости ввода-вывода. Существуют ли какие-либо другие способы для программы проверить и, возможно, исправить себя?
6 ответов
На ваш первоначальный вопрос, если программа может исправить себя, я думаю, что ответ должен быть НЕТ, потому что, когда переменная повреждена, функционал программы больше не доверяется.
Реализация безопасности включает в себя механизм как аппаратного, так и программного обеспечения, основанный на анализе возможных отказов и последствий отказов. Следовательно, только программного обеспечения недостаточно для мер безопасности/реакции.
В общем случае существует некоторый механизм предотвращения/восстановления после такого рода ошибок:
- ECC: это аппаратный механизм, однако он способен обнаруживать/исправлять только один бит. Для ошибок, которые происходят более чем с 1 битом, восстановление также невозможно.
- Используйте CRC для обнаружения ошибок критических данных и использования избыточной (удвоенной памяти) для восстановления. Однако этот подход может защитить только некоторые конкретные данные при условии, что остальные должны по-прежнему функционировать должным образом. И нормальный план реакции/восстановления для этого — выключение/сброс.
- Для более критической системы добавление дополнительного оборудования для перекрестной проверки также является хорошим выбором.
Как правило, следует соблюдать рекомендации стандарта функциональной безопасности заявителя (IEC 61508 или ISO 26262 и т. д., «SIL»/«ASIL»). Они рекомендуют использование ECC, и в настоящее время, когда есть MCU безопасности, они должны поставляться с аппаратным ECC и заявлять о соответствии таким стандартам функциональной безопасности. Такие микроконтроллеры, скорее всего, будут вызывать аппаратное исключение при ошибках, и с этого момента вы мало что можете сделать, кроме как перевести программу в безопасный режим, если это возможно, или иным образом сбросить настройки.
Я бы не рекомендовал более «старые школьные» способы, такие как программное обеспечение ECC или CRC, тесты «шагающего бита» и т. д., поскольку их сложно реализовать и правильно настроить, добавляя дополнительную сложность программного обеспечения и, следовательно, риски. На самом деле нет веской причины, по которой вам не следует использовать безопасный MCU.
Если я сравню старое программное обеспечение, связанное с безопасностью, которое я написал в середине 2000-х, которое реализует CRC, проходя битовые тесты ОЗУ, избыточность в дублирующихся сегментах памяти и т. д., то оно намного сложнее, чем программы, которые я написал для микроконтроллера безопасности, где аппаратное обеспечение справляется практически со всем.
Внедрение сложных механизмов безопасности, а также сложность программного обеспечения в целом представляет опасность! Снова и снова было доказано, что количество ошибок в программе зависит от ее сложности — всегда следуйте принципу «Не усложняй, глупо» (KISS).
Вам нужно будет выполнить некоторую математическую операцию с определенными частями вашей памяти, где ваши критические переменные, например: CRC, Hashing (@klutt уже упоминал об этом). Вы также можете создать некоторую оболочку вокруг вашей переменной и сохранить их избыточными (дважды или более) и проверять изменения при их чтении. Это не гарантирует систематических ошибок (например, 7-я битовая позиция на шине повреждена), но, вероятно, является очень простой реализацией. Существует множество различных подходов к обмену данными для проверки ошибок или изменений, таких как контрольные суммы, которые можно довольно легко реализовать.
Другая возможность - избыточное оборудование (как также упоминал @klutt). Они являются стандартными в современных приложениях безопасности, в зависимости от SIL (умирают люди или нет).
Проверка программного обеспечения на наличие собственных ошибок не является интуитивно понятной, каждый имеющийся у вас компилятор c будет работать против вас. Если сделать все избыточные переменные изменчивыми, это также приведет к нежелательному эффекту замедления работы вашей программы.
В этом ответе много сложно реализуемых возможностей, может быть, кто-то знает какое-нибудь программное решение? Хотя я не думаю, что есть один...
« Я знаю, что могу регистрировать каждое изменение переменной где-нибудь и проверять каждую переменную перед использованием… »
- ты "знаешь"? Как это сработает? Откуда вы знаете, что программное обеспечение , выполняющее регистрацию и проверку, не пострадало? Это совсем не практично.
Критические данные (особенно постоянные/неопасные данные) могут использовать избыточность, обнаружение/исправление ошибок, но для целостности "всей системы" лучше следить за правильной работой. Часто самопроизвольное повреждение данных либо из-за внешнего вмешательства, либо из-за ошибки программного обеспечения приводит к неправильной работе. Используя программные и аппаратные сторожевые таймеры, вы можете обнаружить многие из этих ошибок и предпринять корректирующие действия — часто вы сможете сделать немного больше, чем выполнить сброс.
Программные сторожевые таймеры применимы только в многопоточных/многозадачных системах, и в некоторых случаях вы можете перезапустить поток, но для этого требуется довольно сложная программная архитектура, чтобы реализовать этот трюк и доверять целостности системы.
На самом деле, если у вас есть определенный уровень безопасности, то вам с самого начала нужна так называемая «Техническая концепция безопасности» и Анализ опасностей/Система FMEA. Эта концепция фактически приведет к техническим требованиям безопасности, которые также могут быть требованиями к оборудованию, например, к процессору и внешним периферийным устройствам с функциями безопасности. Обычно у поставщика SoC/чипа также есть какое-то руководство по безопасности, в котором указано, что процессор/SoC поддерживает, а что нет, и какие меры безопасности вы должны обеспечить самостоятельно (например, два разных расчета, проверки ALU/FPU, BIST, сравнение двойных часов (привязка часов к источнику), ...).
Вот почему эти критичные для безопасности вещи стоят дороже, чем некритичные для безопасности вещи (начиная с HW до дополнительных тестов и обзоров исходного кода), и похоже, что в вашем случае такой анализ не проводился, и кто-то выбрал не тот ХВ. Если у вас нет аппаратной поддержки, вам придется справляться с использованием дополнительных ресурсов/среды выполнения.
Возможно, вам придется сделать:
- циклические проверки ALU/FPU
- Проверки памяти (CRC), если нет ECC, вы должны сделать это и справиться с дополнительным временем выполнения и памятью
- Для данных NvM может потребоваться CRC, хранящийся вместе с данными и проверенный перед использованием данных NvM.
Для систем, критически важных для безопасности, вы должны применять «современную» технику, в противном случае вы можете быть привлечены к ответственности и привлечены к ответственности в случае возникновения опасностей. Я прошел такой тренинг по безопасности и надежности продукта, как 20 лет назад, и вышел из него, на самом деле думая, что уже одной ногой в тюрьме.
Если вы используете Arduino или что-то в этом роде, я бы предложил использовать два одинаковых оборудования для выполнения одной и той же программы. Затем вы можете проверить, что они дают тот же результат. Может быть, даже периодически сравнивать всю память, чтобы убедиться, что она идентична.
Конечно, это можно сделать и с виртуальными машинами, если для этого достаточно вашего оборудования.
Если критически важно, чтобы программа продолжала работать, используйте три машины и используйте результат, полученный как минимум на двух машинах. Это то, что они сделали на Сатурне V.