Segurança e Condições de Corrida

Outra área de preocupação é o potencial de falhas de segurança exploradas pelas condições de corrida. Há várias maneiras pelas quais isso pode acontecer. Os subtópicos a seguir descrevem algumas das principais armadilhas que o desenvolvedor deve evitar.

Condições de Corrida no Método de Eliminação

Se o método Dispose de uma classe (para obter mais informações, consulte Garbage Collection) não estiver sincronizado, é possível que o código de limpeza dentro de Dispose possa ser executado mais de uma vez, conforme mostrado no exemplo a seguir.

Sub Dispose()  
    If Not (myObj Is Nothing) Then  
       Cleanup(myObj)  
       myObj = Nothing  
    End If  
End Sub  
void Dispose()
{  
    if (myObj != null)
    {  
        Cleanup(myObj);  
        myObj = null;  
    }  
}  

Como essa implementação Dispose não está sincronizada, é possível Cleanup ser chamado primeiro por um thread e, em seguida, um segundo thread antes _myObj é definido como null. Se isso é uma preocupação de segurança depende do que acontece quando o Cleanup código é executado. Um grande problema com implementações Dispose não sincronizadas envolve o uso de identificadores de recursos, como arquivos. O descarte inadequado pode fazer com que o identificador errado seja usado, o que muitas vezes leva a vulnerabilidades de segurança.

Condições de Corrida em Construtores

Em alguns aplicativos, pode ser possível que outros threads acessem membros de classe antes que seus construtores de classe tenham sido completamente executados. Você deve revisar todos os construtores de classe para certificar-se de que não há problemas de segurança, se isso acontecer, ou sincronizar threads, se necessário.

Condições de corrida com objetos armazenados em cache

O código que armazena em cache informações de segurança ou usa a segurança de acesso ao código A operação Assert também pode ser vulnerável a condições de corrida se outras partes da classe não estiverem adequadamente sincronizadas, conforme mostrado no exemplo a seguir.

Sub SomeSecureFunction()  
    If SomeDemandPasses() Then  
        fCallersOk = True  
        DoOtherWork()  
        fCallersOk = False  
    End If  
End Sub  
  
Sub DoOtherWork()  
    If fCallersOK Then  
        DoSomethingTrusted()  
    Else  
        DemandSomething()  
        DoSomethingTrusted()  
    End If  
End Sub  
void SomeSecureFunction()
{  
    if (SomeDemandPasses())
    {  
        fCallersOk = true;  
        DoOtherWork();  
        fCallersOk = false;  
    }  
}  
void DoOtherWork()
{  
    if (fCallersOK)
    {  
        DoSomethingTrusted();  
    }  
    else
    {  
        DemandSomething();  
        DoSomethingTrusted();  
    }  
}  

Se houver outros caminhos que DoOtherWork podem ser chamados de outro thread com o mesmo objeto, um chamador não confiável pode passar por uma demanda.

Se o seu código armazenar informações de segurança em cache, certifique-se de que o analisa para esta vulnerabilidade.

Condições de Corrida em Finalizadores

As condições de corrida também podem ocorrer em um objeto que faz referência a um recurso estático ou não gerenciado que ele libera em seu finalizador. Se vários objetos compartilharem um recurso que é manipulado no finalizador de uma classe, os objetos devem sincronizar todo o acesso a esse recurso.

Consulte também