Rust开发的安全工具列表:
- x8 一个目录发现的工具,对比链接 x8, Arjun, Param Miner comparison
- ppfuzz 一个扫描原型污染的工具
Rust开发的安全工具列表:
第2周作业链接: https://reberhardt.com/cs110l/spring-2020/assignments/week-2-exercises/
本周将带你更加的熟悉Rust,包括所有权和引用等知识。
fn main()
{
let mut s = String::from("hello");
let ref1 = &s;
let ref2 = &ref1;
let ref3 = &ref2;
//s = String::from("goodboy"); //错误 s
println!("{}", ref3.to_uppercase());
}
fn drip_drop() -> String {
let s = String::from("hello,world");
//return &s; //错误
return s;
}
let s1 = String::from("hello");
let mut v = Vec::new();
v.push(s1);
//let s2: String = v[0]; //错误
let ref s2: String = v[0];
println!("{}",s2);
我们将实现diff
命令行实用程序的简单版本以比较两个文件。
代码:
代码:
第一周作业链接: https://reberhardt.com/cs110l/spring-2020/assignments/week-1-exercises/
第一周的作业主要是熟悉Rust的工具链安装和一些Rust语法
安装工具链,访问Rust官方: https://www.rust-lang.org/tools/install
helloworld
cargo 提供了命令行来创建rust项目
cargo new helloworld
然后就可以cargo build 或者cargo run
➜ helloworld git:(main) ✗ tree
.
├── Cargo.lock
├── Cargo.toml
├── src
│ └── main.rs
└── target
├── CACHEDIR.TAG
└── debug
├── build
├── deps
│ ├── helloworld-681c2ade33f71cab
│ └── helloworld-681c2ade33f71cab.d
├── examples
├── helloworld
├── helloworld.d
└── incremental
└── helloworld-3gmsxxterlir4
├── s-fw1pxstg53-1leo6ld-2439fudoc3hif
│ ├── 14i0bcdbfi2ugad2.o
│ ├── 15ne1gcrt9rvpglq.o
│ ├── 18abmkatn3n4l0hu.o
│ ├── 27s29o1kcsspusdg.o
│ ├── 2xwm4i2jxgoiz5co.o
│ ├── 3050lnwbirtj1yb5.o
│ ├── dep-graph.bin
│ ├── gp126zvew3eug9.o
│ ├── q4wkdgq1k2s2v4m.o
│ ├── query-cache.bin
│ └── work-products.bin
└── s-fw1pxstg53-1leo6ld.lock
从上面可以看到,整个项目的结构。src/main.rs 是源代码 target中的目录为编译生成的目录
main.rs 自带hello,world
fn main() {
println!("Hello, world!");
}
Cargo.toml是包依赖
[package]
name = "helloworld"
version = "0.1.0"
authors = ["Jimmy Xiang <xxg1413@gmail.com>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
let n:i32 = 1;
let n = 1;
//可变类型
let mut n = 0;
n = n + 1;
//Rust有两种字符串: &str和String
let s: &str = "hello,world"; //只读数据段
let mut s: String = String::from("hello,");
s.push_str("world");
println!("{}", s);
//动态数组
let mut v: Vec<i32> = Vec::new();
v.push(2);
v.push(3);
//固定大小数组
let mut arr: [i32; 4] = [0,2,4,8];
arr[0] = -2;
println!("{}", arr[0]+arr[1]);
//迭代器
for i in arr.iter()
{
println!("{}",i);
}
//while
let mut sum = 0;
let mut i = 0;
while i < 20
{
i += 1;
sum += i;
}
println!("sum={}",sum);
//loop 它有助于编译器对变量初始化进行一些假设。
let mut i = 0;
loop {
i += 1;
if i == 10 {
break;
}
}
println!("i={}",i);
//函数
fn mysum(a: i32, b:i32) -> i32
{
a + b //Rust是一种基于表达式的 语言,不需要分号
//a + b ; 会出错
}
println!("sum={}", mysum(1,2));
练习:
use std::collections::HashSet;
//练习
fn add_n(v: Vec<i32>, n: i32) -> Vec<i32> {
let mut result: Vec<i32> = Vec::new();
for i in v.iter() {
result.push(i+n)
}
result
}
fn add_n_inplace(v: &mut Vec<i32>, n: i32) {
let mut i = 0;
while i < v.len() {
v[i] = v[i] + n;
i = i + 1;
}
}
fn dedup(v: &mut Vec<i32>) {
let mut hs = HashSet::new();
let mut i = 0;
while i < v.len() {
if !hs.contains(&v[i]) {
hs.insert(v[i]);
i += 1;
} else {
v.remove(i);
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_add_n() {
assert_eq!(add_n(vec![1], 2), vec![3]);
}
#[test]
fn test_add_n_inplace() {
let mut v = vec![1];
add_n_inplace(&mut v, 2);
assert_eq!(v, vec![3]);
}
#[test]
fn test_dedup() {
let mut v = vec![3, 1, 0, 1, 4, 4];
dedup(&mut v);
assert_eq!(v, vec![3, 1, 0, 4]);
}
}
代码: https://github.com/xxg1413/CS110L/tree/main/Assignments/week1/Hangman
视频:
Youtube:https://www.youtube.com/watch?v=cUrggIAPJEs&feature=youtu.be
Slides:https://reberhardt.com/cs110l/spring-2020/slides/lecture-02.pdf
课程笔记:https://reberhardt.com/cs110l/spring-2020/lecture-notes/lecture-02/
B站中字:https://www.bilibili.com/video/BV1Ra411A7kN?p=2
解释:https://stanford-cs242.github.io/f19/lectures/06-2-memory-safety
#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; //指针的值改变了 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);//*n 迭代失效
free(vec->data);
vec_free(vec);// 双重释放
}
Rust只是比其他语言犯错更难一些,并不代表不可以犯错。而且很多逻辑错误是无关语言的。
https://stanford-cs242.github.io/f19/lectures/06-2-memory-safety
视频:
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处错误:
作业链接: