เหตุใดจึงยากที่จะทำให้ C มีแนวโน้มน้อยลงในการบัฟเฟอร์ล้น?


23

ฉันกำลังทำหลักสูตรอยู่ในวิทยาลัยที่หนึ่งในห้องปฏิบัติการคือการใช้ประโยชน์จากบัฟเฟอร์โอเวอร์โฟลว์บนโค้ดที่พวกเขาให้เรา ช่วงนี้จากการหาประโยชน์ง่าย ๆ เช่นการเปลี่ยนที่อยู่ผู้ส่งคืนสำหรับฟังก์ชั่นในสแต็คเพื่อกลับไปที่ฟังก์ชั่นที่แตกต่างกันไปจนถึงรหัสที่เปลี่ยนสถานะการลงทะเบียน / หน่วยความจำของโปรแกรม ฟังก์ชั่นที่คุณเรียกว่าหลงลืมไปอย่างสิ้นเชิง

ฉันได้ทำการวิจัยเกี่ยวกับเรื่องนี้และการใช้ประโยชน์จากการใช้ประโยชน์เหล่านี้ยังมีอยู่ทุกหนทุกแห่งแม้กระทั่งตอนนี้ในสิ่งต่าง ๆ เช่นการใช้ homebrew บน Wiiและการเจลเบรคที่ไม่มีการผูกมัดสำหรับ iOS 4.3.1

คำถามของฉันคือเหตุใดปัญหานี้จึงแก้ไขได้ยาก เห็นได้ชัดว่านี่เป็นช่องโหว่ที่สำคัญที่ใช้ในการแฮ็คหลายร้อยสิ่ง แต่ดูเหมือนว่ามันจะง่ายต่อการแก้ไขโดยการตัดทอนข้อมูลใด ๆ ที่ผ่านมาตามความยาวที่อนุญาตและกำจัดข้อมูลทั้งหมดที่คุณทำ

แก้ไข: มุมมองอื่นที่ฉันต้องการคำตอบที่จะต้องพิจารณา - ทำไมผู้สร้างของ C ไม่สามารถแก้ไขปัญหาเหล่านี้ได้โดยการปรับใช้ห้องสมุดใหม่?

คำตอบ:


35

พวกเขาซ่อมห้องสมุด

ห้องสมุดมาตรฐานใด ๆ ที่ทันสมัย C มีสายพันธุ์ที่ปลอดภัยของstrcpy, strcat, sprintfและอื่น ๆ

บนระบบ C99 ซึ่งเป็น Unixes ส่วนใหญ่คุณจะพบสิ่งเหล่านี้ด้วยชื่อที่คล้ายกันstrncatและsnprintf"n" ซึ่งระบุว่าจะรับอาร์กิวเมนต์ที่ขนาดของบัฟเฟอร์หรือจำนวนองค์ประกอบสูงสุดที่จะคัดลอก

ฟังก์ชั่นเหล่านี้สามารถใช้ในการจัดการการดำเนินการหลายอย่างปลอดภัยยิ่งขึ้น แต่ในการหวนกลับการใช้งานของพวกเขาไม่ดี ตัวอย่างเช่นsnprintfการใช้งานบางอย่างไม่รับประกันว่าบัฟเฟอร์จะถูกยกเลิก strncatใช้องค์ประกอบจำนวนหนึ่งเพื่อคัดลอก แต่หลายคนผ่านขนาดของบัฟเฟอร์ปลายทางโดยไม่ตั้งใจ

บน Windows, หนึ่งมักจะพบstrcat_s, sprintf_sที่ "_S" ต่อท้ายที่ระบุ "ปลอดภัย" สิ่งเหล่านี้ได้ค้นพบวิธีการของพวกเขาในไลบรารีมาตรฐาน C ใน C11 และให้การควบคุมเพิ่มเติมสิ่งที่เกิดขึ้นในกรณีที่มีการล้น (ยกตัวอย่างเช่นการตัดกับการยืนยัน)

ผู้ขายหลายรายมีทางเลือกที่ไม่ได้มาตรฐานมากกว่าเช่นasprintfใน GNU libc ซึ่งจะจัดสรรบัฟเฟอร์ขนาดที่เหมาะสมโดยอัตโนมัติ

