Tabla de Contenidos

Los permisos de un sistema de archivos en GNU/Linux

En este artículo, profundizaremos un poco en los permisos utilizados en los sistemas de archivos de GNU/Linux.

La idea no es rescribir los manuales existentes, sino mas bien ofrecer en un solo artículo una breve explicación de los principios y las operaciones más utilizadas, con algunos ejemplos y alguna que otra observación.

En ocasiones utilizaremos caracteres entre paréntesis para indicar la forma en que el sistema operativo suele representar los diferentes objetos o propiedades. Estos caracteres suelen provenir de las iniciales o parte del nombre de dichos objetos en inglés, o de representaciones numéricas.

Los comandos que se mencionen, en GNU/Linux normalmente se distribuyen junto con su página de manual, y para acceder a esta, solo es necesario ejecutar en una terminal un comando como este:

man elnombredelcomando

Directorios, archivos, usuarios y grupos

La mayoría de los sistemas de archivos para GNU/Linux reconocen dos objetos principales: los directorios (d) y los archivos (f). Sobre ambos pueden aplicarse diferentes permisos, en dependencia de la funcionalidad que se busque.

Pero antes de adentrarnos en los permisos, es necesario referirse brevemente a los usuarios. En GNU/Linux, cada usuario pertenece a uno o más grupos, aunque por seguridad usualmente pertenecen a un solo grupo creado con el mismo nombre del usuario, para evitar que otros usuarios del mismo grupo tengan acceso a directorios o archivos privados. Para garantizar justamente esta privacidad, todos los directorios y archivos tienen un propietario y un grupo.

No obstante, el propietario y el grupo al que pertenezca un archivo o directorio puede modificarse mediante el comando chown.

Nótese que este comando solamente permite cambiar el propietario y/o el grupo de uno o varios archivos o directorios, pero no así establecer los propios permisos (aunque en ocasiones cambiar el propietaro o grupo de un archivo o directorio puede ser una forma indirecta, pero útil de modificar los permisos).

Los permisos

Pues bien, existen tres permisos principales, cuya función varía ligeramente en dependencia de si se aplican a un archivo o a un directorio:

Estos permisos pueden establecerse respectivamente para:

A nivel informático, cada permiso es un bit de propiedad que se representa con un número octal:

Permiso Octal
Ejecución 1
Escritura 2
Lectura 4

Entonces, la suma de varios permisos define las propiedades finales de un archivo. Así, el número 7 ofrece todos los permisos, el 6 permite lectura y escritura (pero no ejecución), el 5 permite lectura y ejecución (pero no escritura), el 4 solo lectura, y así sucesivamente.

Para modificar los permisos se utiliza el comando chmod. Por ejemplo, para agregar a un archivo que hemos creado el bit de ejecución (útil para scripts, pues en GNU/Linux los archivos no son ejecutables por defecto), podemos hacer lo siguiente:

chmod u+x elarchivo

Para especificar que a ese archivo tengan acceso de escritura los usuarios del grupo, podemos hacer esto:

chmod g=w elarchivo

Y para especificar que el resto de los usuarios tenga acceso de solo lectura, podemos hacer esto:

chmod o=r

Estos tres permisos podrían combinarse de la siguiente manera:

chmod u=rwx,g=rw,o=r elarchivo

Una manera de referirse a los propietarios, el grupo y los demás es como “todos” (a). De modo que también podría haberse hecho esto:

chmod a=r,ug=w,u+x elarchivo

Otra forma de lograr lo mismo pero invirtiendo la forma de asignación:

chmod a=rwx,go-x,o-w elarchivo

Como vemos, establecer varios permisos de una vez puede resultar un poco engorroso de teclear, y aqui es donde tiene utilidad práctica el modo octal, que nos permite establecer todos los permisos anteriores haciendo solo esto:

chmod 764 elarchivo

Nótese que en este comando el primer dígito establece los permisos para el propietario del archivo, el segundo dígito para el grupo del archivo, y el tercer dígito para el resto de los usuarios y grupos.

La recursividad

Ahora bien, el comando chmod también permite el argumento -R que aplica los permisos de manera recursiva en un directorio y todos los subdirectorios que contenga, pero con esto debemos tener cuidado, especialmente al asignar permisos de ejecución.

Si por algun motivo necesitásemos asignar privilegios muy permisivos para todos los usuarios recursivamente sobre todos los subdirectorios y archivos dentro de un directorio, podría hacerse así:

chmod -R a=rwX eldirectorio

Nótese que la X está en mayúscula; si se coloca en minúscula se asignará el permiso de ejecución no solo a los directorios, sino también a los archivos, algo que desde el punto de vista de la seguridad no es recomendable.

Por ejemplo, algunos principiantes en GNU/Linux suelen experimentar dificultades con los permisos al crear un sitio web digamos en /var/www/elsitioweb/, y para garantizar que el sitio funcione, intentan solucionarlo de la siguiente manera:

chmod -R 777 /var/www/elsitioweb

Obviamente, ahora el sitio web funciona y todos tienen acceso a el, pero como los permisos se aplicaron de manera recursiva, ahora cada directorio del sitio tiene permiso de escritura para todos los usuarios del equipo y cada archivo tiene permisos de escritura y ejecución, por lo que se ha creado una vulnerabilidad innecesaria que algún usuario malintencionado podría aprovechar para alterar el sitio web, intentar escalar privilegios para leer o modificar información privada de otros usuarios, instalar o distribuir software malicioso, usar el equipo para atacar otros equipos de la red, etc.

Una manera de arreglar esto y garantizar un buen compromiso entre funcionalidad y seguridad es la siguiente:

chown -R elusuario:www-data /var/www/elsitioweb
chmod 755 /var/www/elsitioweb
find /var/www/elsitioweb -type d -print0 | xargs -0 chmod 755
find /var/www/elsitioweb -type f -print0 | xargs -0 chmod 644

Esto envía al sistema las siguientes instrucciones:

Este esquema de permisos no impide que posteriormente se asignen permisos puntuales sobre algún archivo o directorio, según sea necesario; por ejemplo, de haber algún archivo con información de autentificación, se le pueden asignar permisos 640, etc.

A propósito de los dos últimos comandos: como observarán, si en el comando find se especifica que busque solo directorios (-type d) nunca devolverá archivos, y si se especifica que busque archivos (-type f) nunca devolverá directorios. De esta manera pueden asignarse permisos recursivos precisos.

Notarán que se utiliza además la combinación del comando find con xargs, devolviendo los nombres de archivos o directorios encontrados como cadenas de texto delimitadas por el carácter nulo (-print0) y esto se le pasa al comando xargs habilitando el soporte para cadenas delimitadas en nulo (-0), para que entonces sobre dichos archivos o directorios se ejecute el comando chmod. Puede parecer innecesariamente complejo, pero esto permite cambiar recursivamente permisos sobre archivos o directorios cuyos nombres pudieran contener espacios y saltos de línea. Aunque el comando find también incluye parámetros para la ejecución de comandos, lo consigue lanzando un intérprete de comandos para cada archivo encontrado, lo cual consume recursos, mientras que la variante de xargs es más eficiente (aunque tiene sus propios límites impuestos por el sistema operativo, que pueden averiguarse con el comando xargs --show-limits).

La "pegajosidad" o permanencia

Además de estos bits de propiedades, existe otro menos conocido pero muy útil (sobre todo para directorios compartidos) llamado “bit pegajoso” (en inglés sticky bit) que cuando se antepone a los otros, permite que solo el superusuario (root) o el propietario del archivo pueda mover o eliminar un objeto (sin este permiso, cualquier usuario con permisos de escritura podría hacerlo).

Entonces, si un usuario ejecuta los siguientes comandos:

mkdir ~/upload
chmod 1730 ~/upload

El conjunto de instrucciones que se está enviando al sistema operativo es este:

Crea en mi directorio inicial un subdirectorio llamado upload, y cambia el modo de permisos de dicho subdirectorio estableciendo lo siguiente:

La personificación

Además de la propiedad de permanencia (1), el dígito octal que se antepone a los otros tres puede representar dos propiedades adicionales, conocidas como setgid (2) y setuid (4), que pueden sumarse al valor de la permanencia para establecer varios permisos simultáneamente. Estas dos propiedades pueden ser útiles, pero también pueden constituir una de las mayores vulnerabilidades de un sistema, por lo que deben utilizarse con mucha precaución, pero de todas formas es conveniente conocerlas.

Supongamos que el superusuario crea en un directorio compartido un script al cual asigna los permisos 5750. Es decir, el archivo tiene propiedades de lectura, escritura y ejecución para el propietario, lectura y ejecución para el grupo, y el resto de los usuarios y grupos no tiene acceso. Adicionalmente, ningún usuario que no sea el creador puede eliminar el script, y aquí viene la novedad: el usuario que tenga permisos para ejecutar el script lo hace tomando temporalmente la identidad del creador. La propiedad sgid hace algo similar, pero en este caso tomando la identidad del grupo al que pertenece el archivo.

La inmutabilidad y otras hierbas

Otro bit muy útil y tampoco muy conocido, es el “bit de inmutabilidad” (i), que como su nombre lo indica, permite establecer la inmutabilidad sobre el archivo al que se aplique. En otras palabras, nadie podrá modificar, mover o eliminar el archivo (ni siquiera el superusuario) mientras el archivo tenga el bit inmutable habilitado.

