CMPT 295 - Unit - Machine-Level Programming

Lecture 22:

Last lecture

Today’s Menu

Buffer Overflow

C and Stack … so far

What kind of trouble? -> buffer overflow (overrun)

M[]
Stack
...
return address
Unused stack space
local var
buf[ ]
%rsp -> Top

Demo the trouble -> buffer overflow

(Transcriber’s note: no content on slide)

Why is buffer overflow a problem

Code injection attack

void func1(){
  func2();
  // C statement
     at return
     address A
  ...
}
int func2() {
  char buf[64];
  gets(buf);
  ...
  return ...;
}
M[] Stack Stack Frame/Note
 
  func1 stack frame
return address func1 stack frame
func2 stack frame
buf[64] func2 stack frame
same buf[64] section labled B func2 stack frame
same buf[64] func2 stack frame
%rsp top

How to protection against such attack

  1. Avoid creating overflow vulnerabilities in the code that we write by always checking bounds
    • For example, by calling library functions that limit string lengths
    • “Unsafe” : gets(), strcpy(), strcat(), sprintf(), …
      • These functions can generate a byte sequence without being given any indication of the size of the destination buffer (see next slide) * “Safe”: fgets()

From our Lab 4

void proc1(char *s, int *a, int *b) {
  int y;
  int t;

  t = *a;
  v = proc2(*a, *b);

  sprintf(s, "The result of proc2(%d,%d) is %d.", *a, *b, v);

  *a = *b - 2;
  *b = t;

  return;

Suggestion from developer.apple.com

char destination[5];
char * source = “LARGER”;
  1. `strcpy(destination, source);
    • Color Value
      White L
      White A
      White R
      White G
      White E
      Brown R
      Brown \0
      Brown  
    • Copies the string pointed to by source (including the null character) to the destination and returns it.
  2. strncpy(destination, source, sizeof(destination))
    • Color Value
      White L
      White A
      White R
      White G
      White E
      Brown  
      Brown  
      Brown  
    • Copies up to sizeof(destination) -> n characters from the string pointed to by source to destination. In a case where the length of source is less than n, the remainder of destination will be padded with null bytes. In a case where the length of source is greater than n, the destination will contain a truncated version of source.
  3. strlcpy(destination, source, sizeof(destination))
    • Color Value
      White L
      White A
      White R
      White G
      White \0
      Brown  
      Brown  
      Brown  
    • Copies up to sizeof(destination) - 1 -> n - 1 characters from null-terminated source to destination, it then “null” terminates destination and returns the length of source.

https://linux.die.net/man/3/strlcpy

How to protection against such attack

2) Employ system-level protections -> Randomized stack offsets

M[] Note
  (crossed off) %rsp
brown shaded box, no value  
top %rsp

How to protection against such attack

2) Employ system-level protections -> Non-executable code segments

Any attempt to execute the bottom “B” set of code, will fail.

How to protection against such attack

3) Compiler (like gcc) uses a stack canary value

main: # main.c from our Lab 4
  endbr64
  pushq %rbp
  ...
  subq $64, %rsp
  movq %fs:40, %rax
  movq %rax, 56(%rsp)
  ...
  leaq 16(%rsp), %rbp
  ...
  movq 56(%rsp), %rax
  xorq %fs:40, %rax
  jne .L5
  addq $64, %rsp
  popq %rbp
  ret
.L5:
  call __stack_chk_fail@PLT

How to protection against such attack

3) Newest version of our gcc compiler (version 8 and up) uses Control-Flow Enforcement Technology (CET) From stackoverflow

Brief overview of floating-point data and operations

(Transcriber’s node: no content on slide)

Background

XMM Registers

x86-64 registers and instructions seen so far are referred to as integer registers and integer instructions Now we introduce a new set of registers for floating point numbers:

Scalar versus Vector (SIMD) instructions

Assembly Instruction Operation Type Percision Note
addss %xmm0,%xmm1 scalar single Add single precision at the last 32 bits of %xmm0 to the last 32 bit of %xmm1. Save in the last 32-bits of %xmm1.
addps %xmm0,%xmm1 SMID (packed) single Add 4 sets of single percision numbers. Each 32 bit section of %xmm0 is added to each 32 bit section of %xmm1.
addsd %xmm0,%xmm1 scalar double Add two double-precision numbers. Add the last 64 bits of %xmm0 to the last 64 bits of %xmm1.
addpd %xmm0,%xmm1 SMID (packed) double Add a pair of double-precision numbers. Add each 64 bit sections of %xmm0 to each 64 bit section of %xmm1. Store results in %xmm1.

Data movement instructions

Assembly:

float_mov:
# --------# float float_mov(float f1,
#
float *src,
#
float *dst) {
# float f2 = *src;
# *dst = f1;
# return f2;
# }
# --------# f1 in %xmm0, src in %rdi, dst in %rsi
movss (%rdi), %xmm1 # f2 = *src
movss %xmm0, (%rsi) # *dst = f1
movaps %xmm1, %xmm0
# return value = f2
ret

Function call and register saving conventions

Data conversion instructions

Converting between data types: (“t” is for “truncate”)

from int float long double
int N/A cvtsi2ss N/A cvtsi2sd
float cvttss2si N/A cvttss2siq cvtss2sd
long N/A cvtsi2ssq N/A cvtsi2sdq
double cvtsi2sd cvtsd2ss cvttsd2siq N/A

Data manipulation instructions

Arithmetic

Logical

Comparison: ucomiss/d

Others

Example

fadd:
# --------
# float fadd(float x, float y){
#   return x + y;
# }
# --------
# x in %xmm0, y in %xmm1
  addss
  %xmm1, %xmm0
  ret

dadd:
# --------
# double dadd(double x, double y){
#   return x + y;
# }
# --------
# x in %xmm0, y in %xmm1
  addsd
  %xmm1, %xmm0
  ret

Storing Data in Various Segments of Memory - Optional

(Transcriber’s note: no content on slide)

Storing Data in Memory

This material is optional –> It is for your learning pleasure!

We already know about data on stack and on heap.

Data stored in Data Segment

This material is optional –> It is for your learning pleasure!

Example 1:

C:

long x = 6;
long y = 9;
void main {
  ...
}

x86-64:

x: .quad 6 # 0x0000000000000006
y: .quad 9 # 0x0000000000000009
label Stack
0 1 2 3 4 5 6 7
y 09 (LSB; remember little endian) 00 00 00 00 00 00 00
x 06 (LSB) 00 00 00 00 00 00 00

Data stored in Data Segment

This material is optional –> It is for your learning pleasure!

C:

#define N 6

int A[N] = {12,34,56,78,-90,1};

void main(){
  printf("The total is %d.\n", sum_arrau(A,N));
  return;
}

Assembly:

main:
.LFB38:
  .cfi_startproc
  subq $0,%rsp
  .cfi_def_cfa_offset 16
  movl $6,%esi
  movl $A,%edi
  call sum_array
  movl %.LC0,%esi
  movl %eax,%eax
  movl $1,%edi
  xorl %eax,%eax
  addq $8,%rsp
  .cfi_def_cfa_offset 8
  jmp __printf_chk
...
A:
  .long 12 # or .long 12,34,56,78,-90,1
  .long 34
  .long 56
  .long 78
  .long -90
  .long 1
  .ident "GCC: (Ubuntu 7.3.0-21ubuntu1-16.04) 7.3.0"
  .section .note.GNU-stack,"",@progbits

Data stored on Stack – Example 1

This material is optional –> It is for your learning pleasure!

C:

void main(int argc, char* argv){
  int A[] = {12,34,56,78,-90,1}; // 12 and 34 are highlighted.
  printf("The total is %d.\n", sum_array(A,N));
  return;
}

Assembly:

main:
.LFB38:
  .cfi_startproc
  subq $40,%rsp
  .cfi_def_cfa_offset 48
  movl $6,%esi
  movq %fs:40,%rax
  movq %rax,24(%rsp)
  xorl %eax,%eax
  movabsq $146028888076,%rax # highloghted
  movq %rsp,%rdi
  movq %rax,(%rsp)
  movabsq $335007449144,%rax # highlighted
  movq %rax,8(%rsp)
  movabsq $8589934502,%rax # highlighted
  movq %rax,16(%rsp)
  call sum_array
  movl $.LC0,%esi
  movl %eax,%edx
  movl $1,%edi
  xorl %eax,%eax
  call __printf_chk
  movq 24(%rsp), %rax
  xorq %fs:40,%rax
  jne .L5
  addq $40,%rsp
  .cfi_remember_state
  .cfi_def_cfa_offset 8
  ret

How does this large # end up representing 12 and 34:

Summary - 1

Summary - 2

Next Lecture

Start a new unit …