O Vista faz uma verificação mais rigorosa dos IDs de interface nas chamadas DCOM?(o stub recebeu dados incorretos)?

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

  •  09-06-2019
  •  | 
  •  

Pergunta

Espero que todos perdoem a extensão e o estilo narrativo desta questão.Decidi descrever a situação com alguns detalhes em meu blog.Mais tarde vi o convite de Joel para este site e pensei em colá-lo aqui para ver se alguém tem alguma ideia da situação.

Eu escrevi, e agora apoio, um aplicativo que consiste em um cliente espesso do Visual Basic falando DCOM para componentes COM+ de camada intermediária escritos em C++ usando ATL.Funciona em todos os nossos oito escritórios.Cada escritório hospeda um servidor back-end que contém o aplicativo COM+ (consistindo de 18 componentes separados) e o SQLServer.O SQLServer normalmente está no mesmo servidor back-end, mas não precisa estar.

Recentemente, migramos o servidor back-end em nosso maior escritório – Nova York – de um cluster MSC para uma nova máquina virtual hospedada na tecnologia ESX da VMWare.Como a localização do aplicativo COM+ mudou do servidor antigo para um novo com um nome diferente, tive que redirecionar todos os clientes para que eles ativassem o aplicativo COM+ no novo servidor.O procedimento era antigo, pois eu havia feito essencialmente a mesma coisa em vários de meus escritórios menores que haviam passado por atualizações de infraestrutura semelhantes.

Tudo parecia rotineiro e na manhã de segunda-feira todo o escritório – cerca de 1.000 estações de trabalho com Windows XP – estava funcionando sem incidentes no novo servidor.Mas então veio a ligação do meu grupo móvel - havia um advogado trabalhando em casa com uma conexão VPN que estava recebendo um erro estranho após ser redirecionado para o novo servidor:

Error on FillTreeView2 - The stub received bad data.

Huh?Eu nunca tinha visto essa mensagem de erro antes.Foi o novo servidor?Mas todas as estações de trabalho do escritório estavam funcionando bem.Eu disse ao grupo móvel para mudar o advogado de volta para o servidor antigo (que ainda estava ativo) e o erro desapareceu.Então qual foi a diferença?Acontece que esse advogado administrava o Vista em casa.

Não administramos o Vista em nenhum de nossos escritórios, mas temos alguns advogados que administram o Vista em casa (certamente alguns em meu escritório em Nova York).Eu também faço isso e nunca vi esse problema.Para confirmar que havia um problema, liguei meu laptop Vista, apontei-o para o novo servidor e recebi o mesmo erro.Apontei de volta para o servidor antigo e funcionou bem.Claramente houve algum problema com o Vista e os componentes do novo servidor – um problema que não parece afetar os clientes XP.O que poderia ser?

Próxima parada – o log de erros do aplicativo no meu laptop.Isso rendeu mais informações sobre o erro:

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.

Os IDs da interface forneceram a pista que eu precisava para desvendar o mistério.O ID de interface "esperado" identifica a interface Recordset do MDAC - especificamente a versão 2.1 dessa interface.A interface "retornada" corresponde a uma versão posterior do Recordset (versão 2.5 que difere da versão 2.1 pela inclusão de uma entrada adicional no final da vtable - método Save).

Na verdade, as interfaces do meu componente expõem muitos métodos que passam Recordset como parâmetro de saída.Então, eles estavam retornando repentinamente uma versão posterior do Recordset - com um ID de interface diferente?Certamente parecia ser o caso.E então pensei: por que isso deveria importar?A vtable parece a mesma para clientes da interface mais antiga.Na verdade, suspeito que se estivéssemos falando de COM em processo, e não de DCOM, essa incompatibilidade de impedância aparentemente inócua teria sido ignorada silenciosamente e não teria causado problemas.

É claro que, quando os limites do processo e da máquina entram em ação, existe um proxy e um stub entre o cliente e o servidor.Nesse caso, eu estava usando o empacotamento da biblioteca de tipos com o empacotador de thread gratuito.Portanto, havia dois mistérios para resolver:

Por que eu estava retornando uma interface diferente nos parâmetros de saída dos métodos no meu novo servidor?

