- p°edchozφ Φlßnek - nßsledujφcφ Φlßnek - obsah -

LinuxovΘ noviny B°ezen 1998

S-bit - ╛ivotu nebezpeΦno

Pavel Ka≥kovsk², 3. b°ezna 1998

Mnoho systΘmov²ch program∙ v UNIXovΘm operaΦnφm systΘmu - Linux nevyjφmaje - pot°ebuje pro sv∙j b∞h zvlß╣tnφ privilegia. P°φkladem budi╛ program passwd, kter² musφ b²t schopen zapisovat do souboru /etc/passwd resp. /etc/shadow, ani╛ by k tomu byl oprßvn∞n sßm u╛ivatel (z pochopiteln²ch d∙vod∙). NejΦast∞ji pou╛φvan²m mechanismem, kter² toto umo╛≥uje, je tzv. prop∙jΦenφ identifikace.

U programu, jeho╛ spustiteln² soubor mß nastaven² aspo≥ jeden z s-bit∙, nap°φklad takto:

  -r-sr-xr-x  1 root   bin     15796 /usr/bin/passwd
dojde po jeho spu╣t∞nφ systΘmov²m volßnφm execve() k tomu, ╛e efektivnφ vlastnφk, efektivnφ skupina, p°φpadn∞ oboje - podle toho, zda je v p°φstupov²ch prßvech nastaven setuid bit (04000), setgid bit (02000), nebo oba dva - jsou nastaveny na hodnoty urΦenΘ u╛ivatelem resp. skupinou vlastnφcφ soubor. (Mno╛ina dopl≥kov²ch skupin (supplemental groups) je v╛dy ponechßna beze zm∞ny.) Program pak pracuje se stejn²mi oprßvn∞nφmi, jako kdyby byl spu╣t∞n sv²m vlastnφkem resp. u╛ivatelem v danΘ skupin∞.

ProΦ je to nebezpeΦnΘ?

V²╣e popsan² mechanismus nenφ prost rizik. Musφ b²t zaji╣t∞no, aby zvlß╣tnφ privilegia p°id∞lenß programu nemohla b²t zneu╛ita. ╚ßst odpov∞dnosti le╛φ na samotnΘm jßd°e systΘmu, kterΘ musφ mj. zabrßnit jeho trasovßnφ nebo Φtenφ jeho pam∞╗ovΘho prostoru (kde se mohou nachßzet d∙v∞rnß data) ze strany skuteΦnΘho vlastnφka, ov╣em p°evß╛nß Φßst spoΦφvß na bedrech samotnΘho programu (a takΘ jφm pou╛φvan²ch knihovnßch).

Privilegovan² proces musφ peΦliv∞ kontrolovat prost°edφ, ve kterΘm je spu╣t∞n, a vstupy, kterΘ jsou mu u╛ivatelem p°edklßdßny. Nane╣t∞stφ mnoho program∙ (Φi spφ╣e jejich autor∙) toto podce≥uje a v²sledkem jsou zßva╛nΘ bezpeΦnostnφ problΘmy, kterΘ jsou je╣t∞ umocn∞ny tφm, ╛e velkß Φßst takov²ch program∙ pracuje rovnou s nejvy╣╣φmi mo╛n²mi privilegii - s prßvy superu╛ivatele.

K nejΦast∞j╣φm chybßm, kterΘ majφ za nßsledek bezpeΦnostnφ problΘmy (a kterΘ budou detailn∞ji diskutovßny nφ╛e) pat°φ:

  • p°eteΦenφ mezφ pole
  • neopatrnß manipulace se soubory
  • neopatrnΘ spou╣t∞nφ dal╣φch program∙

Odstra╣ujφcφ p°φklad - Xserver

Jak si asi mnozφ, kte°φ majφ na svΘm Linuxu nainstalovan² balφk XFree86, v╣imli, Xserver b∞╛φ s prßvy superu╛ivatele. Je tomu tak, aby mu bylo dovoleno p°istupovat p°φmo ke grafickΘmu hardware, k jeho╛ ovlßdßnφ neposkytuje standardnφ linuxovΘ jßdro prakticky ╛ßdnou podporu. Ov╣em Xserver je velmi komplikovan² program a vyskytujφ se v n∞m (nynφ bude °eΦ o aktußlnφ verzi 3.3.1 zalo╛enΘ na X11R6.3) r∙znΘ problΘmy, dokonce ze v╣ech t°φ v²╣e vyjmenovan²ch kategoriφ. Jednß se o nßsledek toho, ╛e k≤d Xserveru (a do jistΘ mφry to platφ o celΘm X11) byl v∞t╣inou navrhovßn a implementovßn, ani╛ byl kladen dostateΦn² d∙raz na jeho bezpeΦnost. Svou roli zde nepochybn∞ hraje velk² rozsah a slo╛itost k≤du, stejn∞ jako jeho znaΦnß r∙znorodost.

