Hem tancat el mòdul 4 amb tres suposicions penjades a l'aire: que l'UID 990 és meteora, que qui inicia sessió és qui diu que és, i que un procés que s'executa com a meteora fa el que faria meteora. Les dues primeres les resoldrem a la lliçó següent. Aquesta es dedica sencera a la tercera, que és la més incòmoda de les tres, perquè és la que continua sent falsa encara que tots els permisos siguin perfectes.

Pensa-hi així. meteo-api té exactament els permisos que necessita: llegeix /var/lib/meteora/lectures/*.dat, llegeix /etc/meteora/meteora.conf, escriu a /var/log/meteora/meteo-api.log. Ni un més. Ara imagina que algú troba una errada al codi que analitza les peticions HTTP i aconsegueix que el procés executi instruccions seves. Aquell atacant hereta el procés sencer, amb els permisos intactes. I amb aquests permisos —els correctes, els mínims, els que va aprovar la revisió de seguretat— pot obrir un sòcol a Internet, llegir les 17.280.000 línies de dades del dia, executar /bin/sh, crear un procés fill que sobrevisqui al reinici del servei i muntar /dev/md0 en un altre lloc si el nucli l'hi permet. Els nou bits no van dir res sobre res d'això, perquè els nou bits només parlen de fitxers.

Aquesta lliçó construeix el marc conceptual que falta. Primer la teoria, que és sorprenentment petita i explica tota la resta: subjectes, objectes, drets, dominis i la matriu d'accés. Després els vuit principis de disseny que el 1975 van fixar el vocabulari de la seguretat de sistemes i que continuen sent la millor llista de comprovació que existeix. Després els quatre models de control d'accés que veuràs anomenats en qualsevol document professional —DAC, MAC, RBAC, ABAC—. I finalment els tres mecanismes amb què Linux implementa avui aquestes idees: capabilities, que trossegen el poder de root; SELinux i AppArmor, que imposen regles que ni root es pot saltar; i seccomp, que redueix el joc de crides al sistema que un procés pot ni tan sols intentar. Al final tindràs la resposta a la pregunta del paràgraf anterior: què se li posa al davant a un meteo-api compromès perquè els seus permisos correctes no bastin.

Contingut

  1. Protecció davant de seguretat: per què la distinció importa
  2. El model formal: subjectes, objectes, drets i dominis de protecció
  3. La matriu d'accés i les seves dues implementacions reals
  4. Els vuit principis de Saltzer i Schroeder, aplicats a Meteora
  5. Models de control d'accés: DAC, MAC, RBAC i ABAC
  6. El problema del "tot o res" de root
  7. Capabilities de Linux: trossejar el poder de root
  8. Control d'accés obligatori: SELinux i AppArmor
  9. Confinament i sandboxing: seccomp i la superfície de syscalls
  10. Base de còmput fiable i superfície d'atac
  11. El problema del delegat confús

Protecció davant de seguretat: per què la distinció importa

En el llenguatge corrent són sinònims. En sistemes operatius són dues coses diferents i convé separar-les des del principi, perquè determinen què pots esperar d'un mecanisme.

Protecció Seguretat
Què és Un mecanisme intern del SO que controla l'accés de processos i usuaris als recursos La propietat global del sistema davant d'un adversari que la vol violar
Àmbit Dins de la màquina La màquina, la xarxa, les persones, els procediments
Pregunta que respon Pot aquest subjecte fer aquesta operació sobre aquest objecte? Pot algú aconseguir el que vol, per la via que sigui?
Exemple a Meteora El bit r de 2026-08-31.dat, una capability, un perfil d'AppArmor Que ningú robi les dades: inclou l'anterior, i també el xifratge, les còpies, el tallafocs i que ningú deixi la contrasenya en un post-it
Es verifica Amb regles i proves: o el mecanisme concedeix o denega Amb un model d'amenaces: qui ataca, amb quins recursos i amb quin objectiu
Falla quan Hi ha un error al mecanisme Hi ha un error al mecanisme, o al disseny, o a l'operació, o a les persones

La distinció no és acadèmica; té una conseqüència pràctica molt concreta. La protecció es pot raonar i demostrar; la seguretat, no. Pots afirmar amb certesa que un procés amb UID 990 no pot escriure en un fitxer root:root 0644, perquè és una regla del nucli. No pots afirmar amb la mateixa certesa que les dades de Meteora estan segures, perquè això depèn de tot el sistema i d'un adversari del qual només tens hipòtesis.

D'aquí surt la regla de treball de tot el mòdul:

Un mecanisme de protecció mai no és una solució de seguretat; és una capa. La seguretat es construeix apilant capes independents, de manera que la fallada d'una no anul·li les altres. És el que s'anomena defensa en profunditat.

Els permisos de 04-06 són una capa. Les capabilities són una altra. AppArmor és una altra. Seccomp una altra. Cap no és suficient tota sola, i precisament per això cap no és inútil.

El model formal: subjectes, objectes, drets i dominis de protecció

Tot control d'accés, en qualsevol sistema operatiu, es descriu amb quatre conceptes. Aprendre'ls estalvia molt de temps després, perquè cada mecanisme concret no és més que una implementació particular d'aquest esquema.

Subjecte. L'entitat activa que vol fer alguna cosa. A Linux, el subjecte real és el procés, no l'usuari: l'usuari és una etiqueta que el procés porta a sobre. Quan l'agregador obre un fitxer, el subjecte és aquell procés concret amb el seu PID, el seu UID efectiu 990, els seus grups suplementaris, les seves capabilities i la seva etiqueta de SELinux.

Objecte. L'entitat passiva sobre la qual s'actua. En un sistema UNIX la llista és llarga i no es limita a fitxers: fitxers i directoris, processos (se'ls envien senyals), sòcols, segments de memòria compartida com /dev/shm/meteora-cache, dispositius, semàfors, cues de missatges, entrades de /proc, i fins i tot el mateix rellotge del sistema o la taula de rutes.

Dret d'accés. El permís per executar una operació concreta sobre un objecte concret: llegir, escriure, executar, esborrar, enviar un senyal, muntar, connectar. El conjunt de drets depèn del tipus d'objecte.

Domini de protecció. És el concepte que sol costar i el que més rendiment dona. Un domini és el conjunt de parells (objecte, drets) que un subjecte pot fer servir en un moment donat. És a dir: no "qui ets", sinó "què pots fer ara mateix".

Domini D_ingestor = {
    (/var/lib/meteora/lectures/*.dat, {llegir, escriure, crear}),
    (/run/meteora/lectures.fifo,      {llegir}),
    (/etc/meteora/meteora.conf,       {llegir}),
    (/dev/shm/meteora-cache,          {llegir, escriure}),
    (sòcol TCP port 9010,             {escoltar, acceptar})
}

L'important és que un procés canvia de domini al llarg de la seva vida, i aquests canvis són la part interessant de la seguretat. Recorda el cas de passwd de 04-06: el procés comença al domini de l'usuari joan, i en fer execve sobre un binari setuid salta al domini de root. Això és un canvi de domini, i és exactament on es concentren els atacs: si aconsegueixes provocar un canvi de domini que no estava previst, has escalat privilegis.

graph LR
    A["Domini 'joan'<br/>UID 1000<br/>llegeix els seus fitxers"] -->|"execve de<br/>/usr/bin/passwd<br/>(setuid root)"| B["Domini 'root'<br/>UID efectiu 0<br/>escriu /etc/shadow"]
    B -->|"el procés acaba"| C["El domini<br/>desapareix"]
    A -->|"execve de<br/>/bin/ls"| D["Domini 'joan'<br/>sense canvi"]

A Linux, un domini es defineix de facto per la combinació de: UID i GID efectius, grups suplementaris, conjunt de capabilities, etiqueta de SELinux o perfil d'AppArmor, filtre seccomp actiu, límits de recursos i —des del mòdul 6— espais de noms. Tot el que veurem a partir d'aquí és una manera de fer els dominis més petits i controlar millor els salts entre ells.

La matriu d'accés i les seves dues implementacions reals

Si poses els subjectes en files i els objectes en columnes, obtens la matriu d'accés, que és la representació completa i abstracta de la política de protecció d'un sistema:

lectures/*.dat meteora.conf meteo-api.log /usr/bin/meteo-api
ingestor llegir, escriure llegir
agregador llegir llegir
meteo-api llegir llegir escriure (afegir) executar
nuria (anàlisi) llegir
root tot tot tot tot

La matriu és un model excel·lent per pensar i un desastre per implementar: amb 500 usuaris i 200.000 fitxers tindria 100 milions de cel·les, gairebé totes buides. Cap sistema real no l'emmagatzema sencera. Tots la trossegen, i només hi ha dues maneres de trossejar una matriu.

Per columnes: llistes de control d'accés (ACL). Cada objecte guarda qui pot fer què amb ell. És el que fan els nou bits d'UNIX (una ACL comprimida de tres entrades) i les ACL POSIX de 04-06 (una llista de debò). La llista viu amb l'objecte, al seu inode.

Objecte: /var/lib/meteora/lectures/2026-08-31.dat
  ├── meteora  : rw-
  ├── grup meteora : r--
  ├── nuria    : r--      (entrada d'ACL POSIX)
  └── altres   : ---

Per files: llistes de capacitats (capability lists). Cada subjecte porta a sobre una llista de "claus", i cada clau anomena un objecte i els drets sobre ell. La clau viatja amb el subjecte; l'objecte no sap qui la té.

Subjecte: procés meteo-api (PID 1481)
  ├── clau → fd 3 : /var/lib/meteora/lectures/2026-08-31.dat {llegir}
  ├── clau → fd 4 : /var/log/meteora/meteo-api.log {afegir}
  └── clau → fd 5 : sòcol TCP 8080 {acceptar}

I aquí una revelació que ordena tot el que hem après: els descriptors de fitxer de 04-04 són capacitats. Quan open() et retorna el descriptor 3, el nucli t'ha lliurat una clau: un testimoni no falsificable —no et pots inventar un descriptor vàlid— que concedeix uns drets concrets sobre un objecte concret. Per això els permisos es comproven a open() i no a read(): la comprovació passa en fabricar la clau, no en fer-la servir. I per això un chmod 000 posterior no talla qui ja la té. És exactament el comportament característic d'un sistema de capacitats, i ara ja saps per què és així.

La comparació completa:

Criteri ACL (per columnes) Capacitats (per files)
On viu la informació A l'objecte (inode, xattr) Al subjecte (taula de descriptors)
Pregunta ràpida de respondre "Qui pot accedir a aquest fitxer?" "A què pot accedir aquest procés?"
Cost de la comprovació Recórrer la llista a cada open(): O(entrades) O(1): la clau ja és a la mà
Auditar un objecte Fàcil: getfacl fitxer Difícil: cal inspeccionar tots els subjectes
Auditar un subjecte Difícil: recórrer tot el sistema de fitxers Fàcil: ls -l /proc/<pid>/fd/
Revocació Fàcil: s'edita la llista i afecta els accessos futurs Difícil: cal perseguir les claus ja repartides
Delegació Necessita privilegi per editar l'ACL Natural: es passa la clau (SCM_RIGHTS per un sòcol UNIX)
Risc característic Que la llista creixi i ningú no l'entengui Que una clau es filtri a qui no l'havia de tenir
Exemples reals Permisos UNIX, ACL POSIX, ACL d'NTFS Descriptors de fitxer, pidfd, tokens OAuth, seL4, Capsicum

Els dos riscos característics mereixen un comentari, perquè els veuràs a la vida real. Al món ACL, el problema és l'acumulació: ningú no retira permisos, la llista d'accés a una carpeta compartida acaba amb trenta entrades i grups imbricats, i ja ningú no sap qui hi entra. Al món capacitats, el problema és la fuita: si meteo-api hereta per descuit un descriptor obert de /etc/meteora/meteora.conf que el seu pare va deixar obert, té la clau encara que els permisos del fitxer l'hi prohibissin. Per això execve tanca els descriptors marcats amb FD_CLOEXEC, i per això convé obrir amb O_CLOEXEC per defecte (04-04): és higiene de capacitats.

Un avís de vocabulari, perquè no et confonguis més endavant: les capabilities de Linux de l'apartat 7 es diuen així per herència històrica, però no són capacitats en aquest sentit. No anomenen un objecte concret; són permisos globals del tipus "pot fer X a tot el sistema". És una desafortunada col·lisió de noms que convé tenir present.

Els vuit principis de Saltzer i Schroeder, aplicats a Meteora

El 1975, Jerome Saltzer i Michael Schroeder van publicar vuit principis de disseny de sistemes protegits. Mig segle després no ha calgut afegir-ne cap, i la majoria dels desastres de seguretat que llegiràs a les notícies són la violació d'un d'ells. Els recorrem un a un, amb la seva aplicació exacta a meteo-01.

  1. Privilegi mínim

Cada subjecte ha d'operar amb el conjunt mínim de privilegis necessari per a la seva tasca, i durant el mínim temps.

És el principi del qual es deriven gairebé tots els altres. A Meteora es tradueix en decisions concretes que ja hem pres: meteora és un compte sense shell (ningú no hi inicia sessió), /etc/meteora/meteora.conf pertany a root i el servei només el llegeix, /usr/bin/meteo-api pertany a root perquè el servei no pugui reescriure el seu propi binari, i meteo-api escolta al 8080 per no necessitar privilegis de port baix. I el que veurem a l'apartat 7: si hagués d'escoltar al 443, la resposta correcta és CAP_NET_BIND_SERVICE, no root.

La cua "i durant el mínim temps" és la que més s'oblida. Un procés que necessita privilegi només en arrencar l'ha d'amollar després: obrir el port, obrir els fitxers, i llavors baixar a UID 990 i descartar les capabilities. A partir d'aquell instant, un compromís ja no les té.

  1. Economia del mecanisme

El mecanisme de protecció ha de ser tan petit i simple com sigui possible, per poder-lo revisar exhaustivament.

El codi que no existeix no té errades, i el codi que ningú no entén no es pot auditar. És l'argument a favor dels nou bits d'UNIX davant d'una ACL de trenta entrades heretades: un mecanisme comprensible es verifica d'un cop d'ull. A Meteora, aplicar-lo significa preferir un perfil d'AppArmor de quaranta línies que tot un equip entén a una política de SELinux de sis-centes que només entén qui la va escriure —i que acabarà en mode permissiu el dia que faci nosa—.

  1. Valors per defecte segurs (denegar per defecte)

El que és permès s'ha de llistar explícitament; tota la resta es denega. La base ha de ser la manca d'accés, no la seva presència.

La diferència entre una llista negra ("prohibeix aquestes rutes") i una llista blanca ("permet només aquestes") és que la primera falla en silenci davant de tot allò que els seus autors no van imaginar. Aplicat a Meteora, és el que fa other::--- a les dades, el que fa la política per defecte drop del tallafocs que muntarem a 05-03, i el que fa un perfil d'AppArmor: enumera el que meteo-api pot tocar i denega la resta del sistema de fitxers, inclòs el que s'instal·li demà.

  1. Mediació completa

Tot accés a tot objecte s'ha de comprovar, sempre, sense excepcions ni memòries cau que es puguin saltar.

Si el mecanisme comprova el permís la primera vegada i després confia, hi ha una finestra. És el punt on els descriptors de fitxer d'UNIX fan una concessió deliberada: es comprova a open() i no a cada read(), per rendiment. La concessió està estudiada —la clau només es lliura si el permís existia— però explica l'efecte del chmod 000 que no talla ningú. I l'atac contra la mediació completa té nom i ja el coneixes: TOCTOU (04-04), on l'atacant canvia l'objecte entre la comprovació i l'ús. La contramesura és sempre la mateixa: comprovar i actuar sobre el mateix descriptor, no sobre el mateix nom.

  1. Disseny obert

La seguretat no ha de dependre del secret del disseny, sinó del secret de les claus.

És el principi de Kerckhoffs, i explica per què l'algorisme de xifratge de contrasenyes de /etc/shadow està publicat fins a l'últim detall i tot i així el sistema funciona. El seu contrari és la seguretat per obscuritat: moure SSH al port 2222, ofuscar el codi, amagar l'URL d'administració. No són inútils com a soroll —treuen escaneigs automàtics del damunt—, però no són un control de seguretat, perquè el seu valor desapareix tan bon punt algú mira. Regla operativa per a Meteora: canviar el port de SSH està bé; fer-ho en lloc de configurar claus públiques i fail2ban està malament.

  1. Separació de privilegis

Quan sigui possible, exigir dues condicions independents per concedir un accés, en comptes d'una de sola.

Dues claus per llançar el míssil. Dues signatures per a una transferència. A Meteora, és la raó que els registres tinguin grup adm i no meteora: administrar i executar són dos privilegis diferents i no els donem a la mateixa identitat. També és la raó de dividir el servei en tres processos (ingestor, agregador, meteo-api) en lloc d'un de sol: comprometre el que parla amb Internet no dona el que pot fer el que escriu al disc. I és el que fa l'autenticació en dos factors de 05-02.

  1. Mecanisme comú mínim

Minimitzar els mecanismes compartits entre usuaris, perquè cada recurs compartit és un canal potencial de fuita o d'interferència.

Tot allò que dos subjectes comparteixen és una via per la qual l'un pot afectar o espiar l'altre: un /tmp comú, una base de dades comuna, una CPU amb memòria cau comuna —d'aquí atacs com Spectre—, un segment de memòria compartida. A Meteora, /dev/shm/meteora-cache és exactament un mecanisme comú entre els tres processos, i per això els seus permisos i la seva mida importen tant: és superfície compartida. La directiva PrivateTmp=yes de systemd (05-03) és aquest principi fet configuració: cada servei rep el seu propi /tmp.

  1. Acceptabilitat psicològica

El mecanisme ha de ser fàcil d'utilitzar correctament, o els usuaris l'esquivaran.

És el principi més ignorat i el que més bretxes causa. Una política que obliga a canviar la contrasenya cada 30 dies produeix Meteora2026! seguit de Meteora2026!!, i post-its. Un sudo que demana la contrasenya cada trenta segons produeix un NOPASSWD: ALL. Un perfil d'AppArmor que trenca el servei cada vegada que es desplega una versió produeix aa-complain permanent. Un control que fa nosa es desactiva, i un control desactivat protegeix zero. Quan dissenyis seguretat per a Meteora, pregunta't sempre quin és el camí fàcil, i assegura't que el camí fàcil sigui el segur.

Models de control d'accés: DAC, MAC, RBAC i ABAC

Amb el vocabulari a la mà, ja es poden anomenar els quatre models que estructuren el control d'accés en qualsevol sistema professional.

Model Qui decideix la política Idea central Exemple típic Punt feble
DAC
Discrecional
El propietari de l'objecte Si el fitxer és teu, tu decideixes qui hi entra Permisos UNIX, ACL POSIX, ACL d'NTFS L'amo pot regalar l'accés; un procés compromès hereta aquesta discreció
MAC
Obligatori
L'administrador, mitjançant una política global Ni l'amo es pot saltar la política; el sistema la imposa SELinux, AppArmor, nivells militars de classificació Complex d'escriure, de depurar i de mantenir
RBAC
Per rols
L'administrador, assignant rols Els permisos es donen a rols, i les persones s'assignen a rols sudo amb grups, rols de Kubernetes, grup adm de Meteora Explosió de rols si la granularitat és fina
ABAC
Per atributs
Un motor de regles amb atributs de subjecte, objecte i context "Permet si rol=analista I hora∈laboral I origen=xarxa interna" Polítiques IAM del núvol, Open Policy Agent Difícil d'auditar: el resultat depèn del context

La clau per entendre per què existeix MAC és a la casella "punt feble" de DAC, i mereix un exemple concret:

Amb DAC, meteo-api s'executa com a meteora i meteora és l'amo dels .dat. Si un atacant controla el procés, pot fer chmod o+r sobre les dades, o copiar-les a /tmp, o enviar-les per un sòcol. Té la discreció de l'amo, perquè és l'amo.

Amb MAC, existeix a més una política del sistema que diu: "un procés etiquetat meteo_api_t pot llegir fitxers etiquetats meteora_data_t i res més; no pot escriure a /tmp, no pot executar /bin/sh, no pot obrir sòcols sortints". Aquesta regla no la pot canviar el procés, ni tan sols si aconsegueix UID 0, perquè no l'aplica l'amo del fitxer sinó el nucli amb la seva política carregada.

Aquesta és tota la diferència, i és la raó per la qual el mòdul no acaba a 04-06. A la pràctica, un servidor Linux modern combina els quatre: DAC als permisos de fitxer, MAC a AppArmor o SELinux, RBAC a l'organització de grups i regles de sudo, i ABAC a les polítiques del núvol que l'envolten.

El problema del "tot o res" de root

UNIX va néixer amb un model de privilegi binari: UID 0 ho pot tot, qualsevol altre UID no pot res d'especial. El nucli era ple de comprovacions de la forma if (uid == 0) permetre;. És d'una economia de mecanisme admirable, i és també un problema seriós.

El problema es veu amb un exemple quotidià. ping necessita obrir un sòcol ICMP en brut, una cosa que un usuari normal no pot fer. La solució clàssica va ser fer-lo setuid root. Resultat: un programa que qualsevol pot executar, que s'executa amb tots els privilegis del sistema, quan l'única cosa que necessitava era un. Si ping té una errada, l'atacant no obté "la capacitat d'enviar paquets ICMP": obté la màquina sencera. La desproporció entre el privilegi necessari i el privilegi concedit és de diversos ordres de magnitud, i és una violació de manual del principi de privilegi mínim.

Multiplica això pels quinze o vint binaris setuid d'un sistema i tindràs la superfície d'atac històrica d'UNIX. La solució de Linux des de 1998 és trossejar el poder de root en peces.

Capabilities de Linux: trossejar el poder de root

Linux divideix els privilegis de root en unes quaranta capabilities independents. Cada comprovació del nucli que abans deia "és UID 0?" ara diu "té la capability tal?".

Capability Què permet Ús legítim
CAP_NET_BIND_SERVICE Escoltar en ports < 1024 Un servidor web o meteo-api al 443
CAP_NET_RAW Sòcols en brut ping, tcpdump
CAP_NET_ADMIN Configurar xarxa, interfícies, rutes, tallafocs ip, dimonis de VPN
CAP_CHOWN Canviar el propietari d'un fitxer Gestors de paquets
CAP_DAC_OVERRIDE Saltar-se tots els permisos de fitxer Còpies de seguretat
CAP_DAC_READ_SEARCH Saltar-se els permisos de lectura i travessia Còpies de seguretat de només lectura
CAP_KILL Enviar senyals a qualsevol procés Supervisors
CAP_SETUID / CAP_SETGID Canviar d'identitat Servidors que baixen de privilegi
CAP_LINUX_IMMUTABLE Treure chattr +i / +a Administració (04-06)
CAP_SYS_TIME Canviar el rellotge del sistema NTP
CAP_SYS_PTRACE Depurar i inspeccionar la memòria d'altres processos gdb, strace
CAP_SYS_MODULE Carregar mòduls del nucli Gairebé mai
CAP_SYS_ADMIN Muntar, pivot_root, i desenes d'operacions més El "calaix de sastre"

Les quatre últimes estan marcades per una raó. CAP_SYS_ADMIN, CAP_SYS_MODULE, CAP_SYS_PTRACE i CAP_DAC_OVERRIDE equivalen pràcticament a root, i cal tractar-les com a tal:

  • CAP_SYS_MODULE: si pots carregar un mòdul, pots executar codi al nucli. És més que root.
  • CAP_SYS_PTRACE: si pots inspeccionar i modificar la memòria d'altres processos, pots prendre el control d'un procés privilegiat.
  • CAP_DAC_OVERRIDE: si et saltes tots els permisos de fitxer, pots reescriure /etc/shadow i /etc/sudoers.
  • CAP_SYS_ADMIN: es va convertir en el calaix on es va ficar tot el que no encaixava en cap altra categoria, i avui cobreix muntar sistemes de fitxers, manipular namespaces i molt més. Concedir-la és, a la pràctica, concedir root amb passos intermedis.

Els quatre conjunts, sense misteri

Cada procés porta diversos conjunts de capabilities. Els que cal entendre són aquests:

Conjunt Què significa
Permès (permitted) El límit superior: el que el procés podria activar
Efectiu (effective) El que el nucli comprova ara mateix a cada operació
Heretable (inheritable) El que pot sobreviure a un execve (amb l'ambiental, a la pràctica)
Limitador (bounding set) Un sostre que mai no es pot apujar: el que es treu d'aquí no torna, ni per als fills
Ambiental (ambient) El mecanisme modern perquè un procés no privilegiat conservi capabilities en executar un altre binari

La lògica d'ús és senzilla i segueix el principi de privilegi mínim en el temps: un servei arrenca amb el que té permès, activa a l'efectiu només el que necessita en l'instant en què ho necessita, i buida el limitador de tota la resta perquè ni ell ni cap dels seus fills no ho pugui recuperar mai. Aquest buidatge és el que fa CapabilityBoundingSet= en una unitat de systemd (05-03).

A la pràctica: meteo-api al port 443

# Sense capabilities: un servei no root NO pot escoltar per sota del 1024
$ sudo -u meteora /usr/bin/meteo-api --port 443
error: bind(0.0.0.0:443): Permission denied

# Opció A — concedir la capability al BINARI (fitxer)
sudo setcap 'cap_net_bind_service=+ep' /usr/bin/meteo-api
getcap /usr/bin/meteo-api
# /usr/bin/meteo-api cap_net_bind_service=ep

# Ara sí, sense ser root i sense setuid
sudo -u meteora /usr/bin/meteo-api --port 443    # arrenca correctament

# Veure les capabilities d'un procés en marxa
grep Cap /proc/$(pgrep -f meteo-api)/status
# CapInh: 0000000000000000
# CapPrm: 0000000000000400
# CapEff: 0000000000000400
# CapBnd: 0000003fffffffff
capsh --decode=0000000000000400
# 0x0000000000000400=cap_net_bind_service

Què ha passat exactament. setcap escriu un atribut estès security.capability a l'inode del binari —els xattr de 04-06—, i en executar-lo el nucli li concedeix aquella capability i només aquella. El procés s'executa com a UID 990, sense cap privilegi de root, tret de la capacitat puntual d'associar-se a un port baix. Compara-ho amb l'alternativa clàssica —chmod u+s i root—: el privilegi concedit passa de "tot el sistema" a "una operació". capsh --decode tradueix la màscara hexadecimal de /proc/<pid>/status a noms llegibles, i CapBnd amb tots els bits a u indica que el limitador és intacte, cosa que en un servei ben configurat no hauria de passar.

Hi ha una opció B millor que l'A, i convé conèixer-la ja encara que la desenvolupem a 05-03: en lloc de marcar el fitxer, es demana la capability a la unitat de systemd:

[Service]
User=meteora
AmbientCapabilities=CAP_NET_BIND_SERVICE
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
NoNewPrivileges=yes

És superior per tres raons. El binari del disc no queda marcat, així que copiar-lo a un altre lloc no arrossega privilegi. El limitador es redueix a aquella única capability, de manera que ni el procés ni els seus fills no poden obtenir mai cap altra. I NoNewPrivileges=yes impedeix qualsevol guany de privilegi posterior, inclòs l'efecte de qualsevol binari setuid que el procés executi.

Auditar capabilities

# Quins binaris del sistema tenen capabilities assignades?
sudo getcap -r /usr /bin /sbin 2>/dev/null
# /usr/bin/ping cap_net_raw=ep
# /usr/bin/meteo-api cap_net_bind_service=ep

# Veure les capabilities de la shell actual
capsh --print | head -5

Igual que la llista de binaris setuid de 04-06, la llista de binaris amb capabilities és un inventari que cal conèixer i comparar periòdicament. Un binari amb cap_dac_override o cap_sys_admin aparegut del no-res és una alarma tan vermella com un setuid root nou, i crida menys l'atenció perquè ls -l no el mostra: no hi ha cap s que delati el privilegi. Només apareix amb getcap.

Control d'accés obligatori: SELinux i AppArmor

Tornem a l'escenari del principi. meteo-api està compromès, s'executa com a meteora, i tots els permisos són correctes. Amb DAC pot: llegir tots els .dat, escriure a /tmp, executar /bin/sh, obrir un sòcol a Internet i enviar-se les dades. Res d'això no viola ni un sol bit de permís.

El control d'accés obligatori afegeix una segona comprovació, després de la de DAC i completament independent d'ella:

graph TB
    A["El procés demana una operació<br/>(open, connect, exec...)"] --> B{"Comprovació DAC<br/>UID, GID, bits, ACL"}
    B -->|Denega| Z["EACCES"]
    B -->|Permet| C{"Comprovació MAC<br/>política de SELinux / AppArmor"}
    C -->|Denega| Y["EACCES + entrada al registre<br/>d'auditoria"]
    C -->|Permet| X["Operació concedida"]

La propietat clau és al diagrama: cal passar totes dues. DAC pot permetre i MAC denegar; MAC mai no concedeix el que DAC denega. I la política de MAC la fixa l'administrador del sistema, no l'amo del fitxer, així que un procés amb UID 0 tampoc no se la salta.

Les dues implementacions habituals a Linux:

SELinux AppArmor
Origen NSA; per defecte a Red Hat, Fedora, Android Canonical/SUSE; per defecte a Ubuntu, disponible a Debian
Unitat de política Etiquetes a l'objecte (meteora_data_t) i al subjecte (meteo_api_t) Rutes del sistema de fitxers
On viu l'etiqueta Al xattr security.selinux de l'inode Enlloc: el perfil anomena rutes
Conseqüència pràctica Moure un fitxer conserva la seva etiqueta; copiar-lo la pot canviar Moure un fitxer canvia la regla que se li aplica
Expressivitat Molt alta: tipus, rols, MLS/MCS, transicions Mitjana: suficient per confinar serveis
Corba d'aprenentatge Costeruda Suau: un perfil es llegeix com una llista
Diagnòstic típic ausearch -m AVC, sealert, restorecon dmesg, journalctl, aa-logprof
Modes enforcing, permissive, disabled enforce, complain (per perfil)

Com que meteo-01 és Debian, l'exemple natural és AppArmor. Així es veu l'esquelet d'un perfil per a meteo-api —incomplet a propòsit, perquè escriure una política completa no és l'objecte d'aquesta lliçó—:

# /etc/apparmor.d/usr.bin.meteo-api   (esquema il·lustratiu, no complet)
#include <tunables/global>

/usr/bin/meteo-api {
  #include <abstractions/base>
  #include <abstractions/nameservice>

  network inet stream,                        # sòcols TCP: sí
  network inet6 stream,

  /etc/meteora/meteora.conf            r,     # configuració: NOMÉS LECTURA
  /var/lib/meteora/lectures/*.dat      r,     # dades: NOMÉS LECTURA
  /var/log/meteora/meteo-api.log       aw,    # registre: només AFEGIR
  /run/meteora/api.sock                rw,
  /dev/shm/meteora-cache               rw,

  deny /etc/shadow                     rwx,   # explícit, encara que DAC ja ho impedeixi
  deny /home/**                        rwx,
  deny /**/.ssh/**                     rwx,
  # No hi ha cap regla 'ix' ni 'px': aquest perfil NO permet executar res
}

Llegeix el perfil amb atenció, perquè cada línia és una decisió. Les regles són una llista blanca: el que no hi apareix està denegat, inclòs qualsevol fitxer que s'instal·li demà —principi 3, valors per defecte segurs—. meteora.conf és r i no rw, de manera que el procés no pot reescriure la seva pròpia configuració encara que els permisos DAC s'espatllin algun dia. El registre és aw (append), la versió MAC del chattr +a de 04-06. I el decisiu és el que no hi ha: cap regla d'execució. Un meteo-api compromès no pot llançar /bin/sh, ni curl, ni python3, perquè AppArmor denega l'execve de tot allò que no estigui llistat. Això trenca la majoria de les cadenes d'atac automatitzades, que donen per fet que després de l'errada hi ha una shell.

El flux de treball realista per arribar a un perfil així, sense trencar producció:

sudo aa-status                              # quins perfils hi ha i en quin mode?
sudo aa-complain /usr/bin/meteo-api         # mode QUEIXA: registra, no bloqueja
# ... deixar córrer el servei uns dies amb càrrega real ...
sudo journalctl -k | grep -i apparmor       # veure què hauria bloquejat
sudo aa-logprof                             # refinar el perfil amb el que s'ha observat
sudo aa-enforce /usr/bin/meteo-api          # activar el bloqueig real

L'ordre importa i és l'aplicació pràctica del principi d'acceptabilitat psicològica: es comença en mode queixa, que registra sense bloquejar, s'observa uns quants dies amb trànsit real —inclòs el tancament de mes, la rotació de registres i el desplegament d'una versió— i només llavors es passa a obligatori. Un perfil escrit de cop i activat en producció trenca el servei, i un servei trencat per seguretat es desactiva en vint minuts i no torna.

Confinament i sandboxing: seccomp i la superfície de syscalls

Queda una capa més, i és la més profunda. A 01-06 vam veure que tot el que un procés pot demanar al sistema passa per una crida al sistema: unes 350 a Linux x86-64. Aquesta és, literalment, la superfície completa d'interacció entre un programa i el nucli.

Ara fes-te la pregunta: quantes d'aquestes 350 necessita l'ingestor? Rep lectures per un sòcol, les valida i les escriu en un fitxer. La seva llista real ronda les quaranta: read, write, openat, close, accept4, recvfrom, fsync, clock_gettime, mmap, exit_group i poca cosa més. Les 310 restantsmount, ptrace, init_module, keyctl, bpf, kexec_load, execve…— no les fa servir mai, però estan disponibles, i cadascuna és superfície d'atac: codi del nucli que un procés compromès pot intentar assolir, incloses les errades del mateix nucli.

seccomp (secure computing mode) resol això permetent que un procés renunciï voluntàriament i irreversiblement a un conjunt de crides al sistema. A partir d'aquell moment, qualsevol intent de fer-les servir acaba amb EPERM, amb SIGSYS o amb la mort del procés, segons com es configuri. La renúncia és irreversible —un procés no es pot treure el seu propi filtre— i s'hereta per fork i execve, així que cap shell llançada des d'allà no s'escapa.

/* Idea de l'arrencada de l'ingestor, en pseudocodi comentat.
   En producció es fa servir libseccomp, que evita escriure BPF a mà. */
