Header Ads

O que é Stack Smashing? Pode ser consertado?

Shutterstock / Gabor Tinz

Cada minuto de paralisação da produção geralmente custa dinheiro para a empresa. Se o seu aplicativo tiver um problema sério que causa o estouro de pilha, você está pronto para uma viagem. Saiba o que o empilhamento é inicial e o que pode ser feito sobre isso!

O que é Stack Smashing?

Trabalhando como engenheiro de garantia de qualidade, mais cedo ou mais tarde se encontrará o termo stack smashing. Como desenvolvedor, é provável que alguém descubra esse termo ainda mais cedo, especialmente se tiver introduzido um bug no código, que causa uma pilha quebrada. É relativamente fácil (como em & # 8216; um pouco fácil &’) para um desenvolvedor cometer um erro que introduz o esmagamento de pilha. Como usuário, quando você aprende sobre destruição de pilha, o dano provavelmente já está feito.

A destruição de pilha pode acontecer involuntariamente – por exemplo, quando o desenvolvedor introduziu um bug que causou o esmagamento da pilha – ou maliciosamente – um invasor tentando de alguma forma estourar ou corromper a pilha de um programa.

Stack smashing é um termo vagamente definido que pode apontar para vários problemas e pode vir de uma variedade de fontes. Os dois problemas mais proeminentes que podem causar o esmagamento da pilha são; 1) gravar / superalocar muitos dados em uma determinada parte da pilha, sobrescrevendo outra parte da pilha, e 2) onde alguma fonte externa (maliciosa ou não) sobrescreveu a pilha de outro programa, embora isso é muito menos comum.

Então, o que é uma pilha? Este também é um termo vagamente definido. De um modo geral, uma pilha se refere a uma pilha de processamento de programa, uma pilha de funções definidas em um determinado programa / código de software.

Comece imaginando uma pilha de ladrilhos de banheiro empilhados, prontos para serem usados ​​por um ladrilhador. Esta é uma boa representação de uma pilha de computador, com algumas modificações. Se cada bloco estivesse um pouco deslocado em relação ao anterior, seria uma imagem melhor e logo veremos o porquê.

Shutterstock / Piotr Debowski

Imagine que cada ladrilho empilhado é uma função do programa de computador. A função mais básica está na parte inferior e pode ser, por exemplo, a função main () em um programa C ou C ++. C e C ++ são duas linguagens de programação que usam a pilha extensivamente.

Cada uma dessas funções no programa C / C ++ terá um nome e provavelmente um conjunto de variáveis ​​de entrada e variáveis ​​de saída. Em termos simplificados, imagine se uma dessas variáveis ​​tinha um comprimento de 10 caracteres e alguma outra função escreveu acidentalmente 100 caracteres nessa variável. Isso pode corromper toda a pilha.

Em termos do exemplo de ladrilhos acima, imagine alguém com um martelo batendo no primeiro ladrilho com força demais e, assim, quebrando todos os outros ladrilhos. Eh voila; pilha quebrando

A analogia funciona porque, assim como todos os blocos estão quebrados em nossa imagem de memória fictícia, uma pilha quebrada resultará em & # 8216; funções quebradas &’ Se você for. Cada deslocamento de bloco é uma função aninhada mais profundamente – mais sobre funções quebradas na próxima seção.

Depuração de pilha (s) quebrada (s)

Considerando que, tecnicamente, uma referência a & # 8216; funções interrompidas &’ pode não estar totalmente correto, ou seja, provavelmente há apenas uma função quebrada, e pode até mesmo não haver função quebrada quando há um ataque externo ou programa com defeito, é uma ótima maneira de pensar sobre uma pilha destruída.

De repente, os nomes das variáveis ​​e das funções podem ser mutilados, e um backtrace (o fluxo de funções que o computador utilizou para chegar a uma determinada função que travou e (em nosso exemplo) destruiu a pilha) não faz mais sentido.

De um modo geral, quando olhamos para um backtrace, ele terá um fluxo claro de funções que foram chamadas. Embora um programa com falha não possa ser chamado imediatamente de & # 8216; saudável, &’ em termos de backtracing / depuração, isso é o que uma & # 8216; saudável &’ o backtrace se parece com:

Quando uma pilha está corrompida, entretanto, a depuração se torna muito mais difícil. A pilha pode ter a seguinte aparência:

Este é um exemplo de problema de esmagamento de pilha que aconteceu no MySQL, o servidor de banco de dados (consulte o arquivo log. txt anexo ao Bug 37815 do MySQL para obter a saída completa) em 2008, causando o banco de dados daemon do servidor (mysqld) para encerrar.

