Capabilities API
Unix tabanlı sistemlerde yetki kontrolü temel olarak iki adımdan oluşur:
Çalışan uygulamanın o anki etkin sahibi (effective user id, EUID) 0 ise yetki kontrolü yapılmaz
EUID değeri sıfırdan farklı ise, ilgili uygulamanın efektif kullanıcı ve grubunun yetkileri doğrultusunda kontrol işlemi gerçekleştirilir
Bazı uygulamaların çalıştığı süre boyunca daha geniş yetkilerle donatılması ihtiyacına (SUID, SGIT bitleri) önceki konularda değinmiştik. En tipik örnek olarak passwd uygulamasını gösterebiliriz. Bu uygulama ile sistemdeki kullanıcılar kendi parolalarını değiştirebilmektedirler. Ancak parolaların şifrelenmiş hallerinin tutulduğu /etc/shadow
dosyasına yazabilmek için root kullanıcı haklarıyla (yani user id = 0 olarak) çalışmak gereklidir.
Problemin çözümü için passwd uygulamasına SUID biti verilmiş ve bu uygulamayı hangi kullanıcı çalıştırırsa çalıştırsın, etkin sahibinin (EUID) root olması sağlanmıştır:
$ ls -l /usr/bin/passwd -rwsr-xr-x 1 root root 54192 Nov 21 00:03 /usr/bin/passwd
Geleneksel Unix yetki kontrolü modelindeki SUID uygulama çalıştırma imkanı problemi çözmüş görünmektedir. Ancak SUID biti verilmiş uygulamalardaki kritik hatalar, sistemde tam yetkiye sahip bir kullanıcı olarak istenmeyen kodların çalıştırılabilmesine kapı açmaktadır. İdeal bir uygulama, mümkünse root kullanıcısının haklarına ihtiyaç duymadan çalışabilmelidir. Böylelikle yıkıcı eylemlerin işletim sistemi çekirdeği tarafından engellenmesi mümkün olabilir.
Problem sadece SUID biti ile de bitmemektedir. Unix tabanlı sistemlerde 1024'den küçük olan ayrıcalıklı bir TCP veya UDP portunu dinlemek istediğinizde de root kullanıcı haklarına sahip olmanız gerekir. Örneğin bir e-posta sunucu servisi ya da web sunucusu çalıştırmak istiyorsanız, sırasıyla TCP port 25 ve TCP port 80'i dinleyebiliyor olmanız gerekir. Bu da ancak ilgili uygulamaların root kullanıcısı ile çalıştırılması ile mümkün olabilir. Yıllar içerisinde bu şekilde özellikle ağ ortamına servis sunan yazılımların tam yetkili kullanıcı hesabıyla çalıştırılmalarının ne kadar yıkıcı etkileri olduğu tecrübe edilince, bir ara çözüm olarak programın sadece belirli ve daha küçük bir kısmının ayrıcalıklı portu root olarak dinlemesi, sonrasındaki işlemler içinse etkin kullanıcı kimliğini bir başka kullanıcıya değiştirmesi yöntemi (örneğin kısıtlı haklara sahip nobody kullanıcısı gibi) benimsendi.
Yıllardır kullanılan bu sistem basitliğiyle iyi iş gördü ve halen verimli olarak kullanılmaktadır. Ancak günümüzde yukarıda anlatılan sistematiğin dışında root haklarına ihtiyaç duymaksızın, uygulama spesifik olarak bazı ek yeteneklere, Linux Capabilities API üzerinden kavuşmak mümkündür.
Standartlar
Capabilities API, ihtiyaçlardan doğan bir çözüm yöntemidir. POSIX.1e versiyon 17 taslak dokümanında 25. bölüm bu konuya ayrılmıştır.
Belgeyi http://wt.tuxomania.net/publications/posix.1e/download.html adresinden indirebilirsiniz.
Capabilities API, bazı önemli yetkilerin ayrı bir başlıkta değerlendirilmesine ve bu şekilde root olarak çalışma ihtiyacı olmaksızın ilgili işlemlere izin verilmesine olanak sağlamaktadır.
POSIX.1e'de tanımlanan yetkiler ve daha fazlasının geliştirimi Linux çekirdeği versiyon 2.6.26 ile tamamlanmıştır.
Linux Capability Modeli
Capabilities API'nin en kapsamlı gerçekleştirimi Linux altında olmuştur. Modern Linux dağıtımları da bu yeni modeli sistem genelinde olabildiğince kullanmaya çalışmaktadır.
Örnek verecek olursak, eğer eski tarihli bir Linux dağıtımı kullanıyorsanız (örnek olarak 2007 çıkışlı Debian 4.0) şaşırtıcı biçimde ping uygulamasının SUID yetkileriyle donatılmış olduğunu görebilirsiniz:
$ ls -l /bin/ping -rwsr-xr-x 1 root root 33064 2007-01-31 01:22 /bin/ping
Bunun sebebi, ping
uygulamasının çalışabilmesi için normalde sadece root kullanıcısına has olan RAW soket açabilmesinin gerekliliğidir. Eski Linux dağıtımlarında sorun uygulamaya SUID biti verilerek, normal kullanıcılar tarafından da kullanılabilmesi sağlanmıştır. Bu versiyonlarda SUID bitini uygulamadan kaldırıp normal bir kullanıcı olarak uygulamayı çalıştırmayı denediğimizde aşağıdaki gibi bir hata alırız:
$ ping 8.8.8.8
ping: icmp open socket: Operation not permitted
Oysa şu an kullandığınız Linux dağıtımında ping
uygulaması muhtemelen SUID bitine sahip değildir:
$ ls -l /bin/ping
-rwxr-xr-x 1 root root 44104 Nov 8 19:04 /bin/ping
Buna rağmen normal kullanıcı olarak başarılı biçimde uygulamayı çalıştırabilmektesiniz. İşte bunu mümkün kılan mekanizma, ping uygulamasının CAP_NET_RAW özel yeteneğine sahip olmasıdır.
Uygulamanın sahip olduğu ek yetenekleri getcap komutu ile aşağıdaki gibi öğrenebiliriz:
$ sudo getcap /bin/ping
/bin/ping = cap_net_raw+ep
Process Capability Modeli
Linux gerçekleştiriminde her bir process'in 3 başlık altında capability yetenekleri gruplanır:
Capability | Açıklama |
---|---|
permitted | Bu kümede ilgili process'in izin verilen ek capability listesi bulunur. İzin verilmesi o an aktif olarak kullanılabileceği anlamına gelmeyebilir, ek bir işlemle buradaki yetkilerin etkin (effective) capability kümesine dahil edilmesi mümkündür. |
effective | İlgili process'in o anki etkin capability listesini gösterir. Capability sistemini düzenleyen yardımcı fonksiyonlarla bir capability'den vazgeçilebileceği gibi tekrar geri de alınabilir. Ancak her durumda bu işlem sadece permitted grubunda zaten izin verilmiş olanlar arasından yapılabilir. |
inheritable | Process tarafından yeni bir process çalıştırıldığında, yeni çalıştırılan process'in permitted listesine miras yoluyla aktarılacak capability listesini gösterir. |
Çalışan process'ler için herhangi bir andaki permitted, effective ve inheritable capability listesi, /proc/<PID>/status
dosyasında CapPrm, CapEff ve CapInh satırlarında bitmask olarak gösterilir. Ayrıca CapBnd satırıyla da capability sınır kontrolü (boundary) işleminde kullanılan bitmask yer alır. Örnek olarak çalışan kabuk uygulamamıza ait değerleri /proc/self/status
dosyasından okuyalım:
$ cat /proc/self/status | grep Cap
CapInh: 0000000000000000
CapPrm: 0000000000000000
CapEff: 0000000000000000
CapBnd: 0000003fffffffff
Dosya Capability Modeli
Dosyalar için capability sisteminin çalışması, Virtual File System katmanında bu özelliklerin saklanabilmesi önşartına bağlıdır. Process modeline benzer şekilde 3 başlık altında dosyalar için capability yetenekleri gruplanır:
Capability | Açıklama |
---|---|
permitted | Bu kümede ilgili executable dosya çalıştırıldığında, process'in izin verilen (permitted) capability kümesine dahil edilecek yetenekler belirtilir. |
effective | Bu başlık Process Capability modelinden farklı olarak dosyalar için 1 bitlik sadece aktif ya da değil bilgisini saklamaktadır. Eğer bit aktif ise, dosyanın permitted listesindeki tanımlı capability'ler, bu dosya çalıştırılıp bir process oluşturulduğunda ilgili process'in effective capability listesine otomatik olarak aktarılır. Bit aktif değilse dosya üzerindeki permitted capability'lerin çalışan process'e otomatik aktarımı gerçekleştirilmez. Bununla birlikte ilgili uygulamanın kodu Capability sistemiyle entegre çalışıyorsa, dosyanın permitted kümesindeki izinleri sistem çağrıları ile etkin hale getirebilir. Bu davranış şeklinin temel amacı, yazılım kodu seviyesinde capability sistemine özgü kod geliştirmesi içermeyen eski uygulamaların herhangi bir kaynak kod değişikliğine ihtiyaç kalmaksızın, capability sistemiyle çalışabilmesini sağlamaktır. Daha iyi yazılmış uygulamaların capability'leri sadece gerektiğinde kullanması beklenir. Bit aktif ise, permitted listesindeki tüm capability'ler uygulama çalışmaya başladığında aktifleştirilmektedir. |
inheritable | Process modeline benzer şekilde ilgili dosya çalıştırılıp bir process üretildikten sonra eğer process içerisinden bir başka uygulama daha çalıştırılacak olursa, yeni çalışacak olan process'in permitted listesine miras yoluyla aktarılacak capability listesini gösterir. |