El modelo de permisos Unix tiene nueve bits conocidos (rwxrwxrwx), pero hay tres más que operan en una capa diferente: SUID, SGID y el sticky bit. No controlan quién puede leer o escribir un archivo, sino bajo qué identidad corre un proceso o quién puede borrar archivos en un directorio compartido. Son mecanismos del kernel, no convenciones de usuario.
SUID (Set User ID, bit octal 4000) sobre un ejecutable le dice al kernel: cuando alguien ejecute este binario, el proceso no hereda el UID del usuario que lo lanzó, sino el UID del propietario del archivo. El ejemplo más ilustrativo del sistema es /usr/bin/passwd. Tu usuario no tiene permiso de escritura sobre /etc/shadow —y no debería tenerlo—, pero passwd necesita modificarlo para cambiar tu contraseña. La solución: passwd pertenece a root y tiene SUID activado. Cuando lo ejecutas como usuario normal, el kernel eleva el effective UID del proceso a 0 (root) durante esa ejecución. Si lo ves con ls -l, aparece una s minúscula donde normalmente estaría la x del propietario:
-rwsr-xr-x 1 root root 72072 ene 16 2024 /usr/bin/passwd
Si la s fuera mayúscula (S), significaría que SUID está activado pero el bit de ejecución no lo está —una configuración que casi nunca tiene sentido y que normalmente indica un error.
SGID (Set Group ID, bit 2000) funciona de forma análoga pero con el GID. En ejecutables, el proceso adopta el GID del archivo en lugar del del usuario. En directorios, el comportamiento es distinto y más útil en la práctica: cualquier archivo o subdirectorio creado dentro hereda el grupo del directorio padre, en lugar del grupo primario del usuario que lo crea. Esto resuelve el problema clásico de las carpetas compartidas entre un equipo: sin SGID, cada miembro crearía archivos con su propio grupo primario y los demás no tendrían acceso.
El sticky bit (bit 1000) en directorios activa una restricción de borrado: aunque un usuario tenga permiso de escritura en el directorio, solo puede borrar los archivos de los que es propietario. /tmp tiene sticky bit precisamente por esto —cualquier proceso puede escribir archivos temporales allí, pero no puede borrar los de otros. En ls -l aparece como t al final de los permisos del directorio:
drwxrwxrwt 14 root root 4096 may 10 08:33 /tmp
Equivocarse con estos bits tiene consecuencias concretas. SUID en un script de shell es ignorado por el kernel en Linux (medida de seguridad deliberada desde los años 80), pero SUID en un binario compilado que tenga una vulnerabilidad de escalada de privilegios es exactamente lo que busca un atacante. SGID mal configurado en un directorio compartido puede filtrar archivos entre equipos que no deberían verse. Y olvidar el sticky bit en /tmp o en cualquier directorio de escritura pública significa que cualquier usuario puede borrar archivos ajenos.
Ejemplo completo: carpeta compartida de equipo con SGID + sticky bit
El escenario: un servidor donde los usuarios alice y bob pertenecen al grupo dev. Queremos un directorio donde ambos puedan crear y leer archivos, pero ninguno pueda borrar los del otro.
# Crear el grupo y añadir usuarios (como root) groupadd dev usermod -aG dev alice usermod -aG dev bob # Crear el directorio compartido mkdir /srv/proyecto # Asignar propietario y grupo chown root:dev /srv/proyecto # Permisos base: rwx para owner y grupo, nada para otros chmod 770 /srv/proyecto # Activar SGID: los archivos nuevos heredarán el grupo 'dev' chmod g+s /srv/proyecto # Activar sticky bit: cada usuario solo borra sus propios archivos chmod +t /srv/proyecto # Verificar el resultado ls -ld /srv/proyecto # Salida esperada: # drwxrws--T 2 root dev 4096 may 10 09:00 /srv/proyecto # ^ ^ # | └── T mayúscula: sticky bit activo, pero 'otros' no tiene x # └───── s minúscula: SGID activo con bit de ejecución # También se puede hacer en un solo chmod con notación octal: # chmod 3770 /srv/proyecto # El 3 = sticky(1) + SGID(2) = bits especiales combinados # Auditoría: buscar todos los binarios con SUID en el sistema find / -perm -4000 -type f 2>/dev/null # Buscar SGID en ejecutables (potencialmente interesante para auditorías) find / -perm -2000 -type f 2>/dev/null # Comprobar que el grupo se hereda (como alice) # su - alice -c "touch /srv/proyecto/archivo_de_alice.txt" # ls -l /srv/proyecto/archivo_de_alice.txt # -rw-rw-r-- 1 alice dev 0 may 10 09:01 /srv/proyecto/archivo_de_alice.txt # ^^^ # grupo 'dev', no el grupo primario de alice
Desglose
El chmod 3770 del ejemplo merece atención. El primer dígito (3) es la suma de sticky (1) + SGID (2). La notación octal de los permisos especiales funciona igual que la de los permisos normales: SUID vale 4, SGID vale 2, sticky vale 1. Se suman y se colocan como cuarto dígito delante del trío habitual. chmod 4755 sería SUID + rwxr-xr-x; chmod 1777 sería sticky + rwxrwxrwx (la configuración real de /tmp).
La T mayúscula en la salida de ls -ld merece explicación. Aparece porque el directorio tiene sticky activado pero el bit de ejecución de “otros” (o+x) no está presente —al no haber x donde mostrar la t, ls usa mayúscula para indicar que el bit especial está ahí aunque el de ejecución no lo esté. En /tmp verás t minúscula porque “otros” sí tiene x. La distinción s/S y t/T es puramente visual en ls; el kernel trata ambas formas igual en cuanto al bit especial.
El find / -perm -4000 de la auditoría usa el guion antes del modo octal, que en find significa “al menos estos bits activados”, no “exactamente este modo”. Sin el guion buscaría archivos cuyo modo sea exactamente 4000, lo que no encontraría nada útil. El 2>/dev/null descarta los errores de permiso en directorios como /proc o /sys donde find no tiene acceso. En un sistema Debian recién instalado, la lista de SUID es corta y conocida: passwd, su, sudo, mount, umount, newgrp… Si aparece algo inesperado ahí, vale la pena investigarlo.
El hecho de que SUID en scripts de shell no funcione en Linux no es una limitación del intérprete, sino una decisión del kernel: cuando el cargador detecta que el ejecutable es un script (empieza por #!), desactiva el bit SUID antes de invocar el intérprete. Esto previene una clase entera de ataques de condición de carrera (TOCTOU) que serían triviales en scripts. Si necesitas que un script se ejecute con privilegios elevados, el camino correcto es sudo con reglas específicas en /etc/sudoers.
N° 39