P°eteΦenφ mezφ pole

Toto je snad nejfrekventovan∞j╣φ chyba vyskytujφcφ se v cΘΦkov²ch programech v∙bec. Pon∞kud p°ekvapiv∞ se v╣ak chyba vyskytuje mnohem Φast∞ji nep°φmo - p°i pou╛itφ n∞kter²ch funkcφ standardnφ knihovny. Zvlß╣t∞ se jednß o funkce sprintf(), strcpy() a strcat(), kterΘ neumo╛≥ujφ explicitn∞ stanovit velikost pole, do kterΘho je uklßdßn v²sledek, a bezstarostn∞ zapisujφ za jeho konec. (Co╛ vede k otßzce, zda je celkovß koncepce standardnφ knihovny vhodnß.) Podrobn∞ji k tΘto problematice v Φlßnku P°eteΦenφ bufferu.

Pomocφ vhodn∞ sestrojen²ch vstupnφch dat pak m∙╛e zl² u╛ivatel p°epsat nßvratovou adresu na zßsobnφku nebo jinΘ d∙le╛itΘ ·daje a donutit program k vykonßnφ prakticky libovoln²ch akcφ - nap°. ke spu╣t∞nφ privilegovanΘho shellu. Detailnφ popis p°inß╣φ nap°φklad http://www-miaif.ibp.fr/willy/security/.

P°φklad (xc/programs/Xserver/os/access.c) je na v²pisu NesprßvnΘ meze polφ.

  void
  ResetHosts (display)
      char *display;
  {
      register HOST  *host;
      char lhostname[120], ohostname[120];
      char *hostname = ohostname;
      char fname[100];
  ...
      strcpy (fname, "/etc/X");
      strcat (fname, display);
      strcat (fname, ".hosts");
      if (fd = fopen (fname, "r"))
  ...
  }

V²pis 3: NesprßvnΘ meze polφ

U╛ivatel m∙╛e p°i spu╣t∞nφ Xserveru specifikovat libovoln² (i nesmysln² a hlavn∞ libovoln∞ dlouh²) nßzev displaye pomocφ parametru uvozenΘho dvojteΦkou. Tato hodnota je p°edßna do funkce ResetHosts(), kterß ji pou╛φvß pro konstrukci jmΘna souboru. Av╣ak p°φli╣ dlouhß hodnota zp∙sobφ p°eteΦenφ mezφ pole fname.

Neopatrnß manipulace se soubory

V∞t╣ina program∙ pracuje n∞jak²m zp∙sobem se souborov²m systΘmem. Pokud program neprovßdφ dostateΦnΘ kontroly jmen soubor∙ nebo jin²ch u╛ivatelem poskytnut²ch dat, z nich╛ jsou jmΘna soubor∙ konstruovßna, lze snadno zφskat neoprßvn∞n² p°φstup k soubor∙m, systΘmov²m zvlß╣t∞.

P°φklad (xc/programs/Xserver/os/utils.c) je na v²pisu P°φklad nesprßvnΘho zachßzenφ se souborem.

  static void
  InsertFileIntoCommandLine(resargc, resargv, prefix_argc, prefix_argv, filename,\
     suffix_argc, suffix_argv)

      int *resargc;
  ...
  {
      struct stat    st;
      FILE           *f;
      char           *p;
      char           *q;
      int            insert_argc;
      char           *buf;
      int            len;
      int            i;

      f = fopen(filename, "r");
  ...
  } /* end InsertFileIntoCommandLine */

  void
  ExpandCommandLine(pargc, pargv)
      int *pargc;
      char ***pargv;
  {
      int i;
      for (i = 1; i < *pargc; i++)
      {
          if ( (0 == strcmp((*pargv)[i], "-config")) && (i < (*pargc - 1)) )
          {
              InsertFileIntoCommandLine(pargc, pargv,
                                            i, *pargv,
                                      (*pargv)[i+1], /* filename */
                                      *pargc - i - 2, *pargv + i + 2);
              i--;
          }
      }
  } /* end ExpandCommandLine */

V²pis 4: P°φklad nesprßvnΘho zachßzenφ se souborem

Funkce ExpandCommandLine() interpretuje parametr -config tak, ╛e naΦte obsah specifikovanΘho souboru a p°idß ho k parametr∙m zadan²m na p°φkazovΘ °ßdce. NicmΘn∞ v∙bec nekontroluje, zda je dan² soubor u╛ivateli, kter² Xserver spustil, p°φstupn² pro Φtenφ. Nap°φklad, pokud zl² u╛ivatel zadß soubor /etc/shadow, dostane se mu chybovΘho hlß╣enφ typu:

