desenvolvimento para sistemas embarcados (cea 513) · * história da linguagem c - 1989/1990: 1o...

72
Universidade Federal de Ouro Preto Departamento de Computação e Sistemas - DECSI Vicente Amorim [email protected] www.decom.ufop.br/vicente Desenvolvimento para Sistemas Embarcados (CEA 513) Codificação Segura para Embarcados

Upload: phamcong

Post on 03-Dec-2018

219 views

Category:

Documents


0 download

TRANSCRIPT

Universidade Federal de Ouro Preto Departamento de Computação e Sistemas - DECSI

Vicente [email protected]/vicente

Desenvolvimento para Sistemas Embarcados (CEA 513)Codificação Segura para Embarcados

www.decom.ufop.br/vicente

Sumário

* Introdução

* Problemas mais comuns

www.decom.ufop.br/vicente

Introdução

www.decom.ufop.br/vicente

Introdução

* Desenvolvimento atualmente para embarcados se ancora basicamente em duas linguagens: C/C++

- Linguagem antiga? Sem uso? Ultrapassada?

- TIOBE (09/2014)

www.decom.ufop.br/vicente

Introdução

* História da linguagem C- 1969: Ken Thompson criou o Unix (Bell Labs), em Assembly à partir de ideias do sistema operacional MULTICS.

- 1970: UNIX reescrito para PDP-11.

- 1973: Dennis Ritchie criou a linguagem C, a partir da linguagem B (Ken Thompson) e BCPL.

- Linguagem C utilizada para escrever o UNIX!

- 1978: Linguagem oficialmente publicada com o livro “The C Programming Language”.

www.decom.ufop.br/vicente

Introdução

* História da linguagem C- 1989/1990: 1o padrão: ANSI criou o comitê X3J11 em 1983 para a criação de um padrão para a linguagem, o que efetivamente só aconteceu em 1989. Tal padrão também foi aceito pela ISO e nomeado ISO/IEC 9899-1990 (C90).

- 1995/1996: Lançado o C95 através de várias correções em padrões anteriores.

- 1999: 2o padrão: ISO/IEC 9899:1999, conhecido como C99.

- 2011: 3o padrão: ISO/IEC 9899:2011, conhecido como C11.

www.decom.ufop.br/vicente

Introdução

* C e Embarcados- Linguagem utilizada em uma série de ambientes e soluções.

- Em embarcados talvez o contexto mais apropriado.

- Na presença de um Sistema Operacional: Ex.: Linux.

www.decom.ufop.br/vicente

Introdução

* C e Embarcados- Entretanto, pode não haver um Sistema Operacional:

www.decom.ufop.br/vicente

Introdução

* C e Embarcados- C é flexível, portável entre arquiteturas distintas e enxuta (44 keywords).

✓ Verificação em tempo de execução do C é pobre: Entretanto, código é pequeno e eficiente.

- Nem tudo são flores:

✓ Erros mais comuns encontrados:‣ Manipulação de strings;

‣ Pilha;

‣ Alocação dinâmica de memória.

www.decom.ufop.br/vicente

Introdução

* C e Embarcados- Maioria dos erros são causados por humanos. Padrões de codificação podem ajudar na redução dos mesmos:

✓ MISRA-C (aplicado na aviação).

✓ Netrino’s Embedded C coding standard.

✓ CERT C.

www.decom.ufop.br/vicente

Introdução

* Problemas podem aparecer durante o processo de desenvolvimento.

- Avaliação dos padrões através de ferramentas de análise:

✓ Estáticas: QA-C, CodeCheck, PC-lint, ...

✓ Grátis: Splint.

* Ferramentas podem auxiliar na busca automatizada por erros e falhas:

✓ Dinâmicas: Valgrind / DUMA.

www.decom.ufop.br/vicente

Introdução

* Testes, validação e confiabilidade:- Testes podem provar a existência de erros, mas não a falta deles.

✓ Unity✓ CppUTest

- Quanto melhor a cobertura dos testes, mais confiável é seu programa.

- Ferramentas para automatização de testes:

www.decom.ufop.br/vicente

Problemas mais comuns

www.decom.ufop.br/vicente

Problemas mais comuns

* Desenvolvedores em C/C++ comumente cometem erros parecidos.

* Linguagem possui particularidades que precisam ser respeitadas.

* Medidas a se “evitar o pior caso” são normalmente a alternativa mais comum: programação defensiva.

* Conhecer o erros/problemas mais comuns ajuda a evitá-los.

www.decom.ufop.br/vicente

Problemas mais comuns

* Manipulação de strings:- Cópias de strings sem limites;

- Erros de off-by-one;

- Null-termination;

- Strings truncadas.

www.decom.ufop.br/vicente

Problemas mais comuns

* Manipulação de strings:- Cópias de strings sem limites:

✓ Problema: Os dados são copiados de uma origem sem delimitação para um array de caracteres com tamanho fixo.

✓ Exemplo: Uso da função gets() -> “deprecated” no padrão C99 e inexistente no C11.

✓ “MSC34-C: Do not use deprecated or obsolescent functions.”

✓ “STR35-C. Do not copy data from an unbounded source to a fixed-length array.”

www.decom.ufop.br/vicente

Problemas mais comuns

* Manipulação de strings:

- Cópias de strings sem limites:

#include <stdio.h> static void get_user_name(void);

static void get_user_name(void) { char name[8]; puts("Insira seu nome: "); gets(name); if (name[0] == '\0') { printf("Nenhum dado inserido!\n"); } else { printf("Muito obrigado!\n"); } //TODO: processamento... }

int main(void) { get_user_name(); return 0; }

- Exemplo 1:

✓ Problema??

✓ Buffer Overflow!!!

www.decom.ufop.br/vicente

Problemas mais comuns

* Manipulação de strings:

- Cópias de strings sem limites:

$ splint Exemplo1.c Splint 3.1.2 --- 03 May 2009

Exemplo1.c: (in function get_user_name) Exemplo1.c:8:5: Return value (type int) ignored: puts("Insira seu... Result returned by function call is not used. If this is intended, can cast result to (void) to eliminate message. (Use -retvalint to inhibit warning) Exemplo1.c:9:5: Use of gets leads to a buffer overflow vulnerability. Use fgets instead: gets Use of function that may lead to buffer overflow. (Use -bufferoverflowhigh to inhibit warning) Exemplo1.c:9:5: Return value (type char *) ignored: gets(name) Result returned by function call is not used. If this is intended, can cast result to (void) to eliminate message. (Use -retvalother to inhibit warning)

Finished checking --- 3 code warnings

www.decom.ufop.br/vicente

Problemas mais comuns

* Manipulação de strings:

- Cópias de strings sem limites:

#include <stdio.h> static void get_user_name(void);

static void get_user_name(void) { char name[8]; (void) puts("Insira seu nome: "); if (fgets(name, (int) sizeof(name), stdin) == NULL) { printf("Nenhum dado inserido!\n"); } else { printf("Nome: %s\n",name); printf("Muito obrigado!\n"); } // TODO: processamento... }

int main(void) { get_user_name(); return 0; }

- Exemplo 2:

✓ Corrigido!

www.decom.ufop.br/vicente

Problemas mais comuns

* Manipulação de strings:- Cópias de strings sem limites:

$ splint Exemplo2.c Splint 3.1.2 --- 03 May 2009

Finished checking --- no warnings

- Corrigido:

- Outras funções perigosas:✓ strcpy -> strncpy, stdup (não presente em C99 e C11)

✓ strcat -> strncat

✓ sprintf -> snprintf“Never use gets(). Because it is impossible to tell without knowing the data in advance how many characters gets() will read, and because gets() will continue to store characters past the end of the buffer, it is extremely dangerous to use. It has been used to break computer security. Use fgets() instead.”

Fonte: http://www.linuxmanpages.com/man3/gets.3.php

www.decom.ufop.br/vicente

Problemas mais comuns

* Manipulação de strings:- Off-by-One:

- Problema: Devido a um erro de indexação, é acessada uma posição além dos limites do buffer criado.

#include <string.h> #include <stdio.h> #include <stdlib.h>

int main(void) { char s1[] = "012345678"; char s2[] = "0123456789"; char *dest; int i; strncpy(s1, s2, sizeof(s2)); dest = (char *) malloc(strlen(s1)); for (i = 1; i <= 11; i++) { dest[i] = s1[i]; } dest[i] = '\0'; printf("dest = %s", dest); free(dest); return 0; }

- Exemplo 3:

✓ Problema??

www.decom.ufop.br/vicente

Problemas mais comuns

* Manipulação de strings:- Off-by-One:

$ splint Exemplo3.c Splint 3.1.2 --- 03 May 2009

Exemplo3.c: (in function main) Exemplo3.c:16:9: Index of possibly null pointer dest: dest A possibly null pointer is dereferenced. Value is either the result of a function which may return null (in which case, code should check it is not null), or a global, parameter or structure field declared with the null qualifier. (Use -nullderef to inhibit warning) Exemplo3.c:13:12: Storage dest may become null

Finished checking --- 1 code warning

- Problema: Acesso indevido a posição inexistente do buffer.

www.decom.ufop.br/vicente

Problemas mais comuns

* Manipulação de strings:- NULL-termination: #include <string.h>

#include <stdio.h> #include <stdlib.h>

int main(void) { char a[16]; char b[16]; char c[16]; strncpy(a, "0123456789abcdef", sizeof(a)); strncpy(b, "0123456789abcdef", sizeof(b)); strcpy(c, a); return 0; }

- Exemplo 4:

$ splint Exemplo4.c Splint 3.1.2 --- 03 May 2009

Finished checking --- no warnings

- Problema: Não terminar uma string com o caractere NULL (‘\0’).

“STR32-C. Null-terminate byte strings as required.”

CERT C Secure Coding Standard

www.decom.ufop.br/vicente

Problemas mais comuns

* Manipulação de strings:- NULL-termination:

- Exemplo 5:

- Correção: Não terminar uma string com o caractere NULL (‘\0’).

#include <string.h> #include <stdio.h> #include <stdlib.h>

int main(void) { char a[16]; char b[16]; char c[16]; strncpy(a, "0123456789abcdef", sizeof(a)); a[sizeof(a) - 1] = '\0'; strncpy(b, "0123456789abcdef", sizeof(b)); b[sizeof(b) - 1] = '\0'; strcpy(c, a); return 0; }

$ splint Exemplo5.c Splint 3.1.2 --- 03 May 2009

Finished checking --- no warnings

www.decom.ufop.br/vicente

Problemas mais comuns

* Manipulação de strings:- Strings truncadas:

- Exemplo 6:

- Problema: Determinado array de caracteres não é grande o bastante para armazenar uma string.

- Funções perigosas: Se não as uso, não tenho com o que me preocupar, certo??$ splint Exemplo6.c Splint 3.1.2 --- 03 May 2009

Finished checking --- no warnings

#include <stdio.h>

int main(int argc, char *argv[]) { int i = 0; char buffer[32]; char *arg1 = argv[1]; if (argc == 1) { printf("Sem argumentos!\n"); return -1; } while (arg1[i] != '\0') { buffer[i] = arg1[i]; i++; } buffer[i] = '\0'; printf("buffer = %s\n", buffer); return 0; }

www.decom.ufop.br/vicente

Problemas mais comuns

* Manipulação de strings:- Strings truncadas:

- Exemplo 7: (correção)

#include <stdio.h>

int main(int argc, char *argv[]) { char buffer[32]; char *arg1 = argv[1]; if (argc == 1) { printf("Sem argumentos!\n"); return -1; } strncpy(buffer, arg1, sizeof(arg1)); printf("buffer = %s\n", buffer); return 0; }

- Solução: Uma das possíveis é trocar a cópia iterativa por uma função “segura” (strncpy).

- Iterativamente, deve-se levar em conta o tamanho do buffer destino.

www.decom.ufop.br/vicente

Problemas mais comuns

* Vulnerabilidades gerais- Tainted data

✓ Tratamento de strings: Difícil saber o conteúdo dos dados recebidos e o seu tamanho.

✓ Usuários podem acidentalmente prover dados incorretos.

✓ Usuários podem deliberadamente prover dados incorretos.

✓ Então, dados podem estar contaminados (tainted).

✓ Como tratar?

www.decom.ufop.br/vicente

Problemas mais comuns

* Vulnerabilidades gerais- Tainted data✓ Validação dos dados é necessária.

✓ Problemas:

- Exemplo 8: #include <stdio.h> #include <string.h> #include <stdbool.h>

bool IsPasswordOK(void) { char Password[12]; gets(Password); return (0 == strcmp(Password,"goodpass")); }

int main(void) { bool PwStatus; puts("Enter your password: "); PwStatus = IsPasswordOK(); if (PwStatus == false) { puts("Access denied!!"); return -1; } else { puts("Access granted!"); } return 0; }

‣ Uso da função gets();

‣ Não tratamento dos dados vindos do usuário;

“FIO04-C: Detect and handle input and output errors.”

CERT C Secure Coding Standard

www.decom.ufop.br/vicente

Problemas mais comuns

* Vulnerabilidades gerais- Uma falha de segurança não indica, necessariamente, uma vulnerabilidade.

- Vulnerabilidade se caracterizará se o intruso tiver acesso aos dados de entrada do sistema.

- Intruso obteve acesso... E agora? O que pode acontecer?✓ Arc Injection; e

✓ Code Injection.

- Entretanto... Antes, um pouco de teoria.

www.decom.ufop.br/vicente

Problemas mais comuns

* Vulnerabilidades gerais- Buffer Overflows

Destination Memory

Source Memory

Allocated Memory (12 Bytes) Other Memory

16 Bytes of Data

Copy Operation

www.decom.ufop.br/vicente

Problemas mais comuns

* Vulnerabilidades gerais- Organização das regiões de memória em um processo:

www.decom.ufop.br/vicente

Problemas mais comuns

www.decom.ufop.br/vicente

Problemas mais comuns

* Vulnerabilidades gerais

✓ Estrutura de dados dinâmica que suporta a execução de uma aplicação.:

1) Dados passados por funções;

2) Variáveis locais;

3) Endereços de retorno das funções chamadoras;