#include <seccomp.h>

int main(void) {
    inicialitzar_socket_estacions();      /* 1. TOT el que necessita  */
    obrir_fitxer_del_dia();               /*    privilegi, ABANS      */
    alliberar_privilegis();               /*    de baixar a UID 990   */

    /* 2. Política: denegar per defecte, permetre el que s'enumera */
    scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_ERRNO(EPERM));

    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read),     0);
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write),    0);
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(fsync),    0);
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(accept4),  0);
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(recvfrom), 0);
    seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0);
    /* ... la resta de la llista blanca ... */
    /* NO es permeten: execve, ptrace, mount, init_module, sòcol sortint */

    seccomp_load(ctx);                    /* 3. Irreversible des d'aquí */

    bucle_principal();                    /* 4. Ja confinat */
}

L'estructura d'aquesta arrencada és el patró canònic d'un servei enfortit, i val la pena memoritzar-la: primer es fa tot el que requereix privilegi (obrir el sòcol, obrir els fitxers), després s'alliberen els privilegis, i finalment s'instal·la el filtre. L'ordre no és negociable: instal·lar seccomp abans d'obrir el sòcol faria fracassar l'arrencada. A partir de seccomp_load, encara que un atacant controli completament el flux d'execució del procés, no pot cridar execve, i per tant no aconsegueix una shell; no pot cridar ptrace, i per tant no es pot injectar en un altre procés; no pot muntar res. Ha heretat un procés al qual li falta la meitat del sistema operatiu.

