/ Proc / dosyasını ayrıştırmak güvenli midir?


152

Ayrıştırmak istiyorum /proc/net/tcp/, ama güvenli mi?

/proc/Başka bir işlemin (veya işletim sisteminin kendisinin) aynı anda değişeceğinden korkmamalı ve korkmamalı dosyaları nasıl açmalı ve okumalıyım ?


29
+1. Bu çok iyi bir soru. Keşke sadece cevabım olsaydı, ama daha önce biraz bu tür bir şey yaptığım için bulmayı dört gözle bekliyorum.
paxdiablo

1
Ben çok emin sadece ediyorum okurken ne zaman oldukları gibi o, size bağlantıların bir listesini, ayrıca her birine sahiptir UID verecektir açıldı onu. Ancak, bu belgelenmiş bulamıyorum, bu yüzden bu şimdilik bir yorum yapmak.
Tim Post

3
Basit bir cevap açıkçası evet, çünkü bir dosya değil - okumak her zaman güvenli olmalıdır. Yanıtlar daha sonra okuduğunuzda tutarlı olmayabilir, ancak güvenli olacaktır.
Rory Alsop

Onun yerine sysctl kullanmalısınız. (ayrıca daha az syscalls)
Good Person

@GoodPerson - bu örneğin sysctlbir /proc/net/tcp/dosyayı ayrıştırmama nasıl yardımcı olabilir ?
Kiril Kirov

Yanıtlar:


111

Genel olarak, hayır. (Yani buradaki cevapların çoğu yanlıştır.) İstediğiniz mülke bağlı olarak güvenli olabilir . Ancak, bir dosyanın tutarlılığı hakkında çok fazla şey varsayarsanız, kodunuzdaki hatalarla sonuçlanmak kolaydır /proc. Örneğin, tutarlı bir anlık görüntü olduğunu varsayarak ortaya çıkan bu hataya/proc/mounts bakın .

Örneğin:

  • /proc/uptimeolduğu tamamen atomik birisi başka cevapta belirtildiği gibi - ama sadece Linux 2.6.30 beri az iki yaşında. Bu nedenle, bu küçük, önemsiz dosya bile o zamana kadar bir yarış koşuluna maruz kaldı ve hala çoğu işletme çekirdeğinde. Bkz fs/proc/uptime.cakım kaynağı için ya o atom yapılan işlemek . 2.6.30 öncesi bir çekirdekte, opendosyayı, birazını read, daha sonra readtekrar tekrar gelirseniz , aldığınız parça ilk parça ile tutarsız olacaktır. (Bunu yeni gösterdim - eğlenmek için kendiniz deneyin.)

  • /proc/mountsolan tek dahilinde atomik readsistem çağrısı. Yani readtüm dosyayı bir kerede yaparsanız, sistemdeki bağlama noktalarının tek bir tutarlı anlık görüntüsünü alırsınız. Ancak, birkaç readsistem çağrısı kullanırsanız - ve dosya büyükse, normal G / Ç kütüphanelerini kullanırsanız ve bu konuya özellikle dikkat etmezseniz tam olarak ne olur - bir yarışa tabi olacaksınız durum. Sadece tutarlı bir enstantane elde etmekle kalmayacak, aynı zamanda başlamadan önce mevcut olan ve mevcut olmayı asla bırakmayan bağlama noktaları gördüğünüz şeyde kaybolabilir. O biri için atomik olduğunu görmek için read()bakmak de m_start()içindefs/namespace.c ve bir semafor kapmak görmek gardiyanlar onu kadar tutar mountpoints listesi, m_stop()denir, ne zamanread()yapıldı. Neyin yanlış gidebileceğini görmek için , aksi halde okuyan yüksek kaliteli yazılımlarda geçen yıldan (yukarıda bağlandığım hata) bu hataya bakın /proc/mounts.

  • /proc/net/tcpaslında sorduğunuz şey bundan daha az tutarlıdır. Bu var sadece tablonun her satır içinde atomik . Bunu görmek için , aynı dosya listening_get_next()içindenet/ipv4/tcp_ipv4.c ve established_get_next()hemen aşağısına bakın ve sırayla her girişte çıkardıkları kilitleri görün. Ben satır satırdan tutarlılık eksikliğini göstermek için kullanışlı repro kodu yok, ama orada tutarlı kilitler var (ya da başka bir şey). Bunu düşünürseniz mantıklıdır - ağ oluşturma genellikle sistemin çok yoğun bir parçasıdır, bu nedenle bu teşhis aracında tutarlı bir görünüm sunmak için ek yüke değmez.