4) Endereço base da pilha da função chamadora.

- Stack (pilha)

✓ Quando uma função é chamada, esta estrutura armazena:

✓ Este conjunto de informações = Stack frame.

www.decom.ufop.br/vicente

Problemas mais comuns

* Vulnerabilidades gerais- Stack (pilha)

www.decom.ufop.br/vicente

Problemas mais comuns

* Vulnerabilidades gerais

✓ Review funções principais registradores arquitetura x86 Intel:

- Stack (pilha)

Registrador Funçãoebp base pointer registeresp stack pointer registereax accumulator registerecx counter register (loop counter)edx data registereip index pointer register (inst. atual)

www.decom.ufop.br/vicente

Problemas mais comuns

* Vulnerabilidades gerais- Stack (pilha)

Exemplo 9: #include <stdio.h>

void foo(int, char *);

int main(void) { int MyInt = 1; char *MyStrPtr = "MyString"; foo(MyInt,MyStrPtr); return 0; }

void foo(int MyInt, char *MyStrPtr) { char LocalChar[24]; int LocalInt;

LocalInt++; return; }

foo(MyInt,MyStrPtr); 19: 8b 44 24 1c mov eax,DWORD PTR [esp+0x1c] 1d: 89 44 24 04 mov DWORD PTR [esp+0x4],eax 21: 8b 44 24 18 mov eax,DWORD PTR [esp+0x18] 25: 89 04 24 mov DWORD PTR [esp],eax 28: e8 fc ff ff ff call 29 <main+0x29>

