web-dev-qa-db-fra.com

Protection de l'espace mémoire de l'ancien système d'exploitation - était-ce vraiment si mauvais?

Dans son livre Security Engineering, Anderson se concentre vraiment sur la façon dont les programmes des années 90 et du début des années 2000 auraient besoin d'accéder à une mémoire qui n'était pas la leur, et les programmeurs programmaient en supposant que le programme serait exécuté avec des privilèges administratifs:

Le dernier système Microsoft, Vista, essaie de s'éloigner de l'exécution de tout le code avec des privilèges d'administrateur, et ces trois techniques modernes tentent chacune, indépendamment, de réaliser la même chose - pour nous ramener où nous serions si toutes les applications avaient pour s'exécuter avec des privilèges utilisateur plutôt qu'en tant qu'administrateur. C'est plus ou moins là où l'informatique était dans les années 1970, lorsque les gens exécutaient leur code en tant que processus non privilégiés sur des mini-ordinateurs et des mainframes partagés en temps. Seul le temps dira si nous pouvons reprendre l'Eden perdu de l'ordre et du contrôle ..., et pour échapper à la réalité désordonnée d'aujourd'hui ... mais certainement la tentative vaut la peine d'être faite.

En particulier cette citation

Les PC ont un héritage malheureux, en ce sens que les anciens systèmes d'exploitation mono-utilisateur tels que DOS et Win95/98 permettent à n'importe quel processus de modifier toutes les données; par conséquent, de nombreuses applications ne s'exécuteront que si elles sont exécutées avec des privilèges d'administrateur et donc autorisées à accéder à l'ensemble de la machine.

Est-ce à dire que des idées comme celles-ci , où vous pouvez attribuer n'importe quelle adresse à un pointeur et avoir accès à la mémoire fonctionnerait sous Windows 95/98? Pourquoi le concevraient-ils de cette façon comme quel serait l'avantage de lire la mémoire d'autres programmes (ou d'y écrire!)?

int * firefoxmemory = (char*) 0x11111111 //this is just an example of address.
*firefoxmemory = 200;//screw firefox
52
Celeritas

Isolement de la mémoire

Votre exemple ne fonctionnerait pas sur Windows 95, mais il fonctionnait sur DOS et Windows jusqu'à 3.11 (pas Windows NT).

