ฉันต้องการแยกวิเคราะห์/proc/net/tcp/แต่ปลอดภัยหรือไม่
ฉันจะเปิดและอ่านไฟล์จาก/proc/และไม่ต้องกลัวว่ากระบวนการอื่น ๆ (หรือระบบปฏิบัติการของตัวเอง) จะเปลี่ยนแปลงในเวลาเดียวกันได้อย่างไร
sysctlช่วยฉันแยกวิเคราะห์/proc/net/tcp/ไฟล์ได้อย่างไร?
ฉันต้องการแยกวิเคราะห์/proc/net/tcp/แต่ปลอดภัยหรือไม่
ฉันจะเปิดและอ่านไฟล์จาก/proc/และไม่ต้องกลัวว่ากระบวนการอื่น ๆ (หรือระบบปฏิบัติการของตัวเอง) จะเปลี่ยนแปลงในเวลาเดียวกันได้อย่างไร
sysctlช่วยฉันแยกวิเคราะห์/proc/net/tcp/ไฟล์ได้อย่างไร?
คำตอบ:
โดยทั่วไปไม่มี (ดังนั้นคำตอบส่วนใหญ่ที่นี่ผิด) มันอาจปลอดภัยขึ้นอยู่กับว่าคุณต้องการบ้านแบบใด แต่มันง่ายที่จะจบลงด้วยข้อบกพร่องในรหัสของคุณถ้าคุณถือว่ามากเกินไปเกี่ยวกับความสอดคล้องของไฟล์/procมา ตัวอย่างเช่นดูข้อผิดพลาดนี้ซึ่งมาจากสมมติว่า/proc/mountsเป็นภาพที่สอดคล้องกัน
ตัวอย่างเช่น:
/proc/uptimeเป็นอะตอมโดยสิ้นเชิงอย่างที่ใครบางคนพูดถึงคำตอบอื่น - แต่เฉพาะตั้งแต่ Linux 2.6.30ซึ่งมีอายุน้อยกว่าสองปี ดังนั้นแม้แต่ไฟล์เล็ก ๆ น้อย ๆ นี้ก็ยังขึ้นอยู่กับสภาพการแข่งขันจนกระทั่งถึงตอนนั้นและยังคงอยู่ในเมล็ดส่วนใหญ่ขององค์กร ดูfs/proc/uptime.cสำหรับแหล่งปัจจุบันหรือกระทำที่ทำให้มันอะตอม บนเคอร์เนลก่อน 2.6.30 คุณสามารถopenไฟล์readบิตของมันแล้วถ้าคุณกลับมาในภายหลังและreadอีกครั้งชิ้นที่คุณได้รับจะไม่สอดคล้องกับชิ้นแรก (ฉันเพิ่งสาธิตเรื่องนี้ - ลองด้วยตัวเองเพื่อความสนุก)
/proc/mountsเป็นatomic ภายในการreadเรียกใช้ระบบเดียว ดังนั้นหากคุณreadรวมไฟล์ทั้งหมดพร้อมกันคุณจะได้รับสแนปช็อตที่สอดคล้องกันของจุดเชื่อมต่อในระบบ อย่างไรก็ตามหากคุณใช้การreadเรียกของระบบหลายครั้ง- และถ้าไฟล์มีขนาดใหญ่สิ่งนี้จะเกิดอะไรขึ้นถ้าคุณใช้ไลบรารี I / O ปกติและไม่สนใจเรื่องนี้เป็นพิเศษ - คุณจะต้องถูกแย่งชิง เงื่อนไข. ไม่เพียง แต่คุณจะไม่ได้รับสแนปชอตที่สอดคล้องกัน แต่จุดเชื่อมต่อที่มีอยู่ก่อนที่คุณจะเริ่มต้นและไม่เคยหยุดนิ่งอยู่อาจหายไปในสิ่งที่คุณเห็น หากต้องการดูว่ามันเป็นอะตอมหนึ่งread(), ดูที่m_start()ในfs/namespace.cและเห็นมันคว้าสัญญาณที่ยามรายการ mountpoints ซึ่งจะช่วยให้จนกว่าm_stop()ซึ่งเรียกว่าเมื่อread()เสร็จแล้ว หากต้องการดูสิ่งที่ผิดพลาดโปรดดูข้อผิดพลาดนี้จากปีที่แล้ว (อันเดียวกับที่ฉันลิงค์ด้านบน) ในซอฟต์แวร์คุณภาพสูงที่อ่าน/proc/mountsได้
/proc/net/tcpซึ่งเป็นสิ่งที่คุณถามจริง ๆ ก็มีความสอดคล้องน้อยกว่านั้น มันเป็นอะตอมเฉพาะภายในแถวของตารางแต่ละ ดูนี่ดูที่listening_get_next()ในnet/ipv4/tcp_ipv4.cและestablished_get_next()ด้านล่างในไฟล์เดียวกันและดูล็อคที่พวกเขาจะออกในแต่ละรายการในทางกลับกัน ฉันไม่มีโค้ดการทำซ้ำที่สะดวกในการสาธิตการขาดความสอดคล้องจากแถวหนึ่งไปอีกแถวหนึ่ง แต่ไม่มีการล็อกที่นั่น (หรือสิ่งอื่นใด) ที่จะทำให้มันสอดคล้องกัน ซึ่งเหมาะสมถ้าคุณคิดเกี่ยวกับมัน - เครือข่ายมักเป็นส่วนที่ยุ่งสุดของระบบดังนั้นจึงไม่คุ้มค่าที่จะนำเสนอมุมมองที่สอดคล้องกันในเครื่องมือวิเคราะห์นี้
ชิ้นอื่น ๆ ที่ช่วยให้/proc/net/tcpอะตอมในแต่ละแถวเป็นบัฟเฟอร์ในseq_read()ซึ่งคุณสามารถอ่านใน fs/seq_file.cสิ่งนี้ทำให้มั่นใจได้ว่าเมื่อคุณread()เป็นส่วนหนึ่งของแถวข้อความของทั้งแถวจะถูกเก็บไว้ในบัฟเฟอร์เพื่อให้แถวถัดไปread()จะได้รับส่วนที่เหลือของแถวนั้นก่อนที่จะเริ่มแถวใหม่ มีการใช้กลไกเดียวกันนี้/proc/mountsเพื่อเก็บอะตอมมิกของแถวแต่ละแถวแม้ว่าคุณจะread()โทรหลายครั้งและก็เป็นกลไกที่/proc/uptimeในเมล็ดที่ใหม่กว่านั้นก็ยังคงใช้งานได้เหมือนเดิม กลไกนั้นไม่ได้บัฟเฟอร์ไฟล์ทั้งหมดเนื่องจากเคอร์เนลระมัดระวังเกี่ยวกับการใช้หน่วยความจำ
ไฟล์ส่วนใหญ่/procจะมีความสอดคล้องอย่างน้อย/proc/net/tcpกับแต่ละแถวจะมีรูปภาพที่สอดคล้องกันของหนึ่งรายการในข้อมูลใดก็ตามที่พวกเขากำลังให้เพราะส่วนใหญ่จะใช้seq_fileสิ่งที่เป็นนามธรรมเดียวกัน ตาม/proc/uptimeตัวอย่างแสดงให้เห็นว่าบางไฟล์ยังคงถูกย้ายไปใช้seq_fileเมื่อเร็ว ๆ นี้ในปี 2009 ฉันพนันได้ว่ายังมีบางอย่างที่ใช้กลไกที่เก่ากว่าและไม่มีแม้แต่ระดับอะตอมมิก คำเตือนเหล่านี้ไม่ค่อยมีการบันทึกไว้ สำหรับไฟล์ที่กำหนดการรับประกันเพียงอย่างเดียวของคุณคือการอ่านต้นฉบับ
ในกรณีของ/proc/net/tcpคุณสามารถอ่านและแยกแต่ละบรรทัดโดยไม่ต้องกลัว แต่ถ้าคุณพยายามที่จะดึงข้อสรุปใด ๆ จากหลายบรรทัดพร้อมกัน - ระวังกระบวนการอื่น ๆ และเคอร์เนลจะเปลี่ยนมันในขณะที่คุณอ่านมันและคุณอาจจะสร้างข้อบกพร่อง
clock_gettime(2)กับCLOCK_MONOTONIC(แม้ว่าอาจจะมีเทคนิคที่ฉันไม่รู้จักที่นี่ sysinfo(2)สำหรับลินุกซ์ที่คุณยังมีตัวเลือกของ
แม้ว่าแฟ้มใน/procปรากฏเป็นไฟล์ปกติใน userspace พวกเขาไม่ได้จริงๆไฟล์ แต่หน่วยงานที่สนับสนุนการดำเนินงานไฟล์มาตรฐานจาก userspace ( open, read, close) โปรดทราบว่านี่ค่อนข้างแตกต่างจากการมีไฟล์ธรรมดาบนดิสก์ที่เคอร์เนลเปลี่ยนไป
เคอร์เนลทั้งหมดจะพิมพ์สถานะภายในลงในหน่วยความจำของตัวเองโดยใช้sprintfฟังก์ชัน -like และหน่วยความจำนั้นจะถูกคัดลอกลงใน userspace ทุกครั้งที่คุณread(2)เรียกใช้ระบบ
เคอร์เนลจัดการกับการเรียกเหล่านี้ในวิธีที่แตกต่างอย่างสิ้นเชิงกว่าสำหรับไฟล์ปกติซึ่งอาจหมายความว่าสแน็ปช็อตทั้งหมดของข้อมูลที่คุณจะอ่านอาจจะพร้อมในเวลาที่คุณopen(2)ในขณะที่เคอร์เนลทำให้แน่ใจว่าการโทรพร้อมกันนั้น ฉันไม่ได้อ่านมันเลย แต่มันก็ไม่สมเหตุสมผลเลย
คำแนะนำของฉันคือการดูการใช้งานไฟล์ proc ใน Unix รสของคุณโดยเฉพาะ นี่เป็นปัญหาการใช้งานจริง (ตามรูปแบบและเนื้อหาของเอาต์พุต) ที่ไม่ได้ควบคุมโดยมาตรฐาน
ตัวอย่างที่ง่ายที่สุดคือการใช้งานuptimeไฟล์ proc ใน Linux สังเกตว่าการผลิตบัฟเฟอร์ทั้งหมดในฟังก์ชั่นการโทรกลับที่ให้single_openไว้
procไฟล์นั้นเป็นไฟล์ธรรมดาที่เปิดเพื่อเขียนโดยเคอร์เนล
open()ผิดสำหรับหลาย ๆ ไฟล์และโดยเฉพาะอย่างยิ่งสำหรับ/proc/net/tcpOP ที่เกี่ยวข้อง วิธีนี้เหมาะสมถ้าคุณคิดค่าใช้จ่ายในการให้ความหมายเหล่านั้น - คุณต้องทำอะไรบางอย่างเช่นล็อคโครงสร้างข้อมูลภายในที่บันทึกการเชื่อมต่อ TCP ทั้งหมดซึ่งในระบบไม่ว่างเป็นหายนะแม้ว่าคุณจะค้างไว้นาน เพียงพอที่จะสแกนและจัดรูปแบบข้อมูลไปยังบัฟเฟอร์ ดูคำตอบของฉันสำหรับรายละเอียดเกี่ยวกับสิ่งที่เกิดขึ้นจริง
/ proc เป็นระบบไฟล์เสมือนจริง ๆ แล้วมันให้มุมมองที่สะดวกของเคอร์เนลภายใน แน่นอนว่ามันปลอดภัยที่จะอ่าน (นั่นคือเหตุผลที่อยู่ที่นี่) แต่มีความเสี่ยงในระยะยาวเนื่องจากภายในของไฟล์เสมือนเหล่านี้อาจมีการพัฒนาด้วยเคอร์เนลเวอร์ชันใหม่กว่า
แก้ไข
มีข้อมูลเพิ่มเติมในเอกสารประกอบ proc ใน Linux kernel docบทที่ 1.4 ระบบเครือข่ายฉันไม่สามารถค้นหาข้อมูลที่มีการเปลี่ยนแปลงตลอดเวลา ฉันคิดว่ามันค้างเมื่อเปิด แต่ไม่สามารถมีคำตอบที่ชัดเจน
EDIT2
จากข้อมูลของSco doc (ไม่ใช่ linux แต่ฉันค่อนข้างมั่นใจว่าทุกอย่างของ * nix นั้นเป็นแบบนั้น)
แม้ว่าสถานะกระบวนการและจากนั้นเนื้อหาของไฟล์ / proc สามารถเปลี่ยนจากทันทีเป็นทันที แต่การอ่าน (2) ของไฟล์ / proc นั้นรับประกันว่าจะส่งกลับสถานะการเป็นตัวแทนของ `` สติ '' นั่นคือการอ่านจะเป็น สแน็ปช็อตอะตอมมิกของสถานะของกระบวนการ ไม่มีการรับประกันดังกล่าวกับการอ่านต่อเนื่องที่นำไปใช้กับไฟล์ / proc สำหรับกระบวนการทำงาน นอกจากนี้อะตอมมิกซิตี้ไม่ได้รับประกันเป็นพิเศษสำหรับ I / O ใด ๆ ที่นำไปใช้กับไฟล์ as (address-space) เนื้อหาของพื้นที่ที่อยู่ของกระบวนการใด ๆ อาจมีการแก้ไขพร้อมกันโดย LWP ของกระบวนการนั้นหรือกระบวนการอื่น ๆ ในระบบ
procราวกับว่ามันมีพฤติกรรมที่คล้ายกันระหว่างเมล็ดที่แตกต่างกัน ) จะพาคุณไปสู่โลกแห่งความเจ็บปวด
/proc/net/tcpซึ่งเป็นข้อกังวลหลักของ OP ค่อนข้างเฉพาะแต่ละแถวในผลลัพธ์คืออะตอม ดูคำตอบของฉันสำหรับรายละเอียด
procfs API ในเคอร์เนล Linux จัดเตรียมอินเตอร์เฟสเพื่อให้แน่ใจว่าการอ่านส่งคืนข้อมูลที่สอดคล้องกัน __proc_file_readอ่านความคิดเห็นใน รายการ 1) ในบล็อกความคิดเห็นขนาดใหญ่จะอธิบายถึงอินเทอร์เฟซนี้
ที่ถูกกล่าวว่ามันเป็นของหลักสูตรถึงการใช้งานของไฟล์ proc ที่เฉพาะเจาะจงเพื่อใช้อินเตอร์เฟซนี้อย่างถูกต้องเพื่อให้แน่ใจว่าข้อมูลที่ส่งคืนมีความสอดคล้อง ดังนั้นเพื่อตอบคำถามของคุณ: ไม่เคอร์เนลไม่รับประกันความสอดคล้องของไฟล์ proc ระหว่างการอ่าน แต่ให้วิธีการใช้งานของไฟล์เหล่านั้นเพื่อให้สอดคล้อง
/procไม่ได้มีความสอดคล้องกัน ดูคำตอบของฉันสำหรับรายละเอียด
__proc_file_read() seq_fileดูความคิดเห็นที่ค่อนข้างทำให้โกรธ (โดย Linus) เหนือความคิดเห็นบล็อกยาว
ฉันมีแหล่งที่มาสำหรับ Linux 2.6.27.8 ที่มีประโยชน์เนื่องจากฉันกำลังพัฒนาไดรเวอร์ในขณะนี้บนเป้าหมาย ARM ที่ฝังอยู่
linux-2.6.27.8-lpc32xx/net/ipv4/raw.cตัวอย่างเช่นไฟล์ ... ที่บรรทัด 934 มี
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));
ซึ่งผลลัพธ์
[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
...
in function raw_sock_seq_show()ซึ่งเป็นส่วนหนึ่งของลำดับชั้นของฟังก์ชันการจัดการprocfs ข้อความไม่ได้ถูกสร้างขึ้นจนกว่าจะมีการread()ร้องขอ/proc/net/tcpไฟล์ซึ่งเป็นกลไกที่เหมาะสมเนื่องจากการอ่านprocfsนั้นเป็นเรื่องปกติที่พบได้น้อยกว่าการอัพเดทข้อมูล
บางคนขับ (เช่นเหมือง) ใช้ฟังก์ชั่น proc_read sprintf()ที่มีเพียงหนึ่งเดียว ความซับซ้อนพิเศษในการใช้งานไดรเวอร์หลักคือการจัดการเอาต์พุตที่มีความยาวมากซึ่งอาจไม่พอดีกับบัฟเฟอร์กลางและเคอร์เนลพื้นที่ระหว่างการอ่านครั้งเดียว
ฉันทดสอบว่าด้วยโปรแกรมที่ใช้บัฟเฟอร์การอ่าน 64K แต่มันส่งผลให้บัฟเฟอร์พื้นที่เคอร์เนลของ 3072 ไบต์ในระบบของฉันสำหรับ proc_read เพื่อส่งคืนข้อมูล จำเป็นต้องโทรหลายครั้งด้วยตัวชี้ที่ก้าวหน้าเพื่อให้ได้รับมากกว่าข้อความที่ส่งคืน ฉันไม่ทราบว่าวิธีที่ถูกต้องในการทำให้ข้อมูลที่ส่งคืนสอดคล้องกันเมื่อต้องการมากกว่าหนึ่ง i / o แน่นอนว่าแต่ละรายการ/proc/net/tcpมีความสอดคล้องกันในตัวเอง มีความเป็นไปได้บางอย่างที่เส้นข้างกันเป็นภาพรวมในเวลาที่ต่างกัน
ifstreamมันจะไม่ปลอดภัย แต่ถ้าฉันใช้readมันจะปลอดภัยหรือไม่ หรือifstreamใช้ภายในread? แล้วคุณแนะนำอะไร?
/proc/net/tcpถูกจัดรูปแบบอย่างไรและไม่เกี่ยวข้องกับวิธีการอ่านข้อมูลของทุกคน
/proc/net/tcp) ไม่ได้มาจากสแนปชอตเดียวกัน ดูคำตอบของฉันสำหรับคำอธิบาย
ไม่มีข้อบกพร่องที่ไม่ทราบสาเหตุมีเงื่อนไขการแข่งขัน/procที่จะนำไปสู่การอ่านข้อมูลที่เสียหายหรือข้อมูลเก่าและใหม่ ในแง่นี้มันปลอดภัย อย่างไรก็ตามยังคงมีสภาพการแข่งขันที่ข้อมูลส่วนใหญ่ที่คุณอ่าน/procนั้นอาจล้าสมัยทันทีที่มีการสร้างและแม้กระทั่งช่วงเวลาที่คุณอ่าน / ประมวลผล สำหรับกระบวนการอินสแตนซ์สามารถตายได้ตลอดเวลาและกระบวนการใหม่สามารถกำหนด pid เดียวกัน; รหัสกระบวนการเดียวที่คุณสามารถใช้ได้โดยไม่มีเงื่อนไขการแข่งขันคือกระบวนการลูกของคุณเอง กันไปสำหรับข้อมูลเครือข่าย (เปิดพอร์ต ฯลฯ ) และส่วนใหญ่ของข้อมูล/procมา ฉันคิดว่ามันเป็นการปฏิบัติที่ไม่ดีและอันตรายที่ต้องพึ่งพาข้อมูลใด ๆ/procมีความถูกต้องยกเว้นข้อมูลเกี่ยวกับกระบวนการของคุณและกระบวนการลูก แน่นอนว่ามันอาจจะมีประโยชน์ในการนำเสนอข้อมูลอื่น ๆ จาก/procผู้ใช้ / ผู้ดูแลระบบสำหรับข้อมูล / การบันทึก / ฯลฯ วัตถุประสงค์
getpid()) ดังนั้นจะต้องปลอดภัย
/procอินเทอร์เฟซเกี่ยวข้องพวกเขาทั้งหมดมีจุดอ่อนและจุดแข็งเหมือนกัน อย่างไรก็ตาม OP จะถามเกี่ยวกับข้อมูลเกี่ยวกับไดรเวอร์อุปกรณ์ไม่ใช่กระบวนการ
Nเป็นกระบวนการลูกของคุณคุณสามารถมั่นใจได้ว่า pid Nยังคงอ้างถึงกระบวนการเดียวกัน (อาจถูกยกเลิก) จนกว่าคุณจะเรียกใช้waitฟังก์ชัน -family สิ่งนี้ทำให้มั่นใจได้ว่าจะไม่มีการแข่งขัน
เมื่อคุณอ่านจากไฟล์ / proc เคอร์เนลกำลังเรียกใช้ฟังก์ชั่นที่ได้ลงทะเบียนล่วงหน้าเพื่อให้เป็นฟังก์ชั่น "อ่าน" สำหรับไฟล์ proc นั้น ดู__proc_file_readฟังก์ชั่นใน fs / proc / generic.c
ดังนั้นความปลอดภัยของ proc read จึงปลอดภัยเท่ากับฟังก์ชันที่เคอร์เนลเรียกใช้เพื่อตอบสนองการร้องขอการอ่าน หากฟังก์ชั่นนั้นล็อคข้อมูลทั้งหมดที่ถูกสัมผัสและกลับมาหาคุณในบัฟเฟอร์อย่างปลอดภัยแสดงว่าการอ่านโดยใช้ฟังก์ชันนั้นปลอดภัยอย่างสมบูรณ์ เนื่องจากไฟล์ proc เช่นไฟล์ที่ใช้สำหรับการตอบสนองการร้องขอการอ่านไปยัง / proc / net / tcp ได้รับการรอสักครู่และได้รับการตรวจสอบอย่างละเอียดพวกเขามีความปลอดภัยมากที่สุดเท่าที่จะทำได้ ที่จริงแล้วยูทิลิตี้ลีนุกซ์ทั่วไปจำนวนมากนั้นพึ่งพาการอ่านจากระบบไฟล์ proc และการจัดรูปแบบเอาต์พุตในวิธีที่แตกต่างกัน (นอกหัวฉันคิดว่า 'ps' และ 'netstat' ทำสิ่งนี้)
เช่นเคยคุณไม่ต้องใช้คำพูดของฉันมัน คุณสามารถดูแหล่งที่มาเพื่อสงบความกลัวของคุณ เอกสารต่อไปนี้จาก proc_net_tcp.txt บอกคุณว่าฟังก์ชัน "อ่าน" สำหรับ / proc / net / tcp live ดังนั้นคุณสามารถดูรหัสจริงที่ทำงานเมื่อคุณอ่านจากไฟล์ proc นั้นและตรวจสอบด้วยตัวคุณเองว่าไม่มี อันตรายจากการล็อค
เอกสารนี้อธิบายถึงอินเตอร์เฟส / proc / net / tcp และ / proc / net / tcp6
โปรดทราบว่าอินเทอร์เฟซเหล่านี้ถูกคัดค้าน tcp_diag อินเตอร์เฟส / proc เหล่านี้จัดเตรียมข้อมูลเกี่ยวกับการเชื่อมต่อ TCP ที่แอ็คทีฟในปัจจุบันและถูกนำไปใช้โดย tcp4_seq_show () ใน net / ipv4 / tcp_ipv4.c และ tcp6_seq_show () ใน net / ipv6 / tcp_ipv6.c ตามลำดับ