2o argumento colocado na pilha!! (MyStrPtr)

1o argumento colocado na pilha!! (MyInt)

Chamada ao método!! (foo(MyInt, MyStrPtr)

www.decom.ufop.br/vicente

Problemas mais comuns

* Vulnerabilidades gerais- Stack (pilha) “antes da chamada”

Endereço Valor Descrição Tamanho

... ... ... ...0xbffff338 1 Variável local MyInt(int) 40xbffff33C 0x8048540 "MyString" Variável local MyStrPtr(char*) 40xbffff340 ? Endereço stack frame do SO 40xbffff344 0x804841d Endereço de retorno do SO 40xbffff348 SO (1) Primeiro argumento main (argc) 40xbffff34C 0xb7e3a4d3 Endereço que chamou main 4

$ebp$eip

www.decom.ufop.br/vicente

Problemas mais comuns

* Vulnerabilidades gerais- Stack (pilha)✓ Função foo() prólogo:‣ Instruções que são executadas no início da função chamada:

void foo(int MyInt, char *MyStrPtr) { 34: 55 push ebp 35: 89 e5 mov ebp,esp 37: 83 ec 38 sub esp,0x38

✓ Função foo() epílogo:‣ Instruções que são executadas ao final da função chamada:

return; 4b: 8b 45 f4 mov eax,DWORD PTR [ebp-0xc] 4e: 65 33 05 14 00 00 00 xor eax,DWORD PTR gs:0x14 55: 74 05 je 5c <foo+0x28> 57: e8 fc ff ff ff call 58 <foo+0x24> 5c: c9 leave 5d: c3 ret

www.decom.ufop.br/vicente

Problemas mais comuns

* Vulnerabilidades gerais- Stack (pilha)✓ Função foo() é chamada e seus parâmetros são adicionados a pilha.

✓ Variáveis locais precisam ser consideradas.

✓ Contexto da função main() é mantido na pilha.

www.decom.ufop.br/vicente

Problemas mais comuns

* Vulnerabilidades gerais- Stack (pilha) “durante a chamada”

Endereço Valor Descrição Tamanho

0xbffff2ec 0x8048540 "MyString" Segundo argumento de foo() 40xbffff2f0 - Variável local LocalInt 40xbffff2f4 - Variável local LocalChar 240xbffff318 0xbffff348 Endereço stack frame da função main() 40xbffff31c 0x08048431 Endereço de retorno da função main() 40xbffff320 1 Primeiro argumento de foo() 4

... ... ... ...0xbffff338 1 Variável local MyInt(int) 40xbffff33c 0x8048540 "MyString" Variável local MyStrPtr(char*) 40xbffff340 ? Endereço stack frame do SO 40xbffff344 0x804841d Endereço de retorno do SO 40xbffff348 SO (1) Primeiro argumento main (argc) 40xbffff34C 0xb7e3a4d3 Endereço que chamou main 4

$ebp$eip

$ebp$eip

www.decom.ufop.br/vicente

Problemas mais comuns

* Vulnerabilidades gerais- Stack (pilha)✓ Ao final da função foo(), é necessário retomar o contexto da função main().

✓ Variáveis locais precisam ser novamente consideradas.

✓ Contexto da função main() é mantido na pilha - mesmo na chamada de foo().

www.decom.ufop.br/vicente

Problemas mais comuns

* Vulnerabilidades gerais- Stack (pilha) “após a chamada”

Endereço Valor Descrição Tamanho

0xbffff2ec ??? ??? 40xbffff2f0 ??? ??? 40xbffff2f4 ??? ??? 240xbffff318 ??? ??? 40xbffff31c ??? ??? 40xbffff320 ??? ??? 4

... ... ... ...0xbffff338 1 Variável local MyInt(int) 40xbffff33c 0x8048540 "MyString" Variável local MyStrPtr(char*) 40xbffff340 ? Endereço stack frame do SO 40xbffff344 0x804841d Endereço de retorno do SO 40xbffff348 SO (1) Primeiro argumento main (argc) 40xbffff34C 0xb7e3a4d3 Endereço que chamou main 4

$ebp$eip

www.decom.ufop.br/vicente

Problemas mais comuns

* Vulnerabilidades gerais- Stack Smashing✓ Como visto, buffer overflow pode causar danos.

✓ Na memória de pilha recebe o nome de stack smashing.

✓ Pode causar sérios problemas de confiabilidade de segurança.

✓ Buffer overflow na pilha pode permitir um atacante modificar valores de variáveis automáticas.

✓ Perda da integridade ou perda de dados confiáveis.

✓ Pior: Execução de código arbitrário!!!

www.decom.ufop.br/vicente

Problemas mais comuns

* Vulnerabilidades gerais- Stack Smashing✓ O exemplo de obtenção de senha do usuário pode sofrer com esse tipo de ataque.

... puts("Enter your password: "); PwStatus = IsPasswordOK(); if (PwStatus == false) { puts("Access denied!!"); return -1; } else { puts("Access granted!"); } return 0; }

✓ Antes da chamada ao IsPasswordOK():

$eip Stack

Arm. de PwStatus (4bytes)

%ebp q/ chamou (OS 4bytes)

Endereço retorno main (OS 4bytes)

$esp

... puts("Enter your password: "); PwStatus = IsPasswordOK(); if (PwStatus == false) { puts("Access denied!!"); return -1; } else { puts("Access granted!"); } return 0; }

