Est-ce que Vista effectue une vérification plus stricte des identifiants d'interface dans les appels DCOM? (le stub a reçu de mauvaises données)?

StackOverflow https://stackoverflow.com/questions/63720

  •  09-06-2019
  •  | 
  •  

Question

J'espère que tout le monde pardonnera la longueur et la mode narrative de cette question. J'ai décidé de décrire la situation en détail dans mon blog. Par la suite, j’ai vu l’invitation de Joel sur ce site et j’ai pensé que je la collerais ici pour voir si quelqu'un avait une idée de la situation.

J'ai écrit et supporte maintenant une application qui consiste en un client lourd Visual Basic parlant DCOM aux composants COM + de niveau intermédiaire écrits en C ++ à l'aide d'ATL. Il fonctionne dans nos huit bureaux. Chaque bureau héberge un serveur principal qui contient l'application COM + (composée de 18 composants distincts) et le serveur SQL. Le serveur SQL se trouve généralement sur le même serveur principal, mais pas nécessairement.

Nous avons récemment migré le serveur principal de notre plus grand bureau - New York - d'un cluster MSC vers une nouvelle machine virtuelle hébergée sur la technologie ESX de VMWare. L'emplacement de l'application COM + ayant été déplacé de l'ancien serveur vers un nouveau serveur portant un nom différent, j'ai dû rediriger tous les clients pour qu'ils activent l'application COM + sur le nouveau serveur. La procédure était vieille, car j'avais essentiellement fait la même chose pour plusieurs de mes plus petits bureaux, qui avaient subi des mises à niveau similaires de leur infrastructure.

Tout semblait banal et lundi matin, tout le bureau - environ 1 000 postes de travail Windows XP - fonctionnait sans incident sur le nouveau serveur. Mais ensuite, l’appel a été lancé par mon groupe de téléphonie mobile. Un avocat travaillant à domicile avec une connexion VPN recevait une erreur étrange après avoir été redirigé sur le nouveau serveur:

Error on FillTreeView2 - The stub received bad data.

Hein? Je n'avais jamais vu ce message d'erreur auparavant. Était-ce le nouveau serveur? Mais tous les postes de travail du bureau fonctionnaient bien. J'ai dit au groupe de téléphonie mobile de renvoyer l'avocat à l'ancien serveur (qui était toujours en place), et l'erreur a disparu. Alors quelle était la différence? Il se trouve que cet avocat exécutait Vista à la maison.

Nous n'exécutons Vista dans aucun de nos bureaux, mais certains de nos avocats utilisent Vista à la maison (certains dans mon bureau de New York). Je fais aussi bien et je n'ai jamais vu ce problème. Pour confirmer l'existence d'un problème, j'ai allumé mon ordinateur portable Vista, l'ai pointé vers le nouveau serveur et j'ai obtenu la même erreur. Je l'ai redirigé vers l'ancien serveur, et cela a bien fonctionné. Clairement, il y avait un problème avec Vista et les composants sur le nouveau serveur - un problème qui ne semblait pas affecter les clients XP. Que pourrait-il être?

Prochain arrêt - le journal des erreurs d'application sur mon ordinateur portable. Cela a donné plus d'informations sur l'erreur:

Source:        Microsoft-Windows-RPC-Events
Date:          9/2/2008 11:56:07 AM
Event ID:      10
Level:         Error
Computer:      DevLaptop
Description:   Application has failed to complete a COM call because an incorrect
interface ID was passed as a parameter.

The expected Interface ID was 00000555-0000-0010-8000-00aa006d2ea4, 
The Interface ID returned was 00000556-0000-0010-8000-00aa006d2ea4.

User Action - Contact the application vendor for updated version of the application.

Les identifiants d’interface ont fourni l’indice dont j’avais besoin pour résoudre le mystère. Le " attendu " interface id identifie l'interface de MDAC Recordset, en particulier la version 2.1 de cette interface. Le " retourné " interface correspond à une version ultérieure de Recordset (la version 2.5 diffère de la version 2.1 par l’inclusion d’une entrée supplémentaire à la fin de la méthode vtable - Save).

En effet, les interfaces de mes composants exposent de nombreuses méthodes qui transmettent Recordset en tant que paramètre de sortie. Alors revenaient-ils soudainement une version ultérieure de Recordset - avec un identifiant d'interface différent? Cela semblait certainement être le cas. Et puis j'ai pensé, pourquoi cela devrait-il compter. La vtable a le même aspect pour les clients de l'ancienne interface. En effet, je soupçonne que si nous parlions de COM en cours de traitement, et non de DCOM, cette inadéquation apparemment inoffensive d’impédance aurait été ignorée en silence et n’aurait causé aucun problème.

Bien sûr, lorsque les limites des processus et des machines entrent en jeu, il existe un proxy et un stub entre le client et le serveur. Dans ce cas, j'utilisais la bibliothèque de types marshaling avec le libre threaded marshaller. Il y avait donc deux mystères à résoudre:

Pourquoi est-ce que je renvoie une interface différente dans les paramètres de sortie des méthodes de mon nouveau serveur?

Pourquoi cela n'affecte-t-il que les clients Vista?

Le logiciel de mon serveur étant hébergé sur des serveurs situés dans chacun de mes huit bureaux, j'ai décidé d'essayer de pointer mon client Vista en séquence pour voir ceux qui avaient des problèmes avec Vista et ceux qui n'en avaient pas. Test éclairant. Certains des anciens serveurs fonctionnaient toujours avec Vista, mais pas les plus récents. Même si certains des anciens serveurs utilisaient encore Windows 2000 alors que les plus récents étaient à 2003, cela ne semblait pas être le problème.

Après avoir comparé les dates des DLL de composants, il est apparu que chaque fois que le client désignait des serveurs avec des DLL de composants antérieures à 2003, Vista fonctionnait parfaitement. Mais ceux qui avaient des DLL avec des dates postérieures à 2003 posaient problème. Croyez-le ou non, il n'y a eu aucun changement (ou du moins aucun changement significatif) du code sur les composants du serveur depuis de nombreuses années. Apparemment, les dates différentes étaient simplement dues à la recompilation de mes composants sur ma ou mes machines de développement. Et il est apparu qu'une de ces recompilations avait eu lieu en 2003.

L'ampoule s'est allumée. Lors de la retransmission des jeux d'enregistrements d'un serveur à un autre client, les composants ATL C ++ font référence à l'interface sous le nom _Recordset. Ce symbole provient de la bibliothèque de types intégrée à msado15.dll. C’est la ligne que j’avais dans le code C ++:

#import "c:\Program Files\Common Files\System\ADO\msado15.dll" no_namespace rename ( "EOF", "adoEOF" )

Ne vous laissez pas abuser par le 15 dans msdad15.dll. Apparemment, cette DLL n’a pas changé de nom dans la longue série de versions de MDAC.

Lorsque j'ai compilé l'application dans la journée, la version de MDAC était 2.1. Ainsi, _Recordset a été compilé avec l'ID d'interface 2.1 et correspond à l'interface renvoyée par les serveurs exécutant ces composants.

Tous les clients utilisent le proxy d'application COM + qui a été généré (je crois) en 1999. La bibliothèque de types qui définit mes interfaces comprend la ligne:

importlib("msado21.tlb");

ce qui explique pourquoi ils attendent la version 2.1 de Recordset dans les paramètres de sortie de ma méthode. Clairement, le problème venait de ma recompilation de 2003 et du fait qu'à cette époque le symbole _Recordset ne correspondait plus à la version 2.1. En effet, _Recordset correspond à la version 2.5 avec son identifiant d'interface distinct. La solution pour moi était de changer toutes les références de _Recordset à Recordset21 dans mon code C ++. J'ai reconstruit les composants et les ai déployés sur le nouveau serveur. Voilà, les clients semblaient heureux à nouveau.

En conclusion, il me reste deux questions épineuses.

Pourquoi l'infrastructure proxy / stub semble-t-elle se comporter différemment avec les clients Vista? Il semble que Vista vérifie de façon plus stricte que les identifiants d’interface renvoyés par les identifiants d’interface.

Comment aurais-je dû coder cela différemment en 1999 pour que cela ne se produise pas? Les interfaces sont supposées être immuables et lorsque j'ai recompilé une version plus récente de MDAC, j'ai modifié mon interface par inadvertance, car les méthodes renvoyaient désormais une interface Recordset différente en tant que paramètre de sortie. Autant que je sache, à l'époque, la bibliothèque de types ne comportait pas de symbole spécifique à la version. En d'autres termes, des versions ultérieures des bibliothèques de types MDAC définissaient Recordset21, mais ce symbole n'était pas disponible dans la bibliothèque de types 2.1.

Était-ce utile?

La solution

Lorsque Microsoft a adopté la religion de la sécurité, DCOM (et le RPC sous-jacent) a suscité beaucoup d’attention et des modifications ont été apportées pour combler les failles de sécurité qui ont entraîné un marshaling plus strict. Je suis surpris que vous voyiez cela dans Vista mais pas dans XP, mais il est possible que des vérifications supplémentaires aient été ajoutées pour Vista. Sinon, il est possible que la rigueur optionnelle dans XP devienne obligatoire dans Vista.

Bien que je ne connaisse pas suffisamment MDAC pour savoir si vous auriez pu empêcher cela, je sais que la sécurité est l'un des rares domaines dans lequel Microsoft est plutôt disposé à sacrifier la compatibilité en amont, de sorte qu'il est possible que vous n'ayez pas fait quelque chose & mieux; mieux " en 1999.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top