Veure l'estat de seccomp d'un procés en marxa:

grep Seccomp /proc/$(pgrep -f ingestor)/status
# Seccomp:	2          → 0 = desactivat, 1 = mode estricte, 2 = filtre BPF

I la bona notícia pràctica: no cal escriure C per tenir seccomp. Systemd exposa llistes predefinides que cobreixen el 95 % dels casos, i les farem servir a 05-03:

[Service]
SystemCallFilter=@system-service        # llista blanca raonable per a un dimoni
SystemCallFilter=~@privileged @mount @module @debug @reboot @swap
SystemCallArchitectures=native

La primera línia parteix d'un conjunt predefinit pensat per a serveis; les següents, amb ~, resten grups sencers de crides perilloses; i SystemCallArchitectures=native tanca un forat clàssic, el d'invocar crides per l'ABI de 32 bits per esquivar un filtre de 64.

Base de còmput fiable i superfície d'atac

Dos conceptes que ordenen tot l'anterior i et donen un criteri per decidir.

La base de còmput fiable (TCB, trusted computing base) és el conjunt de components dels quals depèn la seguretat del sistema, i la fallada dels quals la compromet. No és el que "et fies" en sentit col·loquial: és el que estàs obligat a fiar-te'n perquè no tens manera de comprovar-ho des de fora. A meteo-01 la TCB inclou el microprogramari i el carregador d'arrencada, el nucli de Linux amb els seus mòduls i la seva política de MAC, els processos que s'executen com a root o amb capabilities perilloses, els binaris setuid, i també —això sorprèn— la infraestructura d'actualització de paquets i les claus amb què se signen.