ความคิดที่คุณสามารถ "เพิ่งแก้ไข C" เป็นความเข้าใจผิด การแก้ไข C ไม่ใช่ปัญหา - และเสร็จเรียบร้อยแล้ว ปัญหาคือการแก้ไขรหัส C เป็นเวลาหลายสิบปีที่เขียนโดยโปรแกรมเมอร์ที่ไม่รู้ง่วงเหนื่อยล้าหรือรีบเร่งหรือโค้ดที่ย้ายจากบริบทที่ความปลอดภัยไม่สำคัญต่อบริบทที่ความปลอดภัยทำ ไม่มีการเปลี่ยนแปลงในไลบรารีมาตรฐานสามารถแก้ไขรหัสนี้แม้ว่าการโยกย้ายไปยังคอมไพเลอร์ใหม่กว่าและไลบรารีมาตรฐานสามารถช่วยระบุปัญหาได้โดยอัตโนมัติ


11
+1 สำหรับการเล็งปัญหาที่โปรแกรมเมอร์ไม่ใช่ภาษา
Nicol Bolas

8
@ นิโคล: การพูดว่า "ปัญหา [คือ] โปรแกรมเมอร์" คือการลดอย่างไม่เป็นธรรม ปัญหาคือหลายปี (หลายสิบปี) C ทำให้การเขียนโค้ดที่ไม่ปลอดภัยง่ายกว่ารหัสที่ปลอดภัยโดยเฉพาะอย่างยิ่งเมื่อคำจำกัดความของ "ปลอดภัย" ของเราพัฒนาเร็วกว่ามาตรฐานภาษาใด ๆ และรหัสนั้นยังอยู่ หากคุณต้องการลองลดคำนามเป็นคำเดียวปัญหาคือ "1970-1999 libc" ไม่ใช่ "โปรแกรมเมอร์"

1
ยังคงเป็นความรับผิดชอบของโปรแกรมเมอร์ที่จะใช้เครื่องมือที่พวกเขามีตอนนี้เพื่อแก้ไขปัญหาเหล่านี้ ใช้เวลาครึ่งวันหรือมากกว่านั้นและทำ grepping ผ่านซอร์สโค้ดสำหรับสิ่งเหล่านี้
Nicol Bolas

1
@Nicol: ถึงแม้ว่าจะตรวจจับบัฟเฟอร์ที่มีขนาดเล็กเกินไป แต่ก็ไม่น่าจะแน่ใจได้ว่ามันเป็นภัยคุกคามที่แท้จริงและเล็กน้อยที่จะหลีกเลี่ยงสิ่งที่จะเกิดขึ้นถ้าบัฟเฟอร์นั้นล้น การจัดการข้อผิดพลาดมักไม่ได้รับการพิจารณาและเป็นไปไม่ได้ที่จะ "ดำเนินการอย่างรวดเร็ว" เพื่อปรับปรุงเนื่องจากคุณสามารถเปลี่ยนลักษณะการทำงานของโมดูลในรูปแบบที่ไม่คาดคิด เราเพิ่งทำสิ่งนี้ในฐานรหัสดั้งเดิมที่มีมูลค่าหลายล้านบรรทัดและแม้ว่าจะคุ้มค่าในขณะที่ออกกำลังกาย แต่ก็ใช้เวลามาก (และเงิน)
mattnz

4
@ NicolBolas: ไม่แน่ใจว่าร้านค้าแบบไหนที่คุณทำงานอยู่ แต่ที่สุดท้ายที่ฉันเขียน C สำหรับการใช้งานในการผลิตจำเป็นต้องแก้ไขเอกสารการออกแบบอย่างละเอียดตรวจทานเปลี่ยนรหัสแก้ไขแผนทดสอบทบทวนแผนทดสอบดำเนินการให้เสร็จสมบูรณ์ การทดสอบระบบตรวจสอบผลการทดสอบจากนั้นยืนยันระบบอีกครั้งที่ไซต์ของลูกค้า นี่เป็นระบบโทรคมนาคมในทวีปอื่นที่เขียนขึ้นสำหรับ บริษัท ที่ไม่มีอยู่อีกต่อไป ล่าสุดฉันรู้ว่าแหล่งที่มาอยู่ในคลัง RCS บนเทป QIC ที่ควรจะยังคงสามารถอ่านได้หากคุณสามารถหาเทปไดรฟ์ที่เหมาะสม
TMN

19

มันไม่ถูกต้องจริงๆจะบอกว่าซีเป็นจริง "ข้อผิดพลาด" โดยการออกแบบ นอกเหนือจากความผิดพลาดที่น่าเศร้าเช่นgetsภาษา C ไม่สามารถเป็นอย่างอื่นได้โดยไม่สูญเสียคุณสมบัติหลักที่ดึงดูดผู้คนไปยัง C ในตอนแรก