Tutar diğer parça /proc/net/tcpher satır içindeki atom içinde tamponlamadır seq_read()okuyabilir, içindefs/seq_file.c . Bu read(), bir satırın parçası olduğunuzda , tüm satırın metninin bir arabellekte tutulmasını sağlar, böylece bir sonraki read()satır yeni bir satır başlamadan önce o satırın geri kalanını alır. Aynı mekanizma, /proc/mountsbirden fazla read()çağrı yapsanız bile her satırı atomik tutmak için kullanılır ve aynı zamanda /proc/uptimeyeni çekirdeklerde atomik kalmak için kullanılan mekanizmadır . Bu mekanizma yok değil çekirdek bellek kullanımı konusunda ihtiyatlı olması nedeniyle, tüm dosyayı tampon.

İçindeki çoğu dosya /procen az aynı tutarlı olacaktır /proc/net/tcp, her satırda sağladıkları bilgilerde bir girdinin tutarlı bir resmi vardır, çünkü çoğu aynı seq_filesoyutlamayı kullanır. /proc/uptimeÖrnekte de görüldüğü gibi , bazı dosyalar seq_file2009'a kadar kullanılmaya devam ediyordu ; Eminim hala eski mekanizmaları kullanan ve hatta bu seviyede bir atomisiteye sahip olmayanlar vardır. Bu uyarılar nadiren belgelenir. Belirli bir dosya için tek garantiniz kaynağı okumaktır.

Durumunda, /proc/net/tcpokuyabilir ve her satırı korkmadan ayrıştırabilirsiniz. Tek seferde birden fazla hatlarından bir sonuca varmak için deneyin eğer - sakının, diğer süreçler ve çekirdek vardır bunu okurken değiştirmeyi ve muhtemelen bir hata yaratıyor.


1
readdir atomisitesi ne olacak? / proc / self / fd okumak gibi mi? güvenli mi?
16:14

Değil o soruya cevap verir fakat kullanabilirsiniz çalışma süresini kontrol etme hakkında eklemek için bu clock_gettime(2)ile CLOCK_MONOTONIC(gerçi belki de burada habersiz değilim ama ben şahsen sadece boot beri zamanla gördük teknik bir yoktur). Linux için de seçeneğiniz vardır sysinfo(2).
Pryftan

44

Dosyalar rağmen /procuserspace düzenli dosyalar olarak görünür, onlar gerçekten userspace gelen standart dosya işlemlerini destekleyen dosyalar ziyade varlıklar değildir ( open, read, close). Bunun, çekirdek tarafından değiştirilen diskte sıradan bir dosyaya sahip olmaktan oldukça farklı olduğunu unutmayın.

Çekirdek, tek sprintfişlevini kullanarak dahili durumunu kendi belleğine yazdırmaktır ve read(2)sistem çağrısı yaptığınızda bu bellek kullanıcı alanına kopyalanır .

Çekirdek, bu çağrıları normal dosyalardan tamamen farklı bir şekilde ele alır, bu da okuyacağınız verilerin tüm anlık görüntüsünün siz hazır olduğunuzda hazır olabileceği anlamına open(2)gelirken, çekirdek eşzamanlı çağrıların tutarlı ve atomik olmasını sağlar. Bunu hiçbir yerde okumadım, ama başka türlü olmak gerçekten mantıklı değil.

Benim tavsiyem, kendi Unix lezzetinizde bir proc dosyasının uygulanmasına bir göz atmaktır. Bu gerçekten bir standart tarafından yönetilmeyen bir uygulama sorunudur (çıktının biçimi ve içeriği gibi).

Bunun en basit örneği uptimeproc dosyasının Linux'ta uygulanması olabilir. Sağlanan geri arama işlevinde arabelleğin nasıl üretildiğine dikkat edin single_open.