La regla d'or és directa: com més petita és la TCB, més creïble és la seguretat del sistema, perquè hi ha menys codi per auditar i menys coses poden fallar. És el principi 2 —economia del mecanisme— convertit en criteri de disseny, i és l'argument tècnic a favor dels microkernels de 01-05: moure el controlador de xarxa fora del nucli el treu de la TCB, i una fallada seva deixa de ser una presa de control total.

La superfície d'atac és el conjunt de punts per on entra l'entrada d'un atacant. Per a Meteora, enumerar-la és un exercici de mitja hora que ret moltíssim:

Superfície Què la compon a meteo-01 Com es redueix
Xarxa Port d'estacions, API HTTP, SSH Tallafocs, escoltar només a la interfície necessària (05-03)
Crides al sistema ~350 disponibles per procés seccomp: baixar a ~40
Sistema de fitxers Tot el que l'UID 990 pot obrir AppArmor, ProtectSystem=strict
Privilegi Binaris setuid, fitxers amb capabilities nosuid, NoNewPrivileges, auditoria periòdica
Programari instal·lat Cada paquet i cada dependència Minimitzar paquets; gestionar dependències (05-03)
Persones Comptes amb accés, regles de sudo Cicle de vida de comptes, privilegi mínim (05-02)

Cada mecanisme d'aquesta lliçó ataca una fila diferent d'aquesta taula, i cap no en cobreix dues. Això és, exactament, el que significa defensa en profunditat.