Por ejemplo, supongamos que deseamos que nadie pueda modificar el nombre del equipo, podemos lograrlo con el siguiente comando:

chattr +i /etc/hostname

El comando chattr permite establecer o quitar más atributos; otro de los útiles es el de la adición (a). Si deseamos que pueda escribirse a un archivo, pero no eliminar el contenido que ya existe en este, sino solamente añadir contenido nuevo, podemos utilizar el siguiente comando:

chattr +a elarchivo

La máscara de creación

Puede que a estas alturas esté pensando: bueno, todo eso está muy bien, pero es bastante engorroso estar asignando constantemente permisos, ¿como sabe el sistema que permisos asignar por defecto a los diferentes directorios y archivos, y cómo podría uno cambiarlos?

Para esto existe el comando umask, que permite establecer una variable de entorno que automáticamente quita los permisos seleccionados sobre los archivos y directorios que se creen (asumiendo como base 777 para directorios y 666 para archivos). Usualmente no se utiliza el comando directamente porque la mayoría de las distribuciones establecen su valor por defecto a 022, en los archivos /etc/bashrc o /etc/profile. Esto hace que por defecto los directorios se crean con los permisos 755 y los archivos con los permisos 644. Nótese que por seguridad cualquier archivo recién creado tiene deshabilitado el bit de ejecución, ya que umask no permite habilitarlo, hay que hacelo manualmente.

Si uno quisiera por ejemplo que en su directorio de usuario todos los directorios por defecto se creen con permisos 750 y los archivos con permisos 640, podría colocar en el archivo ~/.bashrc o en ~/.profile el siguiente comando:

umask 027

Para conocer la máscara que está activa, podemos ejecutar los comandos umask -p o también umask -pS

Las listas de control de acceso

Existe una manera adicional de establecer permisos a un nivel más detallado mediante listas de control de acceso, que pueden instalarse mediante el paquete acl. Este paquete tiene dos comandos muy útiles: getfacl y setfacl.

El comando getfacl permite consultar los valores de control de acceso de un directorio o archivo cualquiera (con el argumento -R, la consulta será recursiva). Por ejemplo, sobre el directorio de configuración del sistema:

getfacl /etc/

Debería aparecer un resultado como este:

# file: etc
# owner: root
# group: root
user::rwx
group::r-x
other::r-x

Obsérvese que los permisos para el directorio /etc/ deberían coincidir con los que aparecen al ejecutar ls -l /:

drwxr-xr-x 90 root root  4096 May 12 22:33 etc

Para establecer las listas de control de acceso sobre un archivo o directorio, se utiliza el comando setfacl.

Por ejemplo, para prohibir cualquier tipo de permisos sobre un directorio y todo su contenido a todos los otros usuarios (es decir, diferentes al propietario o el grupo), podría ejecutarse este comando:

setfacl -R -P -m o::---,d:o::--- ruta

Expliquemos brevemente este comando:

Para asignar permisos específicos, a veces es necesario combinar varias ACL. Para ilustrarlo mejor, pongamos un ejemplo.

Supongamos que en una estación de trabajo tenemos bajo el directorio /var/www/ varios subdirectorios con aplicaciones web hospedadas mediante virtualhosts de Apache, y que deseamos dar solamente a un usuario identificado como mengano la posibilidad de listar, crear, eliminar y modificar archivos de una aplicación en el subdirectorio /var/www/aplicacion/, pero prohibirle el acceso a los otros subdirectorios de aplicaciones. Asumiremos además que el subdirectorio /var/www/aplicacion/ tendrá como propietario al usuario fulano, y pertenecerá al grupo www-data.

Lo primero es cerciorarnos de que el usuario mengano tenga acceso de entrada (pero no de otro tipo) a los directorios adecuados para poder recorrer la ruta hasta el directorio de la aplicación:

setfacl -m u:mengano:--x /var
setfacl -m u:mengano:--x /var/www

Lo segundo es evitar que el usuario tenga acceso a las aplicaciones hospedadas:

