সুরক্ষার জন্য যদি গাদাটি শূন্য-সূচনা হয় তবে স্ট্যাকটি নিছক অবিচ্ছিন্ন করা হবে কেন?


15

আমার ডেবিয়ান জিএনইউ / লিনাক্স 9 সিস্টেমে, যখন বাইনারি কার্যকর হয়,

  • স্ট্যাকটি অবিচ্ছিন্ন তবে
  • গাদা শূন্য-আরম্ভ হয়।

কেন?

আমি ধরে নিয়েছি যে শূন্য-সূচনাটি সুরক্ষা প্রচার করে তবে, যদি গাদা হয়ে থাকে, তবে কেন স্ট্যাকের জন্য নয়? স্ট্যাকেরও কি সুরক্ষার দরকার নেই?

আমার প্রশ্নটি আমি যতটা জানি দেবিয়ানের সাথে সুনির্দিষ্ট নয়।

নমুনা সি কোড:

#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>

const size_t n = 8;

// --------------------------------------------------------------------
// UNINTERESTING CODE
// --------------------------------------------------------------------
static void print_array(
  const int *const p, const size_t size, const char *const name
)
{
    printf("%s at %p: ", name, p);
    for (size_t i = 0; i < size; ++i) printf("%d ", p[i]);
    printf("\n");
}

// --------------------------------------------------------------------
// INTERESTING CODE
// --------------------------------------------------------------------
int main()
{
    int a[n];
    int *const b = malloc(n*sizeof(int));
    print_array(a, n, "a");
    print_array(b, n, "b");
    free(b);
    return 0;
}

আউটপুট:

a at 0x7ffe118997e0: 194 0 294230047 32766 294230046 32766 -550453275 32713 
b at 0x561d4bbfe010: 0 0 0 0 0 0 0 0 

সি স্ট্যান্ডার্ড malloc()অবশ্যই বরাদ্দ করার আগে মেমরি পরিষ্কার করতে বলবে না , তবে আমার সি প্রোগ্রামটি কেবল উদাহরণের জন্য। প্রশ্নটি সি সম্পর্কে বা সি-র মানক গ্রন্থাগার সম্পর্কে কোনও প্রশ্ন নয়। বরং, কার্নেল এবং / অথবা রান-টাইম লোডার স্ট্যাকের পরিবর্তে কেন গাদাটি শূন্য করছে এমন প্রশ্ন একটি প্রশ্ন।

অন্য অভিজ্ঞতা

আমার প্রশ্ন মান নথিগুলির প্রয়োজনীয়তার চেয়ে পর্যবেক্ষণযোগ্য জিএনইউ / লিনাক্স আচরণকেই সম্মান করে। আমার অর্থটি সম্পর্কে যদি অনিশ্চিত থাকে তবে এই কোডটিটি ব্যবহার করে দেখুন, যা আরও অনির্ধারিত আচরণের ( অনির্ধারিত, অর্থাৎ সি স্ট্যান্ডার্ডের সাথে সম্পর্কিত) অনুরোধ করে:

#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>

const size_t n = 4;

int main()
{
    for (size_t i = n; i; --i) {
        int *const p = malloc(sizeof(int));
        printf("%p %d ", p, *p);
        ++*p;
        printf("%d\n", *p);
        free(p);
    }
    return 0;
}

আমার মেশিন থেকে আউটপুট:

0x555e86696010 0 1
0x555e86696010 0 1
0x555e86696010 0 1
0x555e86696010 0 1

যতদূর সি স্ট্যান্ডার্ড সম্পর্কিত, আচরণটি অপরিজ্ঞাত, সুতরাং আমার প্রশ্নটি সি স্ট্যান্ডার্ডকে বিবেচনা করে না। একটি কল malloc()প্রতিটি বার একই ঠিকানা ফেরত দেওয়া প্রয়োজন না, যেহেতু এই কলটি malloc()প্রকৃতপক্ষে প্রতিবার একই ঠিকানা ফিরে আসে, তাই এটি লক্ষ্য করা আকর্ষণীয় যে মেমরিটি, যে স্তূপে রয়েছে, প্রতিবার শূন্য হয়েছে।

বিপরীতে, স্ট্যাকটি শূন্য বলে মনে হয় নি।

আপনার মেশিনে পরবর্তী কোডটি কী করবে তা আমি জানি না, কারণ জিএনইউ / লিনাক্স সিস্টেমের কোন স্তরটি পর্যবেক্ষণ আচরণের কারণ ঘটছে তা আমি জানি না। আপনি কিন্তু এটি চেষ্টা করতে পারেন।

হালনাগাদ