El problema del delegat confús

Acabem amb un problema clàssic de 1988 que explica tota una família de vulnerabilitats i que, un cop l'entens, veus per tot arreu.

El plantejament original: un compilador que s'executa com a servei amb privilegis propis. A més de compilar, porta una comptabilitat d'ús en un fitxer /var/lib/compilador/factura, sobre el qual té permís d'escriptura i els usuaris no. El compilador accepta un argument: el nom del fitxer de sortida.

Un usuari li demana compilar indicant com a fitxer de sortida... /var/lib/compilador/factura. El compilador, obedient, hi escriu. I pot, perquè ell sí que hi té permís. L'usuari acaba de destruir la comptabilitat sense tenir-hi cap permís.

El delegat confús és un programa privilegiat a qui s'enganya perquè faci servir la seva pròpia autoritat en nom de qui no la té. El programa no està compromès: fa exactament el que li demanen. L'errada és que confon dues autoritats: la seva i la de qui l'hi demana.

Aplicat a Meteora, amb un cas que podria escriure qualsevol:

# ❌ meteo-api amb un delegat confús
@app.route("/exportar")
def exportar():
    desti = request.args.get("desti")                # ve de fora!
    dades = llegir_lectures_del_dia()
    with open(f"/var/lib/meteora/export/{desti}", "w") as f:
        f.write(dades)                               # escriu amb permisos de meteora
    return "OK"

