Jump to content
  • Entendendo malloc() e heap na glibc

       (1 review)

    Felipe.Silva
     Share

    A heap é uma estrutura especial de memória usada pelo processo. O que tem de especial nela é o fato de seu tamanho ser variável, já que sua memória pode ser alocada ou desalocada dinamicamente pelo processo. Isso pode ser feito usando syscalls do sistema operacional e o mesmo é responsável por alocar mais páginas de memória para a seção caso seja necessário.

    No Linux o segmento de dados pode ser aumentado ou diminuído usando a syscall brk, e é esse espaço de memória que os programas normalmente usam para a heap. Em C nós normalmente não usamos a heap diretamente e, ao invés disso, usamos a função malloc() e semelhantes para lidar com a alocação dinâmica de memória. O que alguns não sabem é que na verdade chamadas para a função malloc() ou free() não necessariamente irão resultar na alocação ou desalocação de memória para o processo. Isso se dá porque é a libc quem de fato gerencia a heap e nós não estamos diretamente solicitando ou liberando memória para o sistema operacional.

    *libc é a biblioteca padrão da linguagem C que contém funções essenciais para tarefas básicas como: Manipulação de strings e arquivos, entrada e saída de dados, funções básicas de matemática etc.

    A função malloc(), de acordo com a implementação da glibc, usa o segmento de dados, o dividindo em uma ou mais regiões de memória que eles chamam de “arenas”. A arena principal corresponde à heap original do processo, porém outras arenas também podem ser alocadas para o processo. Inicialmente cada thread criada no processo tem uma arena individual até atingir um certo limite pré-definido de arenas que podem ser alocadas no processo. Atingindo esse limite, as threads posteriores passam a compartilhar a mesma arena. Em cada arena de memória existem divisões da memória que são chamadas de maneira homônima de heap, e são nessas heaps que a função malloc() de fato aloca memória para o usuário da libc.

    Cada bloco de memória que malloc() aloca na heap é chamado de chunk, e cada chunk contém metadados usados pelo sistema interno de malloc para organizar a heap como uma lista duplamente encadeada. Para fins de ilustração, abaixo está a estrutura de um chunk, usada na glibc:

    struct malloc_chunk {
      INTERNAL_SIZE_T      mchunk_prev_size;
      INTERNAL_SIZE_T      mchunk_size;
    
      struct malloc_chunk* fd;
      struct malloc_chunk* bk;
    
      /* Only used for large blocks: pointer to next larger size. */
      struct malloc_chunk* fd_nextsize;
      struct malloc_chunk* bk_nextsize;

    O valor mchunk_prev_size seria o tamanho do chunk anterior e mchunk_size o tamanho do chunk atual. Os ponteiros *fd e *bk são usados somente quando o chunk está livre, e seriam ponteiros usados para a lista circular duplamente encadeada de chunks que apontam para o chunk posterior e anterior, respectivamente. No entanto, essa estrutura não representa muito claramente como o chunk é de fato usado pelo sistema de malloc, na figura abaixo isso é ilustrado com mais precisão.

    1.thumb.PNG.e30535a88536511b4a04a8591e7371dd.PNG

    O ponteiro que malloc() retorna não aponta para o início do chunk mas sim para o início do espaço de memória que pode ser usado pelo usuário. O tamanho do espaço de memória de um chunk é alinhado pelo tamanho de um double word na arquitetura. Caso malloc() seja chamado passando um tamanho desalinhado como argumento, um espaço extra é alocado para manter o alinhamento. Por exemplo, se o alinhamento está sendo feito para 8 bytes e malloc é chamada com 9 como argumento, malloc irá te devolver um chunk com 16 bytes de espaço de memória usável. Além do alinhamento no tamanho do chunk, também existe um alinhamento no endereço de memória retornado por malloc() que é sempre alinhado para o tamanho de uma word. Isso é feito porque em algumas arquiteturas esse alinhamento de memória é necessário para se evitar uma exceção. Em outras arquiteturas (x86, por exemplo) o alinhamento melhora a performance do processador no acesso à memória.

    Como existe esse alinhamento no tamanho de um chunk isso garante que os três bits menos significativos de mchunk_size não sejam necessários para definir o tamanho do chunk. Se aproveitando disso, os três últimos bits são usados como flags para determinar alguns metadados usados pelo sistema de chunks.

    2.thumb.PNG.d93481677ee394d2906266603f677ac4.PNG

    O bit M indica que o chunk não pertence a nenhuma arena e, ao invés disso, foi alocado dinamicamente em uma memória mapeada. Caso este bit esteja ligado, os outros dois são ignorados. No contexto de um chunk livre este bit está sempre desligado, tendo em vista que a lista encadeada de chunks livres somente se aplica a chunks que estão em alguma arena.

    Os chunks diretamente mapeados na memória (com bit M ligado) são criados para chunks muito grandes. Esses chunks quando liberados com a função free() são imediatamente liberados da memória. Por outro lado, usar free() em um chunk comum não necessariamente irá liberar memória para o sistema operacional. O que free() faz nesse caso é marcar o chunk como livre o adicionando de volta à lista de chunks livres. Assim como é indicado nesse trecho da glibc:

    /* Mark the chunk as belonging to the library again.  */
    (void)tag_region (chunk2mem (p), memsize (p));

    Repare como o comentário descreve a ação como “marcar o chunk como pertencente à biblioteca novamente”, e é efetivamente isso que a função free() faz, não sendo necessariamente uma liberação de memória para o sistema operacional. Inclusive um recurso de otimização que a glibc usa é o que eles chamam de tcache (Thread Local Cache), que se trata de uma lista de chunks existente em cada thread individualmente. Quando você aloca um novo chunk na thread e posteriormente o libera, ele é adicionado ao tcache daquela thread e pode ser reutilizado em uma nova alocação posterior.

    Um adendo que a função free() pode efetivamente liberar memória para o sistema operacional se houver vários chunks livres no topo do segmento de dados (o que raramente acontece). Ela faz isso chamando a função interna systrim(), que por sua vez (no Linux) usa a syscall brk para diminuir novamente o segmento de dados.

    Um detalhe interessante que vale citar aqui é que na glibc (no Linux) existem as funções brk e sbrk que servem como wrappers para aumentar/diminuir o segmento de dados. O sistema de liberação de memória do systrim() espera que essas funções não sejam utilizadas diretamente para poder fazer a liberação de memória apropriadamente. Se você usá-las em seu código por algum motivo, irá “quebrar” o sistema de liberação de memória automático do free(), o fazendo não mais liberar memória quando é usado em chunks de arenas. Logo, não é recomendável que você use essas funções diretamente a menos que você esteja implementando seu próprio sistema de gerenciamento de memória dinâmica.

    O código abaixo é um experimento a fim de vermos na prática os metadados do chunk no Linux:

    // gcc test.c -o test
    #include <stdio.h>
    #include <stdlib.h>
    
    int main(void)
    {
      size_t *content = malloc(8);
    
      size_t chunk_size = content[-1] & ~0b111;
      size_t chunk_flags = content[-1] & 0b111;
    
      printf("size:  %zu\nflags: %zu\n", chunk_size, chunk_flags);
      return 0;
    }

    No meu Linux é retornado 32 como tamanho do chunk e 1 como flag, indicando que somente o bit P está ligado. Sugiro ao leitor variar o tamanho passado para malloc a fim de comprovar que o alinhamento do tamanho do chunk de fato ocorre. Também sugiro passar um número grande para malloc() a fim de ver a partir de qual tamanho malloc() irá deixar de usar uma arena e irá alocar o chunk com mmap(). Caso isso ocorra o bit M será ligado e o número 2 (decimal) será indicado como flags.

    Nota: Esse código propositalmente não utiliza free() antes de finalizar o programa. É redundante e desnecessário usá-la quando o programa é finalizado, tendo em vista que todas as páginas de memória usadas pelo processo serão liberadas pelo sistema operacional.

    Referências


    Revisão: Leandro Fróes
    • Curtir 5
     Share


    User Feedback

    Join the conversation

    You can post now and register later. If you have an account, sign in now to post with your account.
    Note: Your post will require moderator approval before it will be visible.

    Guest

    • This will not be shown to other users.
    • Add a review...

      ×   Pasted as rich text.   Paste as plain text instead

        Only 75 emoji are allowed.

      ×   Your link has been automatically embedded.   Display as a link instead

      ×   Your previous content has been restored.   Clear editor

      ×   You cannot paste images directly. Upload or insert images from URL.



  • Similar Content

    • By Fernando Mercês
      No últmo artigo falei sobre como montar uma máquina virtual básica para ER em Windows. Agora chegou a vez do Linux, já que o mundo não é feito só de PE. 🙂
       A ideia aqui é montar um ambiente legal para reverter binários ELF. Dá uma olhada neste vídeo (em tela cheia de preferência) pra ter uma ideia do poder dessas ferramentas:
      Legal né? Então mãos à obra!
      Máquina virtual
      1 GB de memória Placa de rede em modo NAT Sistema operacional
      Utilizo a ISO netinstall do Debian 64-bits, mas como sempre você é livre para utilizar a distribuição que quiser, só que este artigo é escrito com base nesta. 😉
      Algumas dicas de instalação:
      Não utilizar seu nome verdadeiro na criação da conta de usuário. Não instalar as extensões do software virtualizador como VMware Tools ou VirtualBox Guest Additions. Não configurar nenhuma regra de firewall ou qualquer software de proteção. /etc/apt/sources.list
      Eu deixo do seguinte jeito:
      deb http://deb.debian.org/debian/ testing main contrib non-free deb-src http://deb.debian.org/debian/ testing main contrib deb http://security.debian.org/debian-security testing-security main contrib non-free deb-src http://security.debian.org/debian-security testing-security main contrib O importante aqui é ter o contrib non-free após o main, já que alguns programas como o rar não são livres.
      Depois de configurado este arquivo, é bom atualizar os pacotes existentes:
      # apt update # apt upgrade -y Instalação de software
      Agora é hora de instalar os pacotes necessários:
      # apt install man gdb binutils vim strace ltrace ht build-essential tcpdump unhide foremost sudo p7zip-full rar unrar fasm gcc-multilib git file zip unzip python3-pip GEF
      Este é um plugin para o GDB que adiciona muitos recursos:
      # pip3 install capstone keystone-engine unicorn ropper # git clone https://github.com/hugsy/gef.git # echo "source $PWD/gef/gef.py" >> ~/.gdbinit Observações finais
      Após instalar todos os softwares, é de extrema utilidade criar um snapshot da máquina virtual, pra você voltar facilmente a este estado limpo após analisar um arquivo suspeito, por exemplo. Não precisa instalar um ambiente gráfico. Existe uma distribuição Linux chamada REMnux com foco em engenharia reversa, se você preferir.
    • By Fabiano Furtado
      Pessoal, disponibilizei no meu GitHub o meu primeiro projeto OpenSource, como forma de retornar para a comunidade o que tenho aprendido nestes últimos anos.
      O projeto se chama LIBCPF (C Plugin Framework - https://github.com/fabianofurtado/libcpf/) e se trata de uma biblioteca/framework pra gerenciamento de Plugins (".so") no Linux, feita em C. Para maiores detalhes, veja a documentação no arquivo README.md.
      Ela foi lançada utilizando-se a licença GPL v2, uma vez que não entendo muito sobre esse assunto e precisava de uma licença para o projeto.
      Espero que, de alguma forma, este projeto possa ser útil para você. Mesmo que não exista a necessidade de utilização desta lib em sua aplicação, a mesma pode ser usada para listar os nomes das funções e os offsets que existem dentro de uma shared library, algo que considero bem interessante. Veja no exemplo como isso funciona.
      Como qualquer programa em C, o desenvolvimento deu muito trabalho pois tentei desenvolvê-la com foco na segurança, tentando evitar possíveis "buffer overflows" ou qualquer outro tipo de vulnerabilidades.
      Sugestões e críticas serão sempre bem-vindas!
      Desde já, agradeço.
    • By Theldus
      Introdução
      Há poucas semanas, um amigo comentou que estava buscando automatizar um processo que envolvia buscas por expressões regulares em arquivos binários. Essa tarefa normalmente é realizada com ferramentas de linha de comando específicas (grep, git-grep, ack-grep, ag, ripgrep, ugrep, entre outras), e um script pode invocá-las e fazer o parsing do output. A ripgrep em particular oferece resultados em JSON, o que facilita bastante o processo.
      Apesar disso, chamar um processo externo e intepretar a saída não é a maneira ideal de incorporar uma funcionalidade em um programa, sendo a mais correta o uso de uma biblioteca, mas surpreendi-me ao perceber que não havia nenhuma que cumprisse tal propósito.
      E assim nasceu a libag, um fork da ferramenta ag com o objetivo de transformá-la em uma biblioteca para facilitar a incorporação, em outros programas, do recurso de busca avançada no conteúdo de arquivos.
      Uso e recursos
      A libag requer as mesmas dependências do ag: liblzma, libpcre e zlib.
      No Ubuntu (e possivelmente em outras distribuições Debian-like):
      $ sudo apt install libpcre3-dev zlib1g-dev liblzma-dev Uma vez resolvidas as dependências o processo de build é bastante simples.
      Basta clonar o repositório:
      $ git clone https://github.com/Theldus/libag $ cd libag/ e compilar:
      Makefile
      $ make -j4 $ make install # Opcional CMake
      $ mkdir build && cd build/ $ cmake .. -DCMAKE_BUILD_TYPE=Release $ make -j4 O uso da biblioteca é bastante simples e consiste no uso de três funções básicas: ag_init(), ag_search() e ag_finish() (embora funções mais avançadas também estejam disponíveis).
      Um exemplo mínimo e completo segue abaixo:
      #include <libag.h> int main(void) { struct ag_result **results; size_t nresults; char *query = "foo"; char *paths[1] = {"."}; /* Initiate Ag library with default options. */ ag_init(); /* Searches for foo in the current path. */ results = ag_search(query, 1, paths, &nresults); if (!results) { printf("No result found\n"); return (1); } printf("%zu results found\\n", nresults); /* Show them on the screen, if any. */ for (size_t i = 0; i < nresults; i++) { for (size_t j = 0; j < results[i]->nmatches; j++) { printf("file: %s, match: %s\n", results[i]->file, results[i]->matches[j]->match); } } /* Free all results. */ ag_free_all_results(results, nresults); /* Release Ag resources. */ ag_finish(); return 0; } Uma vez que a libag possui bindings para Python e Node.js, seguem os mesmos exemplos abaixo:
      Python:
      from libag import * # Initiate Ag library with default options. ag_init() # Search. nresults, results = ag_search("foo", ["."]) if nresults == 0: print("no result found") else: print("{} results found".format(nresults)) # Show them on the screen, if any. for file in results: for match in file.matches: print("file: {}, match: {}, start: {} / end: {}". format(file.file, match.match, match.byte_start, match.byte_end)) # Free all resources. if nresults: ag_free_all_results(results) # Release Ag resources. ag_finish() Node.js (sujeito a alterações):
      const libag = require('./build/Release/libag_wrapper'); libag.ag_init(); r = libag.ag_search("foo", ["."]); r.results.forEach((file, i) => { file.matches.forEach((match, j) => { console.log( "File: " + file.file + ", match: " + match.match + ", start: " + match.byte_start + " / end: " + match.byte_end ); }); }); libag.ag_finish(); Uso "avançado" e pesquisa em arquivos binários
      O uso básico é como ilustrado acima e representa também as opções padrões do ag. Entretanto, a libag permite um controle fino sobre as opções de busca e também sobre as worker threads.
      As opções podem ser tunadas a partir da estrutura struct ag_config, que contém uma série de inteiros que representam diretamente o recurso desejado. Opções como num_workers e search_binary_files definem a quantidade de worker threads e habilitam a busca em arquivos binários, respectivamente.
      Um exemplo mais interessante segue abaixo, vamos localizar arquivos ELF e PE32 que também contenham meu nome de usuário neles:
      from libag import * pattern = "david"; elf_signature = "^\x7f\x45\x4c\x46"; pe_signature = "^\x4d\x5a"; signatures = elf_signature + "|" + pe_signature; # Enable binary files search config = ag_config() config.search_binary_files = 1 # Initiate Ag library with custom options. ag_init_config(config) # Search. nresults, results = ag_search(signatures, ["dir/"]) if nresults == 0: print("no result found") sys.exit(1) print("{} pe+elf found".format(nresults)) for file in results: print("file: {}".format(file.file)) pe_elf = [] # Add to our list for file in results: pe_elf.append(file.file); ag_free_all_results(results) # Search again looking for pattern nresults, results = ag_search(pattern, pe_elf) if nresults == 0: print("no result found") sys.exit(1) # Show them print("{} binaries found that matches {}".format(nresults, pattern)) for file in results: for match in file.matches: print("file: {}, match: {}, start: {} / end: {}". format(file.file, match.match, match.byte_start, match.byte_end)) # Free all resources. ag_free_all_results(results) # Release Ag resources. ag_finish() A pasta dir/ contém um arquivo ELF, um PE32+, um plaintext e uma imagem .png. Note que o range informado pode ser verificado com dd+hexdump, como segue abaixo:
      $ file dir/* dir/hello: PE32+ executable (console) x86-64, for MS Windows dir/img.png: PNG image data, 1247 x 711, 8-bit/color RGB, non-interlaced dir/libag.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, with debug_info, not stripped dir/random.txt: ASCII text $ ./elf_pe.py 2 pe+elf found file: dir/libag.so file: dir/hello 1 binaries found that matches david file: dir/libag.so, match: david, start: 90094 / end: 90098 $ dd if=dir/libag.so bs=1 skip=90094 count=5 | hexdump -C 5+0 records in 5+0 records out 5 bytes copied, 2.1437e-05 s, 233 kB/s 00000000 64 61 76 69 64 |david| 00000005 É claro que o exemplo acima é bastante simplório e serve apenas para ilustrar possíveis casos de uso da biblioteca.
      O processo de "libificação"
      A escolha do fork do ag foi bem natural: eu já tinha alguma familiaridade com o código fonte do ag e eu já havia brincado com ele alguns meses atrás. Além disso, o código do ag não é tão grande e eu sou um programador C em 99.9% do meu tempo, o que elimina alternativas como ripgrep (Rust) e ugrep (C++).
      O processo de "libificação" não foi tão complicado: primeiro eu extraí apenas o código fonte do projeto e escrevi meus próprios/novos scripts de build por cima (Makefile e CMake). Depois disso, foi investigar o processo de search original do ag e trazer isso para a minha biblioteca.
      De forma resumida, o ag original pode ser divido em três grandes etapas:
      Inicialização Configura o log_level (para propósitos de debug); Inicializa as estruturas de .gitignore (o ag é capaz de ignorar esse tipo de arquivo); Inicializa as opções default da linha de comando; Realiza o parsing das opções de linha de comando; Compila a regex via PCRE; Inicializa os mutexes e as worker threads. Busca O processo de busca e path traversal é realizado por uma única thread, que a partir da lista de paths recuperados via linha de comando invoca a rotina search_dir(), que para cada novo path encontrado o adiciona em uma "work_queue_t" e acorda todas as worker threads (se estiverem dormindo) para recuperar mais trabalhos.
      O processo de sincronização é feito via mutexes, mas em defesa do maintainer original do ag, um profiling no Intel VTune mostra que o tempo de hold de cada thread é mínímo, o que realmente torna o ag (e libag) escalável com o aumento da quantidade de cores.
      Resultados Uma vez que uma worker thread (WT) obtém um novo "job", ela então começa a leitura do arquivo: seja via mmap (padrão) ou todo o arquivo de uma só vez. Para buscas de texto literal, a "WT" utiliza os algoritmos de BoyerMoore e de hash para identificação da string. Em caso de expressão regular, utiliza-se a biblioteca PCRE. A decisão dos algoritmos é feita automaticamente, para maior desempenho.
      À medida que novos resultados são encontrados (para um único arquivo), eles são adicionados em uma lista de matches, definida pelo tipo match_t e ao finalizar a leitura do arquivo os resultados encontrados são impressos na tela, protegidos por um mutex.
      Salvando os resultados
      Uma vez obtidos os resultados, entra então a maior "incisão" da libag: interferir no processo de dump dos resultados e salvá-los de forma estruturada e facilmente recuperável posteriormente.
      Para isso, foi introduzido um vetor de resultados (dinâmico) por WT, que armazena os dados obtidos até o momento. Além disso, a rotina principal das worker threads (search_file_worker()) foi levemente modificada para notificar do término das threads e também permitir facilmente manipular o "start/stop" delas sob demanda.
      Uma vez que toda a work queue foi preenchida e processada, a rotina de search (da biblioteca) pode resumir sua execução, fazendo o join dos resultados parciais das threads e retornando um "struct ag_search**", que contém uma lista de resultados por arquivo, a string do match, flags e byte de início e fim da ocorrência, algo como:
      /** * Structure that holds a single result, i.e: a file * that may contains multiples matches. */ struct ag_result { char *file; size_t nmatches; struct ag_match { size_t byte_start; size_t byte_end; char *match; } **matches; int flags; }; Bindings
      Para facilitar a utilização da libag, o projeto também possui bindings experimentais para Python 2/3 e também Node.js (em desenvolvimento). 
      Python
      Os bindings para Python foram escritos utilizando o SWIG: um programa que, dado um arquivo de interface, é capaz de gerar um "glue-code" que, quando compilado em conjunto com o código original, funciona como um wrapper/binding para a linguagem em questão.
      O SWIG gera código compilável para CPython e os tipos não-primitivos (como as duas estruturas introduzidas pela biblioteca) são mapeados via "type-maps".
      Node.js
      Embora o SWIG suporte Node.js, ele parece utilizar diretamente a API da v8 engine, que está sempre em constante mudanças, e portanto, o código gerado não compila na última versão estável (v14.17.1 LTS) do Node.
      Para contornar isso, os bindings para Node.js foram escritos em cima da Node-API, uma API em C (também disponível em C++, com nome de node-addon-api) que oferece um conjunto mínimo de recursos em cima da v8 e que têm como objetivo manter a estabilidade de addons escritos mesmo entre versões distintas do Node e v8.
      Limitações
      Ao contrário de programas construídos em cima de uma biblioteca, como o cURL+ libcurl, ag (aparentemente) nunca foi idealizado como tal e portanto o código fonte impõe certas restrições ao adaptá-lo para uma biblioteca, das quais vale destacar:
      Apenas uma única configuração "global": não é possível (no momento) utilizar opções distintas de search para múltiplos searchs; Uma alternativa a isso é manter múltiplos "ag_config" e setá-los com ag_set_config() antes de cada busca. Esta limitação se deve ao ag utilizar uma única estrutura global para armazenar os parâmetros de linha de comando, estrutura essa utilizada em diversos pontos em todo o código fonte. Uma busca de cada vez: assim como no item anterior, o ag também usa diversas estruturas globais para manter o estado da busca durante um ag_search(), o que impossibilita de utilizar múltiplos searchs simultaneamente. Uma solução temporária foi adicionada com o uso da função ag_search_ts(), que internamente utiliza locks para serializar todas as chamadas a ag_search(). Dentre outros. Qualquer contribuição em pontos como esses e outros é muito bem vinda =).
      Conclusão
      Por fim, convido todos a conhecerem a página da libag no GitHub. Trata-se de um projeto de código aberto e, portanto, está aberto a contribuições. Espero que ele possa ser tão útil para mais pessoas quanto está sendo para os que já o utilizam!
      ~ Theldus signing off!
    • By Bruna Chieco
      O Google está trabalhando para permitir que código Rust seja utilizado no kernel Linux, o que se trata de uma grande mudança tecnológica e cultural após décadas usando apenas a linguagem C. Para isso, a empresa financiará o projeto com o objetivo aumentar a segurança do sistema operacional, conforme publicou o CNet.
      A empresa já financia um projeto do Internet Security Research Group para deixar toda a Internet mais segura. Trata-se de um módulo para o Apache HTTP web server (ou simplesmente httpd), que é um software livre, sendo o servidor web mais utilizado no mundo, também escrito em linguagem C, utilizando a linguagem chamada Rust.
      Agora, o projeto permite possível adicionar novos elementos escritos em Rust no coração do Linux, chamados de kernel, o que tornaria os sistemas operacionais Android e Chrome do Google mais seguros. Miguel Ojeda está sendo contratado para escrever software em Rust para o kernel Linux. O Google está pagando pelo contrato, que será estendido por meio do Internet Security Research Group. 
      A melhor segurança para o Linux é uma boa notícia para todos, exceto para os atacantes. Além dos sistemas operacionais Android e Chrome, os serviços do Google, como YouTube e Gmail, contam com servidores que executam Linux. Ele também capacita a Amazon e o Facebook, e é um acessório nos serviços de computação em nuvem.
      Não está claro se os líderes do kernel do Linux irão acomodar o Rust. Segundo o CNet, Linus Torvalds, o fundador do Linux, disse que está aberto a mudanças se o Rust para Linux provar seu valor. 
    • By Bruna Chieco
      O Cisco Talos, grupo global de inteligência de ameaças de cibersegurança da Cisco, descobriu uma vulnerabilidade de divulgação de informações no kernel do Linux.
      A vulnerabilidade, rastreada como CVE-2020-28588, pode permitir que um invasor visualize a pilha de memória do kernel, o que significa que dados ou informações que não deveriam ser vistas possam ser acessadas. O problema foi visto pela primeira vez pelo Cisco Talos em um dispositivo Azure Sphere (versão 20.10), um dispositivo ARM de 32 bits que executa um kernel do Linux corrigido.
      O kernel do Linux é o núcleo livre e de código aberto dos sistemas operacionais do tipo Unix. A vulnerabilidade existe especificamente na funcionalidade /proc/pid/syscall de dispositivos ARM de 32 bits executando Linux.
      Um invasor pode explorá-la lendo /proc/<pid>/syscall, um arquivo legítimo do sistema operacional Linux, podendo aproveitar esse vazamento de informações para explorar com êxito vulnerabilidades adicionais não corrigidas.
      O Cisco Talos trabalhou com o Linux para garantir que esse problema seja resolvido e uma atualização já está disponível para os clientes afetados. Os usuários são incentivados a atualizar esses produtos afetados o mais rápido possível para o Kernel Linux versões 5.10-rc4, 5.4.66 e 5.9.8.
×
×
  • Create New...