@ কুসালানন্দ মন্তব্যগুলিতে লক্ষ্য করেছেন:

এটি মূল্যবান কিসের জন্য, আপনার অতি সাম্প্রতিক কোড ওপেনবিএসডি চালানোর সময় বিভিন্ন ঠিকানা এবং (মাঝে মাঝে) আনবিটিয়ালাইজড (শূন্য নয়) ডেটা দেয়। এটি লিনাক্সে আপনি যে আচরণের সাক্ষ্য দিচ্ছেন সে সম্পর্কে স্পষ্টতই কিছু বলা যায় না।

আমার ফলাফলটি ওপেনবিএসডি-র ফলাফলের চেয়ে পৃথক হওয়া সত্যই আকর্ষণীয়। স্পষ্টতই, আমার পরীক্ষাগুলি কার্নেল (বা লিঙ্কার) সুরক্ষা প্রোটোকলটি আবিষ্কার করছিল না, যেমনটি আমি ভেবেছিলাম, তবে একটি নিখরচায় বাস্তবায়িত শৈল্পিক।

এই আলোকে, আমি বিশ্বাস করি যে, একসাথে, @ ম্যাসভি, @ স্টেফেনকিট এবং @ অ্যান্ড্রেস গ্র্যাপেনটিনের নীচের উত্তরগুলি আমার প্রশ্ন নিষ্পত্তি করে।

স্ট্যাক ওভারফ্লোতেও দেখুন: ম্যালোক কেন গিসিতে 0 টি মানগুলিকে আরম্ভ করে? (ক্রেডিট: @ বিটিএ)


2
এটি মূল্যবান কিসের জন্য, আপনার অতি সাম্প্রতিক কোড ওপেনবিএসডি চালানোর সময় বিভিন্ন ঠিকানা এবং (মাঝে মাঝে) আনবিটিয়ালাইজড (শূন্য নয়) ডেটা দেয়। এটি লিনাক্সে আপনি যে আচরণের সাক্ষ্য দিচ্ছেন সে সম্পর্কে স্পষ্টতই কিছু বলা যায় না
কুসালানন্দ

দয়া করে আপনার প্রশ্নের ক্ষেত্র পরিবর্তন করবেন না, এবং উত্তর এবং মন্তব্যগুলি অপ্রয়োজনীয় করার জন্য এটি সম্পাদনা করার চেষ্টা করবেন না। সি-তে, "হিপ" মেলোক () এবং কলোক () দ্বারা ফিরে আসা স্মৃতি ছাড়া আর কিছুই নয়, এবং কেবল পরেরটিই স্মৃতিটিকে শূন্য করে চলেছে; newসি ++ এ অপারেটর (এছাড়াও "হিপ") লিনাক্সে ম্যালোক () এর জন্য কেবল একটি মোড়ক রয়েছে; কার্নেল "হিপ" কী তা জানে না বা যত্ন করে না।
মশভী

3
আপনার দ্বিতীয় উদাহরণটি কেবল গ্লিবিসি-তে ম্যালোক বাস্তবায়নের একটি শৈল্পিকতা প্রকাশ করছে; যদি আপনি 8 বাইটের চেয়ে বড় বাফারটি দিয়ে বারবার ম্যালোক / ফ্রি করেন তবে আপনি পরিষ্কারভাবে দেখতে পাবেন যে কেবল প্রথম 8 বাইট শূন্য রয়েছে are
মশভী

@ কুসালানন্দ আমি দেখতে পাচ্ছি। আমার ফলাফলটি ওপেনবিএসডি-র ফলাফলের চেয়ে পৃথক হওয়া সত্যই আকর্ষণীয়। স্পষ্টতই, আপনি এবং মোসভি দেখিয়েছেন যে আমার পরীক্ষাগুলি কার্নেল (বা লিঙ্কার) সুরক্ষা প্রোটোকলটি আবিষ্কার করছিল না, যেমনটি আমি ভেবেছিলাম, তবে একটি নিছক বাস্তবায়নমূলক নিদর্শন।
thb

@thb আমি বিশ্বাস করি যে এটি হ'ল একটি সঠিক পর্যবেক্ষণ হতে পারে।
কুসালানন্দ

উত্তর:


28

স্টোরেজ malloc দ্বারা তিনি ফিরে () হল না শূন্য সক্রিয়া। কখনই ধরে নিবেন না।

আপনার পরীক্ষা প্রোগ্রামে, এটি কেবল একটি সাবলীল: আমি অনুমান করি যে malloc()সবেমাত্র একটি নতুন ব্লক বন্ধ হয়ে গেছে mmap(), তবে এটির উপরও নির্ভর করবেন না।

