CS110L-#01: Welcome to CS 110L

第一节 Welcome to CS 110L

视频:

Slides:https://reberhardt.com/cs110l/spring-2020/slides/lecture-01.pdf

笔记

1.为什么使用Rust

2.为什么不是用C/C++?

安全问题:

例子程序:https://www.tutorialspoint.com/convert-a-string-to-uppercase-in-c

看了一下,程序的作用是把字符串转成大写,明显gets存在缓冲区溢出。在编译的时候,编译器也提醒了。

➜  01 git:(main) ✗ ./a.out 

Enter a string:ashdasihdddddddddddddddddddddddddddddddddddddddddddddddddddddddd

String in Upper Case = ASHDASIHDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD%                                              
➜  01 git:(main) ✗ ./a.out

Enter a string:GgaudiasSSSSSSSSSASUGDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

*** stack smashing detected ***: terminated
[1]    18336 abort      ./a.out

很明显,C/C++的内存安全的问题很严重,这其实也是众所周知的,老师还提到一篇论文,关于汽车攻击面的。

论文:http://www.autosec.org/pubs/cars-usenixsec2011.pdf

YouTube解读: https://www.youtube.com/watch?v=bHfOziIwXic

还提到Chrome OS中的一个 one byte overflow and symlinks,DNS库的一个字节的溢出

链接: https://googleprojectzero.blogspot.com/2016/12/chrome-os-exploit-one-byte-overflow-and.html

然后老师讨论缓冲区溢出的问题,举了一个例子:

char buffer[128];
int bytesToCopy = packet.length;
if (bytesToCopy < 128) {
 strncpy(buffer, packet.data, bytesToCopy);
}

看起来是有边界检查的,也使用了带有长度的strncpy函数。但是其实strncpy也是有问题的,容易产生空字符结尾错误和其他的问题。

但是这里的问题,其实是整数转换的问题。

C/C++的内存安全问题,也有很多人搞了一些工具来检查。主要是动态分析和静态分析,动态分析需要预测输入,静态分析主要是错误非常多。

比如: valgrind

我用valgrind来跑convert程序,看看会出什么样的结果

➜  01 git:(main) ✗ valgrind --tool=memcheck --leak-check=full ./conver
==2022== Memcheck, a memory error detector
==2022== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==2022== Using Valgrind-3.16.1 and LibVEX; rerun with -h for copyright info
==2022== Command: ./conver
==2022==

Enter a string:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

*** stack smashing detected ***: terminated
==2022==
==2022== Process terminating with default action of signal 6 (SIGABRT)
==2022==    at 0x489C18B: raise (raise.c:51)
==2022==    by 0x487B858: abort (abort.c:79)
==2022==    by 0x48E63ED: __libc_message (libc_fatal.c:155)
==2022==    by 0x4988B49: __fortify_fail (fortify_fail.c:26)
==2022==    by 0x4988B15: __stack_chk_fail (stack_chk_fail.c:24)
==2022==    by 0x109245: main (convert.c:22)
String in Upper Case = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==2022==
==2022== HEAP SUMMARY:
==2022==     in use at exit: 0 bytes in 0 blocks
==2022==   total heap usage: 2 allocs, 2 frees, 2,048 bytes allocated
==2022==
==2022== All heap blocks were freed -- no leaks are possible
==2022==
==2022== For lists of detected and suppressed errors, rerun with: -s
==2022== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
[1]    2022 abort      valgrind --tool=memcheck --leak-check=full ./conver

其实valgrind检查不了这种缓冲区溢出的漏洞。

3.为什么不是用其他有GC的语言?

GC 有性能问题,垃圾一般都是丢在你家里,收集垃圾的需要敲你的门来收集垃圾。

  • 代价昂贵
  • 具有破坏性
  • 存在非确定性
  • 排除了手动优化的可能

需要程序都需要高性能,比如

  • 用户界面程序
  • 游戏
  • 自动驾驶
  • 支付处理
  • 高频交易

4.预习

找bug,链接: https://web.stanford.edu/class/cs110l/lecture-notes/lecture-02/

解答:

程序如下

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

// There are at least 7 bugs relating to memory on this snippet.
// Find them all!

// Vec is short for "vector", a common term for a resizable array.
// For simplicity, our vector type can only hold ints.
typedef struct {
  int* data;     // Pointer to our array on the heap
  int  length;   // How many elements are in our array
  int  capacity; // How many elements our array can hold
} Vec;

Vec* vec_new() {
  Vec vec;
  vec.data = NULL;
  vec.length = 0;
  vec.capacity = 0;
  return &vec;
}

void vec_push(Vec* vec, int n) {
  if (vec->length == vec->capacity) {
    int new_capacity = vec->capacity * 2;
    int* new_data = (int*) malloc(new_capacity);
    assert(new_data != NULL);

    for (int i = 0; i < vec->length; ++i) {
      new_data[i] = vec->data[i];
    }

    vec->data = new_data;
    vec->capacity = new_capacity;
  }

  vec->data[vec->length] = n;
  ++vec->length;
}

void vec_free(Vec* vec) {
  free(vec);
  free(vec->data);
}

void main() {
  Vec* vec = vec_new();
  vec_push(vec, 107);

  int* n = &vec->data[0];
  vec_push(vec, 110);
  printf("%d\n", *n);

  free(vec->data);
  vec_free(vec);
}

运行:

[1] 4278 segmentation fault ./pre

直接段错误

7处错误:

  1. 在vec_new中,创建了一个局部变量vec,并返回了&vec
  2. vec.data 应该是vec->data = NULL
  3. vec_push中不要使用assert
  4. vec_push中vec->length没有检查,而且可以设置为unsigned
  5. free(vec->data)错误
  6. vec_free中应该先free(vec->data)
  7. vec_push 中 ++vec->length错误

第一周的作业

作业链接: