ปัญหาอยู่ที่นี่:
strncpy(buffer,str,strlen(str));
^^^^^^^^^^^
หากสตริงมากกว่าความยาวของบัฟเฟอร์เป้าหมาย strncpy จะยังคงคัดลอกไป คุณกำลังอ้างอิงจำนวนอักขระของสตริงเป็นหมายเลขที่จะคัดลอกแทนขนาดของบัฟเฟอร์ วิธีที่ถูกต้องในการทำเช่นนี้มีดังนี้:
strncpy(buffer,str, sizeof(buff) - 1);
buffer[sizeof(buff) - 1] = '\0';
สิ่งนี้ทำคือ จำกัด จำนวนข้อมูลที่คัดลอกไปยังขนาดที่แท้จริงของบัฟเฟอร์ลบหนึ่งสำหรับอักขระที่ยกเลิก null จากนั้นเราจะตั้งค่าไบต์สุดท้ายในบัฟเฟอร์ให้เป็นอักขระ null เพื่อเป็นการป้องกันเพิ่มเติม เหตุผลนี้เป็นเพราะ strncpy จะคัดลอกไม่เกิน n ไบต์รวมถึงการยกเลิก null ถ้า strlen (str) <len - 1 ถ้าไม่เช่นนั้น null จะไม่ถูกคัดลอกและคุณมีสถานการณ์ความผิดพลาดเพราะตอนนี้บัฟเฟอร์ของคุณมีการทำลาย เชือก
หวังว่านี่จะช่วยได้
แก้ไข: เมื่อตรวจสอบเพิ่มเติมและป้อนข้อมูลจากผู้อื่นการเข้ารหัสที่เป็นไปได้สำหรับฟังก์ชั่นดังต่อไปนี้:
int func (char *str)
{
char buffer[100];
unsigned short size = sizeof(buffer);
unsigned short len = strlen(str);
if (len > size - 1) return(-1);
memcpy(buffer, str, len + 1);
buffer[size - 1] = '\0';
return(0);
}
เนื่องจากเราทราบความยาวของสตริงเราจึงสามารถใช้ memcpy เพื่อคัดลอกสตริงจากตำแหน่งที่อ้างอิงโดย str ลงในบัฟเฟอร์ โปรดทราบว่าในหน้าคู่มือสำหรับ strlen (3) (บนระบบ FreeBSD 9.3) จะมีการระบุสิ่งต่อไปนี้:
The strlen() function returns the number of characters that precede the
terminating NUL character. The strnlen() function returns either the
same result as strlen() or maxlen, whichever is smaller.
ซึ่งฉันตีความว่าเป็นความยาวของสตริงที่ไม่รวมถึงโมฆะ นั่นคือเหตุผลที่ฉันคัดลอก len + 1 ไบต์เพื่อรวม null และการทดสอบตรวจสอบเพื่อให้แน่ใจว่าความยาว <ขนาดของบัฟเฟอร์ - 2 ลบหนึ่งเพราะบัฟเฟอร์เริ่มต้นที่ตำแหน่ง 0 และลบอีกหนึ่งเพื่อให้แน่ใจว่ามีที่ว่าง สำหรับ null
แก้ไข: ปรากฎขนาดของบางสิ่งเริ่มต้นด้วย 1 ในขณะที่การเข้าถึงเริ่มต้นด้วย 0 ดังนั้น -2 ก่อนหน้านี้ไม่ถูกต้องเพราะมันจะส่งกลับข้อผิดพลาดสำหรับอะไร> 98 ไบต์ แต่ควร> 99 ไบต์
แก้ไข: แม้ว่าคำตอบสั้น ๆ ที่ไม่ได้ลงชื่อจะถูกต้องเนื่องจากความยาวสูงสุดที่สามารถแสดงได้คือ 65,535 ตัวอักษร แต่ก็ไม่สำคัญเพราะหากสตริงยาวกว่านั้นค่าจะตัดไป มันเหมือนกับเอา 75,231 (ซึ่งคือ 0x000125DF) และปิดบัง 16 บิตแรกที่ให้คุณ 9695 (0x000025DF) ปัญหาเดียวที่ฉันเห็นด้วยกับเรื่องนี้เป็น 100 ตัวอักษรแรกที่ผ่านมา 65,535 การตรวจสอบความยาวจะช่วยให้คัดลอกแต่จะคัดลอกขึ้นไป 100 ตัวอักษรแรกของสตริงในทุกกรณีและ null ยุติสตริง ดังนั้นแม้จะมีปัญหาการตัดผ่านบัฟเฟอร์ยังคงไม่ถูกโอเวอร์โฟลว์
สิ่งนี้อาจหรือไม่อาจมีความเสี่ยงด้านความปลอดภัยขึ้นอยู่กับเนื้อหาของสตริงและสิ่งที่คุณใช้งาน หากเป็นเพียงข้อความตรงที่มนุษย์สามารถอ่านได้แสดงว่าไม่มีปัญหา คุณเพิ่งได้รับสตริงที่ถูกตัดทอน อย่างไรก็ตามหากเป็นเหมือน URL หรือแม้แต่ลำดับของคำสั่ง SQL คุณอาจมีปัญหา