উদাহরণস্বরূপ, যদি আমি এইভাবে আমার মেশিনে আপনার প্রোগ্রামটি চালাই:

$ echo 'void __attribute__((constructor)) p(void){
    void *b = malloc(4444); memset(b, 4, 4444); free(b);
}' | cc -include stdlib.h -include string.h -xc - -shared -o pollute.so

$ LD_PRELOAD=./pollute.so ./your_program
a at 0x7ffd40d3aa60: 1256994848 21891 1256994464 21891 1087613792 32765 0 0
b at 0x55834c75d010: 67372036 67372036 67372036 67372036 67372036 67372036 67372036 67372036

আপনার দ্বিতীয় উদাহরণটি কেবল গ্লিবিসি-তে mallocবাস্তবায়নের একটি শৈল্পিকতা প্রকাশ করছে ; যদি আপনি সেই পুনরাবৃত্তিটি করেন malloc/ free8 টি বাইটের চেয়ে বড় বাফার দিয়ে থাকেন তবে আপনি পরিষ্কারভাবে দেখতে পাবেন যে কেবলমাত্র প্রথম 8 বাইট শূন্য রয়েছে, নীচের নমুনা কোডের মতো।

#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>

const size_t n = 4;
const size_t m = 0x10;

int main()
{
    for (size_t i = n; i; --i) {
        int *const p = malloc(m*sizeof(int));
        printf("%p ", p);
        for (size_t j = 0; j < m; ++j) {
            printf("%d:", p[j]);
            ++p[j];
            printf("%d ", p[j]);
        }
        free(p);
        printf("\n");
    }
    return 0;
}

আউটপুট:

0x55be12864010 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 0:1 
0x55be12864010 0:1 0:1 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 1:2 
0x55be12864010 0:1 0:1 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 2:3 
0x55be12864010 0:1 0:1 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4 3:4

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

19
আমি আপনাকে খুশী করে আমি হাসি তবে আপনার অনুমান এবং কুসংস্কার মোটেও মজার নয়। একটি "আধুনিক জিএনইউ / লিনাক্স সিস্টেম" এ, বাইনারিগুলি সাধারণত একটি ডায়নামিক লিঙ্কার দ্বারা লোড করা হয়, যা আপনার প্রোগ্রাম থেকে মূল () ফাংশনে যাওয়ার আগে ডায়নামিক লাইব্রেরি থেকে কনস্ট্রাক্টর চালিত হয়। আপনার খুব ডেবিয়ান জিএনইউ / লিনাক্স 9 সিস্টেমে, কোনও প্রিললোডেড লাইব্রেরি না ব্যবহার করার পরেও, আপনার প্রোগ্রাম থেকে মূল () ফাংশনের আগে ম্যালোক () এবং ফ্রি () উভয়ই একাধিকবার ডাকা হবে।
মস্কি

23

স্ট্যাকটি কীভাবে শুরু করা হয় তা নির্বিশেষে, আপনি কোনও প্রাচীন স্ট্যাকটি দেখছেন না, কারণ সি লাইব্রেরি কল করার আগে বেশ কয়েকটি কাজ করে mainএবং তারা স্ট্যাকটি স্পর্শ করে।

জিএনইউ সি লাইব্রেরির সাথে, x86-64 এ, এক্সিকিউশনটি _ স্টার্ট এন্ট্রি পয়েন্টে শুরু হয় , যা __libc_start_mainজিনিসগুলি সেট আপ করার জন্য ডাকে, এবং শেষটি কলিং শেষ হয় mainmainকল করার আগে , এটি বেশ কয়েকটি অন্যান্য ফাংশন কল করে, যার ফলে স্ট্যাকের জন্য বিভিন্ন টুকরো ডেটা লেখা হয়। স্ট্যাকের বিষয়বস্তু ফাংশন কলগুলির মধ্যে পরিষ্কার করা হয় না, সুতরাং আপনি যখন প্রবেশ করবেন তখন mainআপনার স্ট্যাকটিতে পূর্ববর্তী ফাংশন কলগুলির বাম অংশ রয়েছে।

এটি কেবল স্ট্যাক থেকে প্রাপ্ত ফলাফলগুলি ব্যাখ্যা করে, আপনার সাধারণ পদ্ধতির এবং অনুমান সম্পর্কিত অন্যান্য উত্তরগুলি দেখুন।


নোট করুন যে সময়ের main()মধ্যে, আরম্ভের রুটিনগুলি খুব ভালভাবে পরিবর্তিত মেমরি দ্বারা ফিরে আসতে পারে malloc()- বিশেষত যদি সি ++ লাইব্রেরিগুলি সংযুক্ত থাকে। "গাদা" যে কোনও কিছুর সাথে আরম্ভ হয় তা ধরে নেওয়া সত্যই একটি খারাপ ধারণা।
অ্যান্ড্রু হেনেল