Por que isso afetou apenas os clientes Vista?

Como meu software de servidor estava hospedado em servidores em cada um dos meus oito escritórios, decidi tentar apontar meu cliente Vista para todos eles em sequência para ver quais tinham problemas com o Vista e quais não tinham.Teste esclarecedor.Alguns dos servidores mais antigos ainda funcionavam com o Vista, mas os mais novos não.Embora alguns dos servidores mais antigos ainda estivessem executando o Windows 2000, enquanto os mais novos estavam em 2003, esse não parecia ser o problema.

Depois de comparar as datas dos componentes DLLs, parecia que sempre que o cliente apontava para servidores com componentes DLLs anteriores a 2003, o Vista estava bem.Mas aqueles que tinham DLLs com datas posteriores a 2003 eram problemáticos.Acredite ou não, não houve (ou pelo menos não houve alterações significativas) no código dos componentes do servidor em muitos anos.Aparentemente, as datas diferentes foram simplesmente devido a recompilações dos meus componentes na(s) minha(s) máquina(s) de desenvolvimento.E parece que uma dessas recompilações aconteceu em 2003.

A lâmpada acendeu.Ao passar Recordsets de volta do servidor para o cliente, meus componentes ATL C++ referem-se à interface como _Recordset.Este símbolo vem da biblioteca de tipos incorporada em msado15.dll.Esta é a linha que eu tinha no código C++:

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

Não se deixe enganar pelos 15 em msdad15.dll.Aparentemente esta DLL não mudou de nome na longa série de versões do MDAC.

Quando compilei o aplicativo naquela época, a versão do MDAC era 2.1.Então _Recordset compilado com o ID da interface 2.1 e essa é a interface retornada pelos servidores que executam esses componentes.

Todos os clientes usam o proxy de aplicativo COM+ que foi gerado (acredito) em 1999.A biblioteca de tipos que define minhas interfaces inclui a linha:

importlib("msado21.tlb");

o que explica por que eles esperam a versão 2.1 do Recordset nos parâmetros de saída do meu método.Claramente o problema estava na minha recompilação de 2003 e no fato de que naquela época o símbolo _Recordset não correspondia mais à versão 2.1.Na verdade, _Recordset correspondia à versão 2.5 com seu ID de interface distinto.A solução para mim foi alterar todas as referências de _Recordset para Recordset21 no meu código C++.Reconstruí os componentes e os implantei no novo servidor.Voila – os clientes pareciam felizes novamente.

Concluindo, há duas questões incômodas que permanecem para mim.

Por que a infraestrutura de proxy/stub parece se comportar de maneira diferente com os clientes Vista?Parece que o Vista está fazendo verificações mais rigorosas dos IDs de interface provenientes dos parâmetros do método do que o XP.

Como eu deveria ter codificado isso de forma diferente em 1999 para que isso não tivesse acontecido?As interfaces deveriam ser imutáveis ​​e quando recompilei em uma versão mais recente do MDAC, mudei inadvertidamente minha interface porque os métodos agora retornavam uma interface Recordset diferente como parâmetro de saída.Até onde eu sei, a biblioteca de tipos daquela época não tinha um símbolo específico de versão - ou seja, versões posteriores das bibliotecas de tipos MDAC definem Recordset21, mas esse símbolo não estava disponível na biblioteca de tipos 2.1.

Foi útil?

Solução

Quando a Microsoft adotou a religião da segurança, o DCOM (e o RPC subjacente) recebeu muita atenção, e definitivamente foram feitas mudanças para fechar brechas de segurança que resultaram em uma organização mais rigorosa.Estou surpreso que você veja isso no Vista, mas não no XP, mas é possível que verificações adicionais tenham sido adicionadas ao Vista.Alternativamente, é possível que o rigor opcional no XP tenha se tornado obrigatório no Vista.

Embora eu não saiba o suficiente sobre o MDAC para saber se você poderia ter evitado isso, sei que a segurança é uma das poucas áreas em que a Microsoft está disposta a sacrificar a compatibilidade com versões anteriores, então é possível que você não pudesse ter feito nada " melhor" em 1999.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top