Comment fonctionne copy_from_user du kernel Linux en interne?

Quelqu’un peut-il m’expliquer comment fonctionne exactement la fonction copy_from_user? Utilise-t-il des tampons ou y a-t-il un mappage de mémoire en tenant compte du fait que le kernel a le privilège d’accéder à la mémoire de l’espace utilisateur?

L’implémentation de copy_from_user() dépend fortement de l’architecture.

Sur x86 et x86-64, il effectue simplement une lecture directe à partir de l’adresse de l’espace utilisateur et écrit sur l’adresse de l’espace kernel, tout en désactivant temporairement SMAP (prévention d’access en mode superviseur) s’il est configuré. La partie délicate consiste en ce que le code copy_from_user() est placé dans une région spéciale afin que le gestionnaire de défauts de page puisse reconnaître le moment où une panne se produit. Une erreur de protection de la mémoire qui se produit dans copy_from_user() ne supprime pas le processus comme s’il était déclenché par un autre code de contexte de processus ou panique le kernel comme s’il se produisait dans un contexte d’interruption. un chemin de code qui renvoie -EFAULT à l’appelant.

concernant “comment bout copy_to_user puisque le kernel transmet l’adresse de l’espace kernel, comment un processus d’espace utilisateur peut-il y accéder”

Un processus d’espace utilisateur peut tenter d’accéder à n’importe quelle adresse. Toutefois, si l’adresse n’est pas mappée dans cet espace utilisateur de processus (c.-à-d. Dans les tables de pages de ce processus) ou s’il y a un problème d’access comme une tentative d’écriture en lecture seule, une erreur de page est générée. Notez qu’au moins sur le x86, chaque processus a tout l’espace du kernel mappé dans le plus bas 1 gigaoctet de l’espace d’adressage virtuel de ce processus, tandis que les 3 gigaoctets supérieurs de l’espace d’adressage total de 4 Go (j’utilise ici le classique 32 bits) cas) sont utilisés pour le texte du processus (c.-à-d. le code) et les données. Une copie vers ou depuis l’espace utilisateur est exécutée par le code du kernel qui s’exécute au nom du processus et correspond en fait au mappage de la mémoire (c’est-à-dire aux tables de pages) de ce processus qui est utilisé pendant la copie. Cela se produit lorsque l’exécution est en mode kernel – c’est-à-dire en mode privilégié / superviseur en langage x86. En supposant que le code de l’espace utilisateur a passé un emplacement cible légitime (c’est-à-dire une adresse correctement mappée dans cet espace d’adressage de processus) pour copier des données, copy_to_user, exécutez le contexte du kernel normalement problèmes et après que le contrôle retourne à l’utilisateur, l’espace utilisateur peut également lire à partir de cette configuration de l’emplacement par le processus lui-même pour commencer. Des détails plus intéressants peuvent être trouvés dans les chapitres 9 et 10 de Understanding the Linux Kernel, 3ème édition, par Daniel P. Bovet, Marco Cesati. En particulier, access_ok () est un contrôle de validité nécessaire mais non suffisant. L’utilisateur peut toujours transmettre des adresses n’appartenant pas à l’espace d’adressage du processus. Dans ce cas, une exception de défaillance de page se produit lorsque le code du kernel exécute la copie. La partie la plus intéressante est la façon dont le gestionnaire de pannes de la page du kernel détermine que la défaillance de la page dans ce cas n’est pas due à un bogue dans le kernel mais plutôt à une mauvaise adresse de l’utilisateur (surtout si le code chargé).

L’implémentation de l’appel système copy_from_user () s’effectue à l’aide de deux tampons provenant de différents espaces d’adressage.

  • Le tampon de l’espace utilisateur dans l’adresse virtuelle de l’utilisateur.
  • Le tampon de l’espace kernel à l’adresse virtuelle du kernel.

Lorsque l’appel système copy_from_user () est appelé, les données sont copiées du tampon utilisateur vers la mémoire tampon du kernel.

Une partie (opération d’écriture) du code du pilote de périphérique de caractères où copy_from_user () est utilisé est donnée ci-dessous:

ssize_t cdev_fops_write (fichier struct * flip, const char __user * ubuf, size_t count, loff_t * f_pos)

{

 unsigned int *kbuf; copy_from_user(kbuf, ubuf, count); printk(KERN_INFO "Data: %d",*kbuf); 

}

La meilleure réponse a quelque chose qui ne va pas, copy_ (de | à) utilisateur ne peut pas être utilisé dans un contexte d’interruption, ils peuvent dormir, la fonction utilisateur copy (from | to) ne peut être utilisée qu’en contexte de processus. informations dont le kernel a besoin pour y accéder, afin que le kernel puisse accéder directement à l’adresse de l’utilisateur si nous pouvons nous assurer que la page adressée est en mémoire, utilisez la fonction copy (from | to) _user, car ils peuvent la vérifier espace adressé page n’est pas résident, il va le réparer directement pour nous.