3
@Ignacio: Ben sadece OP bu yönde işaret çünkü ben procçekirdek tarafından yazmak için açılan sıradan dosyalar olduğunu düşündüğü izlenimi bıraktı .
Blagovest Buyukliev

4
Belirli bir dosyanın uygulanmasına bakma tavsiyeniz iyidir. Ne yazık ki, her şeyin anlık görüntüsü olduğu tahmin, open()birçok dosya için ve özellikle /proc/net/tcpOP'nin ilgilendiği için yanlıştır . Bu anlambilim sağlamanın maliyetini düşünürseniz bu mantıklıdır - yoğun bir sistemde sadece uzun süre tutsanız bile bir felaket olan tüm bu TCP bağlantılarını kaydeden dahili veri yapılarını kilitlemek gibi bir şey yapmanız gerekir. verileri taramak ve bir arabelleğe biçimlendirmek için yeterli. Gerçekte ne olduğuna dair ayrıntılar için cevabıma bakın.
Greg Price

16

/ proc sanal bir dosya sistemidir: aslında, sadece çekirdek içlerini rahatça görebilmenizi sağlar. Okumak kesinlikle güvenlidir (bu yüzden buradadır), ancak bu sanal dosyaların iç kısmı daha yeni çekirdek sürümüyle gelişebileceğinden uzun vadede risklidir.

DÜZENLE

Linux çekirdek belgesindeki proc belgelerinde daha fazla bilgi mevcuttur , bölüm 1.4 Ağ iletişimi Bilgilerin zaman içinde nasıl geliştiğini bulamıyorum. Ben açık dondurulmuş olduğunu düşündüm, ama kesin bir cevap olamaz.

EDIT2

Sco doc'a göre (linux değil, ama * nix'in tüm tatlarının böyle davrandığından eminim)

İşlem durumu ve sonuç olarak / proc dosyalarının içeriği anlık olarak değişebilse de, / proc dosyasının tek bir okumasının (2) durumun `` aklı '' bir temsilini döndürmesi garanti edilir, yani okuma sürecin durumunun atomik bir anlık görüntüsü. Çalışan bir işlem için / proc dosyasına uygulanan ardışık okumalar için böyle bir garanti uygulanmaz. Ek olarak, as (adres alanı) dosyasına uygulanan herhangi bir I / O için atomisite özellikle garanti edilmez; herhangi bir işlemin adres alanının içeriği, eş zamanlı olarak söz konusu işlemin LWP'si veya sistemdeki başka bir işlem tarafından değiştirilebilir.


3
"Bence" ? Kesin bir cevap vermek güzel olurdu :)
static_rtti

Çekirdeğe / proc uygulaması göz önüne alındığında, bu linux için de geçerlidir. Bir procfs dosyasını tek bir okuma çağrısında okursanız, tutarlıdır - tabii ki okuduğunuz proc dosyasının çekirdek tarafında doğru bir şekilde uygulandığı varsayılır.
Erik

8
SCO'dan daha kötü bir bilgi kaynağı bulabileceğinizi düşünmüyorum ve procfarklı çekirdekler arasında benzer bir davranışa sahipmiş gibi davranmaya çalışıyorum (hatta var olduğunu varsayarak - bir Unix sisteminde olması gerekmiyor) size acı veren bir dünya verecek.
Nicholas Knight

1
@Nicholas: Eh, çekirdek doktorda kesin bir cevap bulamadım, eğer biliyorsan onu işaret etmekten çekinmeyin.
Bruce

2
İlginçtir ki SCO belgeleri bunu söylüyor. Ne yazık ki Linux'ta her zaman doğru değildir ve özellikle /proc/net/tcpOP'nin ana kaygısı olan için doğru değildir . Aksine, çıktıdaki sadece her bir sıra atomiktir. Ayrıntılar için cevabıma bakın.
Greg Price

14

Linux çekirdeğindeki procfs API'si, okumaların tutarlı veriler döndürmesini sağlamak için bir arabirim sağlar. İçindeki yorumları okuyun __proc_file_read. Madde 1) büyük yorum bloğundaki bu arayüzü açıklar.