C ได้รับการออกแบบเป็นภาษาระบบเพื่อทำหน้าที่เหมือน "ชุดประกอบแบบพกพา" คุณสมบัติที่สำคัญของภาษา C คือไม่เหมือนกับภาษาระดับสูงรหัส C มักจะจับคู่กับรหัสเครื่องจริงมาก กล่าวอีกอย่างหนึ่ง++iก็คือincคำสั่งและคุณมักจะได้รับความคิดทั่วไปเกี่ยวกับสิ่งที่โปรเซสเซอร์จะทำในเวลาทำงานโดยดูที่รหัส C

แต่การเพิ่มการตรวจสอบขอบเขตโดยนัยเพิ่มค่าใช้จ่ายเพิ่มเติม - ค่าใช้จ่ายจำนวนมากซึ่งโปรแกรมเมอร์ไม่ได้ร้องขอและอาจไม่ต้องการ โอเวอร์เฮดนี้เหนือกว่าที่เก็บข้อมูลพิเศษที่จำเป็นสำหรับการจัดเก็บความยาวของแต่ละอาเรย์ อะไรที่เกี่ยวกับเลขคณิตของตัวชี้? หรือถ้าคุณมีฟังก์ชั่นที่ใช้ในตัวชี้? สภาวะแวดล้อมรันไทม์ไม่มีวิธีที่จะทราบว่าตัวชี้นั้นอยู่ในขอบเขตของบล็อกหน่วยความจำที่จัดสรรอย่างถูกต้องหรือไม่ เพื่อติดตามสิ่งนี้คุณจะต้องมีสถาปัตยกรรมรันไทม์ที่ร้ายแรงซึ่งสามารถตรวจสอบแต่ละตัวชี้เทียบกับตารางของบล็อกหน่วยความจำที่จัดสรรในปัจจุบัน ณ จุดที่เรากำลังเข้าสู่พื้นที่รันไทม์ที่ได้รับการจัดการ Java / C # -style


12
จริงๆแล้วเมื่อมีคนถามว่าทำไม C ถึงไม่ "ปลอดภัย" มันทำให้ฉันสงสัยว่าพวกเขาจะบ่นว่าชุดประกอบนั้นไม่ "ปลอดภัย"
Ben Brocka

5
ภาษา C นั้นเหมือนกับการประกอบแบบพกพาในเครื่อง Digital Equipment Corporation PDP-11 ในขณะเดียวกันเครื่อง Burroughs ก็มีการตรวจสอบขอบเขตของอาร์เรย์ในซีพียูดังนั้นพวกเขาจึงง่ายต่อการรับโปรแกรม Array ตรวจสอบอายุการใช้งานฮาร์ดแวร์ในฮาร์ดแวร์ Rockwell Collins (ส่วนใหญ่ใช้ในการบิน)
Tim Williscroft

15

ผมคิดว่าปัญหาที่แท้จริงไม่ได้อยู่ที่ว่าเหล่านี้ชนิดของข้อบกพร่องจะยากที่จะแก้ไข แต่พวกเขาจึงง่ายที่จะทำให้: ถ้าคุณใช้strcpy, sprintfและเพื่อน ๆ ใน (ดูเหมือน) วิธีที่ง่ายที่สุดที่สามารถทำงานแล้วคุณอาจได้ เปิดประตูสำหรับบัฟเฟอร์ล้น และไม่มีใครสังเกตเห็นจนกว่าจะมีคนเอาเปรียบมัน (เว้นแต่คุณจะมีบทวิจารณ์โค้ดที่ดีมาก) ตอนนี้เพิ่มความจริงที่ว่ามีโปรแกรมเมอร์ระดับปานกลางจำนวนมากและพวกเขากำลังกดดันเวลาส่วนใหญ่อยู่ตลอดเวลาและคุณมีสูตรสำหรับโค้ดที่เต็มไปด้วยบัฟเฟอร์ล้นซึ่งจะยากที่จะแก้ไขทั้งหมดเพียงเพราะมี มีคนมากมายและพวกเขาซ่อนตัวอยู่อย่างดี


3
คุณไม่จำเป็นต้องมี "บทวิจารณ์โค้ดที่ดีมาก" คุณต้องการ ban sprintf หรือ re-# define sprintf กับสิ่งที่ใช้ sizeof () และข้อผิดพลาดเกี่ยวกับขนาดของตัวชี้หรืออื่น ๆ คุณไม่จำเป็นต้องมีบทวิจารณ์โค้ดคุณสามารถทำสิ่งนี้กับ SCM คอมมิท hooks และ grep

