linux kernel 下的类似于one_gadget(但不同于glibc中的作用)的内核函数

学习于XNUCA2019 babykernel

regcache_mark_dirty这个函数的地址可以在/proc/kallsyms中查看到,其函数体为

1
2
3
4
5
6
7
void regcache_mark_dirty(struct regmap *map)
{
map->lock(map->lock_arg);
map->cache_dirty = true;
map->no_sync_defaults = true;
map->unlock(map->lock_arg);
}

关于regmap的结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
struct regmap {
union {
struct mutex mutex;
struct {
spinlock_t spinlock;
unsigned long spinlock_flags;
};
};
regmap_lock lock;
regmap_unlock unlock;
void *lock_arg; /* This is passed to lock/unlock functions */
gfp_t alloc_flags;

struct device *dev; /* Device we do I/O on */
void *work_buf; /* Scratch buffer used to format I/O */
struct regmap_format format; /* Buffer format */
const struct regmap_bus *bus;
void *bus_context;
const char *name;

bool async;
spinlock_t async_lock;
wait_queue_head_t async_waitq;
struct list_head async_list;
struct list_head async_free;
int async_ret;

#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs;
const char *debugfs_name;

unsigned int debugfs_reg_len;
unsigned int debugfs_val_len;
unsigned int debugfs_tot_len;

struct list_head debugfs_off_cache;
struct mutex cache_lock;
#endif

unsigned int max_register;
bool (*writeable_reg)(struct device *dev, unsigned int reg);
bool (*readable_reg)(struct device *dev, unsigned int reg);
bool (*volatile_reg)(struct device *dev, unsigned int reg);
bool (*precious_reg)(struct device *dev, unsigned int reg);
const struct regmap_access_table *wr_table;
const struct regmap_access_table *rd_table;
const struct regmap_access_table *volatile_table;
const struct regmap_access_table *precious_table;

int (*reg_read)(void *context, unsigned int reg, unsigned int *val);
int (*reg_write)(void *context, unsigned int reg, unsigned int val);
int (*reg_update_bits)(void *context, unsigned int reg,
unsigned int mask, unsigned int val);

bool defer_caching;

u8 read_flag_mask;
u8 write_flag_mask;

/* number of bits to (left) shift the reg value when formatting*/
int reg_shift;
int reg_stride;
int reg_stride_order;

/* regcache specific members */
const struct regcache_ops *cache_ops;
enum regcache_type cache_type;

/* number of bytes in reg_defaults_raw */
unsigned int cache_size_raw;
/* number of bytes per word in reg_defaults_raw */
unsigned int cache_word_size;
/* number of entries in reg_defaults */
unsigned int num_reg_defaults;
/* number of entries in reg_defaults_raw */
unsigned int num_reg_defaults_raw;

/* if set, only the cache is modified not the HW */
bool cache_only;
/* if set, only the HW is modified not the cache */
bool cache_bypass;
/* if set, remember to free reg_defaults_raw */
bool cache_free;

struct reg_default *reg_defaults;
const void *reg_defaults_raw;
void *cache;
/* if set, the cache contains newer data than the HW */
bool cache_dirty;
/* if set, the HW registers are known to match map->reg_defaults */
bool no_sync_defaults;

struct reg_sequence *patch;
int patch_regs;

/* if set, converts bulk read to single read */
bool use_single_read;
/* if set, converts bulk read to single read */
bool use_single_write;
/* if set, the device supports multi write mode */
bool can_multi_write;

/* if set, raw reads/writes are limited to this size */
size_t max_raw_read;
size_t max_raw_write;

struct rb_root range_tree;
void *selector_work_buf; /* Scratch buffer used for selector */
};

利用方法

map->lock指向mov rdx, rdi

map->lock_arg指向我们的rop链

map->unlock指向栈迁移的指令,例如push rdx; pop rsp;之类的

适用于溢出字节比较少的漏洞