პროგრამირების სამყაროში გავრცელებული მოსაზრებაა, რომ თუ კომპილატორს ერთსა და იმავე კოდს მიაწვდით, შედეგად იდენტურ ბინარულ ფაილს მიიღებთ. თუმცა, რეალობა ბევრად უფრო კომპლექსურია. Anubis-ის პროექტზე მუშაობისას ავტორი სწორედ ამ პრობლემის წინაშე აღმოჩნდა.
პროექტის მიზანია WebAssembly-ზე დაფუძნებული უსაფრთხოების მექანიზმების დანერგვა. იმისთვის, რომ კლიენტსა და სერვერს შორის ლოგიკა სინქრონში იყოს, ავტორმა გადაწყვიტა WebAssembly-ის JavaScript-ად გარდაქმნა, რაც სისტემას უფრო მოქნილს გახდიდა.
რატომ არის რეპროდუცირებადი ბილდები რთული?
თეორიულად, კომპილატორი დეტერმინისტული ფუნქციაა. პრაქტიკაში კი, ისეთი დეტალები, როგორიცაა __DATE__ და __TIME__ მაკროები, ბინარულ ფაილში კომპილაციის დროს აფიქსირებს. შედეგად, მიუხედავად იდენტური წყარო კოდისა, გამომავალი ფაილები განსხვავებულია.
კიდევ ერთი პრობლემა wasm-opt-ის ვერსიებთან იყო დაკავშირებული. Clang-ის კომპილატორი ფონურ რეჟიმში იყენებს ამ ხელსაწყოს ოპტიმიზაციისთვის. თუ სისტემაში დაყენებული ვერსია მოძველებულია, ბილდი ავტომატურად იშლება. ავტორს მოუწია --no-wasm-opt პარამეტრის გამოყენება, რათა თავიდან აეცილებინა შეუთავსებლობა.
მისამართების განლაგება და არაპროგნოზირებადი შედეგი
აღმოჩნდა, რომ Clang-ის მიერ გამოყენებული გამონაკლისების დამუშავების მექანიზმები მეხსიერების მისამართებზეა დამოკიდებული. ეს იწვევს იმას, რომ ბინარული ფაილი ყოველ ჯერზე დაახლოებით 29 ბაიტით განსხვავდება წინა ვერსიისგან. ეს განსხვავება დაფიქსირდა როგორც x86_64, ისე arm64 არქიტექტურებზე.
პრობლემის გადასაჭრელად ავტორმა ორი ნაბიჯი გადადგა:
- გამოიყენა setarch --addr-no-randomize მისამართების რანდომიზაციის გასათიშად.
- შექმნა დამოწმებული SHA256 ჰეშები კონკრეტული არქიტექტურებისთვის, რათა უზრუნველყოფილი იყოს ბილდის სანდოობა.
მიუხედავად იმისა, რომ სრული არქიტექტურათაშორისი რეპროდუცირება ამ ეტაპზე ვერ მოხერხდა, მიღწეულია დეტერმინისტული შედეგი ცალკეულ პლატფორმებზე, რაც პროექტის სტაბილურობისთვის საკმარისია.





დისკუსია
0 კომენტარი
ჯერ კომენტარი არ არის — იყავი პირველი.