1
@ JoeWreschnig: sizeof(ptr)เป็น 4 หรือ 8 โดยทั่วไป นั่นคือข้อ จำกัด C อื่น: ไม่มีวิธีที่จะกำหนดความยาวของอาเรย์
MSalters

@MSalters: ใช่อาร์เรย์ของ int [1] หรือ char [4] หรืออะไรก็ตามที่อาจเป็นผลบวกที่ผิดพลาด แต่ในทางปฏิบัติคุณไม่เคยจัดการบัฟเฟอร์ขนาดนั้นด้วยฟังก์ชั่นเหล่านั้น (ฉันไม่ได้พูดในทางทฤษฎีที่นี่ - ฉันทำงานบนฐานรหัส C ขนาดใหญ่เป็นเวลาสี่ปีที่ใช้วิธีการนี้ฉันไม่เคยโดนข้อ จำกัด ของ sprintfing เข้าสู่ตัวอักษร [4].)

5
@BlackJack: โปรแกรมเมอร์ส่วนใหญ่ไม่ได้โง่ - หากคุณบังคับให้พวกเขาผ่านขนาดพวกเขาจะผ่านหนึ่งที่เหมาะสม เป็นเพียงส่วนใหญ่จะไม่ผ่านขนาดเว้นแต่ถูกบังคับให้ คุณสามารถเขียนแมโครที่จะคืนค่าความยาวของอาร์เรย์ถ้าเป็นขนาดคงที่หรืออัตโนมัติ แต่เกิดข้อผิดพลาดหากมีตัวชี้ จากนั้นคุณกำหนด # sprintf อีกครั้งเพื่อเรียก snprintf ด้วยแมโครที่ให้ขนาด ตอนนี้คุณมี sprintf รุ่นที่ใช้งานได้กับอาร์เรย์ที่มีขนาดที่รู้จักเท่านั้นและบังคับให้โปรแกรมเมอร์เรียกใช้ snprintf ด้วยขนาดที่ระบุด้วยตนเอง

1
ตัวอย่างง่ายๆอย่างหนึ่งของมาโครเช่นนี้คือ#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]) / (sizeof(a) != sizeof(void *))สิ่งที่จะทริกเกอร์การแบ่งเวลาคอมไพล์โดยศูนย์ อีกหนึ่งฉลาดที่ฉันเห็นครั้งแรกใน Chromium เป็น#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]) / !(sizeof(a) % sizeof((a)[0]))ที่ค้าขายของบวกเท็จสำหรับเชิงลบเท็จบางอย่าง - น่าเสียดายที่มันไร้ประโยชน์สำหรับถ่าน [] คุณสามารถใช้ส่วนขยายคอมไพเลอร์ต่างๆที่จะทำให้มันยิ่งน่าเชื่อถือมากขึ้นเช่นblogs.msdn.com/b/ce_base/archive/2007/05/08/...

7

เป็นการยากที่จะแก้ไขบัฟเฟอร์ล้นเนื่องจาก C ไม่มีเครื่องมือที่มีประโยชน์สำหรับแก้ไขปัญหา มันเป็นข้อบกพร่องภาษาพื้นฐานที่บัฟเฟอร์พื้นเมืองให้ไม่มีการป้องกันและมันเป็นจริงหากไม่สมบูรณ์ไม่สามารถที่จะแทนที่พวกเขาด้วยผลิตภัณฑ์ที่เหนือกว่าเช่น C ++ ทำกับstd::vectorและstd::array, และมันเป็นเรื่องยากแม้ภายใต้โหมดการแก้ปัญหาเพื่อหาบัฟเฟอร์ล้น


13
"ข้อบกพร่องด้านภาษา" คือการอ้างสิทธิ์แบบอคติอย่างมาก การที่ห้องสมุดไม่ให้การตรวจสอบอย่าง จำกัด เป็นข้อบกพร่อง ว่าภาษาไม่ได้เป็นทางเลือกที่มีสติเพื่อหลีกเลี่ยงค่าใช้จ่าย ตัวเลือกนั้นเป็นส่วนหนึ่งของสิ่งที่ช่วยให้การสร้างระดับสูง ๆstd::vectorสามารถนำไปปฏิบัติได้อย่างมีประสิทธิภาพ และvector::operator[]ทำให้เป็นทางเลือกเดียวกันสำหรับความเร็วที่ปลอดภัย ความปลอดภัยvectorมาจากการทำให้ง่ายต่อการซื้อรอบขนาดซึ่งเป็นวิธีการเดียวกันกับห้องสมุด C ที่ทันสมัย