Unrecognized option: root:BFLMpsvzABCD:12345:::::
a m∙╛e zaΦφt lu╣tit superu╛ivatelovo heslo.

Zvlß╣tnφ kapitolu p°edstavujφ doΦasnΘ soubory vytvß°enΘ v oblastech p°φstupn²ch u╛ivateli - zvlß╣t∞ v adresß°i /tmp, ale i v domovskΘm adresß°i u╛ivatele, v aktußlnφm adresß°i apod. Zl² u╛ivatel m∙╛e vytvo°enφm (sym)link∙ nebo p°ejmenovßvßnφm soubor∙ lehce p°esv∞dΦit naivn∞ implementovan² program, aby pracoval s ·pln∞ jin²m souborem, ne╛ zam²╣lel. Bohu╛el tomu op∞t napomßhß standardnφ knihovna - konkrΘtn∞ funkce mktemp() a tmpnam(). V p°φpad∞ Xserveru lze problΘm tohoto typu demonstrovat na prßci s adresß°em /tmp/.X11-unix, i kdy╛ konkrΘtnφ povaha t∞chto rizik pon∞kud vyboΦuje ze zam∞°enφ tohoto Φlßnku.

NeopatrnΘ spou╣t∞nφ dal╣φch program∙

P°φle╛itostn∞ pot°ebuje jeden program vyu╛φt slu╛eb jinΘho programu. Pokud prvnφ program b∞╛φ se zvlß╣tnφmi privilegii, pak jsou Φasto tato privilegia p°enß╣ena i na programy z n∞j spu╣t∞nΘ. To pak znamenß, ╛e se na jednΘ stran∞ nabφzφ mo╛nost vyu╛φt (Φi spφ╣e zneu╛φt) nedostatk∙ jinΘho programu, na druhΘ stran∞ pak mo╛nost p°φmo donutit privilegovan² proces k spu╣t∞nφ libovolnΘho programu dodanΘho zl²m u╛ivatelem (sem lze za°adit pou╛itφ dynamicky linkovanΘ knihovny podle p°ßnφ u╛ivatele). Xserver vykazuje vzßcnou kombinaci obou problΘm∙, jak uvidφme v p°φkladu.

P°φklad (xc/programs/Xserver/xkb/ddxLoad.c) je na v²pisu NeopatrnΘ spou╣t∞nφ dal╣φch program∙.

  Bool
  XkbDDXCompileKeymapByNames(XkbDescPtr              xkb,
                             XkbComponentNamesPtr    names,
                             unsigned                want,
                             unsigned                need,
                             char *                  nameRtrn,
                             int                     nameRtrnLen)
  {
  ...
      if (XkbBaseDirectory!=NULL) {
  ...
          sprintf(buf,
      "%s/xkbcomp -w %d -R%s -xkm -- -em1 %s -emp %s -eml %s \"%s%s.xkm\"",
                XkbBaseDirectory,
                ((xkbDebugFlags<2)?1:((xkbDebugFlags>10)?10:xkbDebugFlags)),
                XkbBaseDirectory,
                PRE_ERROR_MSG,ERROR_PREFIX,POST_ERROR_MSG1,
                xkm_output_dir,keymap);
  ...
      }
      else {
  ...
      }
  ...
      out= popen(buf,"w");
  ...
  }

V²pis 5: NeopatrnΘ spou╣t∞nφ dal╣φch program∙

Prom∞nnß XkbBaseDirectory obsahuje bu∩ implicitnφ hodnotu (/usr/lib/X11/xkb), nebo hodnotu specifikovanou pomocφ parametru -xkbdir. (Z tohoto d∙vodu mi nenφ zcela jasn² v²znam testu na nulovou hodnotu, ale to ponechme stranou.) U╛ivatel mß nynφ dv∞ mo╛nosti jak tento parametr zneu╛φt: jednak m∙╛e vytvo°it libovoln² program pod jmΘnem xkbcomp a p°edat jmΘno adresß°e, ve kterΘm se nachßzφ, nebo m∙╛e vyu╛φt faktu, ╛e funkce popen() zp∙sobφ spu╣t∞nφ shellu, a zadat hodnotu, kterß obsahuje znaky majφcφ pro shell zvlß╣tnφ v²znam (nap°. mezery, obrßcenΘ apostrofy aj.).

V²chodiska z nouze