Una petició amb desti=../../../../etc/meteora/meteora.conf fa que meteo-api escrigui amb la seva pròpia autoritat en un lloc que el peticionari no controla. El procés no ha estat compromès: ha fet servir el seu permís legítim en nom d'un desconegut. És la mateixa estructura que el CSRF al web (el navegador és el delegat confús, i les seves galetes l'autoritat), que l'SSRF (el servidor és el delegat, i la seva posició dins de la xarxa l'autoritat) i que molts abusos de binaris setuid.

La versió correcta separa l'autoritat de la petició:

# ✔ Delegat que no es confon
import os, re
BASE = "/var/lib/meteora/export"

@app.route("/exportar")
def exportar():
    desti = request.args.get("desti", "")
    # 1. Llista blanca de forma, no llista negra de caràcters prohibits
    if not re.fullmatch(r"[a-zA-Z0-9_-]{1,64}\.csv", desti):
        return "Nom no vàlid", 400
    # 2. Resoldre i comprovar que continua dins de BASE
    ruta = os.path.realpath(os.path.join(BASE, desti))
    if os.path.commonpath([ruta, os.path.realpath(BASE)]) != os.path.realpath(BASE):
        return "Ruta fora d'abast", 400
    # 3. Escriure amb O_NOFOLLOW i O_EXCL: ni enllaços ni sobreescriptures
    fd = os.open(ruta, os.O_WRONLY | os.O_CREAT | os.O_EXCL | os.O_NOFOLLOW, 0o640)
    with os.fdopen(fd, "w") as f:
        f.write(llegir_lectures_del_dia())
    return "OK"

Tres defenses, i cadascuna tapa un forat diferent. La validació per llista blanca accepta només la forma esperada, en comptes d'intentar enumerar el que és prohibit —que sempre oblida alguna cosa, com ara ..%2f o una codificació exòtica—. La resolució amb realpath i la comprovació de prefix neutralitza els .. i els enllaços simbòlics que apuntin a fora, i es fa després de resoldre, no abans. I O_NOFOLLOW | O_EXCL tanca la finestra TOCTOU de 04-04: si el destí ja existeix o és un enllaç, l'operació falla en comptes de seguir l'enllaç allà on l'atacant vulgui. Per sobre de les tres hi ha el disseny: el perfil d'AppArmor de l'apartat 8 només permet escriure en rutes concretes, així que encara que les tres validacions fallessin, el nucli denegaria l'escriptura a /etc/meteora/. Quatre capes independents per a una sola errada: això és defensa en profunditat aplicada de debò.

Advertència necessària. Tot el d'aquesta lliçó s'explica per defensar sistemes propis. Qualsevol prova de seguretat —fins i tot una de tan innocent com comprovar si un servei valida bé un paràmetre— s'ha de fer exclusivament sobre sistemes de la teva propietat o amb autorització expressa i per escrit del responsable. Provar-ho sobre sistemes aliens sense permís és un delicte a la majoria de jurisdiccions, amb independència de la intenció. I quan una decisió de seguretat tingui implicacions legals o regulatòries —dades personals, retenció, notificació de bretxes—, consulta-la amb un professional de compliment normatiu o amb assessoria jurídica.

Errors Habituals i Consells

Confondre "té els permisos correctes" amb "està protegit". Els permisos limiten a quins fitxers arriba un procés. No diuen res sobre a quina xarxa es connecta, quins programes executa o quines crides al sistema fa servir. Un meteo-api compromès amb permisos perfectes continua podent obrir una shell si ningú no l'hi impedeix.

Fer servir chmod u+s per resoldre un problema de privilegi. Concedeix tots els privilegis del propietari quan gairebé sempre en cal un. L'alternativa correcta és una capability concreta —millor encara, via AmbientCapabilities a la unitat de systemd—, un grup, o un sòcol amb els permisos adequats.

Creure que les capabilities de Linux són "capacitats" en el sentit teòric. No ho són: no anomenen un objecte. CAP_DAC_OVERRIDE no és "pot llegir aquest fitxer", és "pot llegir-los tots". I precisament per això hi ha capabilities que equivalen a root: CAP_SYS_ADMIN, CAP_SYS_MODULE, CAP_SYS_PTRACE i CAP_DAC_OVERRIDE.

Auditar només els binaris setuid i oblidar getcap. Un binari amb capabilities no mostra cap marca a ls -l. Si el teu inventari de privilegi només mira la s, tens un punt cec. Executa també getcap -r /usr /bin /sbin i guarda la llista de referència.

Escriure un perfil de MAC de cop i activar-lo en producció. Trenca el servei, i un control que trenca el servei es desactiva i no torna. Comença sempre en mode queixa o permissiu, observa uns quants dies amb càrrega real —incloent-hi desplegaments i rotació de registres— i només llavors posa el mode obligatori.

Posar el sistema en permissive o complain "temporalment" per depurar. Aquell "temporalment" dura anys. Si necessites depurar, desactiva un sol perfil, anota-ho amb data i posa-t'hi un recordatori.

Confiar en la seguretat per obscuritat. Canviar el port de SSH redueix el soroll dels escaneigs automàtics, i està bé. No és un control de seguretat, i no substitueix les claus públiques ni el tallafocs. Disseny obert: la seguretat és a la clau, no en el secret del disseny.

Consell: ordena qualsevol decisió de seguretat amb la pregunta dels dominis. Davant de qualsevol component, pregunta't: quin és el seu domini de protecció exacte?, quan canvia de domini?, i què passa si un atacant hereta aquell domini sencer? Les tres respostes et porten directament a la llista de mecanismes que necessites.

Exercicis

Exercici 1: la matriu d'accés de Meteora i la seva implementació

Construeix la matriu d'accés completa de meteo-01 per als subjectes ingestor, agregador, meteo-api, nuria (analista) i carlos (administrador de sistemes), sobre els objectes /var/lib/meteora/lectures/*.dat, /etc/meteora/meteora.conf, /etc/meteora/secrets.conf, /var/log/meteora/meteo-api.log, /dev/shm/meteora-cache i /run/meteora/lectures.fifo. Després: (a) indica per a cada cel·la no buida amb quin mecanisme concret s'implementa avui (bits, ACL, grup, capability); (b) assenyala quina cel·la seria impossible d'expressar només amb els nou bits i per què; (c) explica què canvia a la matriu si meteo-api resulta compromès, i quina fila no canvia.

