LINUX.ORG.RU

Драйвер для дешифрования устройства

 , ,


0

1

Доброго времени суток!

Возникла задача создать минимальный образ, зашифровать его простейшим способом и написать драйвер, который будет дешифровать его «на лету».

Сразу оговорюсь, что почти всё делаю по интуиции, и некоторые моменты могут оказаться для вас абсурдными.

Создаю образ:

dd if=/dev/zero of=myFS bs=1024 count=60
mkfs.ext2 myFS

Шифрую XOR-ом:

int main()
{
	std::fstream streamIn;
	std::fstream streamOut;

	const char key = 0b00001111;

	streamIn.open("myFS", std::ios_base::binary | std::ios_base::in);
	streamOut.open("newFS", std::ios_base::binary | std::ios_base::trunc | std::ios_base::out);

	char b;
	while (streamIn.read(&b, 1))
	{
		b ^= key;
		streamOut.write(&b, 1);
	}

	streamIn.close();
	streamOut.close();

	return 0;
}

Далее пишу драйвер. Он основан на device-mapper target-е, и основная функция обработки запросов имеет следующий прототип:

static int sddm_target_map(struct dm_target *ti, struct bio *bio);

То есть я имею в своём распоряжении структуру bio, в которой, как мне это видится, я должен дешифровать все байты. Хороших примеров я не нашёл, так что прошу не заряжать помидоры) Сделал так:

struct bio_vec vec;
struct bvec_iter it;
unsigned int len;
char *addr;
unsigned int i;

bio_for_each_segment(vec, bio, it)
{
	len = vec.bv_len;
	addr = (char*)(page_address(vec.bv_page) + vec.bv_offset);

	for (i = 0; i != len; ++i)
	{
		*(addr+i) ^= 0b00001111;
	}
}

В драйвере device-mapper target-а необходимо изменить целевое устройство bio->bi_bdev на реальное и повторить запрос submit_bio(bio). Хотя к данной задаче это не особо относится, но может быть кому-то пригодится.

Очевидно, что не всё так просто. При попытке монтирования моего устройства получаю следующее:

mount: wrong fs type, bad option, bad superblock on /dev/mapper/mydevice

Видел ещё такой вариант:

bio_for_each_segment(vec, bio, it)
{
	len = vec.bv_len;
	addr = kmap_atomic(vec.bv_page);
	pointer = (char *)(addr + vec.bv_offset);

	for (i = 0; i != len; ++i)
	{
		*(pointer+i) ^= 0b00001111;
	}

	kunmap_atomic(addr);
}

Но и он выдаёт ту же ошибку.

Подскажите, как правильно реализовать задуманное! Спасибо!

а чем всякие уже существующие dmcrypt не устраивают?

Harald ★★★★★ ()
Ответ на: комментарий от Harald

а чем всякие уже существующие dmcrypt не устраивают?

В будущем функционал драйвера будет наращиваться. Да и так, для общего развития пригодится.

AccumPlus ()

Может лучше fuse вместо драйвера ядра?

urquan ()
Ответ на: комментарий от AccumPlus

так посмотри в том же dmcrypt-e, как сделано. он тоже основан на device-mapper. я его давно ковырял, сходу подсказать не смогу.

vvviperrr ★★★★★ ()
Ответ на: комментарий от vvviperrr

так посмотри в том же dmcrypt-e

Сейчас как раз занимаюсь. Просто это обычно дольше, чем спросить знающего человека. У меня по крайней мере)

AccumPlus ()
Ответ на: комментарий от urquan

Может лучше fuse вместо драйвера ядра?

Не слышал об этом. Почитаю...

AccumPlus ()

В рамках совсем идиотского варианта - а не расшифровывать ли тебе контент в ramfs? Ну это если не планируется расположить там что-то сколь-либо существенного размера, конечно.

alex4321 ()
Ответ на: комментарий от alex4321

если не планируется расположить там что-то сколь-либо существенного размера

Возможно, что надо будет и весь раздел шифровать, так что скорее всего не вариант.

AccumPlus ()

Обратил внимание, что вне зависимости от того, зашифровано устройство или нет, первые несколько вызовов функции map всегда принимают bio, содержащую одни только нули. По всей видимости я их дешифрую и получаю мусор.

Однако следом за этими запросами идут те, которые принимают bio с ненулевым содержимым. Простым сравнением увидел, что это именно содержимое моих образов.

Теперь нужно понять, как пропустить первые нулевые запросы.

AccumPlus ()
Ответ на: комментарий от AccumPlus

Я не прав. Несколько первых запросов не обязательно содержат нули. Но они почти точно не содержат ничего, что лежит в моём образе.

AccumPlus ()

В нормальном образе читаются следующие сектора:

0, 24, 8, 56, 8, 0, 24, 56

В зашифрованном:

0, 24, 8, 56, 64, 16, 32, 8, 0, 24, 56, 64, 16, 32

По всей видимости в первых четырёх запросах к зашифрованному образу читается что-то такое, что заставляет драйвер читать ещё три сектора.

Я вывожу читаемые данные в первых четырёх запросов, но они всегда нулевые, причём как для шифрованного, так и для нормального образа. Может быть вывожу как-то неправильно... Вот код:

char *output;
char *temp;
unsigned int j;
// .....

bio_for_each_segment(vec, bio, it)
{
	len = vec.bv_len;
	addr = (char*)(page_address(vec.bv_page) + vec.bv_offset);

	output = (char*)kmallok(15000, GFP_KERNEL);
	output[0] = '\0';

	j = 0;
	for (i = 0; i != len; ++i)
	{
		temp = (char*)kmallok(10, GFP_KERNEL);

		//*(addr+i) ^= 0b00001111;

		itoa(((unsigned short)(*(addr + i))) & 0x00FF, temp, 16);
		strcat(output, " ");
		strcat(output, temp);
		if (++j == 256)
		{
			j = 0;
			printk(KERN_CRIT, output);
			output[0] = '\0';
		}
		kfree(temp);
	}

	printk(KERN_CRIT, output);
	kfree(output);
}

Смотрю вывод в журнале с помощью утилиты dmesg. Такая странная конструкция вывода по 256 символов сделана лишь из-за ограничения длины строки вывода в журнал (около 300).

Имплементацию itoa взял здесь. Там используется функция reverse, взял здесь.

То бишь, если вывод верный, то в этих четырёх секторах лежат нули чтоли. Да даже если и нормально, то почему в зашифрованном образе читаются ещё какие-то сектора?

AccumPlus ()

Не знаю, почему не попробовал сделать это раньше...

В общем запустил нешифрованный образ под этим драйвером - работает. То есть никаких изменений в структуру bio мой драйвер не вносит... Может быть, эти изменения надо как-то фиксировать.

AccumPlus ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.