3 / 6 tamamlandı
görev 3 · ~30 dk

Tek karakterlik gizli kapı

Linux, 2003 — = ile == arasındaki fark bir sistemi ele geçirmeye yetiyordu

hedef

= ile == karışınca, hiçbir şey olmuyor gibi görünürken neler olabileceğini görmek.

Ne oldu?

Kasım 2003. Linux — dünyada milyonlarca sunucunun, bugün de çoğu telefonun temelinde çalışan işletim sistemi çekirdeği.

Biri, Linux'un kaynak kodunun bir kopyasına iki satırlık bir değişiklik soktu. İlk bakışta sıradan bir hata kontrolüne benziyordu: "şu iki şart birden doğruysa, isteği reddet."

Ama satırın içinde, == olması gereken yerde tek bir = vardı.

Unix tabanlı sistemlerde en yetkili kullanıcının — her şeyi yapabilen yöneticinin — numarası 0'dır. O tek karakter, isteği yapan kullanıcının numarasını sessizce 0 yapıyordu.

Yani belirli, kimsenin normalde kullanmayacağı bir şekilde çağrıldığında, sıradan bir kullanıcı sistemin sahibi oluyordu.

Nasıl yakalandı?

Kodu satır satır okuyan biri bulmadı. Linux geliştiricileri, bu değişikliğin normal yoldan gelmediğini fark etti — her değişikliğin bir kaydı olması gerekiyordu, bunun yoktu. Değişiklik incelendi, gizli kapı bulundu ve hiçbir zaman yayınlanan bir sürüme girmedi.

Senin kartında

Kodun dili Görev 4'te if (x = 5) yazınca şartın hep doğru çıktığını görmüştün. Şimdi tersini göreceksin: = 0 yazınca şart hep yanlış çıkıyor.

Ve "hep yanlış" çok daha sinsi — çünkü hiçbir şey olmuyor gibi görünüyor.

kod · .ino
const int YONETICI = 0;      // en yetkili kullanicinin numarasi
const int MISAFIR  = 1000;

int yetki = MISAFIR;

void istekKontrol(int istek) {
  if ((istek == 7) && (yetki = YONETICI)) {
    Serial.println("Gecersiz istek, reddedildi.");
  }
}

void setup() {
  Serial.begin(9600);

  Serial.print("Once yetki:  ");
  Serial.println(yetki);

  istekKontrol(3);   // normal bir istek
  istekKontrol(7);   // "gizli kapiyi calan" istek

  Serial.print("Sonra yetki: ");
  Serial.println(yetki);
}

void loop() {
}

Çalıştı mı?

kod
Once yetki:  1000
Sonra yetki: 0

İki şeye dikkat et.

"Geçersiz istek" yazısı hiç çıkmadı. Ekran tamamen sakin. Kod hiçbir şey yapmamış gibi görünüyor.

Ama yetki 1000'den 0'a düştü. Misafir artık yönetici.

Neden? (yetki = YONETICI) bir soru değil, bir emir: "yetkiye 0 koy." Ve bu emrin değeri, koyduğu sayının kendisi — yani 0. C dilinde 0 "yanlış" demek. Şart yanlış çıkıyor, if'in içi çalışmıyor, hiçbir şey yazılmıyor.

Ama emir çoktan yerine getirildi.

Şimdi sen yaz

İki adım.

1. Düzelt. Gizli kapıyı kapat.

2. Bir daha olmasın. Aynı hatayı yanlışlıkla yapsan bile derleyicinin seni durduracağı bir yazım şekli bul.

kod · .ino
  // ŞİMDİ SEN YAZ:
  // 1) yetki = YONETICI  satirini dogru karsilastirmaya cevir.
  // 2) Sabiti sola al: derleyici seni korusun.
🔍 İpucu 1

Birinci adım: = bir şey koyar, == sorar. Burada sormak istiyorsun.

🔍 İpucu 2

İkinci adım: YONETICI bir sabit (const). Bir sabitin içine bir şey koyamazsın. Peki YONETICI = yetki yazarsan derleyici ne der?

✅ Cevap