Exercici 2: reduir el domini de meteo-api

meteo-api ha d'escoltar al port 443, llegir els .dat i la configuració, i escriure al seu registre. Res més. Dissenya la protecció completa en tres capes independents i, per a cadascuna, escriu la configuració concreta i explica quin atac concret atura aquella capa i no les altres: (1) DAC, amb propietaris i modes; (2) capabilities, decidint entre setcap sobre el fitxer i AmbientCapabilities a la unitat, i justificant l'elecció; (3) MAC, amb l'esquelet d'un perfil d'AppArmor. Acaba indicant quines crides al sistema no hauria de poder fer servir i amb quina directiva de systemd ho aconseguiries.

Exercici 3: identificar principis violats

Per a cadascuna d'aquestes cinc situacions reals, digues quin principi o principis de Saltzer i Schroeder es violen, quin atac concret ho aprofita i quina és la correcció:

  1. Un script de desplegament executa chmod -R 777 /var/lib/meteora "perquè no doni problemes de permisos".
  2. La política de l'empresa obliga a canviar la contrasenya cada 30 dies i prohibeix els gestors de contrasenyes.
  3. meteo-api s'executa com a root "perquè així segur que funciona".
  4. L'API d'administració no està documentada i és a /admin-x7f3, sense autenticació, "perquè ningú no la coneixerà".
  5. Els tres processos de Meteora comparteixen /tmp i es passen fitxers temporals amb noms predictibles com ara /tmp/meteora-cache-avui.

Solucions

Solució 1

La matriu (L = llegir, E = escriure, A = afegir, X = executar, — = sense accés):

*.dat meteora.conf secrets.conf meteo-api.log meteora-cache lectures.fifo
ingestor L, E L L L, E L (llegeix del FIFO)
agregador L L L, E
meteo-api L L L A L
nuria L
carlos L (via sudo) L, E (via sudo) L, E (via sudo) L (grup adm)

(a) Mecanismes. Les cel·les dels tres processos s'implementen amb DAC clàssic: tots tres s'executen amb UID 990 i GID 990, i els fitxers són meteora:meteora 0640, tret de la configuració que és root:meteora 0640 —lectura pel grup, escriptura només root—. La cel·la de nuria és una entrada d'ACL POSIX (setfacl -m u:nuria:r) més la seva ACL per defecte per als fitxers futurs. La cel·la de carlos sobre els registres és pertinença al grup adm, i les altres són regles de sudo (05-02), no accés directe. Si meteo-api escoltés al 443, apareixeria una capability, CAP_NET_BIND_SERVICE, que no és una cel·la d'aquesta matriu sinó un privilegi global sobre el sistema: és justament l'anomalia que comentàvem a l'apartat 7.

(b) La cel·la impossible amb nou bits és la de nuria sobre els .dat. Els nou bits només expressen permisos per a un usuari, un grup i la resta; l'usuari ja és meteora i el grup també, així que l'única manera de donar-li accés a una quarta identitat seria ficar-la al grup meteora —cosa que li donaria a més meteora.conf i secrets.conf— o obrir other —cosa que ho donaria a tot el sistema—. És exactament el desbordament del model de tres classes que motiva les ACL, i per això cal una entrada nominal.

(c) Si meteo-api es compromet, la seva fila no canvia formalment: l'atacant hereta exactament aquests drets. I això és el greu, perquè inclou secrets.conf amb les claus d'API, tots els .dat i meteora-cache. Però l'atacant obté a més tot allò que la matriu no representa: executar /bin/sh, obrir sòcols sortints, escriure a /tmp, llegir /etc/passwd, i persistir. La fila que no canvia és la de carlos: els seus privilegis passen per sudo i exigeixen una autenticació addicional que l'atacant no té. Aquesta és la lliçó de l'exercici: la matriu d'accés descriu DAC, i DAC no és tota la història; per acotar el que la matriu no veu calen AppArmor i seccomp.

Solució 2

Capa 1 — DAC:

sudo chown root:root  /usr/bin/meteo-api      && sudo chmod 0755 /usr/bin/meteo-api
sudo chown root:meteora /etc/meteora/meteora.conf && sudo chmod 0640 /etc/meteora/meteora.conf
sudo chown -R meteora:meteora /var/lib/meteora
sudo find /var/lib/meteora -type d -exec chmod 2750 {} +
sudo find /var/lib/meteora -type f -exec chmod 0640 {} +
sudo chown meteora:adm /var/log/meteora/meteo-api.log && sudo chmod 0640 /var/log/meteora/meteo-api.log
sudo chattr +a /var/log/meteora/meteo-api.log

Què atura aquesta capa i no les altres: l'accés d'altres usuaris i altres serveis del sistema a les dades de Meteora. Si demà s'instal·la una altra aplicació amb el seu propi compte de servei, no podrà llegir ni un sol .dat. És la capa que separa llogaters dins de la mateixa màquina, i ni les capabilities ni AppArmor no la substitueixen.

Capa 2 — capabilities. L'elecció correcta és AmbientCapabilities a la unitat, no setcap sobre el fitxer:

[Service]
User=meteora
Group=meteora
AmbientCapabilities=CAP_NET_BIND_SERVICE
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
NoNewPrivileges=yes

Raons de l'elecció: amb setcap, el privilegi queda gravat a l'inode del binari, de manera que qualsevol que l'executi l'obté i una còpia del fitxer el podria arrossegar; amb AmbientCapabilities, el privilegi el concedeix systemd només a aquest servei, el binari del disc queda net, i CapabilityBoundingSet a més impedeix per sempre que el procés o els seus fills adquireixin cap altra capability.

Què atura aquesta capa i no les altres: l'escalada a root. Sense ella, la manera "fàcil" d'escoltar al 443 seria executar-se com a root o amb setuid, i llavors una errada en l'anàlisi de peticions donaria el sistema sencer. Amb ella, el procés compromès no pot carregar mòduls, ni muntar, ni saltar-se els permisos de fitxer, ni depurar altres processos. NoNewPrivileges=yes ho remata: encara que el procés executés un binari setuid, no guanyaria privilegi.

