linux - গ্লিবিসি স্ক্যানফ বিভাজন ত্রুটিগুলি যখন কোনও ফাংশন থেকে কল করা হয় যা আরএসপি প্রান্তিককরণ করে না



assembly nasm (1)

কোডের নীচে সংকলন করার সময়:

global main
extern printf, scanf

section .data
   msg: db "Enter a number: ",10,0
   format:db "%d",0

section .bss
   number resb 4

section .text
main:
   mov rdi, msg
   mov al, 0
   call printf

   mov rsi, number
   mov rdi, format
   mov al, 0
   call scanf

   mov rdi,format
   mov rsi,[number]
   inc rsi
   mov rax,0
   call printf 

   ret

ব্যবহার:

nasm -f elf64 example.asm -o example.o
gcc -no-pie -m64 example.o -o example

এবং তারপর চালানো

./example

এটি চালায়, মুদ্রণ করুন: একটি নম্বর লিখুন: তবে ক্রাশ এবং মুদ্রণগুলি: বিভাগীয়করণ ত্রুটি (কোর ডাম্পড)

প্রিন্টফ ঠিকঠাক কাজ করে তবে স্ক্যানফ করে না। আমি স্ক্যানফের সাথে কী ভুল করছি?


আপনার ফাংশন call আগে স্ট্যাকটি 16 বাইটে পুনরায় সারিবদ্ধ করতে আপনার ফাংশনটির শুরু / শেষে sub rsp, 8 / add rsp, 8 ব্যবহার করুন

বা আরও ভাল একটি ডামি রেজিস্টার ধাক্কা / পপ করুন, উদাহরণস্বরূপ push rdx / pop rcx , বা pop rcx মতো একটি কল-সংরক্ষিত রেজিস্টার সংরক্ষণ / পুনরুদ্ধার করুন।

ফাংশন এন্ট্রিতে, আরএসপিটি 16-বাইট প্রান্তিককরণ থেকে 8 বাইট দূরে রয়েছে কারণ call একটি 8-বাইট রিটার্ন ঠিকানাটি ঠেলে দিয়েছে। X86-64 থেকে প্রোটিং ফ্লোটিং পয়েন্ট নম্বরগুলি জিএনইউ এসেম্বলারের সাহায্যে xb__p এ সংরক্ষণ করতে মূল এবং স্ট্যাক সারিবদ্ধকরণ এবং প্রিন্টফ কলিংয়ের জন্য% rbp প্রয়োজন বলে মনে হচ্ছে । এটি একটি এবিআইয়ের প্রয়োজনীয়তা যা আপনি প্রিন্টফের জন্য কোনও এফপি আরগস না থাকলে লঙ্ঘন করে পালিয়ে যেতে সক্ষম হতেন। কিন্তু আর কখনো না.

গ্লিবিসি স্ক্যানফের জন্য জিসিসির কোড-জেন এখন AL == 0 সত্ত্বেও 16-বাইট স্ট্যাক সারিবদ্ধকরণের উপর নির্ভর করে

মনে হচ্ছে এটি __GI__IO_vfscanf কোথাও 16 বাইট অনুলিপি করে অটো-ভেক্টরাইজ __GI__IO_vfscanf , যা নিয়মিত __GI__IO_vfscanf তার রেজিস্টার __GI__IO_vfscanf স্ট্যাক 1 এ ছড়িয়ে দেওয়ার পরে কল করে। (স্ক্যানফ কল করার অনেকগুলি একই ধরণের বিভিন্ন লিবিসি এন্ট্রি পয়েন্ট যেমন scanf , fscanf ইত্যাদির ব্যাক এন্ড হিসাবে একটি বড় বাস্তবায়ন ভাগ করে দেয়)

আমি উবুন্টু 18.04 এর libc6 বাইনারি প্যাকেজটি ডাউনলোড করেছি: https://packages.ubuntu.com/bionic/amd64/libc6/download এবং ফাইলগুলি বের করেছি ( 7z x blah.deb এবং tar xf data.tar , কারণ 7z জানে কীভাবে প্রচুর ফাইল ফর্ম্যাটগুলি বের করুন)।