1
@Charles: "C ไม่ได้จัดเตรียมบัฟเฟอร์ที่ขยายแบบไดนามิกใด ๆ ซึ่งเป็นส่วนหนึ่งของไลบรารีมาตรฐาน" ไม่สิ่งนี้ไม่เกี่ยวข้องกับมัน ขั้นแรกให้ C ให้พวกเขาผ่านrealloc(C99 ยังช่วยให้คุณสามารถขนาดอาร์เรย์สแต็กโดยใช้รันไทม์ที่กำหนด แต่ขนาดคงที่ผ่านตัวแปรอัตโนมัติใด ๆ ซึ่งมักจะชอบมากกว่าchar buf[1024]) ประการที่สองปัญหาไม่เกี่ยวกับการขยายบัฟเฟอร์มันจะทำอย่างไรกับบัฟเฟอร์ที่มีขนาดและตรวจสอบขนาดนั้นเมื่อคุณเข้าถึง

5
@ โจ: ปัญหาไม่มากนักที่อาร์เรย์ในระบบแตก มันเป็นไปไม่ได้ที่พวกเขาจะมาแทนที่ สำหรับการเริ่มต้นvector::operator[]จะทำการตรวจสอบขอบเขตในโหมดดีบัก - สิ่งที่อาร์เรย์เนทีฟไม่สามารถทำได้ - และประการที่สองไม่มีวิธีใน C เพื่อสลับประเภทอาร์เรย์เนทีฟแบบดั้งเดิมกับอันที่สามารถทำการตรวจสอบขอบเขตได้เนื่องจากไม่มีเทมเพลตและไม่มีตัวดำเนินการ การบรรทุกเกินพิกัด ใน C ++ ถ้าคุณต้องการย้ายจากT[]ไปstd::arrayคุณสามารถเปลี่ยนประเภท typedef ใน C ไม่มีทางที่จะประสบความสำเร็จและไม่มีวิธีการเขียนคลาสที่มีฟังก์ชันการทำงานที่เทียบเท่า
DeadMG

3
@ โจ: มันไม่สามารถมีขนาดคงที่ได้และคุณไม่สามารถทำให้เป็นแบบทั่วไปได้ มันเป็นไปไม่ได้ที่จะเขียนห้องสมุดใด ๆ ใน C ซึ่งสำเร็จบทบาทเดียวกับที่std::vector<T>และstd::array<T, N>ทำใน C ++ จะไม่มีวิธีในการออกแบบและระบุไลบรารีใด ๆ แม้แต่มาตรฐานเดียวที่สามารถทำได้
DeadMG

1
ฉันไม่แน่ใจว่าสิ่งที่คุณหมายถึงโดย "มันไม่สามารถขนาดคงที่" ตามที่ฉันใช้คำstd::vectorนั้นไม่สามารถมีขนาดคงที่ได้ ในเรื่องทั่วไปคุณสามารถทำให้เป็นเรื่องทั่วไปได้เช่นเดียวกับ C ที่ดีซึ่งจำเป็นต้องมี - การดำเนินการขั้นพื้นฐานจำนวนน้อยในโมฆะ * (เพิ่มลบปรับขนาด) และทุกสิ่งที่เขียนโดยเฉพาะ หากคุณกำลังจะบ่นว่า C ไม่มี C + + สไตล์ทั่วไปนั่นเป็นวิธีที่อยู่นอกขอบเขตของการจัดการบัฟเฟอร์ที่ปลอดภัย

7

ปัญหาไม่ได้อยู่กับซีภาษา