Embora a biblioteca libc. so.6 do sistema operacional, neste caso, pareça ter lidado com a quebra de pilha muito bem (usando alguma funcionalidade fortify na função __fortify_fail), o problema existia em algum lugar no código e já foi corrigido.

Observe também que, neste caso, não vemos nomes de funções resolvidos, apenas o nome binário é mostrado (curiosamente, o problema parece estar no cliente (mysql) fazendo com que o servidor (mysqld) seja encerrado) que é mysql, junto com um endereço de memória da função: mysql [0x8051565], mysql [0x80525c7] e mysql (main + 0x4f8) [0x8053198].

Normalmente, quando usamos símbolos de depuração (ref abaixo para um artigo sobre GDB que explica o que são símbolos de depuração em detalhes), veríamos nomes de função com variáveis, e até mesmo com alguns níveis de otimização / minimização binária em vigor, veríamos pelo menos os nomes das funções, assim como o que vemos no primeiro item & # 8216; íntegro &’ backtrace acima.

No entanto, no caso de uma pilha destruída, a saída dos nomes de funções, nomes de variáveis ​​ou valores nunca são garantidos e muitas vezes são uma bagunça completa 🙂 Podemos até ver nomes de funções diferentes ou uma pilha completamente mutilada (outro jargão, muitas vezes usado pelo pessoal de TI) de nomes de função diferentes que não fazem muito sentido (e provavelmente são fictícios / falsos, pois a pilha foi substituída de alguma forma).

Isso torna mais difícil tanto para o engenheiro de teste (que pode acabar com muitos resultados diferentes para um único bug, complicando o manuseio do mecanismo de filtragem de bug conhecido) quanto para o desenvolvedor (que provavelmente terá que usar alguns detalhes passo a passo rastreamento de etapas ou um depurador de execução reversa como RR para descobrir o bug em questão).

O que fazer quando você enfrentar o Stack Smashing?

Se você se deparar com o esmagamento de pilha, a primeira coisa a fazer é entender o problema e o ambiente um pouco melhor para saber a fonte. Se você tiver um servidor da web popular exposto na Internet com muitos usuários de jogos que estão tentando ganhar um torneio enquanto o servidor também está minando Bitcoin, você vai querer assumir a possibilidade de jogo sujo e descobrir se alguém está mexendo com o servidor.

No entanto, na maioria dos casos, o problema será apenas um erro de aplicativo. Embora eu diga & # 8216; apenas ’, o problema pode ser muito significativo, pode resultar em tempo de inatividade dos serviços, pode custar muito dinheiro e, finalmente, pode não ser corrigido. Por exemplo, um servidor de banco de dados pode travar persistentemente ao ser iniciado devido aos dados estarem em um determinado estado em combinação com uma deficiência ou limitação no código.

Se tal situação for agravada pelo não esmagamento da pilha, ou em outras palavras, não sendo capaz de gerar um backtrace limpo do problema, a depuração será mais envolvente e às vezes próxima impossível. Não tenha medo, entretanto, que a mesma depuração básica de qualquer bug ou erro / travamento / problema de aplicativo permanece a mesma.

Leia atentamente cada bit dos arquivos de log antes, durante e depois da ocorrência do problema. Faça alguns backups e tente a operação novamente. Ele falha de novo ou não? Pesquise os erros, partes da pilha e até mesmo os quadros (ou seja, funções de pilha individuais mostradas, como a função do_the_maths em nosso rastreamento de pilha & # 8216; saudável &’ original) podem ser colocados em seus mecanismos de pesquisa favoritos.

Concatenar (com um espaço) os frames de travamento mais seletivos (no topo) e pesquisar os mesmos online geralmente encontra um relatório de bug existente para o problema que você está enfrentando. Ainda assim, no caso de quebra de pilha, provavelmente esses quadros (nomes de funções) se tornaram mutilados e, portanto, não podem mais ser usados ​​da mesma maneira. Se você vir uma mensagem de declaração (uma declaração instituída pelo desenvolvedor no código) de qualquer tipo, pesquise-a também.

Sempre registre um novo relatório de bug se o problema não parecer estar conectado ainda (você pode estar ajudando outras pessoas que estão vendo o mesmo!) e forneça o máximo de informações sobre o problema como você pode encontrar. Milhares de relatórios de bug em relação a tantos aplicativos são registrados online todos os dias. Esperançosamente, a equipe de suporte para seu aplicativo de destruição de pilha está disponível para ajudar rapidamente.

Você também pode gostar de ler nosso artigo Depurando com GDB: Primeiros passos a seguir, pois ele se baseia em como os programas C e C ++ (e outros) podem ser depurados com o depurador GDB. Ele também explica mais detalhadamente os conceitos de uma pilha.

Nenhum comentário