L'architecture du PC et la série de systèmes d'exploitation Microsoft ont commencé avec processeur Intel 8086 et un système d'exploitation ( DOS ) conçu pour exécuter un seul programme à la fois. Vous exécuteriez un programme, et lorsque vous en auriez fini, vous le quitteriez, donc les données d'écrasement d'un autre processus n'étaient pas vraiment un problème. (Vous pourriez avoir programmes qui sont restés en mémoire après la fermeture ; ils faisaient essentiellement partie du système d'exploitation.)

Le processeur Intel 80386 a changé la donne en étant le premier de sa lignée à avoir un nité de gestion de la mémoire (MMU) . Un MMU est un composant matériel qui fournit mémoire virtuelle en traduisant des adresses virtuelles (pointeurs dans un programme) en adresses physiques (emplacements réels dans la RAM¹). Windows 95 était le premier de sa lignée à en profiter: chaque application Windows 95 s'exécutait avec sa propre configuration MMU, de sorte que *firefoxmemory pointerait soit vers le propre espace d'adressage du programme (auquel cas toute mauvaise action ne pourrait affecter que ce programme), soit ne pointerait pas du tout (dans ce cas, le programme - et non l'ensemble du système - planterait).

Windows 3.0–3.11 a profité de certaines des nouveautés du 386, mais ils ont exécuté toutes les applications dans le même espace d'adressage. Cela était dû à plusieurs facteurs:

  • une exigence pour garder les anciennes applications Windows 1.x/2.x en cours d'exécution (elles ont été conçues pour fonctionner sur du matériel à espace d'adressage unique, et beaucoup en ont profité pour fouiller dans les internes du système d'exploitation pour réaliser des choses qui n'étaient pas possibles grâce à des documents interfaces);
  • manque de temps de développement pour repenser l'ensemble du système d'exploitation basé sur une architecture complètement différente;
  • une exigence pour fonctionner sur des ordinateurs qui avaient peu de RAM: garder les applications isolées coûte plus de mémoire sur une échelle de 2 Mo ou 4 Mo (parce que les données doivent être copiées entre les programmes et parce que le système d'exploitation doit garder une trace de toutes les interactions de programme permettre aux applications de communiquer et réguler la communication).

Ce n'était pas tant que le système d'exploitation a été explicitement conçu pour permettre aux programmes d'accéder à la mémoire de l'autre, mais qu'il n'y avait aucun moyen de l'empêcher. Lorsque les moyens de l'empêcher sont devenus abordables, il a fallu quelques versions de système d'exploitation pour en profiter.

Par exemple, considérons une fonctionnalité telle que le copier-coller inter-programme (presse-papiers). Si vous n'avez pas d'isolement de la mémoire, cela peut être implémenté en demandant au programme source de conserver une copie des données dans sa propre mémoire; lorsque les données sont collées dans un autre programme, cet autre programme copie les données directement à partir du programme source. La seule chose dont le système d'exploitation a besoin pour suivre est à qui appartient actuellement le presse-papiers. Si la mémoire des applications est isolée, le système d'exploitation doit organiser la copie des données et éventuellement stocker une copie des données indépendamment de l'application source. Cela nécessite plus de travail de développement pour écrire ce code, et plus de ressources pour stocker ce code en mémoire et l'exécuter.

J'ai simplifié un certain nombre de choses ici; pour en savoir plus sur la façon dont un système d'exploitation utilise un MMU pour isoler les applications, vous pouvez lire Comment le noyau peut empêcher un programme malveillant de fonctionner? , Comment deux adresses virtuelles identiques peuvent-elles pointer vers des adresses physiques différentes? , Est-il possible de prendre en charge plusieurs processus sans prise en charge de la mémoire virtuelle? (ils sont orientés Unix mais les principes s'appliquent à Windows ou à tout autre OS que vous êtes susceptible de rencontrer sur un PC).

Isolement des privilèges

Dans ce passage, Anderson n'est pas réellement une discussion sur l'isolement de la mémoire, mais sur l'isolement des privilèges, où un programme en cours d'exécution ne peut pas affecter certaines parties du système. L'isolement de la mémoire est nécessaire, mais pas suffisant. Le système d'exploitation doit également contrôler la façon dont les processus interagissent, contrôler les fichiers qu'ils ouvrent, etc. Même avec chaque application s'exécutant dans son propre espace mémoire, les applications peuvent interagir. L'isolement de la mémoire oblige simplement les applications à utiliser les services du système d'exploitation (via appels système vers un noya qui peut accéder à toute la mémoire) pour interagir.

La série de systèmes d'exploitation Windows 1.x/3.x/9x/ME a été conçue comme un système d'exploitation mono-utilisateur et n'a pas isolé les applications. L'isolement de la mémoire a été ajouté dans Windows 95, mais uniquement pour améliorer la stabilité, pas pour mettre en œuvre des restrictions de sécurité. Ces systèmes d'exploitation n'ont aucune restriction de sécurité: si vous avez exécuté un programme sur votre machine, il est autorisé à tout faire. (Ceci est bien sûr utile aux auteurs de virus.) L'espace mémoire est isolé, mais pas l'espace fichier.

La série de systèmes d'exploitation Windows NT/2000/XP /…, comme les systèmes d'exploitation de la famille Unix, a été conçue comme un système d'exploitation multi-utilisateurs, ce qui introduit un objectif de sécurité de base: ce qu'un utilisateur fait ne doit pas nuire à ce que les autres utilisateurs peut faire. Ainsi, le système d'exploitation doit faire respecter, par exemple, que les programmes exécutés par Alice ne peuvent pas interagir avec les programmes exécutés par Bob, ne peuvent pas modifier les fichiers de Bob, etc. Les programmes et les données qui font partie du système d'exploitation concernent chaque utilisateur et doivent donc être protégés contre tous les utilisateurs. (Bien sûr, certaines interactions sont autorisées par une autorisation explicite, par exemple, un serveur réseau traite les demandes qu'il reçoit du réseau, Bob peut modifier les autorisations d'un fichier pour qu'il soit accessible en écriture par d'autres, certains utilisateurs bénéficient de privilèges administratifs et peuvent donc modifier le fonctionnement système, etc.)

Un grand nombre d'applications ont été écrites pour cibler Windows 9x, qui n'avait aucune restriction de sécurité. Ils ont donc pris des libertés telles que l'écriture dans le répertoire du système d'exploitation (sous Windows 95, la copie du fichier dans le répertoire Windows était la manière normale d'installer une bibliothèque partagée). Une grande partie de ce que font ces applications a été considérée comme quelque peu désordonnée, même par les normes de l'époque, mais cela a fonctionné pour que les gens le fassent. Les versions de Windows de la série NT (qui incluent toutes les versions depuis XP) ont nécessairement cassé certaines de ces applications, bien que Microsoft ait ajouté un certain nombre de solutions de contournement (comme prétendre que l'écriture d'un fichier dans un répertoire partagé a réussi, mais en réalité l'écrire dans un répertoire spécifique à l'utilisateur).

Windows XP a forcé l'isolement des utilisateurs, mais la plupart des installations n'en profitaient pas: de nombreuses installations avaient simplement l'utilisateur comme administrateur, donc tous les programmes qu'ils exécutaient avaient les privilèges de faire à peu près n'importe quoi Il y avait deux raisons principales à cela:

  • Il permet aux applications héritées mal comportées de s'exécuter. Alors que la plupart de ces applications ne sont utilisées que par une petite proportion d'utilisateurs, de nombreux utilisateurs exécutent de telles applications et cela prend beaucoup de temps et un effort énorme pour les renouveler toutes.
  • L'introduction de privilèges signifie que parfois l'utilisateur sera informé que quelque chose ne peut pas être fait en raison d'un manque de privilèges. Soyez témoin des plaintes concernant Vista, selon lesquelles il continuerait d'afficher ces invites d'élévation de privilèges.

Isolement des applications

Si vous êtes assez jeune pour avoir découvert des ordinateurs via des appareils portables, vous pouvez être habitué à un modèle d'isolement centré sur les applications plutôt que sur les utilisateurs. Dans le modèle Unix et Windows, les données d'Alice sont protégées contre Bob. Les applications sont neutres dans le modèle de sécurité: elles s'exécutent simplement sous l'identité de l'utilisateur connecté. Cela signifie que le code d'application doit être approuvé pour ne pas se comporter mal.

Windows a traditionnellement fait face aux applications qui se comportent mal en essayant de les détecter et de les contenir via logiciel antivirus . Ça ne marche pas trop bien. Les systèmes Unix, en particulier Linux, ont tendance à faire face en distribuant plus de logiciels via des canaux traçables desquels les logiciels malveillants sont éliminés.

Les systèmes d'exploitation conçus pour les appareils mobiles, en particulier iOS et Android, ne font pas confiance aux développeurs d'applications, les applications sont donc isolées; par exemple, chaque application a son propre espace fichier. Cela présente un avantage en termes de sécurité, mais également un coût important dans la mesure où il réduit ce que les applications peuvent faire. Les applications nécessitent des privilèges pour modifier le comportement du système d'exploitation (par exemple pour créer des raccourcis et plus généralement l'automatisation), vous ne pouvez pas facilement manipuler le même fichier dans différentes applications, vous ne pouvez pas facilement autoriser plusieurs applications à afficher des informations en même temps, etc. Ou, pour prendre un exemple plus dramatique, vous ne pouvez pas écrire un débogueur avec des privilèges restreints, car tout l'intérêt d'un débogueur est d'espionner et de perturber l'exécution de l'application en cours de débogage. Ce coût est la raison pour laquelle le modèle d'isolation des applications mobiles ne peut pas simplement être greffé sur un environnement PC.

Si l'on remonte à quelques années avant Windows, on s'attendait à peu près à ce que tout programme exécuté sur un micro-ordinateur "possède" l'ordinateur. S'il voulait que certains services restent utilisables, il devrait laisser certaines parties du système tranquilles, mais sinon il n'y avait pas vraiment besoin de "protéger" quoi que ce soit. Les ordinateurs centraux étaient suffisamment grands et coûteux pour que laisser un utilisateur monopoliser la machine soit impossible, et lorsque plusieurs personnes utilisaient une machine simultanément, il était nécessaire qu'elle puisse agir comme plusieurs ordinateurs indépendants qui ne perturberaient pas les opérations des autres, mais sur un micro-ordinateur, ce n'était pas un problème. Contrairement aux ordinateurs d'aujourd'hui qui ont tous des disques durs ou un stockage non volatile, les premiers micro-ordinateurs n'en avaient pas. Si vous éteignez et sauvegardez une machine, son état de mémoire sera effectivement réinitialisé aux paramètres d'usine. Allumez un Altair 680 et il attendra de recevoir un programme du port série au format S-record. Alimentez-le un tel programme (très probablement en utilisant un lecteur de bande papier) et il l'exécutera. En cas de problème, éteignez la machine et rechargez-la à partir du ruban de papier.

Lorsque les ordinateurs ont ajouté des lecteurs de disquette, les mêmes principes ont continué de s'appliquer. Ce n'est qu'après que les ordinateurs personnels ont obtenu des disques durs que les problèmes de sécurité ont commencé à devenir pertinents, mais de nombreuses techniques de programmation qui avaient du sens avec les disquettes ont continué à être utilisées parce qu'elles fonctionnaient.

12
supercat

Un exemple simple: Les capacités d'écriture d'écran DOS laissaient beaucoup à désirer. Il était courant d'écrire directement la mémoire vidéo. Vous deviez le faire pour obtenir des performances raisonnables pour tout ce qui fait beaucoup de mises à jour d'écran et c'était absolument essentiel si vous vouliez écrire la cellule en bas à droite de l'écran vidéo - par exemple, pour tracer une bordure autour de ce que vous montriez.

Dans les versions antérieures, il était également nécessaire d'écrire dans la mémoire du bloc de contrôle juste en face de votre programme si vous vouliez ouvrir beaucoup (plus de 16 ??) de fichiers. J'oublie quelle version a ajouté un appel OS pour accomplir la même chose.

5
Loren Pechtel

Pour développer la réponse MMU, tous les chipsets "ordinateur personnel" du début des années 80 ont commencé sans cette fonctionnalité. Il a un coût non nul dans la zone des puces et un retard dans la mémoire, un coût qui était beaucoup plus élevé à cette époque sur le processus de la puce de 3 µm. N'oubliez pas que nous pouvons adapter environ 20 000 transistors aujourd'hui dans l'espace d'un à l'époque.

Les 8086 et 68000 (tels qu'utilisés sur Mac et Amiga) n'avaient pas de MMU. Ils n'avaient également qu'un maximum d'un mégaoctet de mémoire et généralement seulement un lecteur de disquette (donc pas de mémoire virtuelle sur disque non plus). Avec le manque de réseau et un seul utilisateur, quel serait l'intérêt de la protection de la mémoire? Vous ne protégeriez que l'utilisateur contre lui-même et empêcheriez le partage de données inter-applications potentiellement utile. Le mode d'utilisation courant consistait à charger un programme à partir du disque, puis à remettre l'intégralité de la machine à ce programme. DOS n'avait même pas de multitâche; il y avait un mode "terminer et rester résident" qui permettait aux programmes de laisser du code pour s'exécuter sur une touche ou une minuterie.

les MMU ne sont toujours pas présentes dans la plupart des microcontrôleurs et sont une fonctionnalité optionnelle sur ARM.

La mémoire vidéo était une cible courante pour l'accès direct; si vous vouliez écrire un jeu, c'était considéré comme le seul moyen d'obtenir des performances acceptables. Vous avez également dû écrire directement sur du matériel audio (le cas échéant) car il n'y avait pas de pilotes.

Il y avait aussi l'étrange ère intermédiaire de "DOS/4GW" avant que Windows n'acquière le sous-système DirectX. Afin de dépasser la limite matérielle de 1 Mo de mémoire imposée aux programmes 16 bits, vous pouvez expédier le jeu avec un petit système d'exploitation 32 bits. Cela vous obligeait à quitter Windows 3.0.

J'ai toujours mon code de jeux 16 bits de cette époque. Je continue à vouloir le poster sur github.

4
pjc50