RozsßhlΘ a t∞╛ko prov∞°itelnΘ programy (jako zmφn∞n² Xserver) nem∞ly b²t nikdy spou╣t∞ny se zvlß╣tnφmi privilegii. Principißln∞ vzato by t∞╛ko prov∞°itelnΘ programy nem∞ly v∙bec vznikat. ╚asto pou╛φvanΘ bezpeΦnostnφ obßlky (wrappers) a podobnß opat°enφ jsou pouze nßpravou nßsledk∙, nikoli p°φΦin, kterΘ spoΦφvajφ v ╣patnΘ konstrukci samotn²ch program∙, i kdy╛ za urΦit²ch okolnostφ mohou mφt svΘ v²hody. Nßvod ke sprßvnΘ konstrukci bezpeΦn²ch program∙ lze hledat ve dvou "zßkladnφch bezpeΦnostnφch pravidlech", kterß znφ:

  • Nikdy nikomu nev∞°.
  • Co nenφ dovoleno, je zakßzßno.

Prvnφ pravidlo °φkß, ╛e v programu nesmφ b²t chyby, ale navr╛en musφ b²t s ohledem na to, ╛e tam chyby budou. To nap°φklad znamenß, ╛e ty Φßsti program∙, kterΘ zvlß╣tnφ privilegia vy╛adujφ, je vhodnΘ separovat do mal²ch samostatn²ch program∙ s p°esn∞ definovan²m rozhranφm, jejich╛ sprßvnou funkci bude mo╛no ov∞°it - ideßln∞ formßlnφm d∙kazem.

DruhΘ pravidlo pak doporuΦuje, aby ka╛d² program m∞l p°id∞lena pouze ta privilegia, kterß ke svΘ prßci pot°ebuje a pokud mo╛no ╛ßdnß jinß. To bohu╛el Φasto narß╛φ na omezenφ operaΦnφho systΘmu - zvlß╣t∞ v UNIXovΘm sv∞t∞ (Linux op∞t nevyjφmaje), kde vlßdne silnß dichotomie: v╣e (superu╛ivatel) nebo nic (ostatnφ u╛ivatelΘ). Nenφ-li mo╛no dostateΦn∞ jemn∞ rozli╣ovat privilegia, dochßzφ k tomu, ╛e jsou p°id∞lovßna ╣ir╣φ oprßvn∞nφ, ne╛ je zapot°ebφ, a otevφrß se prostor pro jejich zneu╛itφ. Jedin²m skuteΦn²m °e╣enφm tohoto problΘmu je upravit operaΦnφ systΘm tak, aby programy nemusely mφt v∞t╣φ oprßvn∞nφ ne╛ je nutno. Komplexn∞j╣φ projekty jako LinuxPrivs http://www.kernel.org/pub/linux/libs/security/linux-privs/ (implementace privilegiφ podle POSIX.1e) jsou vykroΦenφ sprßvn²m sm∞rem, ale existujφ i ΦßsteΦnß °e╣enφ, jako nap°φklad patch http://www.phrack.com/52/P52-06, kter² mj. eliminuje dosti nesmyslnou (v dne╣nφ dob∞) pot°ebu superu╛ivatelsk²ch prßv pro n∞kterΘ sφ╗ovΘ slu╛by.

Pon∞kud paradoxnφ je, ╛e popisovanß opat°enφ (pomineme-li obecnΘ doporuΦenφ, ╛e v programech nemajφ b²t chyby) nejsou p°φli╣ vhodnß pro nß╣ Xserver. Ten toti╛ ve skuteΦnosti ╛ßdnß specißlnφ privilegia nepot°ebuje, pouze musφ b²t schopen ovlßdat grafick² hardware. StaΦφ, aby pro to byla v jßd°e dostateΦnß podpora - jako jφ poskytuje nap°φklad GGI http://www.ggi-project.org/.

Zßv∞r

Tento Φlßnek popisuje pouze malou Φßst z rozsßhlΘho repertoßru mo╛n²ch rizik: zmi≥ovanΘ problΘmy (nebo problΘmy jim podobnΘ) mohou vznikat (a bohu╛el takΘ vznikajφ) v╣ude, kde dochßzφ k interakci mezi procesy pracujφcφmi s r∙zn²mi oprßvn∞nφmi, a╗ u╛ jsou to diskutovanΘ programy vyu╛φvajφcφ mechanismus prop∙jΦenφ identifikace, programy komunikujφcφ po sφti (na serverovΘ i na klientskΘ stran∞), nebo dokonce u╛ivatelskΘ aplikace, jsou-li jim p°edlo╛eny vstupy pochßzejφcφ z potencißln∞ ned∙v∞ryhodnΘho zdroje. Proto nelze ne╛ doporuΦit, aby tv∙rce libovolnΘho programu zvß╛il p°i jeho nßvrhu a implementaci mo╛nß bezpeΦnostnφ rizika a sna╛il se je ·pln∞ eliminovat, nebo alespo≥ maximßln∞ omezit. *


- p°edchozφ Φlßnek - nßsledujφcφ Φlßnek - obsah -