www.decom.ufop.br/vicente

Problemas mais comuns

* Vulnerabilidades gerais- Stack Smashing✓ Durante a chamada ao IsPasswordOK():

$eipStack

Arm. de Password (12bytes)

%ebp q/ chamou (main 4bytes)

Endereço retorno chamador (main 4bytes)

Arm. de PwStatus (4bytes)

%ebp q/ chamou (OS 4bytes)

Endereço retorno main (OS 4bytes)

$esp

bool IsPasswordOK(void) { char Password[12]; gets(Password); return (0 == strcmp(Password,"goodpass")); }

www.decom.ufop.br/vicente

Problemas mais comuns

* Vulnerabilidades gerais- Stack Smashing✓ Após a chamada ao IsPasswordOK():

... puts("Enter your password: "); PwStatus = IsPasswordOK(); if (PwStatus == false) { puts("Access denied!!"); return -1; } else { puts("Access granted!"); } return 0; }

$eip

Stack

Arm. de Password (12bytes)

%ebp q/ chamou (main 4bytes)

Endereço retorno chamador (main 4bytes)

Arm. de PwStatus (4bytes)

%ebp q/ chamou (OS 4bytes)

Endereço retorno main (OS 4bytes)

$esp

www.decom.ufop.br/vicente

Problemas mais comuns