Bununla birlikte, geri döndürülen verilerin tutarlı olduğundan emin olmak için bu arayüzü doğru bir şekilde kullanmak elbette belirli bir proc dosyasının uygulanmasına bağlıdır. Yani, sorunuzu cevaplamak için: hayır, çekirdek bir okuma sırasında proc dosyalarının tutarlılığını garanti etmez, ancak bu dosyaların uygulamalarının tutarlılık sağlaması için araçlar sağlar.


4
Ne yazık ki, birçok dosya /procaslında tutarlılık sağlamaz. Ayrıntılar için cevabıma bakın.
Greg Price

3
Ayrıca __proc_file_read()lehine itiraz ediliyor seq_file. Uzun blok açıklamasının hemen üstünde, oldukça çileden çıkmış sondaj yorumuna bakın (Linus tarafından).
Greg Price

6

Şu anda gömülü bir ARM hedefinde sürücü geliştirme yaptığım için Linux 2.6.27.8 için kullanışlı bir kaynağım var.

linux-2.6.27.8-lpc32xx/net/ipv4/raw.c934 satırındaki ... dosya

    seq_printf(seq, "%4d: %08X:%04X %08X:%04X"
            " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d\n",
            i, src, srcp, dest, destp, sp->sk_state,
            atomic_read(&sp->sk_wmem_alloc),
            atomic_read(&sp->sk_rmem_alloc),
            0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp),
            atomic_read(&sp->sk_refcnt), sp, atomic_read(&sp->sk_drops));

hangi çıktılar

[wally@zenetfedora ~]$ cat /proc/net/tcp
  sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout inode                                                     
   0: 017AA8C0:0035 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 15160 1 f552de00 299
   1: 00000000:C775 00000000:0000 0A 00000000:00000000 00:00000000 00000000     0        0 13237 1 f552ca00 299
...

işlevinde raw_sock_seq_show()bir hiyerarşinin parçası olan procfs fonksiyonlarını ele. Procfs okumaları bilgileri güncellemekten çok daha az yaygın olduğundan read(), /proc/net/tcpdosya bir istek yapılana kadar metin üretilmez .

Bazı sürücüler (benimki gibi) proc_read işlevini tek bir sürücü ile uygular sprintf(). Çekirdek sürücüler uygulamasındaki ekstra komplikasyon, tek bir okuma sırasında ara, çekirdek-boşluk tamponuna sığmayabilecek potansiyel olarak çok uzun çıktıları ele almaktır.

Ben bir 64K okuma tamponu kullanarak bir program ile test ama proc_read veri döndürmek için benim sistemde 3072 bayt bir çekirdek alanı tampon sonuçlanır. İade edilen bu metinden daha fazlasını elde etmek için ilerleyen işaretçilerle birden fazla çağrı yapılması gerekir. Birden fazla g / Ç gerektiğinde döndürülen verileri tutarlı hale getirmenin doğru yolunun ne olduğunu bilmiyorum. Şüphesiz ki, her giriş /proc/net/tcpkendiliğinden tutarlıdır. Yan yana satırların farklı zamanlarda anlık görüntü olma olasılığı vardır.


Gerçekten üzgünüm, fazla anlamadım. Yani, eğer kullanırsam ifstream, güvensiz olacak, ama kullanırsam güvenli olacak mı demek istiyorsun read? Veya ifstreamdahili olarak readmı kullanır ? Peki ne öneriyorsun?
Kiril Kirov

@Kiril: Karışıklık için özür dilerim. Bu, verilerin nasıl /proc/net/tcpbiçimlendirildiğinin bir açıklamasıdır ve herkesin onu nasıl okuduğundan tamamen bağımsızdır.
wallyk

1
Evet! Ve tahmininiz, /proc/net/tcpaynı anlık görüntüden farklı satırların (in ) gelmediği doğrudur . Bazı açıklamalar için cevabımı görün.
Greg Price

3

