Доступ к данным из файла proc в модуле ядра

Мне нужно получить доступ к некоторым файлам proc в модуле на ядре Android. В основном мне нужна информация, показанная в команде cat, например cat /proc/uptime, Однако мне нужно сделать это программно.

Я пробовал работать с proc_fs функций, но для меня это было немного нечетко, обычно примеры - создать файл proc, затем прочитать его и все. Мне действительно нужно использовать данные из файлов proc.

Я тоже тред хороший fopen, но, похоже, не работает на модулях.

Как я могу это сделать? Я действительно новичок в этом. Я работаю над ядром Android в виде золотой рыбки.

Благодарю.

3 ответа

Решение

Procfs - это файловая система в памяти. Это интерфейс для пользовательского пространства для извлечения информации и помещения (конфигурации) информации в структуры данных ядра. Другими словами, procfs позволяет пользователям взаимодействовать и просматривать структуры данных ядра так, как они существуют во время выполнения.

Следовательно, любой файл внутри / proc не предназначен для чтения изнутри ядра или модуля ядра. И зачем это делать? В монолитном ядре, таком как Linux, вы можете получить доступ к структурам данных одной подсистемы в ядре через другую напрямую или через предопределенную функцию.

Следующий вызов функции может помочь:

struct timespec uptime;

do_posix_clock_monotonic_gettime(&uptime);

Вы можете обратиться к реализации / proc / uptime по ссылке ниже, это по сути seq_file,

http://lxr.free-electrons.com/source/fs/proc/uptime.c

Я отвечаю на исходный вопрос: как модуль ядра может получить доступ к файлам в формате.

Как модуль ядра получает доступ к файлам в специальных файловых системах

Я нашел следующее полезным справочником:https://elixir.bootlin.com/linux/latest/source/fs/proc/proc_sysctl.c#L1790

Я думаю, это настройка sysctlзначения из командной строки ядра. Последовательность выглядит следующим образом:

A. Смонтируйте файловую систему

  1. proc_fs_type = get_fs_type("proc");
  2. *proc_mnt = kern_mount(proc_fs_type);

Б. Откройте файл по пути относительно корня procfs.

  1. file = file_open_root((*proc_mnt)->mnt_root, *proc_mnt, path, O_WRONLY, 0);

C. Чтение / запись файла

  1. int kernel_read_file(struct file *file, loff_t offset, void **buf, size_t buf_size, size_t *file_size, enum kernel_read_file_id id)
  2. wret = kernel_write(file, val, len, &pos);

D. Закройте файл

  1. err = filp_close(file, NULL);

D. Очистка монтирования файловой системы

  1. kern_unmount(proc_mnt);
  2. put_filesystem(proc_fs_type);

Должен ли модуль ядра обращаться к файлам в специальных файловых системах

Да, в основном предоставляет пользовательскому пространству доступ для чтения / записи к данным уровня ядра. Поскольку модуль ядра работает в ядре, если существует более прямая последовательность вызовов API, которая позволяет модулю получать доступ к таким данным, использование такого API было бы предпочтительным, поскольку он, вероятно, намного чище, меньше кода и более эффективен.

Однако динамически загружаемый модуль ядра не имеет (чистого) прямого доступа ко всем символам (или структурам данных) в ядре.

Модуль ядра может обращаться только к функциям и переменным, которые

  • полностью определяется в файле заголовка, который может быть включен в исходный код модуля ядра

  • или явно доступны модулям ядра через один из макросов в /include/asm-generic/export.h:

    • EXPORT_SYMBOL
    • EXPORT_SYMBOL_GPL
    • EXPORT_DATA_SYMBOL
    • EXPORT_DATA_SYMBOL_GPL

Случаи, когда модулю ядра требуется доступ к данным, которые не отображаются через такие EXPORTED API, но доступный через файлы в procfs или любая другая специальная файловая система кажется законным случаем для доступа к таким файлам из модулей ядра.

Насколько я понимаю, в качестве общего принципа проектирования ядро ​​нацелено на реализацию механизмов без навязывания определенной политики. Любая функция, реализованная таким образом, чтобы принудительно использовать политику, при которой пространство пользователя имеет доступ к данным, а модуль ядра - нет, плохо спроектирован.

Код модуля ядра, по замыслу, выполняется с тем же уровнем привилегий, что и остальная часть ядра. Не существует надежного способа запретить модулю ядра доступ к любым данным, к которым может получить доступ любая другая часть ядра. Любые такие попытки можно обойти с помощью красивых уродливых хаков.

В качестве крайнего примера, на машинах x86 модуль ядра может использовать встроенную сборку для прямого доступа к регистрам управления, обхода таблиц страниц и работать с любой желаемой областью памяти. То же самое и с обработчиками прерываний и исключений.

Для этого я использовал top, потому что он на самом деле дает CPU %. Код, который я использовал, выглядит следующим образом

Process process = Runtime.getRuntime().exec("top -n 1");
                //Get the output of top so that it can be read
                BufferedReader bufferedReader = new BufferedReader(
                new InputStreamReader(process.getInputStream()));
                String line;
                //Read every line of the output of top that contains data
                while (((line = bufferedReader.readLine()) != null)) {
                    //Break the line into parts.  Any number of spaces greater than 0 defines a new element
                    numbersC = line.split("[ ]+");              
                    if (i > 6) {  
                        //Some lines start with a space, so their indices are different than others
                        if (numbersC[0].equals("")){
                            //If name contains the string com.android, then it is a process that we want to take values for
                            if (numbersC[numbersC.length - 1].toLowerCase().contains("com.android".toLowerCase())){
                                //Add the name of the process to the Name arraylist, excluding the com.android. part
                                Name.add(numbersC[numbersC.length - 1].replace("com.android.", ""));
                                //Add the CPU value of the process to the CPU arraylist, without the % at the end
                                CPU.add(Long.parseLong(numbersC[3].replace("%", "")));  
                            }
                        }
                        else {
                            //This is basically the same as above, except with different index values, as there is no leading space in the numbers array
                            if (numbersC[numbersC.length - 1].toLowerCase().contains("com.android.".toLowerCase())){ 
                                Name.add(numbersC[numbersC.length - 1].replace("com.android.", ""));
                                CPU.add(Long.parseLong(numbersC[2].replace("%", "")));
                            }
                        }
                    }
                    i++;
                }
Другие вопросы по тегам