* Vulnerabilidades gerais- Stack Smashing✓ Falha de segurança em IsPasswordOK():‣ Tentativa de armazenar um password maior que 11 caracteres gera crash.

‣ Com uma entrada de 20 caracteres, 21 caracteres são necessários para armazenar password: 21 - 12 = 9 bytes restantes.

‣ 9 bytes restantes sobrescrevem alguma posição de memória previamente alocada.

Stack

Arm. de Password (12bytes) “123456789012”

%ebp q/ chamou (main 4bytes) “3456”

Endereço retorno chamador (main 4bytes) “7890”

Arm. de PwStatus (4bytes) `\0`

%ebp q/ chamou (OS 4bytes)

Endereço retorno main (OS 4bytes)

www.decom.ufop.br/vicente

Problemas mais comuns

* Vulnerabilidades gerais- Stack Smashing✓ Durante a chamada ao IsPasswordOK():

$esp

bool IsPasswordOK(void) { char Password[12]; gets(Password); return (0 == strcmp(Password,"goodpass")); }

$eip

www.decom.ufop.br/vicente

Problemas mais comuns

* Vulnerabilidades gerais- Stack Smashing✓ Falha de segurança em IsPasswordOK():

‣ Quando uma falha ocorre, um usuário comum simplesmente tentará reiniciar o programa como forma de sanar o problema.

‣ Usuário mais experiente irá investigar e tentar descobrir a causa da falha e se a mesma pode ser explorada.

‣ Crash ocorre em razão de se sobrescrever o endereço de retorno.

‣ Memória no endereço: 1) Sem instrução de CPU válida; 2) Contém uma instrução mas valores nos registradores são inválidos; 3) Não é executável.

www.decom.ufop.br/vicente

Problemas mais comuns

* Vulnerabilidades gerais- Arc Injection✓ No exemplo anterior, entrada especial pode fazer com q/ o prog. produza saída inexperada.

Stack

Arm. de Password (12bytes) “123456789012”

%ebp q/ chamou (main 4bytes) “3456”

Endereço retorno chamador (main 4bytes) “ ÄHP”

Arm. de PwStatus (4bytes) `\0`

%ebp q/ chamou (OS 4bytes)

Endereço retorno main (OS 4bytes)

✓ Em memória, os 4bytes da linha destacada alteram o endereço de retorno.

✓ Redirecionamento para outro trecho de código.

www.decom.ufop.br/vicente

Problemas mais comuns

* Vulnerabilidades gerais- Code Injection

✓ Raramente um endereço de retorno sobrescrito irá apontar para alguma instrução válida.

✓ Consequentemente, transferir o controle para o endereço especificado causa uma exceção e corrupção da pilha.

✓ Entretanto, uma entrada especialmente criada por um atacante pode causar a execução de um código malicioso.

www.decom.ufop.br/vicente

Problemas mais comuns

* Vulnerabilidades gerais- Code Injection✓ Quando a função chamada retorna para o endereço especificado - sobrescrito - o controle é transferido para outro código.

✓ Código malicioso irá executar com as mesmas permissões que o programa vulnerável - daí a constante busca pela exploração do “root”.

✓ Frequentemente o código inserido buscará formas de abrir - ou possibilitar a abertura - de um shell remoto.

www.decom.ufop.br/vicente

Problemas mais comuns

* Vulnerabilidades gerais- Code Injection

✓ Voltando ao código do Exemplo 8:

#include <stdio.h> #include <string.h> #include <stdbool.h>

bool IsPasswordOK(void) { char Password[12]; gets(Password); return (0 == strcmp(Password,"goodpass")); }

int main(void) { bool PwStatus; puts("Enter your password: "); PwStatus = IsPasswordOK(); if (PwStatus == false) { puts("Access denied!!"); return -1; } else { puts("Access granted!"); } return 0; }

Stack

Arm. de Password (12bytes)

%ebp q/ chamou (main 4bytes)

Endereço retorno chamador (main 4bytes)

Arm. de PwStatus (4bytes)

%ebp q/ chamou (OS 4bytes)

Endereço retorno main (OS 4bytes)

$esp

$eip

www.decom.ufop.br/vicente

Problemas mais comuns

* Vulnerabilidades gerais- Code Injection

✓ Nova entrada para execução de Exemplo 8:

www.decom.ufop.br/vicente

Problemas mais comuns

* Vulnerabilidades gerais- Stack Canary✓ Aplicativos que fazem uso de sistemas operacionais e hardware com suporte a MMU podem facilmente detectar stack overflow.