Düzeltilmiş hali:

kod · .ino
  if ((istek == 7) && (yetki == YONETICI)) {

Ve korumalı yazım — sabiti sola alırsın:

kod · .ino
  if ((7 == istek) && (YONETICI == yetki)) {

Bu ikinci yazımda yanlışlıkla YONETICI = yetki yazarsan kod derlenmez. Bir sabite bir şey koyamazsın, derleyici seni hemen durdurur. Hata, kart çalışmadan önce yakalanır.

Bazı programcılar bu yazımı sever, bazıları okunmasını garip bulur. Ama arkasındaki fikir değerli: hatayı yapmamaya güvenmek yerine, hatayı yapılamaz hale getir.

📄 Görevin tam kodu
kod · .ino
const int YONETICI = 0;
const int MISAFIR  = 1000;

int yetki = MISAFIR;

void istekKontrol(int istek) {
  if ((7 == istek) && (YONETICI == yetki)) {
    Serial.println("Gecersiz istek, reddedildi.");
  }
}

void setup() {
  Serial.begin(9600);

  Serial.print("Once yetki:  ");
  Serial.println(yetki);

  istekKontrol(3);
  istekKontrol(7);

  Serial.print("Sonra yetki: ");
  Serial.println(yetki);
}

void loop() {
}

Artık yetki iki satırda da 1000.

Derleyici neden uyarmadı?

Arduino IDE'de Dosya → Tercihler → Derleyici uyarıları ayarını Tümü yap ve şunu dene:

kod · .ino
  if (yetki = YONETICI) {

Derleyici uyarır: suggest parentheses around assignment used as truth value — "şart olarak kullanılan bir atama var, emin misin?"

Şimdi aynı satırı Linux'taki gibi yaz:

kod · .ino
  if ((istek == 7) && (yetki = YONETICI)) {

Bu sefer uyarı yok. Derleyiciler, parantez içine alınmış bir atamayı genelde "bunu bilerek yaptın" diye kabul eder ve sesini çıkarmaz.

Linux'taki satır da tam olarak böyle, parantez içinde yazılmıştı.

Olmadıysa

Ne görüyorsun Ne yap
Yetki zaten başta 0 int yetki = MISAFIR; satırını kontrol et
"Geçersiz istek" yazısı çıkıyor YONETICI değerini 0 dışında bir şey yapmışsın. Deney 0 ile çalışıyor
Korumalı yazımda derleme hatası Bu doğru! YONETICI = yetki yazmışsın, derleyici seni yakaladı. == yap
Derleyici uyarısı hiç görünmüyor Uyarı ayarı "Tümü" mü? Uyarılar turuncu yazıyla, hataların üstünde çıkar

Kendini test et

Soru: Bu gizli kapıyı bulan kişi, kodu satır satır okuyup tek karakteri görmedi. Peki nasıl buldular?

Cevabı gör

Süreç sayesinde. Linux'ta her değişikliğin nereden geldiğinin bir kaydı tutulur. Bu değişikliğin kaydı yoktu — normal yoldan gelmemişti. Bir şeylerin yanlış olduğunu kod değil, kayıt söyledi.

Bu önemli bir ders. Tek bir karakteri gözle bulmak çok zor; en dikkatli insan bile kaçırabilir. İyi sistemler, kimsenin hata yapmayacağına güvenmez. Hatayı yakalayacak bir adım koyar: kayıt, inceleme, test, derleyici uyarısı.

Sabiti sola alarak yazmak da aynı fikrin küçük bir hali: kendine güvenme, hatayı yakalayacak bir mekanizma kur.

Bu hata nerede karşına çıkar

Ev güvenlik kitinde kart okuyucu, okunan kartın yetkili olup olmadığına karar veriyor. Orada bir == yerine = yazsaydın, kilidin ya herkese açılırdı ya da hiç kimseye — ve ekranda hiçbir uyarı görmezdin.


Takıldın, hata tablosu da yetmedi mi?

WhatsApp'tan sor — hangi görevdesin, ekranda ne yazıyor, devrenin fotoğrafı.