setfacl -R -m u:mengano:---,d:u:mengano:--- /var/www/*

Entonces, nos cercioramos de que el usuario tenga acceso a la aplicación deseada:

setfacl -R -m u:mengano:rwX,d:u:mengano:rwX /var/www/aplicacion

Nótese que en el comando anterior la X está en mayúscula, el principio es el mismo que en el comando chmod.

Luego, nos cercioramos de que por defecto los nuevos directorios y archivos de la aplicación sigan siendo propiedad del grupo:

chmod -R g+s /var/www/aplicacion

Una vez hecho esto, nos cercioramos de que el propietario (en este caso, fulano) siga teniendo por defecto acceso a cualquier directorio o archivo, aunque los cree mengano:

setfacl -R -m d:u:fulano:rwX /var/www/aplicacion

Finalmente, el usuario mengano puede crear un enlace simbólico en su directorio inicial para un acceso rápido a los archivos de la aplicación:

ln -s /var/www/aplicacion ~/aplicacion

Si por algún motivo deseásemos eliminar todas las ACLs que recién creamos, podríamos ejecutar los siguientes comandos:

setfacl -R -b -k /var/www/aplicacion
setfacl -b -k /var/www
setfacl -b -k /var

El comando setfacl tiene otras utilidades como establecer la máscara de creación por defecto, asignar permisos tomándolos de un archivo o de la entrada estándar, etc. Recomendamos consultar el manual para más detalles.

Los puntos de montaje

Existe además otra forma de establecer ciertos permisos, y es mediante las opciones de montaje.

Por ejemplo, supongamos que tenemos un servidor en producción que deseamos asegurar contra posibles ejecuciones de código malicioso en el espacio de almacenamiento temporal.

En las versiones recientes de GNU/Linux, se utiliza un área de memoria compartida proveniente de la memoria virtual del sistema (es decir, RAM + Swap), que usualmente se monta en /dev/shm/.

En el archivo /etc/fstab usualmente debería haber una línea como esta:

none  /dev/shm  tmpfs  defaults  0  0

Podemos modificarla para que quede así:

none  /dev/shm  tmpfs  defaults,nodev,noexec,nosuid,noatime,nodiratime  0  0

Luego ejecutamos el siguiente comando para remontar con las nuevas opciones:

mount -a

Con las opciones noexec, nosuid y nodev, estaríamos protegiéndonos contra cualquier archivo temporal que intente la ejecución, personificación, y el acceso directo a los dispositivos de bloque especiales del sistema (las unidades de almacenamiento).

Las opciones noatime y nodiratime es para prevenir que el sistema actualice constantemente los tiempos de acceso a los archivos y directorios en ese sistema de archivos, lo cual puede implicar una penalización en rendimiento.

Y a propósito de las optimizaciones, si se tiene suficiente cantidad de RAM, una manera de aumentar el rendimiento (especialmente en servidores donde trabajan múltiples usuarios simultáneamente) es aumentando la capacidad de este espacio de memoria volátil compartida:

mount -t tmpfs -o remount,size=512M /dev/shm

Si nuestro sistema por algún motivo no tuviese en /etc/fstab esta entrada, es recomendable crear una partición dedicada para /tmp/ para así poder personalizar las opciones de montaje de dicho directorio.

No obstante, puede que ya tengamos nuestro sistema particionado y resulte inconveniente reparticionarlo, ¿qué hacer entonces? Muy sencillo, montar un archivo como una partición virtual.

Por ejemplo, para crear una partición virtual de 1 GiB para /tmp/ utilizando el espacio disponible en /var/, podríamos ejecutar los siguientes comandos:

mkdir -p /var/img
dd if=/dev/zero of=/var/img/tmp.bin bs=1 count=0 seek=1G
mkfs -t ext4 /var/img/tmp.bin
mkdir /tmp

Una vez realizado lo anterior, editamos el archivo /etc/fstab para agregar una entrada como esta (nótese el uso de la opción de montaje loop para especificar que el dispositivo es virtual):

/var/img/tmp.bin  /tmp  ext4  loop,rw,nodiratime,noatime,noexec,nodev,nosuid  0  0

Entonces, remontamos y nos cercioramos de que el punto de montaje tenga los permisos adecuados:

mount -a
chmod 1777 /tmp

Nótese que aunque al directorio /tmp/ teóricamente se le han asignado los permisos de ejecución para todos los usuarios, ningún archivo de dicho directorio o sus subdirectorios podrá ejecutarse, debido a la opción de montaje noexec anteriormente establecida.

Para el directorio /var/tmp/ podría seguirse un acercamiento similar. Hay quienes recomiendan que este directorio sea solo un enlace simbólico a /tmp/, pero esto tiene el inconveniente de que el directorio /var/tmp/ pierde parte de su funcionalidad, que es garantizar que los datos que contenga persistan a un reinicio.

Para conocer con qué opciones están montados los diferentes sistemas de archivo, basta con ejecutar mount sin argumentos.

Para los más paranoides

Para aquellos a quienes todo esto parezca poco, se alegrarán en conocer que existe una manera adicional de establecer permisos conocida como SELinux que se utiliza principalmente para definir roles y políticas de ejecución para los servicios, pero esto es otra historia, asi que por ahora damos por terminado este artículo y SELinux queda para estudio individual. ;)

Atribuciones