IMO, อุปสรรคสำคัญเดียวที่จะเอาชนะก็คือ C เป็นเพียงธรรมดาสอนไม่ดี ทศวรรษของการปฏิบัติที่ไม่ดีและข้อมูลที่ผิดได้รับการจัดทำขึ้นในคู่มืออ้างอิงและบันทึกการบรรยายซึ่งทำให้จิตใจของนักเขียนโปรแกรมรุ่นใหม่แต่ละคนตั้งแต่ต้น นักเรียนจะได้รับคำอธิบายสั้น ๆ เกี่ยวกับฟังก์ชั่น I / O อย่างง่ายเช่นgets1หรือscanfจากซ้ายไปยังอุปกรณ์ของตนเอง พวกเขาไม่ได้บอกว่าเครื่องมือเหล่านั้นสามารถล้มเหลวได้อย่างไรหรือวิธีป้องกันความล้มเหลวเหล่านั้น พวกเขาไม่ได้บอกเกี่ยวกับการใช้fgetsและstrtol/strtodเพราะสิ่งเหล่านี้ถือเป็นเครื่องมือ "ขั้นสูง" จากนั้นพวกเขาจะปลดปล่อยความเป็นมืออาชีพเพื่อสร้างความหายนะ ไม่ว่าโปรแกรมเมอร์ที่มีประสบการณ์จำนวนมากรู้ดีไปกว่านี้เพราะพวกเขาได้รับการศึกษาที่สมองเสียหาย มันน่าคลั่ง ฉันเห็นคำถามมากมายที่นี่และใน Stack Overflow และในเว็บไซต์อื่น ๆ ที่เห็นได้ชัดว่าบุคคลที่ถามคำถามนั้นถูกสอนโดยคนที่ไม่รู้ว่าพวกเขากำลังพูดถึงอะไรและแน่นอนคุณไม่สามารถพูดได้ "อาจารย์ของคุณผิด" เพราะเขาเป็นศาสตราจารย์และคุณก็แค่คนที่แต่งตัวประหลาดบนอินเทอร์เน็ต

และแล้วคุณมีฝูงชนที่ disdains คำตอบใด ๆ เริ่มต้นด้วย "ดีตามมาตรฐานภาษา ..." เพราะพวกเขากำลังทำงานอยู่ในโลกแห่งความจริงและเป็นไปตามมาตรฐานที่พวกเขาไม่ได้นำไปใช้กับโลกแห่งความจริง ฉันสามารถจัดการกับคนที่เพิ่งได้รับการศึกษาที่ไม่ดี แต่ใครก็ตามที่ยืนยันว่าเป็นคนโง่เขลานั้นเป็นเพียงความเสียหายต่ออุตสาหกรรม

จะไม่มีปัญหาบัฟเฟอร์ล้นหากภาษาได้รับการสอนอย่างถูกต้องโดยเน้นการเขียนรหัสที่ปลอดภัย มันไม่ใช่ "ยาก" ไม่ใช่ "ขั้นสูง" แต่ต้องระวัง

ใช่นี่เป็นการคุยโว


1ซึ่งโชคดีที่ถูกดึงออกมาจากข้อกำหนดของภาษาในที่สุดแม้ว่ามันจะแฝงตัวอยู่ในรหัสมรดกมูลค่า 40 ปีตลอดไป


1
ในขณะที่ฉันเห็นด้วยกับคุณเป็นส่วนใหญ่ฉันคิดว่าคุณยังไม่ยุติธรรม สิ่งที่เราคิดว่า "ปลอดภัย" เป็นหน้าที่ของเวลาด้วย (และฉันเห็นว่าคุณเป็นนักพัฒนาซอฟต์แวร์มืออาชีพนานกว่าฉันดังนั้นฉันมั่นใจว่าคุณคุ้นเคยกับสิ่งนี้) สิบปีต่อจากนี้จะมีใครบางคนกำลังสนทนากันเรื่องนี้ว่าทำไมทุกคนในปี 2555 ใช้ตารางแฮชของ DoS ที่สามารถใช้งานได้เราไม่รู้อะไรเลยเกี่ยวกับความปลอดภัยใช่ไหม หากมีปัญหาในการสอนมันเป็นปัญหาที่เราให้ความสำคัญกับการสอนแนวปฏิบัติที่ดีที่สุดและไม่ใช่แนวปฏิบัติที่ดีที่สุด

1
และขอซื่อสัตย์ คุณสามารถเขียนรหัสที่ปลอดภัยได้เพียงsprintfแต่นั่นไม่ได้หมายความว่าภาษานั้นไม่สมบูรณ์ C มีข้อบกพร่องและมีข้อบกพร่อง - เช่นภาษาใด ๆ - และเป็นสิ่งสำคัญที่เราต้องยอมรับข้อบกพร่องเหล่านั้นเพื่อให้เราสามารถแก้ไขได้