আপনার উত্তর একসাথে মোসভির সাথে আমার প্রশ্ন মীমাংসা করে। দুর্ভাগ্যক্রমে সিস্টেমটি আমাকে দুজনের মধ্যে একটিরই গ্রহণ করতে দেয় ; অন্যথায়, আমি উভয় গ্রহণ করতে হবে।
thb

18

উভয় ক্ষেত্রেই, আপনি অবিচ্ছিন্ন মেমরি পেয়ে যান এবং আপনি এর বিষয়বস্তু সম্পর্কে কোনও অনুমান করতে পারবেন না।

যখন ওএসটিকে আপনার প্রক্রিয়াতে একটি নতুন পৃষ্ঠা ভাগ করতে হবে (এটি তার স্ট্যাকের জন্য বা ব্যবহৃত আখড়ার জন্য হোক malloc()), এটি গ্যারান্টি দেয় যে এটি অন্যান্য প্রক্রিয়া থেকে ডেটা প্রকাশ করবে না; এটি নিশ্চিত করার স্বাভাবিক উপায়টি হ'ল এটি জিরো দিয়ে পূরণ করা (তবে এটি কোনও পৃষ্ঠা মূল্য সহ অন্য যে কোনও কিছুতে ওভাররাইট করা সমান বৈধ valid/dev/urandom - আসলে কিছু ডিবাগিং malloc()বাস্তবায়ন যেমন আপনার নিজের মতো ভুল অনুমানগুলি ধরার জন্য নন-শূন্য নিদর্শনগুলি লিখে)।

যদি malloc()এই প্রক্রিয়াটির দ্বারা ইতিমধ্যে ব্যবহৃত এবং প্রকাশিত মেমরির অনুরোধটি পূরণ করতে পারে তবে এর বিষয়বস্তু সাফ হবে না (প্রকৃতপক্ষে, ক্লিয়ারিংটি কিছুই করার malloc()নয় এবং এটি হতে পারে না) - মেমরিটিকে ম্যাপ করার আগে এটি ঘটতে হবে আপনার ঠিকানার স্থান)। আপনি ইতিমধ্যে আপনার প্রক্রিয়া / প্রোগ্রাম দ্বারা লিখিত মেমরি পেতে পারেন (যেমন আগে main())।

আপনার উদাহরণ প্রোগ্রামে, আপনি একটি malloc() অঞ্চল যা এখনও এই প্রক্রিয়াটি দ্বারা লিখিত হয়নি (যেমন এটি একটি নতুন পৃষ্ঠা থেকে সরাসরি) এবং একটি স্ট্যাক যা ( main()আপনার প্রোগ্রামের প্রাক- কোড দ্বারা) লিখেছিল । আপনি যদি স্ট্যাকের আরও কিছু পরীক্ষা করেন তবে দেখতে পাবেন এটি আরও নিচে শূন্যে ভরা হবে (বাড়ার দিকের দিকে)।

ওএস স্তরে কী হচ্ছে তা যদি আপনি সত্যিই বুঝতে চান তবে আমি আপনাকে সুপারিশ করি যে আপনি সি লাইব্রেরি স্তরটি বাইপাস করুন এবং সিস্টেম কলগুলি brk()এবং এর mmap()পরিবর্তে এর মাধ্যমে ইন্টারেক্ট করুন।


1
এক সপ্তাহ বা দু'বার আগে, আমি বারবার ফোন করে malloc()এবং free()বারবার চেষ্টা করেছি experiment যদিও কিছুই malloc()পরীক্ষা-নিরীক্ষায় সম্প্রতি মুক্ত করা একই স্টোরেজটির পুনঃব্যবহারের প্রয়োজন হয় নি , malloc()তা ঘটায়। প্রতিবার একই ঠিকানাটি ফিরে আসার ঘটনা ঘটেছিল, তবে প্রতিবারই স্মৃতিটিকে নীল করে দেয় যা আমি প্রত্যাশা করি নি। এটি আমার কাছে আকর্ষণীয় ছিল। আরও পরীক্ষাগুলি আজকের প্রশ্নের দিকে নিয়ে গেছে।
thb

