2016-08-24 5 views
4

Задача

У меня есть небольшой модуль ядра, который я написал для моего Raspberry Pi 2, которая реализует дополнительный системный вызов для формирования показателей энергопотребления. Я хотел бы изменить системный вызов, чтобы он вызывался только тогда, когда его выдает специальный пользователь (например, «root» или «pi» пользователя). В противном случае вызов просто пропускает основную часть своего тела и возвращает успех.Убедитесь, что проверка UID/GID в системном вызове выполняется в РКГ-критической секции


Фоновая работа

Я прочитал в вопрос подробно, и I've found a similar question on SO, но есть многочисленные проблемы, связанные с ней, с моей точки зрения (указано ниже).


Вопрос

  • Связанный вопрос отмечает, что struct task_struct содержит элемент указателя на struct cred, как это определено в linux/sched.h и linux/cred.h. Последний из двух заголовков не существует в моей системе (системах), а первый не показывает объявление указателя на элемент struct cred. Имеет ли это смысл?
    • Глупые ошибки. Это присутствует во всей полноте в заголовках ядра (то есть: /usr/src/linux-headers-$(uname -r)/include/linux/cred.h), я искал в заголовках gcc-build в /usr/include/linux.
  • Даже если вышеуказанное работало, оно не упоминает, если бы я получил the real, effective, or saved UID for the process. Возможно ли даже получить каждое из этих трех значений из системного вызова?
    • cred.h уже содержит все эти данные.
  • Есть ли безопасный способ в модуле ядра, чтобы быстро определить, какие группы пользователь принадлежит без разбора /etc/group?
    • cred.h уже содержит все эти данные.

Update

Итак, единственный правильный вопрос остальные заключается в следующем:

Обратите внимание, что переборе процессов и чтения учетных данных процесса должно быть сделано в рамках РКО критический раздел.

ответ

2

Связанный вопрос касается принципиально иного вопроса. Цитирование:

Обратите внимание, что uid, который я хочу получить, НЕ относится к текущему процессу.

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

Между тем, если вы хотите работать с потоком, выполняющим самый код, вы можете знать, что он не будет завершен (потому что он выполняет ваш код, а не путь выхода). Возникает вопрос о стабильности верительных грамот - хорошие новости, они также гарантированы там и могут быть доступны без какой-либо подготовки. Это можно легко проверить, проверив код, выполняющий переключение учетных данных.

У нас остается вопрос, какие примитивы можно использовать для доступа. С этой целью можно использовать make_kuid, uid_eq и подобные примитивы.

Реальный вопрос, почему это syscall, а не только файл/proc.

Смотрите эту BlogPost для несколько разработанного описания верительных обработки: http://codingtragedy.blogspot.com/2015/04/weird-stuff-thread-credentials-in-linux.html

+0

Хороший читать. Спасибо. – DevNull

+0

'/ proc' предназначен для информации процесса. Также есть некоторые устаревшие материалы, но новый материал, который не связан с процессом, должен находиться под '/ sys'. – Gilles

2

Во-первых, при добавлении нового системного вызова редко правильный способ делать вещи. Лучше всего делать все с помощью существующих механизмов, потому что вы будете использовать уже существующие инструменты с обеих сторон: существующие функции утилиты в ядре, существующие libc и высокоуровневую поддержку языков в пользовательской среде. Файлы представляют собой центральную концепцию в Linux (например, в других Unix-системах), и большинство данных обменивается через файлы: device files или специальные файловые системы, такие как proc и sysfs.

Я хотел бы изменить системный вызов, чтобы он вызывался, только если его вызвал специальный пользователь (например, «root» или «pi» пользователя).

Вы не можете сделать это в ядре. Это не только неправильно с дизайнерской точки зрения, но даже не возможно. Ядро ничего не знает о именах пользователей. Единственное знание о пользователях в ядре в том, что некоторые привилегированные действия зарезервированы для пользователя 0 в корне namespace (не забывайте, что последняя часть! И если это ново для вас, это признак того, что вы не должны делать продвинутые вещи, такие как добавление системных вызовов). (Многие действия на самом деле ищут capability, а не как root.)

sysfs. Прочтите kernel documentation и найдите не древние онлайн-уроки или существующий код ядра (код, который использует sysfs, как правило, довольно чист в наши дни). С помощью sysfs вы публикуете информацию через файлы под номером /sys. Контроль доступа зависит от пользователя - имеет явное значение по умолчанию в ядре и делает такие вещи, как вызов chgrp, chmod или setfacl в сценариях загрузки. Это одно из многих колес, которое вам не нужно изобретать на стороне пользователя при использовании существующих механизмов.

Метод sysfs show автоматически блокирует файл, поэтому только один поток ядра может выполнять его за раз. Это одно из многих колес, которое вам не нужно изобретать на стороне ядра при использовании существующих механизмов.

+0

Незначительная опечатка «вы можете сделать это в ядре». Понимает ли ядро ​​ненулевое значение PID/GID, даже если оно не может сопоставить их с строкой имени пользователя в '/ etc/passwd'? Спасибо. – DevNull

+0

@DevNull Ядро поддерживает значения UID и GID, но не знает, что они означают, кроме 0 = пользователя, которому разрешено делать много вещей, которые другие не могут. Но имейте в виду, что UID/GID имеет смысл только в пространстве имен: это не целое число, а пара {namespace, integer}. В разных виртуальных средах в userland может быть несколько '/ etc/passwd', значение UID само по себе ничего не значит. – Gilles