diff --git a/ru_RU.KOI8-R/books/developers-handbook/driverbasics/chapter.sgml b/ru_RU.KOI8-R/books/developers-handbook/driverbasics/chapter.sgml new file mode 100644 index 0000000000..79bbcf89b7 --- /dev/null +++ b/ru_RU.KOI8-R/books/developers-handbook/driverbasics/chapter.sgml @@ -0,0 +1,409 @@ + + + + Написание драйверов устройств для FreeBSD + + Эту главу написал Мюррэй Стокели (Murray Stokely) на основе множества + источников, включая справочную страницу intro(4), созданную Джоргом + Вуншем (Joerg Wunsch). + + + Введение + + Эта глава является кратким введением в процесс написания драйверов + устройств для FreeBSD. В этом контексте термин устройство используется + в основном для вещей, связанных с оборудованием, относящимся к системе, + таких, как диски, печатающие устройства или графические дисплеи с + клавиатурами. Драйвер устройства является программной компонентой + операционной системы, управляющей некоторым устройством. Имеются также + так называемые псевдо-устройства, в случае которых драйвер устройства + эмулирует поведение устройства программно, без наличия какой-либо + соответствующей аппаратуры. Драйверы устройств могут быть + вкомпилированы в систему статически или могут загружаться по требованию + при помощи механизма динамического компоновщика ядра `kld'. + + Большинство устройств в Unix-подобной операционной системе доступны + через файлы устройств (device-nodes), иногда также называемые + специальными файлами. В иерархии файловой системы эти файлы обычно + находятся в каталоге /dev. Пока система devfs + полностью не интегрирована во FreeBSD, каждый файл устройства должен + создаваться статически и вне зависимости от наличия соответствующего + драйвера устройста. Большинство файлов устройств в системе создаются + при помощи команды MAKEDEV. + + Драйверы устройств могут быть условно разделены на две категории; + драйверы символьных и сетевых устройств. + + + + Механизм динамического компоновщика ядра - KLD + + Интерфейс kld позволяет системным администраторам динамически + добавлять и убирать функциональность из работающей системы. Это + позволяет разработчикам драйверов устройств загружать собственные + изменения в работающее ядро без постоянных перезагрузок для + тестирования изменений. + + Для работы с интерфейсом kld используются следующие команды + администратора: + + + + + kldload - загружает новый модуль ядра + + + + + + kldunload - выгружает модуль ядра + + + + + + kldstat - выводит список загруженных в данный + момент модулей + + + + + + Скелет модуля ядра + + +/* + * KLD Skeleton + * Inspired by Andrew Reiter's Daemonnews article + */ + +#include <sys/types.h> +#include <sys/module.h> +#include <sys/systm.h> /* uprintf */ +#include <sys/errno.h> +#include <sys/param.h> /* defines used in kernel.h */ +#include <sys/kernel.h> /* types used in module initialization */ + +/* + * Load handler that deals with the loading and unloading of a KLD. + */ + +static int +skel_loader(struct module *m, int what, void *arg) +{ + int err = 0; + + switch (what) { + case MOD_LOAD: /* kldload */ + uprintf("Skeleton KLD loaded.\n"); + break; + case MOD_UNLOAD: + uprintf("Skeleton KLD unloaded.\n"); + break; + default: + err = EINVAL; + break; + } + return(err); +} + +/* Declare this module to the rest of the kernel */ + +DECLARE_MODULE(skeleton, skel_loader, SI_SUB_KLD, SI_ORDER_ANY); + + + + Makefile + + Во FreeBSD имеются заготовки для включения в make-файлы, которые + вы можете использовать для быстрой компиляции собственных дополнений + к ядру. + + +SRCS=skeleton.c +KMOD=skeleton + +.include <bsd.kmod.mk> + + + Простой запуск команды make с этим make-файлом + приведет к созданию файла skeleton.ko, который + можно загрузить в вашу систему, набрав: + + +&prompt.root kldload -v ./skeleton.ko + + + + + + + Обращение к драйверу устройства + + Unix дает некоторый общий набор системных вызовов для использования + в пользовательских приложениях. Когда пользователь обращается к + файлу устройства, высокие уровни ядра перенаправляют эти обращения к + соответствующему драйверу устройства. Скрипт + /dev/MAKEDEV создает большинство файлов устройств в + вашей системе, однако если вы ведете разработку своего собственного + драйвера, то может появиться необходимость в создании собственных + файлов устройств при помощи команды mknod. + + + Создание статических файлов устройств + + Для создания файла устройства команде mknod + требуется указать четыре аргумента. Вы должны указать имя этого + файла устройства, тип устройства, старшее число устройства и младшее + число устройства. + + + + Динамические файлы устройств + + Файловая система устройств, devfs, предоставляет доступ к + пространству имен устройств ядра из глобального пространства имен + файловой системы. Это устраняет потенциальную проблемы наличия + драйвера без статического файла устройства или файла устройства без + установленного драйвера устройства. Devfs все еще находится в + разработке, однако она уже достаточно хорошо работает. + + + + + Символьные устройства + + Драйвер символьного устройства передает данные непосредственно в + или из процесса пользователя. Это самый распространенный тип драйвера + устройства и в дереве исходных текстов имеется достаточно простых + примеров таких драйверов. + + В этом простом примере псевдо-устройство запоминает какие угодно + значения, которые вы в него записываете, и затем может выдавать их + назад при чтении из этого устройства. + + +/* + * Simple `echo' pseudo-device KLD + * + * Murray Stokely + */ + +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) + +#include <sys/types.h> +#include <sys/module.h> +#include <sys/systm.h> /* uprintf */ +#include <sys/errno.h> +#include <sys/param.h> /* defines used in kernel.h */ +#include <sys/kernel.h> /* types used in module initialization */ +#include <sys/conf.h> /* cdevsw struct */ +#include <sys/uio.h> /* uio struct */ +#include <sys/malloc.h> + +#define BUFFERSIZE 256 + +/* Function prototypes */ +d_open_t echo_open; +d_close_t echo_close; +d_read_t echo_read; +d_write_t echo_write; + +/* Character device entry points */ +static struct cdevsw echo_cdevsw = { + echo_open, + echo_close, + echo_read, + echo_write, + noioctl, + nopoll, + nommap, + nostrategy, + "echo", + 33, /* reserved for lkms - /usr/src/sys/conf/majors */ + nodump, + nopsize, + D_TTY, + -1 +}; + +typedef struct s_echo { + char msg[BUFFERSIZE]; + int len; +} t_echo; + +/* vars */ +static dev_t sdev; +static int len; +static int count; +static t_echo *echomsg; + +MALLOC_DECLARE(M_ECHOBUF); +MALLOC_DEFINE(M_ECHOBUF, "echobuffer", "buffer for echo module"); + +/* + * This function acts is called by the kld[un]load(2) system calls to + * determine what actions to take when a module is loaded or unloaded. + */ + +static int +echo_loader(struct module *m, int what, void *arg) +{ + int err = 0; + + switch (what) { + case MOD_LOAD: /* kldload */ + sdev = make_dev(&echo_cdevsw, + 0, + UID_ROOT, + GID_WHEEL, + 0600, + "echo"); + /* kmalloc memory for use by this driver */ + /* malloc(256,M_ECHOBUF,M_WAITOK); */ + MALLOC(echomsg, t_echo *, sizeof(t_echo), M_ECHOBUF, M_WAITOK); + printf("Echo device loaded.\n"); + break; + case MOD_UNLOAD: + destroy_dev(sdev); + FREE(echomsg,M_ECHOBUF); + printf("Echo device unloaded.\n"); + break; + default: + err = EINVAL; + break; + } + return(err); +} + +int +echo_open(dev_t dev, int oflags, int devtype, struct proc *p) +{ + int err = 0; + + uprintf("Opened device \"echo\" successfully.\n"); + return(err); +} + +int +echo_close(dev_t dev, int fflag, int devtype, struct proc *p) +{ + uprintf("Closing device \"echo.\"\n"); + return(0); +} + +/* + * The read function just takes the buf that was saved via + * echo_write() and returns it to userland for accessing. + * uio(9) + */ + +int +echo_read(dev_t dev, struct uio *uio, int ioflag) +{ + int err = 0; + int amt; + + /* How big is this read operation? Either as big as the user wants, + or as big as the remaining data */ + amt = MIN(uio->uio_resid, (echomsg->len - uio->uio_offset > 0) ? echomsg->len - uio->uio_offset : 0); + if ((err = uiomove(echomsg->msg + uio->uio_offset,amt,uio)) != 0) { + uprintf("uiomove failed!\n"); + } + + return err; +} + +/* + * echo_write takes in a character string and saves it + * to buf for later accessing. + */ + +int +echo_write(dev_t dev, struct uio *uio, int ioflag) +{ + int err = 0; + + /* Copy the string in from user memory to kernel memory */ + err = copyin(uio->uio_iov->iov_base, echomsg->msg, MIN(uio->uio_iov->iov_len,BUFFERSIZE)); + + /* Now we need to null terminate */ + *(echomsg->msg + MIN(uio->uio_iov->iov_len,BUFFERSIZE)) = 0; + /* Record the length */ + echomsg->len = MIN(uio->uio_iov->iov_len,BUFFERSIZE); + + if (err != 0) { + uprintf("Write failed: bad address!\n"); + } + + count++; + return(err); +} + +DEV_MODULE(echo,echo_loader,NULL); + + + Перед тем, как устанавливать этот драйвер, в вашей файловой системе + вам нужно создать файл устройства при помощи команды, подобной + следующей: + + +&prompt.root mknod /dev/echo c 33 0 + + + Когда этот драйвер загружен, вы можете выполнять следующие + действия: + + +&prompt.root echo -n "Test Data" > /dev/echo +&prompt.root cat /dev/echo +Test Data + + + Об устройствах, обслуживающих реальное оборудование, рассказывается + в следующей главе.. + + Дополнительные источники информации + + + Учебник + по программированию механизма динамического компоновщика ядра + (KLD) - Daemonnews + Октябрь 2000 + + + + + Как + писать драйверы ядра в парадигме NEWBUS - Daemonnews Июль 2000 + + + + + + + + Сетевые драйверы + + В случае драйверов сетевых устройств файлы устройств для доступа к + ним не используются. Их выбор основан на другом механизме, работающем + в ядре, и не использующем вызов open(); об использование сетевых + устройств в общем случае рассказано в описании системного вызова + socket(2). + + Почитайте справочную информацию о вызове ifnet(), устройстве + loopback, почитайте драйверы Билла Пола (Bill Paul), и так + далее.. + + \ No newline at end of file diff --git a/ru_RU.KOI8-R/books/developers-handbook/locking/chapter.sgml b/ru_RU.KOI8-R/books/developers-handbook/locking/chapter.sgml new file mode 100644 index 0000000000..b70a6e7de8 --- /dev/null +++ b/ru_RU.KOI8-R/books/developers-handbook/locking/chapter.sgml @@ -0,0 +1,339 @@ + + + + Замечания по блокировке + + Эта глава поддерживается проектом FreeBSD SMP Next + Generation Project + freebsd-smp@FreeBSD.org. + + Этот документ описывает механизм блокировки, используемый в ядре + FreeBSD для обеспечения эффективной поддержки нескольких процессоров в + ядре. Блокировку можно рассматривать с нескольких точек зрения. + Структуры данных могут быть защищены с помощью блокировок mutex или + &man.lockmgr.9;. Несколько переменных защищены просто в силу атомарности + используемых для доступа к ним операций. + + + Мьютексы + + Мьютекс (mutex) - это просто блокировка, используемая для + реализации гарантированной исключительности. В частности, в каждый + момент времени мьютексом может владеть только один объект. Если + какой-то объект хочет получить мьютекс, который уже кто-то занял, он + должен дождаться момента его освобождения. В ядре FreeBSD владельцами + мьютексов являются процессы. + + Мьютексы могут быть затребованы рекурсивно, но предполагается, что + они занимаются на короткое время. В частности, владельцу мьютекса + нельзя выдерживать паузу. Если вам нужно выполнить блокировку на время + паузы, используйте блокировку через &man.lockmgr.9;. + + Каждый мьютекс имеет несколько представляющих интерес + характеристик: + + + + Имя переменной + + Имя переменной struct mtx в исходных текстах + ядра. + + + + + Логическое имя + + Имя мьютекса, назначенное ему через + mtx_init. Это имя выводится в сообщениях + трассировки KTR и диагностических предупреждающих и ошибочных + сообщениях и используется для идентификации мьютексов в + отладочном коде. + + + + + Тип + + Тип мьютекса в терминах флагов MTX_*. + Значение каждого флага связано с его смыслом так, как это описано + в &man.mutex.9;. + + + + MTX_DEF + + Sleep-мьютекс + + + + + MTX_SPIN + + Spin-мьютекс + + + + + MTX_COLD + + Этот мьютекс инициализируется очень рано. Поэтому он + должен быть объявлен через функции + MUTEX_DECLARE, а флаг + MTX_COLD должен быть передан в функцию + mtx_init. + + + + + MTX_TOPHALF + + Этот spin-мьютекс не запрещает прерывания. + + + + + MTX_NORECURSE + + Этот мьютекс не разрешается блокировать + рекурсивно. + + + + + + + + Защиты + + Список структур данных или членов структур данных, которые + защищает этот мьютекс. Для членов структур данных иям будет в + форме + + + + + + Зависимые функции + + Функции, которые можно вызвать, если этот мьютекс + занят. + + + + + + Список мьютексов + + + + + Имя переменной + Логическое имя + Тип + Защиты + Зависимые функции + + + + + + + sched_lock + sched lock + + MTX_SPIN | + MTX_COLD + + + _gmonparam, + cnt.v_swtch, + cp_time, + curpriority, + P_PROFIL XXX, + P_INMEM, + P_SINTR, + P_TIMEOUT, + P_SWAPINREQ XXX, + P_INMEN XXX), + p_prof/, + p_ru/, + statclock), + pscnt, + slpque, + itqueuebits, + itqueues, + rtqueuebits, + rtqueues, + queuebits, + queues, + idqueuebits, + idqueues, + switchtime, + + + setrunqueue, + remrunqueue, + mi_switch, + chooseproc, + schedclock, + resetpriority, + updatepri, + maybe_resched, + cpu_switch, + cpu_throw + + + + + + vm86pcb_lock + vm86pcb lock + + MTX_DEF | + MTX_COLD + + + vm86pcb + + + vm86_bioscall + + + + + + Giant + Giant + + MTX_DEF | + MTX_COLD + + nearly everything + lots + + + + + callout_lock + callout lock + + MTX_SPIN + + + callfree, + callwheel, + nextsoftcheck, + softticks, + ticks + + + + + + +
+
+ + + Блокировки менеджера блокировок + + Блокировки, которые даются через интерфейс &man.lockmgr.9;, + являются блокировками менеджера блокировок. Эти блокировки являются + блокировками на чтение/запись и ими могут владеть процессы в состоянии + ожидания. + + + Список блокировок &man.lockmgr.9; + + + + + Имя переменной + Защиты + + + + + allproc_lock + + allproc + zombproc + pidhashtbl + nextpid + + proctree_lock + + + + + +
+
+ + + Атомарно защищенные переменные + + Переменной, защищенной атомарно, является особая переменная, + которая не защищается явной блокировкой. Вместо этого для доступа к + данным переменных используются специальные атомарные операции, как + описано в &man.atomic.9;. Лишь несколько переменных используются таким + образом, хотя другие примитивы синхронизации, такие как мьютексы, + реализованы с атомарно защищенными переменными. + + + + astpending + + + + + + + +
diff --git a/ru_RU.KOI8-R/books/developers-handbook/pci/chapter.sgml b/ru_RU.KOI8-R/books/developers-handbook/pci/chapter.sgml new file mode 100644 index 0000000000..e380721dac --- /dev/null +++ b/ru_RU.KOI8-R/books/developers-handbook/pci/chapter.sgml @@ -0,0 +1,221 @@ + + + + Устройства PCI + + Эта глава посвящена механизмам FreeBSD по написанию драйверов + устройств, работающих на шине PCI. + + Обнаружение и подключение + + Здесь находится информация о том, как код шины PCI проходит по + неподключенным устройствам и распознает возможность загруженного драйвера + kld выполнить подключение к какому-либо из них. + + +/* + * Simple KLD to play with the PCI functions. + * + * Murray Stokely + */ + +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) + +#include <sys/types.h> +#include <sys/module.h> +#include <sys/systm.h> /* uprintf */ +#include <sys/errno.h> +#include <sys/param.h> /* defines used in kernel.h */ +#include <sys/kernel.h> /* types used in module initialization */ +#include <sys/conf.h> /* cdevsw struct */ +#include <sys/uio.h> /* uio struct */ +#include <sys/malloc.h> +#include <sys/bus.h> /* structs, prototypes for pci bus stuff */ + +#include <pci/pcivar.h> /* For get_pci macros! */ + +/* Function prototypes */ +d_open_t mypci_open; +d_close_t mypci_close; +d_read_t mypci_read; +d_write_t mypci_write; + +/* Character device entry points */ + +static struct cdevsw mypci_cdevsw = { + mypci_open, + mypci_close, + mypci_read, + mypci_write, + noioctl, + nopoll, + nommap, + nostrategy, + "mypci", + 36, /* reserved for lkms - /usr/src/sys/conf/majors */ + nodump, + nopsize, + D_TTY, + -1 +}; + +/* vars */ +static dev_t sdev; + +/* We're more interested in probe/attach than with + open/close/read/write at this point */ + +int +mypci_open(dev_t dev, int oflags, int devtype, struct proc *p) +{ + int err = 0; + + uprintf("Opened device \"mypci\" successfully.\n"); + return(err); +} + +int +mypci_close(dev_t dev, int fflag, int devtype, struct proc *p) +{ + int err=0; + + uprintf("Closing device \"mypci.\"\n"); + return(err); +} + +int +mypci_read(dev_t dev, struct uio *uio, int ioflag) +{ + int err = 0; + + uprintf("mypci read!\n"); + return err; +} + +int +mypci_write(dev_t dev, struct uio *uio, int ioflag) +{ + int err = 0; + + uprintf("mypci write!\n"); + return(err); +} + +/* PCI Support Functions */ + +/* + * Return identification string if this is device is ours. + */ +static int +mypci_probe(device_t dev) +{ + uprintf("MyPCI Probe\n" + "Vendor ID : 0x%x\n" + "Device ID : 0x%x\n",pci_get_vendor(dev),pci_get_device(dev)); + + if (pci_get_vendor(dev) == 0x11c1) { + uprintf("We've got the Winmodem, probe successful!\n"); + return 0; + } + + return ENXIO; +} + +/* Attach function is only called if the probe is successful */ + +static int +mypci_attach(device_t dev) +{ + uprintf("MyPCI Attach for : deviceID : 0x%x\n",pci_get_vendor(dev)); + sdev = make_dev(&mypci_cdevsw, + 0, + UID_ROOT, + GID_WHEEL, + 0600, + "mypci"); + uprintf("Mypci device loaded.\n"); + return ENXIO; +} + +/* Detach device. */ + +static int +mypci_detach(device_t dev) +{ + uprintf("Mypci detach!\n"); + return 0; +} + +/* Called during system shutdown after sync. */ + +static int +mypci_shutdown(device_t dev) +{ + uprintf("Mypci shutdown!\n"); + return 0; +} + +/* + * Device suspend routine. + */ +static int +mypci_suspend(device_t dev) +{ + uprintf("Mypci suspend!\n"); + return 0; +} + +/* + * Device resume routine. + */ + +static int +mypci_resume(device_t dev) +{ + uprintf("Mypci resume!\n"); + return 0; +} + +static device_method_t mypci_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, mypci_probe), + DEVMETHOD(device_attach, mypci_attach), + DEVMETHOD(device_detach, mypci_detach), + DEVMETHOD(device_shutdown, mypci_shutdown), + DEVMETHOD(device_suspend, mypci_suspend), + DEVMETHOD(device_resume, mypci_resume), + + { 0, 0 } +}; + +static driver_t mypci_driver = { + "mypci", + mypci_methods, + 0, + /* sizeof(struct mypci_softc), */ +}; + +static devclass_t mypci_devclass; + +DRIVER_MODULE(mypci, pci, mypci_driver, mypci_devclass, 0, 0); + + + Дополнительная информация + + PCI Special Interest + Group + + PCI System Architecture, Fourth Edition by + Tom Shanley, et al. + + + + \ No newline at end of file diff --git a/ru_RU.KOI8-R/books/developers-handbook/secure/chapter.sgml b/ru_RU.KOI8-R/books/developers-handbook/secure/chapter.sgml new file mode 100644 index 0000000000..7006818a5f --- /dev/null +++ b/ru_RU.KOI8-R/books/developers-handbook/secure/chapter.sgml @@ -0,0 +1,439 @@ + + + + Безопасное программирование + + Эту главу написал Мюррей Стокели (Murray Stokely). + + + Обзор + + Эта глава описывает некоторые из проблем обеспечения безопасности, + которые десятилетиями преследовали программистов Unix, а также + несколько новых доступных инструментов, помогающих программистам + избежать написания небезопасного кода. + + + + Методология обеспечения безопасности + + Написание безопасных приложений требует весьма критического и + пессимистического взгляда на жизнь. Приложения должны работать по + принципу наименьших привилегий, при котором никакой + процесс не должен работать с привилегиями, превышающими минимально + необходимый для выполнения своих функций минимум. Ранее проверенный + код должен использоваться там, где только это возможно для избежания + общих ошибок, которые могли быть уже исправлены другими. + + Одной из неприятностей в среде Unix является легкость в + предположении безопасности этого окружения. Приложения никогда не + должны верить пользовательскому вводу (во всех его формах), ресурсам + системы, межпроцессному взаимодействию или времени выполнения событий. + Процессы Unix выполняются не синхронно, так что логические операции + редко бывают атомарными. + + + + Переполнения буфера + + Переполнения буфера появились вместе с появление архитектуры + Фон-Неймана . Впервые широкую известность они + получили в 1988 году вместе с Интернет-червем Мурса (Moorse). К + сожалению, точно такая же атака повторилась и в наши дни. Из 17 + бюллетеней безопасности CERT за 1999 год, 10 были непосредственно + вызваны ошибкам в программном обеспечении, связанным с переполнениями + буфера. Самые распространенные типы атак с использованием переполнения + буфера основаны на разрушении стека. + + Самые современные вычислительные системы используют стек для + передачи аргументов процедурам и сохранения локальных переменных. Стек + является буфером типа LIFO (последним вошел первым вышел) в верхней + части области памяти процесса. Когда программа вызывает функцию, + создается новая "граница стека". Эта граница состоит из аргументов, + переданных в функцию, а также динамического количества пространства + локальных переменных. "Указатель стека" является регистром, хранящим + текущее положение вершины стека. Так как это значение постоянно + меняется вместе с помещением новых значений на вершину стека, многие + реализации также предусматривают "указатель границы", который + расположен около начала стека, так что локальные переменные можно легко + адресовать относительно этого значения. Адрес + возврата из функции также сохраняется в стеке, и это является причиной + нарушений безопасности, связанных с переполнением стека, так как + перезаписывание локальной переменной в функции может изменить адрес + возврата из этой функции, потенциально позволяя злоумышленнику + выполнить любой код. + + Хотя атаки с переполнением стека являются замыми распространенными, + стек можно также перезаписать при помощи атаки, основанной на выделении + памяти (malloc/free) из "кучи". + + Как и во многих других языках программирования, в C не выполняется + автоматической проверки границ в массивах или указателях. Кроме того, + стандартная библиотека C полна очень опасных функций. + + + + + + strcpy(char *dest, const char + *src) + Может переполнить целевой буфер + + + + strcat(char *dest, const char + *src) + Может переполнить целевой буфер + + + + getwd(char *buf) + Может переполнить буфер buf + + + + gets(char *s) + Может переполнить буфер s + + + + [vf]scanf(const char *format, + ...) + Может переполнить свои аргументы. + + + + realpath(char *path, char + resolved_path[]) + Может переполнить буфер path + + + + [v]sprintf(char *str, const char + *format, ...) + Может переполнить буфер str. + + + + + + + Пример переполнения буфера + + В следующем примере кода имеется ошибка переполнения буфера, + предназначенная для перезаписи адреса возврата и обхода инструкции, + следующей непосредственно за вызовом функции. (По мотивам ) + + +#include stdio.h + +void manipulate(char *buffer) { + char newbuffer[80]; + strcpy(newbuffer,buffer); +} + +int main() { + char ch,buffer[4096]; + int i=0; + + while ((buffer[i++] = getchar()) != '\n') {}; + + i=1; + manipulate(buffer); + i=2; + printf("The value of i is : %d\n",i); + return 0; +} + + + Давайте посмотрим, как будет выглядеть образ процесса, если в + нашу маленькую программу мы введем 160 пробелов. + + [XXX figure here!] + + Очевидно, что для выполнения реальных инструкций (таких, как + exec(/bin/sh)), может быть придуман более вредоносный ввод. + + + + Как избежать переполнений буфера + + Самым прямолинейным решением проблемы переполнения стека является + использование только памяти фиксированного размера и функций + копирования строк. Функции strncpy и + strncat являются частью стандартной библиотеки + C. Эти функции будут копировать не более указанного количества байт + из исходной строки в целевую. Однако у этих функций есть несколько + проблем. Ни одна из них не гарантирует наличие символа NUL, если + размер входного буфера больше, чем целевого. Параметр длины также + по-разному используется в strncpy и strncat, так что для + программистов легко запутаться в правильном использовании. Есть + также и значительная потеря производительности по сравнению с + strcpy при копировании короткой строки в большой + буфер, потому что strncpy заполняет символами + NUL пространство до указанной длины. + + Для избежания этих проблем в OpenBSD была сделана другая + реализация копирования памяти. Функции strlcpy + и strlcat гарантируют, что они они всегда + терминируют целевую строку нулевым символом, если им будет передан + аргумент ненулевой длины. Более подробная информация об этом + находится здесь . Инструкции OpenBSD + strlcpy и strlcat были + во FreeBSD начиная с 3.5. + + + Вкомпилированная проверка границ во время выполнения + + К несчастью, все еще широко используется очень большой объем + кода, который слепо копирует память без использования только что + рассмотренных функций с проверкой границ. Однако есть другое + решение. Существует несколько расширений к компилятору и + библиотекам C/C++ для выполнения контроля границ во время + выполнения. + + Одним из таких добавлений является StackGuard, который + реализован как маленький патч к генератору кода gcc. Согласно + сайту StackGuard, http://immunix.org/stackguard.html: +
+ "StackGuard распознает и защищает стек от атак, + не позволяя изменять адрес возврата в стеке. При вызове + функции StackGuard помещает вслед за адресом возврата + сигнальное слово. Если после возврата из функции оно + оказывается измененным, то была попытка выполнить атаку на + стек, и программа отвечает на это генерацией сообщения о + злоумышленнике в системном журнале, а затем прекращает + работу." +
+ +
+ "StackGuard реализован в виде маленького патча к генератору + кода gcc, а именно процедур function_prolog() и + function_epilog(). function_prolog() усовершенствована для + создания пометок в стеке при начале работы функции, а + function_epilog() проверяет челостность пометки при возврате из + функции. Таким образом, любые попытки изменения адреса + возврата определяются до возврата из функции." +
+
+ + Перекомпиляция вашего приложения со StackGuard является + эффективным способом остановить большинство атак переполнений + буфера, но все же полностью это проблемы не решает. +
+ + + Проверка границ во время выполнения с использованием + библиотек. + + Механизмы на основе компилятора полностью бесполезны для + программного обеспечения, поставляемого в двоичном виде, которое вы + не можете перекомпилировать. В этих ситуациях имеется некоторое + количество библиотек, в которых реализованы небезопасные функции + библиотеки C (strcpy, + fscanf, getwd, и так + далее..), обеспечивающие невозможность записи после указателя + стека. + + + libsafe + libverify + libparnoia + + + К сожалению, эти защиты имеют некоторое количество недостатков. + Эти библиотеки могут защитить только против малого количества + проблем, и не могут исправить реальные проблемы. Эти защиты могут + не сработать, если приложение скомпилировано с параметром + -fomit-frame-pointer. К тому же переменные окружения LD_PRELOAD и + LD_LIBRARY_PATH могут быть переопределены/сняты + пользователем. + +
+
+ + + Проблемы с установленным битом UID + + Имеется по крайней мере 6 различных идентификаторов (ID), связанных + с любым взятым процессом. Поэтому вы должны быть очень осторожны с + тем, какие права имеет ваш процесс в каждый момент времени. В + частности, все seteuid-приложения должны понижать свои привилегии, как + только в них отпадает необходимость. + + ID реального пользователя может быть изменен только процессом + администратора. Программа login + устанавливает его, когда пользователь входит в систему, и он редко + меняется. + + Эффективный ID пользователя устанавливается функциями + exec(), если у программы установлен бит seteuidt. + Приложение может выполнить вызов seteuid() в любой + момент для установки эффективного ID пользователя в значение реального + ID пользователя или сохраняемого set-user-ID. Когда эффективный ID + пользователя устанавливается функциями exec(), его + предыдущее значение сохраняется в сохраняемом set-user-ID. + + + + Ограничение среды работы вашей программы + + Традиционно используемым методом ограничения доступа к процессу + является использование системного вызова chroot(). + Этот системный вызов меняет корневой каталог, относительно которого + определяются все остальные пути в самом процессе и всех порожденных ими + процессах. Для того, чтобы этот вызов был выполнен успешно, процесс + должен иметь право на выполнение (поиск) каталога, о котором идет речь. + Новая среда реально не вступит в силу, пока вы не выполните вызов + chdir() в вашей новой среде. Следует также + отметить, что процесс может с легкостью выйти из chroot-среды, если он + имеет привилегии администратора. Это может быть достигнуто созданием + файлов устройств для чтения памяти ядра, подключением отладчика к + процессу вне узницы и многими другими способами. + + Поведение системного вызова chroot() можно + некоторым образом контролировать sysctl-переменной + kern.chroot_allow_open_directories. Когда эта переменная установлена в + 0, chroot() не сработает с ошибкой EPERM, если + есть какие-либо открытые каталоги. Если она установлена в значение по + умолчанию, равное 1, то chroot() не сработает с + ошибкой EPERM, если есть какие-либо открытые каталоги и процесс уже + подвергнут вызову chroot(). Для всех других + значений проверка открытости каталогов будет полностью опущена. + + + Функциональность джейлов (jail) во FreeBSD + + Концепция джейлов (Jail) расширяет возможности + chroot(), ограничивая власть администратора + созданием настоящих `виртуальных серверов'. Как только тюремная + камера создана, все сетевые коммуникации должны осуществляться через + выделенный адрес IP, а сила "привилегий пользователя root" в этой + тюрьме довольно ограничена. + + При работе внутри тюрьмы, любые проверки силы администратора в + ядре при помощи вызова suser() будут + оканчиваться неудачно. Однако некоторые вызовы к + suser() были изменены на новый интерфейс + suser_xxx(). Эта функция отвечает за + распознание и разрешение доступа к власти администратора для + процессов, не находящихся в неволе. + + Процесс администратора внутри среды джейла имеет право: + + + Манипулировать привилегиями с помощью + setuid, seteuid, + setgid, setegid, + setgroups, setreuid, + setregid и + setlogin + + + Устанавливать ограничения на использование + ресурсов при помощи + setrlimit + + + Модифицировать некоторые sysctl-переменные + (kern.hostname) + + + chroot() + + Устанавливать следующие флаги на vnode: + chflags, + fchflags + + + Устанавливать такие атрибуты vnode, как права + доступа к файлу, изменять его владельца, группу, размер, время + доступа и модификации. + + + Осуществлять привязку к привилегированному порту + в области портов Интернет (порты с номерами < 1024) + + + + Jail является очень полезным инструментом + для запуска приложений в защищенном окружении, но есть и некоторые + недостатки. На текущий момент к формату + suser_xxx не преобразованы механизмы IPC, так + что такие приложения, как MySQL, не могут работать в джейле. Права + администратора могут имеет малую силу внутри джейла, но нет + способа определить, что значит "малую". + + + + Возможности процессов POSIX.1e + + Posix выпустил рабочий документ, который добавляет аудит событий, + списки управления доступом, тонко настраиваемые привилегии, метки + информации и жесткое управление доступом. + + Этот документ находится в работе и находится в центре внимания + проекта TrustedBSD. + Некоторая начальная функциональность уже была добавлена во + FreeBSD-current (cap_set_proc(3)). + + + + + Доверие + + Приложение никогда не должно полагать, что среда пользователя + безопасна. Сюда включается (но этим не ограничено): ввод пользователя, + сигналы, переменные среды, ресурсы, IPC, отображаемая в файл память, + рабочий каталог файловой системы, дескрипторы файлов, число открытых + файлов и прочее. + + Никогда не думайте, что сможете предусмотреть все формы + неправильного ввода, который может дать пользователь. Вместо этого + ваше приложение должно осуществлять позитивную фильтрацию, пропуская + только конечное множество возможных вариантов ввода, которые вы + считаете безопасными. Неполная праверка данных была причиной многих + нарушений защиты, особенно CGI-скриптов на веб-сайтах. Для имен файлов + вам нужно уделять особое внимание путям ("../", "/"), символическим + ссылкам и экранирующим символам оболочки. + + В perl имеется такая очень полезная вещь, как "безупречный" (taint) + режим, который можно использовать для запрещения скриптам использовать + данные, порожденные вне программы, не безопасным способом. Этот режим + проверяет аргументы командной строки, переменные окружения, информацию + локализации, результаты некоторых системных вызовов + (readdir(), readlink(), + getpwxxx() и весь файловый ввод. + + + + Неожиданное поведение + + Неожиданное поведение - это аномальное поведение, вызванное + непредусмотренной зависимостью от относительной последовательности + событий. Другими словами, программист неправильно предположил, что + некоторое событие всегда случается перед другим. + + Некоторые из широко распространенных причин возникновения таких + проблем являются сигналы, проверки доступа и открытия файлов. Сигналы + по своей природе являются асинхронными событиями, так что по отношению + к ним нужно проявлять особое внимание. Проверка доступа функцией + access(2) с последующим вызовом + open(2) полностью не атомарно. Пользователи могут + переместить файлы в промежутке между двумя вызовами. Вместо этого + привилегированное приложение должно выполнить + seteuid(), а затем сразу вызвать + open(). В тех же строках приложение должно всегда + устанавливать явно маску прав доступа (umask) перед вызовом функции + open() во избежание беспорядочных вызовов + chmod(). + +
\ No newline at end of file