П О Р Т А Л                            
С Е Т Е В Ы Х                          
П Р О Е К Т О В                        
  
Поиск по сайту:
                                                 
Главная

О проекте

Web-мастеру
     HTML & JavaScript
     SSI
     Perl
     PHP
     XML & XSLT
     Unix Shell

MySQL

Безопасность

Хостинг

Другое








Самое читаемое:

Учебник PHP - "Для Чайника".
Просмотров 176189 раз(а).

Иллюстрированный самоучитель по созданию сайтов.
Просмотров 73020 раз(а).

Учебник HTML.
Просмотров 72708 раз(а).

Руководство по PHP5.
Просмотров 43467 раз(а).

Хостинг через призму DNS.
Просмотров 50042 раз(а).

Подборка текстов стандартных документов.
Просмотров 43700 раз(а).

Учебник PHP - Самоучитель
Просмотров 50013 раз(а).

Документация на MySQL (учебник & справочное руководство)
Просмотров 50380 раз(а).

Внешние атаки...
Просмотров 40787 раз(а).

Учебник PHP.
Просмотров 35907 раз(а).

SSI в примерах.
Просмотров 26981 раз(а).






 
 
| Добавить в избранное | Сделать стартовой Project.Net.Ru | Помощь




Условия перехвата и содержимое файла

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

Чтобы программа не была восприимчива к такого рода ситуациям, необходимо ввести механизм монопольного доступа к файлу данных. Это та же проблема, которая возникает в базах данных, когда различным пользователям позволено одновременно делать запрос и изменять содержимое файла. Принцип блокировки файла решает эту проблему.

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

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

Существует два типа блокировок (по большей части друг с другом не совместимых). Первый, из BSD, основан на системном вызове flock(). Первый аргумент вызова - дескриптор файла, к которому вы желаете получить монопольный доступ, второй - именованая константа, задающая операцию, которая будет производиться. Она может принимать различные значения: LOCK_SH (блокировка для чтения), LOCK_EX (для записи), LOCK_UN (снятие блокировки). Система блокирует процесс на время, пока запрошенная операция невозможна. Однако, вы можете произвести операцию ИЛИ | второго аргумента с константой LOCK_NB, чтобы функция неудачно завершалась вместо того, чтобы приостанавливаться.

Второй тип блокировки, из System V, основан на системном вызове fcntl(), немного сложном. Существует библиотечная функция lockf() близкая к системному вызову, но не до конца. Первый аргумент fcntl() - дескриптор файла для блокировки. Второй - представляет необходимую операцию: F_SETLK и F_SETLKW управляют блокировками, вторая команда приостанавливает процесс пока операция не становится доступной, в то время как первая сразу же возвращает управление при неудачной попытке. F_GETLK проверяет состояние блокировки файла (что бесполезно для рассматриваемых приложений). Третий аргумент - указатель на переменную типа struct flock, которая описывает блокировку. Важные поля структуры flock следующие:

Имя Тип Значение
l_type int Ожидаемое действие: F_RDLCK (блокировка для чтения), F_WRLCK (для записи) and F_UNLCK (для снятия блокировки).
l_whence int Тип смещения поля l_start (обычно SEEK_SET).
l_start off_t Позичия начала блокировки (обычно 0).
l_len off_t Длина блокировки, 0 для достижения конца файла.

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

1    /* ex_03.c */
2    #include <fcntl.h>
3    #include <stdio.h>
4    #include <stdlib.h>
5    #include <sys/stat.h>
6    #include <sys/types.h>
7    #include <unistd.h>
8
9    int
10   main (int argc, char * argv [])
11   {
12     int i;
13     int fd;
14     char buffer [2];
15     struct flock lock;
16
17     for (i = 1; i < argc; i ++) {
18       fd = open (argv [i], O_RDWR | O_CREAT, 0644);
19       if (fd < 0) {
20         fprintf (stderr, "Невозможно открыть %s\n", argv [i]);
21         exit(EXIT_FAILURE);
22       }
23       lock . l_type = F_WRLCK;
24       lock . l_whence = SEEK_SET;
25       lock . l_start = 0;
26       lock . l_len = 0;
27       if (fcntl (fd, F_SETLK, & lock) < 0) {
28         fprintf (stderr, "Невозможно заблокировать %s\n", argv [i]);
29         exit(EXIT_FAILURE);
30       }
31     }
32     fprintf (stdout, "Нажмите Ввод для снятия блокировки(ок)\n");
33     fgets (buffer, 2, stdin);
34     exit(EXIT_SUCCESS);
35   }

Вначале мы запускаем эту программу с первой консоли, где она будет ожидать:

$ cc -Wall ex_03.c -o ex_03
$ ./ex_03 myfile
Нажмите Ввод для снятия блокировки(ок)
>С другого терминала...
    $ ./ex_03 myfile
    Невозможно заблокировать myfile
    $
Нажимая Ввод на первой консоли, мы снимаем блокировки.

При помощи механизма блокировок, вы можете избежать появления условий перехвата в директориях и очередях печати, как демон lpd, который использует flock() для блокировки файла /var/lock/subsys/lpd, таким образом допуская только один экземпляр для выполнения. Вы также можете безопасно управлять доступом к системным файлам, также как в библиотеке pam файл /etc/passwd блокируется при помощи fcntl(), при изменении данных пользователя.

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

$ echo "FIRST" > myfile
$ ./ex_03 myfile
Нажмите Ввод для снятия блокировки(ок)
> С другой консоли мы изменяем файл:
    $ echo "SECOND" > myfile
    $
Возвращаясь на первую консоль, мы проверяем "повреждения":
(Ввод)
$ cat myfile
SECOND
$

Чтобы решить эту проблему, ядро Linux предоставляет системному администратору механизм блокирования из System V. Поэтому вы можете использовать этот механизм только при помощи fcntl(), но не flock(). Администратор может сказать ядру, что блокировки fcntl() строгие, использующие специальную комбинацию прав доступа. Тогда, если процесс блокирует файл для записи, другой процесс не сможет изменить этот файл (даже root). Специальная комбинация прав, которая используется, - это установленный бит Set-GID при снятом бите выполнения для группы. Этого можно добиться командой:

$ chmod g+s-x myfile
$
Однако этого не достаточно. Чтобы автоматически пользоваться строгими совместными блокировками при обращении к файлу, должен быть установлен атрибут mandatory для раздела, где находится этот файл. Обычно, вам надо изменить файл /etc/fstab и добавить туда опцию mand в 4-ую колонку или ввести команду:
# mount
/dev/hda5 on / type ext2 (rw)
[...]
# mount / -o remount,mand
# mount
/dev/hda5 on / type ext2 (rw,mand)
[...]
#
Теперь мы можем проверить, что изменение с другой консоли невозможно:
$ ./ex_03 myfile
Нажмите Ввод для снятия блокировки(ок)
>С другого терминала:
    $ echo "THIRD" > myfile
    bash: myfile: Resource temporarily not available
    $
И возвращаясь на первую консоль:
(Ввод)
$ cat myfile
SECOND
$

Администратору-не программисту следует принять решение об использовании строгих блокировок файлов (например /etc/passwd или /etc/shadow). Программисту необходимо котролировать способы доступа к данным, что обеспечит его приложению при чтении правильную работу с данными, а при записи оно не создаст помех другим процессам, если будет правильно настроено окружение для выполнения.

Назад | Содержание | Вперед



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





Copyright © 2005-2016 Project.Net.Ru