@ JoeWreschnig - ในขณะที่ฉันเห็นด้วยกับจุดที่ใหญ่กว่าฉันคิดว่ามีความแตกต่างเชิงคุณภาพระหว่างการใช้งานตารางแฮชของ DoS และการใช้บัฟเฟอร์มากเกินไป อดีตอาจเกิดจากสถานการณ์ที่พัฒนารอบตัวคุณ แต่ข้อที่สองไม่มีข้อแก้ตัว บัฟเฟอร์โอเวอร์รันเป็นข้อผิดพลาดในการเขียนโปรแกรมระยะเวลา ใช่ C ไม่มีการ์ดใบมีดและจะตัดคุณถ้าคุณไม่ประมาท เราสามารถโต้เถียงได้ว่าเป็นข้อบกพร่องในภาษาหรือไม่ นั่นคือฉากกับความจริงที่ว่านักเรียนน้อยมากที่จะได้รับการใด ๆคำแนะนำด้านความปลอดภัยเมื่อพวกเขากำลังเรียนรู้ภาษา
John Bode

5

ปัญหาคือหนึ่งในความสามารถในการบริหารจัดการสั้นกว่าความสามารถของโปรแกรมเมอร์ โปรดจำไว้ว่าแอปพลิเคชัน 90,000 บรรทัดต้องการการดำเนินการที่ไม่ปลอดภัยเพียงหนึ่งครั้งเท่านั้นที่จะไม่ปลอดภัยอย่างสมบูรณ์ เกือบจะเกินขอบเขตของความเป็นไปได้ที่แอปพลิเคชันใด ๆ ที่เขียนบนการจัดการสตริงที่ไม่ปลอดภัยขั้นพื้นฐานจะสมบูรณ์แบบ 100% - ซึ่งหมายความว่าจะไม่ปลอดภัย

ปัญหาคือค่าใช้จ่ายที่ไม่ปลอดภัยนั้นไม่ได้ถูกเรียกเก็บจากผู้รับที่ถูกต้อง (บริษัท ที่ขายแอพนี้แทบจะไม่ต้องคืนเงินในราคาซื้อ) หรือไม่สามารถมองเห็นได้อย่างชัดเจนในเวลาที่ตัดสินใจ ("เราต้องจัดส่ง ในเดือนมีนาคมไม่ว่าจะเกิดอะไรขึ้น! ") ฉันค่อนข้างแน่ใจว่าถ้าคุณแยกแยะต้นทุนและต้นทุนระยะยาวให้กับผู้ใช้ของคุณมากกว่าที่จะทำกำไรกับ บริษัท ของคุณการเขียนในภาษา C หรือภาษาที่เกี่ยวข้องจะมีราคาแพงกว่ามากอาจเป็นราคาที่แพง สาขาที่ปัจจุบันภูมิปัญญาดั้งเดิมบอกว่ามันเป็นสิ่งจำเป็น แต่นั่นจะไม่เปลี่ยนแปลงเว้นแต่จะมีการนำเสนอซอฟต์แวร์ที่เข้มงวดมากขึ้นซึ่งไม่มีใครในอุตสาหกรรมต้องการ


-1: การตำหนิการจัดการในฐานะที่เป็นรากของความชั่วร้ายทั้งหมดไม่ได้สร้างสรรค์ เพิกเฉยต่อประวัติศาสตร์น้อยไปหน่อย คำตอบคือเกือบแลกด้วยประโยคสุดท้าย
mattnz

ผู้ใช้ที่สนใจในเรื่องความปลอดภัยและเต็มใจที่จะชำระค่าใช้จ่ายนั้นจะต้องรับผิดชอบซอฟต์แวร์ที่เข้มงวดมากขึ้น มันอาจถูกนำมาใช้โดยมีบทลงโทษที่รุนแรงสำหรับการละเมิดความปลอดภัย โซลูชันที่อิงตามตลาดจะใช้งานได้หากผู้ใช้ยินดีจ่ายเพื่อความปลอดภัย แต่ไม่ได้
David Thornley

4

หนึ่งในพลังที่ยิ่งใหญ่ของการใช้ C คือมันช่วยให้คุณสามารถจัดการกับหน่วยความจำในแบบที่คุณเห็นสมควร

หนึ่งในจุดอ่อนที่สำคัญของการใช้ C คือช่วยให้คุณสามารถจัดการกับหน่วยความจำในแบบที่คุณเห็นว่าเหมาะสม

มีฟังก์ชันที่ไม่ปลอดภัยใด ๆ ในรุ่นที่ปลอดภัย อย่างไรก็ตามโปรแกรมเมอร์และคอมไพเลอร์ไม่บังคับใช้อย่างเคร่งครัด


2

เหตุใดผู้สร้าง C ไม่สามารถแก้ไขปัญหาเหล่านี้ได้โดยการนำไลบรารีไปใช้อีกครั้ง

