2009-11-08 6 views
9

J'ai implémenté un type de périphérique de caractères et j'ai besoin d'aide avec la fonction copy_ from_user.Noyau Linux: copy_from_user - struct avec des pointeurs

J'ai une structure:

struct my_struct{ 

int a; 

int *b; 
}; 

Je lsinitialisez dans l'espace utilisateur et passer le pointeur à ma_struct sur mon appareil char en utilisant la fonction « d'écriture ». Dans la fonction 'write' du Kernel's Space character, je l'ai transposée d'un caractère * à ce type de structure. J'affecte de la mémoire pour une structure en utilisant kmalloc et y ajoute copy_from_user. C'est bon pour le simple 'int a', mais il ne copie que le pointeur (adresse) de la valeur b, pas la valeur pointée par b, donc je suis maintenant dans l'espace du noyau et je travaille avec un pointeur qui pointe vers une mémoire d'espace utilisateur. Est-ce incorrect et je ne devrais pas accéder au pointeur de l'espace utilisateur directement et je dois copy_from_user chaque pointeur unique dans ma structure, puis recopiez chaque pointeur dans la fonction "lire" en utilisant la fonction copy_to_user?

Répondre

6

Vous avez raison de penser. Si vous devez accéder à la valeur *b, vous devrez utiliser copy_from_user (et copy_to_user pour le mettre à jour dans le processus utilisateur).

+2

Je voudrais également souligner que je ne peux pas penser à tout syscalls ou ioctls qui prennent des structs avec des pointeurs en eux. Même ceux qui ont des chaînes auront un tableau de caractères dans la structure à la place. Le fait qu'il soit très ennuyeux d'écrire du code pour faire cela pour chaque membre du pointeur pourrait avoir quelque chose à voir avec ça. :-) – asveikau

+0

@asveikau: 'readv()' et 'writev()'? – caf

13

Vous devez toujours utiliser copy_from_user et similaire pour accéder à la mémoire de l'espace utilisateur à partir de l'espace noyau, quelle que soit la façon dont vous avez obtenu le pointeur. Puisque b est un pointeur vers la mémoire de l'espace utilisateur, vous devez utiliser copy_from_user pour y accéder.

Ces fonctions font deux tâches supplémentaires importantes:

  1. Ils font que les points de pointeur dans l'espace utilisateur et non dans l'espace noyau. Sans cette vérification, les programmes d'espace utilisateur pourraient être en mesure de lire ou d'écrire dans la mémoire du noyau, en contournant la sécurité normale.
  2. Ils gèrent correctement les erreurs de page. Normalement une erreur de page en mode noyau entraînera un OOPS ou une panique - la famille de fonctions copy_*_user a un override spécial qui indique au gestionnaire PF que tout va bien, et la faute devrait être gérée normalement; et dans le cas où l'erreur ne peut pas être satisfaite par IO (ce qui provoquerait normalement SIGSEGV ou SIGBUS), renvoyez un code d'erreur à la place afin que l'appelant puisse effectuer le nettoyage nécessaire avant de retourner à l'espace utilisateur avec -EFAULT.