1
@ থ্যাব, সম্ভবত আমি যথেষ্ট পরিষ্কার করছি না - বেশিরভাগ বাস্তবায়ন তারা আপনাকে যে স্মৃতি দিয়ে থাকে তার সাথে malloc()একেবারেই কিছুই করেনা - এটি হয় পূর্বে ব্যবহৃত, বা নতুনভাবে নির্ধারিত (এবং এটি ওএস দ্বারা শূন্য)। আপনার পরীক্ষায়, আপনি সম্ভবত পরবর্তীটি পেয়েছিলেন। একইভাবে, স্ট্যাক মেমরিটি আপনার প্রক্রিয়াটি সাফ অবস্থায় পাওয়া যায়, তবে আপনার প্রক্রিয়াটি এখনও স্পর্শ করেনি এমন অংশগুলি দেখার জন্য আপনি এটি এতদূর পরীক্ষা করে দেখেন না। আপনার স্ট্যাক মেমরির হয় এটি আপনার প্রক্রিয়া দেওয়া সাফ করা হয়েছে।
টবি স্পিড

2
@ টবিস্পাইট: এমআরএমপি দ্বারা ব্র্যাক এবং এসবিআরকে অপ্রচলিত। pubs.opengroup.org/onlinepubs/7908799/xsh/brk.html শীর্ষে LEGACY বলছেন।
জোশুয়া

2
আপনার যদি প্রাথমিক মেমরির প্রয়োজন হয় callocতবে এটি বিকল্পের পরিবর্তে (পরিবর্তে memset) হতে পারে
উপস্থাপিত

2
@ থ্যাব এবং টবি: মজাদার ঘটনা: কার্নেল থেকে নতুন পৃষ্ঠাগুলি প্রায়শই অলসভাবে বরাদ্দ করা হয়, এবং কেবল ভাগ করা শূন্য পৃষ্ঠায় কপিরাইট অন লিখিত ম্যাপ করা হয়। mmap(MAP_ANONYMOUS)যদি আপনি MAP_POPULATEপাশাপাশি না ব্যবহার করেন তবে এটির জন্য ঘটে । নতুন স্ট্যাক পৃষ্ঠাগুলি প্রত্যাশিতভাবে তাজা শারীরিক পৃষ্ঠাগুলি দ্বারা সমর্থনযুক্ত এবং তারযুক্ত (হার্ডওয়্যার পৃষ্ঠার টেবিলগুলিতে ম্যাপযুক্ত, পাশাপাশি কার্নেলের পয়েন্টার / ম্যাপিংয়ের দৈর্ঘের তালিকাগুলি) বাড়ার সময়, কারণ প্রথমবার স্পর্শ করার সময় সাধারণত নতুন স্ট্যাক মেমরি লেখা হয় । তবে হ্যাঁ, কার্নেলকে অবশ্যই কোনওভাবে ডেটা ফাঁস করা এড়ানো উচিত এবং জিরোয়িংটি সস্তার এবং সবচেয়ে দরকারী।
পিটার কর্ডস

9

আপনার ভিত্তি ভুল।

আপনি 'সুরক্ষা' হিসাবে যা বর্ণনা করেন তা সত্যই গোপনীয়তা , যার অর্থ এই প্রক্রিয়াগুলির মধ্যে স্পষ্টভাবে ভাগ না করা পর্যন্ত কোনও প্রক্রিয়া অন্য প্রক্রিয়া মেমরিটি পড়তে পারে না। কোনও অপারেটিং সিস্টেমে এটি সহবর্তী ক্রিয়াকলাপগুলি বা প্রক্রিয়াগুলির বিচ্ছিন্নতার একটি দিক ।

অপারেটিং সিস্টেমটি এই বিচ্ছিন্নতাটি নিশ্চিত করার জন্য যা করছে, তা যখনই প্রক্রিয়াটির দ্বারা গাদা বা স্ট্যাক বরাদ্দের জন্য মেমরির অনুরোধ করা হয় তখনই এই স্মৃতিটি শারীরিক স্মৃতিতে এমন একটি অঞ্চল থেকে আসে যা ভরা শূন্যে ভরা হয়, বা এটি যে আবর্জনায় পূর্ণ হয় একই প্রক্রিয়া থেকে আসছে ।

এটি নিশ্চিত করে যে আপনি কেবল জিরো, বা আপনার নিজের জাঙ্ক দেখছেন তাই গোপনীয়তা নিশ্চিত করা হয় এবং উভয় স্তূপ এবং স্ট্যাক 'সুরক্ষিত', যদিও প্রাথমিকভাবে শূন্য করা হয়নি।

আপনি আপনার পরিমাপের মধ্যে খুব বেশি পড়ছেন।


1
প্রশ্নের আপডেট বিভাগ এখন আপনার আলোকিত উত্তরটি স্পষ্টভাবে উল্লেখ করেছে।
thb
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.