อาจเป็นเพราะ C ++ ทำสิ่งนี้แล้วและสามารถใช้งานร่วมกับรหัส C ย้อนหลังได้ ดังนั้นหากคุณต้องการประเภทสตริงที่ปลอดภัยในรหัส C ของคุณคุณเพียงแค่ใช้ std :: string และเขียนรหัส C ของคุณโดยใช้คอมไพเลอร์ C ++

ระบบย่อยหน่วยความจำพื้นฐานสามารถช่วยป้องกันการโอเวอร์โฟลว์บัฟเฟอร์ได้โดยการแนะนำ Guard Guard และการตรวจสอบความถูกต้องดังนั้นการจัดสรรทั้งหมดจะมีการเพิ่ม 'fefefefe' 4 ไบต์เมื่อบล็อกเหล่านี้ถูกเขียนลงในระบบสามารถโยนโมโห ไม่รับประกันว่าจะป้องกันการเขียนหน่วยความจำ แต่จะแสดงว่ามีบางอย่างผิดพลาดและจำเป็นต้องแก้ไข

ฉันคิดว่าปัญหาคือว่างานประจำ strcpy ฯลฯ ยังคงมีอยู่ หากพวกเขาถูกลบออกในความโปรดปรานของ strncpy ฯลฯ นั้นจะช่วย


1
การลบ strcpy ฯลฯ ทั้งหมดจะทำให้เส้นทางการอัพเกรดที่เพิ่มขึ้นนั้นยากยิ่งขึ้นซึ่งจะส่งผลให้คนไม่อัปเกรดเลย ตอนนี้คุณสามารถเปลี่ยนไปใช้คอมไพเลอร์ C11 ได้จากนั้นเริ่มใช้ตัวแปร _s จากนั้นสั่งห้ามตัวแปรไม่ใช่ _s จากนั้นแก้ไขการใช้งานที่มีอยู่ไม่ว่าช่วงเวลาใดจะใช้ได้จริง

-2

มันง่ายที่จะเข้าใจว่าทำไมปัญหาล้นไม่ได้รับการแก้ไข C มีข้อบกพร่องในสองสามพื้นที่ ในขณะที่ข้อบกพร่องเหล่านั้นถูกมองว่าเป็นที่ยอมรับได้หรือแม้กระทั่งเป็นคุณลักษณะ ตอนนี้หลายทศวรรษต่อมาข้อบกพร่องเหล่านั้นไม่สามารถแก้ไขได้

บางส่วนของชุมชนการเขียนโปรแกรมไม่ต้องการเสียบรูเหล่านั้น เพียงแค่ดูเปลวไฟสงครามที่เริ่มต้นด้วยสายอาร์เรย์ตัวชี้การรวบรวมขยะ ...


5
ฮ่า ๆ คำตอบแย่มากและผิดหัว
Heath Hunnicutt

1
เพื่ออธิบายว่าทำไมคำตอบที่ไม่ดีนี้: C มีข้อบกพร่องมากมาย แต่การอนุญาตให้บัฟเฟอร์ล้นเป็นต้นมีน้อยมากที่จะทำกับพวกเขา แต่ด้วยความต้องการภาษาขั้นพื้นฐาน มันเป็นไปไม่ได้ที่จะออกแบบภาษาให้ทำงานของ C และไม่อนุญาตให้มีบัฟเฟอร์มากเกินไป บางส่วนของชุมชนไม่ต้องการละทิ้งความสามารถที่ C อนุญาตให้พวกเขาบ่อยครั้งด้วยเหตุผลที่ดี นอกจากนี้ยังมีความขัดแย้งกันว่าจะหลีกเลี่ยงปัญหาเหล่านี้ได้อย่างไรซึ่งแสดงว่าเราไม่มีความเข้าใจที่สมบูรณ์เกี่ยวกับการออกแบบภาษาโปรแกรม แต่อย่างใด
David Thornley

1
@DavidThornley: ใครสามารถออกแบบภาษาให้ทำงานของ C ได้ แต่ทำอย่างนั้นวิธีการทำสิ่งปกติอย่างน้อยที่สุดจะอนุญาตให้คอมไพเลอร์ตรวจสอบบัฟเฟอร์โอเวอร์โฟลว์อย่างมีประสิทธิภาพพอสมควรหากคอมไพเลอร์เลือกที่จะทำเช่นนั้น มีความแตกต่างอย่างมากระหว่างการมีmemcpy()อยู่และการเป็นเพียงวิธีมาตรฐานในการคัดลอกส่วนอาเรย์อย่างมีประสิทธิภาพ
supercat
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.