আমি আপনার বাগটি LD_LIBRARY_PATH=/tmp/bionic-libc/lib/x86_64-linux-gnu ./bad-printf করতে পারি এবং এটি আমার আর্চ লিনাক্স ডেস্কটপে সিস্টেম গ্লিবসি ২.২27-৩ এ সক্রিয় হয়।

জিডিবি দিয়ে, আমি এটি আপনার প্রোগ্রামে set env LD_LIBRARY_PATH /tmp/bionic-libc/lib/x86_64-linux-gnu এবং তারপর set env LD_LIBRARY_PATH /tmp/bionic-libc/lib/x86_64-linux-gnu করেছিলাম। layout reg , বিচ্ছিন্ন উইন্ডোটি এমন জায়গায় দেখায় যেখানে এটি SIGSEGV পেয়েছিল:

   │0x7ffff786b49a <_IO_vfscanf+602>        cmp    r12b,0x25                                                                                             │
   │0x7ffff786b49e <_IO_vfscanf+606>        jne    0x7ffff786b3ff <_IO_vfscanf+447>                                                                      │
   │0x7ffff786b4a4 <_IO_vfscanf+612>        mov    rax,QWORD PTR [rbp-0x460]                                                                             │
   │0x7ffff786b4ab <_IO_vfscanf+619>        add    rax,QWORD PTR [rbp-0x458]                                                                             │
   │0x7ffff786b4b2 <_IO_vfscanf+626>        movq   xmm0,QWORD PTR [rbp-0x460]                                                                            │
   │0x7ffff786b4ba <_IO_vfscanf+634>        mov    DWORD PTR [rbp-0x678],0x0                                                                             │
   │0x7ffff786b4c4 <_IO_vfscanf+644>        mov    QWORD PTR [rbp-0x608],rax                                                                             │
   │0x7ffff786b4cb <_IO_vfscanf+651>        movzx  eax,BYTE PTR [rbx+0x1]                                                                                │
   │0x7ffff786b4cf <_IO_vfscanf+655>        movhps xmm0,QWORD PTR [rbp-0x608]                                                                            │
  >│0x7ffff786b4d6 <_IO_vfscanf+662>        movaps XMMWORD PTR [rbp-0x470],xmm0                                                                          │

সুতরাং এটি দুটি 8-বাইট অবজেক্টগুলি স্ট্যাকের সাথে movq + movhps এবং লোড করার জন্য movaps করেছে। তবে স্ট্যাকটি movaps [rbp-0x470],xmm0 , movaps [rbp-0x470],xmm0 ফল্ট।

সি উত্সের কোন অংশটি ঠিক এই রূপে রূপান্তরিত হয়েছে তা অনুসন্ধান করার জন্য আমি কোনও ডিবাগ বিল্ডটি ধরলাম না, তবে ফাংশনটি সিতে লেখা হয়েছে এবং জিসিসি দ্বারা অনুকূলিতকরণ সক্ষম করে সংকলিত। জিসিসিকে সর্বদা এটি করার অনুমতি দেওয়া হয়েছে, তবে কেবল সম্প্রতি এসএসই 2 এর এইভাবে আরও ভাল সুবিধা নেওয়ার জন্য এটি যথেষ্ট স্মার্ট হয়েছিল।

পাদটীকা 1: AL != 0 এর সাথে প্রিন্টফ / স্ক্যানফ সর্বদা 16-বাইট প্রান্তিককরণের প্রয়োজন হয় কারণ ভেরিয়েডিক ফাংশনগুলির জন্য জিসিসির কোড-জেন টেস্ট আল, আল / জে ব্যবহার করে পুরো 16-বাইট এক্সএমএম রেজি এক্স মিমি..7 স্পষ্ট করতে সংযুক্ত স্টোরগুলি সহ কেস। __m128i কেবলমাত্র double নয়, একটি বৈকল্পিক ফাংশনের পক্ষে যুক্তি হতে পারে এবং __m128i এই ফাংশনটি আসলে কোনও 16-বাইট এফপি আরগস পড়ে কিনা তা যাচাই করে না।





calling-convention