DedSec Project

C: έλεγχος ορίων εισόδου και δεσμεύσεων μνήμης — DedSec Project

Στη C ο έλεγχος μήκους προηγείται κάθε αντιγραφής Μην εμπιστεύεσαι αυθαίρετα τη χωρητικότητα Ένα buffer έχει πραγματικό μέγεθος ανεξάρτητο από το μήκος της εισόδου. Πριν την αντιγραφή…

Στη C ο έλεγχος μήκους προηγείται κάθε αντιγραφής

Μην εμπιστεύεσαι αυθαίρετα τη χωρητικότητα

Ένα buffer έχει πραγματικό μέγεθος ανεξάρτητο από το μήκος της εισόδου. Πριν την αντιγραφή μέτρησε bytes, κράτησε θέση για το τελικό NUL και απόρριψε οτιδήποτε δεν χωράει. Συνάρτηση που δεν γνωρίζει capacity δεν μπορεί να επιβάλει σωστό όριο. Επίσης το άθροισμα μήκους και τερματιστή δεν πρέπει να υπερχειλίζει.

#include <stdio.h>
#include <string.h>
int copy_label(char dst[static 8], const char *src) {
    size_t n = strlen(src);
    if (n >= 8) return -1;
    memcpy(dst, src, n + 1);
    return 0;
}
int main(void) {
    char label[8];
    if (copy_label(label, "sample") != 0) return 1;
    puts(label);
    return 0;
}

Σημαντική προϋπόθεση

Η strlen() λειτουργεί σωστά μόνο αν το src είναι έγκυρη ακολουθία που τελειώνει σε NUL. Δεν την εφαρμόζουμε σε αυθαίρετα bytes αρχείου ή πακέτου δικτύου χωρίς terminator. Σε τέτοιες εισόδους χρειαζόμαστε explicit length και bounded parser. Το buffer των οκτώ bytes χωρά έως επτά κανονικούς χαρακτήρες.

Μεταγλώττιση και διαγνωστικά

Ενεργοποίησε compiler warnings και, όπου υπάρχει, sanitizers σε δικό σου δοκιμαστικό πρόγραμμα. Η απουσία αναφοράς sanitizer δεν εγγυάται ασφάλεια για κάθε είσοδο. Δοκίμασε μήκη επτά και οκτώ χαρακτήρων καθώς και κενό string και κατάγραψε ακριβείς κωδικούς επιστροφής.

Επέκταση API

Άλλαξε τη συνάρτηση ώστε να δέχεται destination capacity ως όρισμα αντί να έχει σταθερό οκτώ. Περιέγραψε τι πρέπει να γίνει αν η χωρητικότητα είναι μηδέν. Η σιωπηρή περικοπή δεδομένων είναι αποδεκτή μόνο αν έχει οριστεί ρητά από τις απαιτήσεις.

Ανάλυση ακέραιου χωρίς αποδοχή μόνο έγκυρου προθέματος

Η αριθμητική μετατροπή μπορεί να καταναλώσει έγκυρο πρόθεμα αφήνοντας ξένα bytes. Η αποδοχή του 12junk ως 12 είναι λάθος όταν όλο το πεδίο πρέπει να είναι αριθμός. Έλεγξε αν καταναλώθηκαν χαρακτήρες, τον τελικό δείκτη, σφάλματα εύρους και το μικρότερο πεδίο τιμών εφαρμογής πριν στενότερη μετατροπή.

Το παράδειγμα δέχεται μόνο μη προσημασμένα δεκαδικά ψηφία, απορρίπτει αρχικά κενά και πρόσημα και εφαρμόζει όριο 0–1000. Το εύρος μετατροπής της βιβλιοθήκης και το επιτρεπόμενο εύρος εφαρμογής είναι διαφορετικά συμβόλαια. Ένας περιορισμένος buffer δεν επικυρώνει το νόημα των περιεχομένων του.

#include <assert.h>
#include <errno.h>
#include <stdlib.h>
static int parse(const char *s, long *out) {
    if (!*s) return 0;
    for (const char *p=s; *p; ++p) if (*p<'0' || *p>'9') return 0;
    errno=0; char *end; long value=strtol(s,&end,10);
    if (errno==ERANGE || *end || value>1000) return 0;
    *out=value; return 1;
}
int main(void) { long x; assert(parse("12",&x)&&x==12); assert(!parse("12junk",&x)); assert(!parse("-1",&x)); assert(!parse("1001",&x)); }

Πρόσθεσε κενή συμβολοσειρά, πολλά ψηφία και την οριακή τιμή 1000. Απόφυγε σύνταξη εξαρτώμενη από τοπικές ρυθμίσεις σε πρωτόκολλο εκτός αν προβλέπεται. Μη μετατρέπεις long σε int πριν ελέγξεις το επιθυμητό εύρος.

Τεχνική αναφορά