✓ Utilizando GCC, a detecção de stack overflow é possível através de uma técnica conhecida como “canary”.

✓ Canary: Valor inteiro aleatório, gerado pelo processo atual que é adicionado pelo compilador em uma posição entre o endereço de retorno para a função chamadora e as variáveis locais da função.

www.decom.ufop.br/vicente

Problemas mais comuns

* Vulnerabilidades gerais- Stack Canary✓ Sem proteção:

www.decom.ufop.br/vicente

Problemas mais comuns

* Vulnerabilidades gerais- Stack Canary ✓ Com proteção:

www.decom.ufop.br/vicente

Problemas mais comuns

* Alocação Dinâmica de Memória- Posso utilizar alocação dinâmica em sistemas embarcados?

✓ Em geral: Utilizada quando não há conhecimento de antemão - tempo de compilação - do espaço de memória a ser utilizado.

✓ Principais pontos:‣ Recursos voláteis são limitados (RAM, SRAM, DDRAM, etc);

‣ Implementação - ou existência - do gerenciador de memória;

‣ Determinismo: Necessário em sist. embarcados;

‣ Tratamento de erros;

www.decom.ufop.br/vicente

Problemas mais comuns

* Alocação Dinâmica de Memória- Posso utilizar alocação dinâmica em sistemas embarcados?✓ Principais pontos: (cont.)

‣ Normalmente funções de alocação não são reentrantes, o que pode ser um problema para sistemas multithreaded.

✓ Uma aplicação no PC pode gerar uma mensagem de erro, mas não um módulo de injeção do carro, um navegador do avião, etc.

www.decom.ufop.br/vicente

Problemas mais comuns

* Alocação Dinâmica de Memória- Fragmentação de memória (8KB disponível)

... p1 = malloc(1024); p2 = malloc(2048); p3 = malloc(1024); ... free(p3); free(p2); free(p1); ...

www.decom.ufop.br/vicente

Problemas mais comuns

* Alocação Dinâmica de Memória- Fragmentação de memória (8KB disponível)

... p1 = malloc(1024); p2 = malloc(2048); p3 = malloc(1024); ... free(p3); free(p1); ...

✓ Total: 8KB✓ Alocado: 4KB✓ Desalocado: 2KB✓ Disponível: 6KB✓ malloc(6* 1024) funciona??

www.decom.ufop.br/vicente

Problemas mais comuns

* Alocação Dinâmica de Memória- Fragmentação de memória (8KB disponível)

... p1 = malloc(1024); p2 = malloc(2048); p3 = malloc(1024); ... free(p3); free(p1); ...

✓ Não funciona!

✓ Existe memória livre, mas não memória contínua suficiente.

✓ Disponível continuamente: (max) 4KB!

www.decom.ufop.br/vicente

Problemas mais comuns

* Alocação Dinâmica de Memória- Alternativas✓ Memory Pool:‣ Pools de memória contendo um número de blocos de tamanho fixo.

‣ Vantagem: Elimina fragmentação..

‣ Desvantagem: Perda de memória (blocos de tamanho 8, 16, 32, ... mas preciso de 17bytes);

www.decom.ufop.br/vicente

Problemas mais comuns

* Alocação Dinâmica de Memória- Alternativas

✓ Garbage Collector:

‣ Aproxima os blocos de memória utilizados.

‣ Utilizado em linguagens como C#, Java, VisualBasic onde o acesso é feito a uma espécie de “memória virtual”.

‣ Vantagem: Elimina fragmentação aumentando o espaço livre conseguinte.

‣ Desvantagem: Não determinístico. Quando será executado? Quanto tempo levará para executar?

www.decom.ufop.br/vicente

Problemas mais comuns

* Alocação Dinâmica de Memória- Implementação em sistemas bare-metal

✓ Dependente do ambiente usado (GNU, IAR, Keil, Renesas, etc).

✓ Se GNU pode ser usada uma biblioteca específica:

‣ Ex.: newlib - Implementa funcionalidade mínima para usar malloc e faz uso do símbolo _end criado no script do linker).

www.decom.ufop.br/vicente

Problemas mais comuns

* Alocação Dinâmica de Memória- Implementação em sistemas com sistema operacional

✓ RTOS: Oferece implementação própria.‣ Uso de memory pools e allocation call.

✓ Linux Embarcado:‣ Utiliza a glibc/uClibc/etc que usam esquema de página típico de SOs unix-like. (4KB cada página)

‣ malloc (<= 4KB): Usa uma página do heap do processo;