Bilinmeyen hatalardan yoksun, /procbozuk verilerin okunmasına veya eski ve yeni verilerin bir karışımına yol açacak hiçbir yarış koşulu yoktur . Bu anlamda güvenlidir. Bununla birlikte, okuduğunuz verilerin çoğunun oluşturulduğu /procanda potansiyel olarak güncel olmadığı ve hatta okumaya / işlemeye başladığınız zaman bile moreso olduğu yarış durumu hala var . Örneğin, işlemler herhangi bir zamanda ölebilir ve yeni bir işleme aynı pid atanabilir; yarış koşulları olmadan kullanabileceğiniz tek işlem kimlikleri kendi alt süreçlerinizdir. Ağ bilgileri (açık bağlantı noktaları, vb.) Ve içindeki bilgilerin çoğu için de aynı şey geçerlidir /proc. Herhangi bir veriye güvenmenin kötü ve tehlikeli bir uygulama olduğunu düşünürüm/prockendi süreciniz ve potansiyel olarak alt süreçleri hakkındaki veriler dışında doğru olmak. Tabii ki /procbilgilendirici / loglama vb. İçin kullanıcıya / yöneticiye başka bilgiler sunmak da faydalı olabilir . amaçlar.


Bunu kendi işlemim için bazı bilgileri almak ve kullanmak için yapıyorum (PID'im için getpid()). Yani, güvenli olmalı.
Kiril Kirov

1
Evet, tamamen güvenli olduğunu düşünüyorum.
R .. GitHub BUZA YARDIMCI DURDUR

Çocuk süreçlerinin diğer süreçlerden daha iyi davranacağına katılmıyorum. Bildiğim kadarıyla /procarayüzü düşünüldüğünde, hepsi aynı zayıflıkları ve güçleri vardır. Her neyse, OP süreçlerle değil aygıt sürücüsü ile ilgili bilgileri soruyor.
wallyk

1
Pid Nalt işleminizse, siz Nbir wait-family işlevi çağrılıncaya kadar pid'in aynı (muhtemelen sonlandırılmış) işleme başvurduğundan emin olabilirsiniz. Bu, yarış olmamasını sağlar.
R .. GitHub BUZA YARDIMCI DURDUR

-1'in taşkınında ne var ve açıklama yok mu?
R .. GitHub

2

Bir / proc dosyasından okuduğunuzda, çekirdek önceden kaydedilmiş bir işlevi o proc dosyası için "okuma" işlevi olarak çağırıyor. __proc_file_readFs / proc / generic.c içindeki işleve bakın .

Bu nedenle, proc okumanın güvenliği sadece çekirdeğin okuma talebini karşılamak için çağırdığı işlev kadar güvenlidir. Bu işlev, dokunduğu tüm verileri düzgün bir şekilde kilitlerse ve bir arabellekte size geri dönerse, bu işlevi kullanarak okumak tamamen güvenlidir. / Proc / net / tcp'ye yapılan okuma isteklerini karşılamak için kullanılan dosya gibi proc dosyaları bir süredir etrafta bulunduğundan ve titizlikle incelendiğinden, isteyebileceğiniz kadar güvenlidir. Aslında, birçok yaygın Linux yardımcı programı proc dosya sisteminden okumaya ve çıktıyı farklı bir şekilde biçimlendirmeye güvenir. (Başımın üstünden bence 'ps' ve 'netstat' bunu yapıyor).

Her zaman olduğu gibi, benim sözümü almak zorunda değilsiniz; korkularınızı yatıştırmak için kaynağa bakabilirsiniz. Proc_net_tcp.txt dosyasındaki aşağıdaki belgeler size / proc / net / tcp için "read" işlevlerinin nerede bulunduğunu söyler, böylece o proc dosyasından okuduğunuzda çalıştırılan gerçek koda bakabilir ve kendinizin yok olduğunu doğrulayabilirsiniz. kilitleme tehlikeleri.

Bu belgede / proc / net / tcp ve / proc / net / tcp6 arabirimleri açıklanmaktadır.
Bu arabirimlerin tcp_diag lehine kullanımdan kaldırıldığını unutmayın. Bu / proc arabirimleri şu anda etkin olan TCP bağlantıları hakkında bilgi sağlar ve net / ipv4 / tcp_ipv4.c dosyasında sırasıyla tcp4_seq_show () ve net / ipv6 / tcp_ipv6.c dosyalarında sırasıyla tcp6_seq_show () tarafından uygulanır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.