Capa 3 — MAC (esquema d'AppArmor):

/usr/bin/meteo-api {
  #include <abstractions/base>
  network inet stream,
  /etc/meteora/meteora.conf       r,
  /var/lib/meteora/lectures/*.dat r,
  /var/log/meteora/meteo-api.log  aw,
  /run/meteora/api.sock           rw,
  deny /etc/shadow  rwx,
  deny /home/**     rwx,
  deny /tmp/**      wx,
  # sense regles d'execució: no pot llançar CAP programa
}

Què atura aquesta capa i no les altres: l'abús dels permisos legítims. DAC permet a meteora escriure a /tmp, llegir /etc/passwd i executar /bin/sh; les capabilities no diuen res d'això perquè no són privilegis de root. AppArmor ho denega punt per punt, i sobretot talla l'obtenció d'una shell, que és el primer pas de gairebé qualsevol cadena d'atac automatitzada.

Crides al sistema que no hauria de poder fer servir: execve/execveat (res a executar), ptrace (res a depurar), mount/umount2, init_module/finit_module/delete_module, kexec_load, keyctl, bpf, setuid/setgid després de l'arrencada, i unshare/setns. A systemd:

SystemCallFilter=@system-service
SystemCallFilter=~@privileged @mount @module @debug @reboot @swap @obsolete
SystemCallArchitectures=native

Les tres capes són independents: si el perfil d'AppArmor es descarrega per error, DAC i les capabilities continuen allà; si els permisos s'espatllen en un desplegament, AppArmor continua denegant. Això és el que fa que la suma valgui més que les parts.

Solució 3

1. chmod -R 777. Viola el privilegi mínim (concedeix a tot el sistema el màxim dret possible), els valors per defecte segurs (inverteix la política: en comptes de denegar per defecte, permet tot) i la separació de privilegis (esborra la distinció entre qui executa el servei i qualsevol altre). L'atac: qualsevol compte de la màquina —inclòs el d'un altre servei compromès— pot modificar o esborrar les dades, i els fitxers queden a més executables, cosa que habilita el vector "escric un binari i espero que algú el llanci". Correcció: chmod -R u=rwX,g=rX,o= o separar per tipus amb find -type d/-type f, i diagnosticar el permís real amb namei -l en comptes d'obrir de bat a bat.

2. Caducitat a 30 dies sense gestor de contrasenyes. Viola l'acceptabilitat psicològica i, de retruc, el privilegi mínim —perquè produeix contrasenyes reutilitzades entre sistemes—. El resultat observable és Meteora2026!Meteora2026!!Meteora2026!!!, contrasenyes apuntades en post-its i en documents compartits, i reutilització entre serveis. Correcció alineada amb les guies modernes: contrasenyes llargues en comptes de complexes, sense caducitat periòdica obligatòria, canvi només davant d'indici de compromís, comprovació contra llistes de contrasenyes filtrades, i fomentar el gestor de contrasenyes més segon factor. Es detalla a Usuaris, Autenticació i Escalada de Privilegis.

3. meteo-api com a root. Viola el privilegi mínim de la manera més directa possible, i també l'economia del mecanisme —tota la seguretat passa a dependre que no hi hagi ni una sola errada al codi de l'aplicació— i el mecanisme comú mínim —comparteix la identitat més poderosa amb la resta del sistema—. L'atac: qualsevol errada d'anàlisi d'una petició HTTP es converteix en control total de la màquina, sense cap pas intermedi. Correcció: User=meteora, la capability concreta si cal un port baix, NoNewPrivileges=yes i confinament MAC.

4. L'API a /admin-x7f3 sense autenticació. Viola el disseny obert (la seguretat depèn del secret de la ruta, no d'una credencial) i la mediació completa (hi ha un camí que no passa per cap comprovació d'accés). L'atac no requereix endevinar res: la ruta es filtra pels registres del proxy, per l'historial del navegador, per una captura de pantalla en un tiquet, pel Referer d'una petició o per un escaneig de rutes. Correcció: autenticació real en aquell punt —la ruta pot continuar sent poc evident, això no molesta—, restricció per xarxa d'origen i registre de tots els accessos.

5. /tmp compartit amb noms predictibles. Viola el mecanisme comú mínim (els tres processos comparteixen un recurs que a més comparteixen amb tot el sistema) i prepara un TOCTOU de manual: qualsevol usuari pot crear /tmp/meteora-cache-avui abans que Meteora, o substituir-lo per un enllaç simbòlic a un altre fitxer, provocant que el servei escrigui allà on l'atacant vulgui —amb l'autoritat de meteora, cosa que a més el converteix en un delegat confús—. Correcció en tres fronts: PrivateTmp=yes a les unitats de systemd, de manera que cada servei rebi el seu propi /tmp aïllat; fitxers temporals amb mkstemp() en lloc de noms fixos; i per a la comunicació real entre els processos, els mecanismes d'IPC del mòdul 3 —el FIFO /run/meteora/lectures.fifo i /dev/shm/meteora-cache, amb permisos 0750 i 0660 en un directori propi— en comptes de fitxers solts en un directori públic.

Conclusió

La protecció és el mecanisme intern amb què el SO controla accessos; la seguretat és la propietat global davant d'un adversari. La primera es pot demostrar, la segona només es pot raonar amb un model d'amenaces, i d'aquí la regla que governa tot el mòdul: cap mecanisme no és una solució, tots són capes.

Tot control d'accés es descriu amb quatre peces: subjectes (processos, no usuaris), objectes (fitxers, però també sòcols, processos i memòria compartida), drets i dominis de protecció —el conjunt de parells (objecte, drets) vigent ara mateix—. L'interessant són els canvis de domini: l'execve d'un binari setuid n'és un, i és on es concentra l'escalada de privilegis. Posats en una taula, subjectes i objectes formen la matriu d'accés, que cap sistema no emmagatzema sencera i tots trossegen d'una de dues maneres: per columnes són les ACL —la informació viu a l'objecte, s'audita bé "qui accedeix a això?" i es revoca fàcilment—; per files són les capacitats —la clau viu al subjecte, la comprovació és O(1), la delegació és natural i la revocació és difícil—. Els descriptors de fitxer d'UNIX són capacitats, i això explica d'un cop per totes per què el permís es comprova a open() i no a read().

Els vuit principis de Saltzer i Schroeder continuen sent la millor llista de comprovació que existeix: privilegi mínim (i durant el mínim temps), economia del mecanisme, valors per defecte segurs, mediació completa —l'enemic de la qual té nom, TOCTOU—, disseny obert davant de la seguretat per obscuritat, separació de privilegis, mecanisme comú mínim i acceptabilitat psicològica, el més ignorat i el que més bretxes causa, perquè un control que fa nosa es desactiva. Sobre ells es construeixen els quatre models: DAC (decideix l'amo; el seu punt feble és que un procés compromès hereta aquesta discreció), MAC (decideix l'administrador i ni root se la salta), RBAC (permisos a rols) i ABAC (regles amb atributs i context). Un servidor real els combina tots.

I els tres mecanismes de Linux, cadascun atacant una superfície diferent. Les capabilities trossegen el "tot o res" de root en unes quaranta peces: CAP_NET_BIND_SERVICE deixa meteo-api escoltar al 443 sense ser root, mentre que CAP_SYS_ADMIN, CAP_SYS_MODULE, CAP_SYS_PTRACE i CAP_DAC_OVERRIDE equivalen pràcticament a root i cal tractar-les així; es concedeixen millor amb AmbientCapabilities que amb setcap, i s'auditen amb getcap perquè ls -l no les mostra. SELinux i AppArmor afegeixen una segona comprovació obligatòria després de DAC —etiquetes davant de rutes— que converteix els permisos correctes en insuficients per a l'atacant: un perfil sense regles d'execució impedeix que un meteo-api compromès obtingui una shell. I seccomp redueix la superfície més profunda de totes, de ~350 crides al sistema a les ~40 que l'ingestor fa servir de debò, amb el patró canònic d'arrencada: privilegi primer, alliberar després, filtrar al final. Tot plegat s'ordena amb dues idees: fer petita la TCB i enumerar la superfície d'atac. I el delegat confús recorda que un programa privilegiat pot ser abusat sense estar compromès, simplement per confondre la seva autoritat amb la de qui li demana alguna cosa.

Amb això tenim el marc. Però fixa't que tot ell descansa sobre una paraula que no hem definit: identitat. Un domini de protecció s'assigna a un subjecte, i el subjecte s'identifica per un UID. Hem parlat de meteora, de nuria i de carlos com si el sistema sabés qui són, quan l'única cosa que sap el nucli són els números 990, 1002 i 1001. D'on surten aquests números? Què passa exactament entre teclejar una contrasenya i tenir una shell? Com es guarda aquella contrasenya perquè ni root la pugui llegir? I com es puja d'un domini a un altre de manera controlada i auditable, que és el que fa sudo cinquanta vegades al dia?

Això és Usuaris, Autenticació i Escalada de Privilegis, on dissecarem /etc/passwd, /etc/shadow i /etc/group camp a camp, veurem com PAM encadena els mòduls que decideixen si entres, com funciona l'autenticació per clau pública de SSH, i quines categories d'error de configuració converteixen un compte normal en root sense que ningú se n'adoni.

Fonaments de Sistemes Operatius

Mòdul 1: Introducció als Sistemes Operatius

Mòdul 2: Gestió de Recursos

Mòdul 3: Concurrència

Mòdul 4: Estructures de Fitxers

Mòdul 5: Protecció i Seguretat del Sistema

Mòdul 6: Virtualització i Contenidors

Mòdul 7: Administració i Diagnòstic a la Pràctica

© Copyright 2026. Tots els drets reservats