‣ malloc (> 4KB): Usa mmap().

www.decom.ufop.br/vicente

Problemas mais comuns

* Alocação Dinâmica de MemóriaExemplo 10:

#include <stdlib.h>

int main(void) { char *x = malloc(10); x[10] = 'a'; return 0; }

$ splint Exemplo10.c Splint 3.1.2 --- 03 May 2009

Exemplo10.c: (in function main) Exemplo10.c:5:2: Index of possibly null pointer x: x A possibly null pointer is dereferenced. Value is either the result of a function which may return null (in which case, code should check it is not null), or a global, parameter or structure field declared with the null qualifier. (Use -nullderef to inhibit warning) Exemplo10.c:4:12: Storage x may become null Exemplo10.c:7:11: Fresh storage x not released before return A memory leak has been detected. Storage allocated locally is not released before the last reference to it is lost. (Use -mustfreefresh to inhibit warning) Exemplo10.c:4:23: Fresh storage x created

Finished checking --- 2 code warnings

www.decom.ufop.br/vicente

Problemas mais comuns

* Alocação Dinâmica de MemóriaExemplo 10:

#include <stdlib.h>

int main(void) { char *x = malloc(10); x[10] = 'a'; return 0; }

$ valgrind ./Exemplo10 ==3322== Memcheck, a memory error detector ==3322== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al. ==3322== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info ==3322== Command: ./Exemplo10 ==3322== ==3322== Invalid write of size 1 ==3322== at 0x8048404: main (in /media/sf_android_card/Codigos/Exemplo10) ==3322== Address 0x41f1032 is 0 bytes after a block of size 10 alloc'd ==3322== at 0x402BE68: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so) ==3322== by 0x80483F8: main (in /media/sf_android_card/Codigos/Exemplo10) ==3322== ==3322== ==3322== HEAP SUMMARY: ==3322== in use at exit: 10 bytes in 1 blocks ==3322== total heap usage: 1 allocs, 0 frees, 10 bytes allocated ==3322== ==3322== LEAK SUMMARY: ==3322== definitely lost: 10 bytes in 1 blocks ==3322== indirectly lost: 0 bytes in 0 blocks ==3322== possibly lost: 0 bytes in 0 blocks ==3322== still reachable: 0 bytes in 0 blocks ==3322== suppressed: 0 bytes in 0 blocks ==3322== Rerun with --leak-check=full to see details of leaked memory ==3322== ==3322== For counts of detected and suppressed errors, rerun with: -v ==3322== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

www.decom.ufop.br/vicente

Problemas mais comuns

* Alocação Dinâmica de MemóriaExemplo 11:

#include <stdlib.h> #include <string.h>

#define BUFF_SIZE 10

int main(void) { char *x = malloc(BUFF_SIZE);

if (x != NULL) { memset(x, 0, BUFF_SIZE); x[BUFF_SIZE-1] = 'a'; free(x); } return 0; }

$ splint Exemplo11.c Splint 3.1.2 --- 03 May 2009

Finished checking --- no warnings

www.decom.ufop.br/vicente

Problemas mais comuns

* Alocação Dinâmica de MemóriaExemplo 11:

#include <stdlib.h> #include <string.h>

#define BUFF_SIZE 10

int main(void) { char *x = malloc(BUFF_SIZE);

if (x != NULL) { memset(x, 0, BUFF_SIZE); x[BUFF_SIZE-1] = 'a'; free(x); } return 0; }

$ valgrind ./Exemplo11 ==3338== Memcheck, a memory error detector ==3338== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al. ==3338== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info ==3338== Command: ./Exemplo11 ==3338== ==3338== ==3338== HEAP SUMMARY: ==3338== in use at exit: 0 bytes in 0 blocks ==3338== total heap usage: 1 allocs, 1 frees, 10 bytes allocated ==3338== ==3338== All heap blocks were freed -- no leaks are possible ==3338== ==3338== For counts of detected and suppressed errors, rerun with: -v ==3338== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

www.decom.ufop.br/vicente

Referências

www.decom.ufop.br/vicente

Referências* Codificação Segura em C para Sistemas Embarcados. Henrique Pérsico Rossi. 07, 2013. http://henriqueprossi.wordpress.com/2013/07/16/tdc2013-codificacao-segura-em-c-para-sistemas-embarcados/

* Secure Coding in C and C++ (2nd Edition). Seacord, Robert C. Addison-Wesley, 2013.

* Secure Programming With Static Analysis. Chess, Brian. West, Jacob. Addison-Wesley, 2007.