blob: f71adc1515733fdc86d2fd200076bccd9a155263 [file] [log] [blame]
Mtek0512ea5f1c22025-08-21 20:56:51 +08001
2#include <linux/kernel.h>
3#include <linux/module.h>
4#include <linux/fs.h>
5#include <linux/namei.h>
6#include <linux/uio.h>
7#include <linux/workqueue.h>
8#include <linux/delay.h>
9#include <linux/debugfs.h>
10#include <linux/interrupt.h>
11
12extern char *d_path(const struct path *, char *, int);
13static struct file_operations org_operations;
14static struct file_operations hooked_operations;
15static struct inode_operations org_inode_operations;
16static struct file_operations *p_curr_file_operations;
17
18static char opt_file_name[256] = {0};
19static char * hooked_files[32] = {
20 "/media/download/mdm.download",
21 "/media/download/sbl.download",
22 "/media/download/mcu_a.download",
23 "/media/download/mcu_b.download",
24 "/media/download/ble.download",
25 "/media/download/file.download",
26 "/media/download/runtime_file",
27 "/media/download/swk1",
28 "/media/download/swk2",
29 0,
30};
31static int g_hooked_file_cnt = 0;
32static spinlock_t my_lock;
33static struct work_struct my_work;
34static struct work_struct rename_file_work;
35static loff_t g_next_pos;
36static loff_t g_ki_pos;
37static bool g_scheduled = false;
38static struct file * g_hooked_file_filp;
39static const char * g_hooked_file_name;
40static char g_hooked_tmp_file[256];
41static bool g_hooked_tmp_file_writen;
42static char * g_last_hook_file = NULL;
43
44struct cached_items_type
45{
46 struct file * filp;
47 void * cached_buffer;
48 int cached_buffer_len;
49 loff_t curr_offset;
50 void * allocate_ptr;
51};
52
53struct cached_buffer_type
54{
55 void * cached_buffer;
56 void * ptr;
57};
58
59#define BUF_CNT_MASK 0xff
60#define ITEM_CNT_MASK 0xfff
61static struct cached_items_type cached_items[ITEM_CNT_MASK + 1] = {0};
62static struct cached_buffer_type g_buffers[BUF_CNT_MASK+1] = {0};
63static int head_pos = 0;
64static int tail_pos = 0;
65static int max_cnt = 0;
66
67static int buffer_head_pos = 0;
68static int buffer_tail_pos = BUF_CNT_MASK;
69
70static size_t init_and_push_item(struct file *filp, struct kiocb *iocb, struct iov_iter *from)
71{
72 unsigned long flags;
73 int index = (tail_pos) & ITEM_CNT_MASK;
74 int ret, buffer_index;
75 loff_t local_pos = 0;
76 size_t cnt = 0;
77 //if (iocb != NULL)
78 if (g_next_pos != -1)
79 {
80 if (g_next_pos != g_ki_pos)
81 printk("cy: next pos %ld current :%ld\n", g_next_pos);
82 local_pos = g_next_pos;
83 g_next_pos = -1;
84 // if (local_pos != 0 && g_ki_pos != local_pos) {
85 // printk("cy: got pos %ld, curr %ld\n", local_pos, g_ki_pos);
86 // }
87 }
88 else
89 {
90 local_pos = g_ki_pos;
91 }
92
93 cnt = iov_iter_count(from);
94 if (buffer_head_pos >= buffer_tail_pos || cnt > 16*PAGE_SIZE)
95 {
96 cached_items[index].allocate_ptr = kmalloc((cnt/PAGE_SIZE + 2)*PAGE_SIZE, GFP_KERNEL);
97 if (cached_items[index].allocate_ptr == NULL)
98 return 0;
99 cached_items[index].cached_buffer = (char*)((((long long)cached_items[index].allocate_ptr)/PAGE_SIZE + 1)*PAGE_SIZE);
100 }
101 else
102 {
103 buffer_index = (buffer_head_pos++ & BUF_CNT_MASK);
104 cached_items[index].allocate_ptr = NULL;
105 cached_items[index].cached_buffer = g_buffers[buffer_index].cached_buffer;
106 }
107
108 cached_items[index].filp = filp;
109 ret = copy_from_iter(cached_items[index].cached_buffer, cnt, from);
110 cached_items[index].cached_buffer_len = cnt;
111 cached_items[index].curr_offset = local_pos;
112 g_ki_pos = local_pos + cnt;
113
114 tail_pos++;
115 if (!g_scheduled)
116 {
117 g_scheduled = true;
118 schedule_work(&my_work);
119 }
120 return cnt;
121}
122
123struct cached_items_type * get_head_item(void)
124{
125 if (head_pos >= tail_pos)
126 return NULL;
127 return &cached_items[head_pos++ & ITEM_CNT_MASK];
128}
129
130static int my_ext4_file_open(struct inode * inode, struct file * filp)
131{
132 int i, j, ret, found;
133 unsigned long flags;
134 struct file * local_file;
135 char buff[256];
136 ret = org_operations.open(inode, filp);
137 //ret = 0;
138 if (ret == 0)
139 {
140 found = 0;
141 for(i=0; i<32 && found < g_hooked_file_cnt; i++) {
142 if (hooked_files[i] != NULL && strcmp(hooked_files[i], file_path(filp, buff, 256)) == 0)
143 {
144 printk("found hooked file11, %s write ptr %p private_data %p\n", hooked_files[i], filp->f_op->write, filp->private_data);
145
146 for(j=0;j<5;j++) {
147 if (g_hooked_file_filp != NULL)
148 usleep_range(2000,2100);
149 else
150 break;
151 }
152 if (g_hooked_file_filp != NULL)
153 {
154 if (g_last_hook_file == NULL || strcmp(hooked_files[i], g_last_hook_file) != 0)
155 break;
156
157 for(j=0;j<100;j++) {
158 if (g_hooked_file_filp != NULL)
159 usleep_range(20000,21000);
160 else
161 break;
162 }
163 }
164
165 spin_lock_irqsave(&my_lock, flags);
166 head_pos = 0;
167 tail_pos = 0;
168 max_cnt = 0;
169 g_ki_pos = 0;
170 buffer_head_pos = 0;
171 buffer_tail_pos = BUF_CNT_MASK;
172 g_last_hook_file = hooked_files[i];
173 p_curr_file_operations->open = org_operations.open;
174 spin_unlock_irqrestore(&my_lock, flags);
175
176 g_hooked_tmp_file_writen = false;
177 g_hooked_file_name = hooked_files[i];
178 sprintf(g_hooked_tmp_file, "%s.dl", hooked_files[i]);
179 printk("cy: after name is %s\n", g_hooked_tmp_file);
180 local_file = filp_open(g_hooked_tmp_file, O_RDWR | O_CREAT | O_TRUNC, 0644);
181
182 spin_lock_irqsave(&my_lock, flags);
183 if (!IS_ERR(local_file))
184 {
185 g_hooked_file_filp = local_file;
186 filp->private_data = local_file;
187 filp->f_op = &hooked_operations;
188 }
189 else
190 {
191 g_hooked_file_filp = NULL;
192 }
193 p_curr_file_operations->open = my_ext4_file_open;
194 spin_unlock_irqrestore(&my_lock, flags);
195 break;
196 }
197 else if (hooked_files[i] != NULL) {
198 found++;
199 }
200 }
201 //dump_stack();
202 }
203 return ret;
204}
205
206static loff_t my_ext4_llseek(struct file *file, loff_t offset, int whence)
207{
208 //printk("cy: %s, %ld, %d\n", __func__, offset, whence);
209 if (whence == SEEK_SET) {
210 g_next_pos = offset;
211 if (g_hooked_tmp_file_writen)
212 return offset;
213 else
214 return org_operations.llseek(file, offset, whence);
215 }
216 else
217 {
218 printk("unhandle %d\n", whence);
219 return org_operations.llseek(file, offset, whence);
220 }
221}
222
223static ssize_t my_ext4_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
224{
225 printk("cy: %s\n", __func__);
226 return org_operations.read_iter(iocb, to);
227}
228
229static ssize_t my_ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
230{
231
232 int i, ret;
233 int left_cnt, waited = 0;
234 loff_t write_cnt=0;
235 for (i=0; i<40;i++)
236 {
237 left_cnt = tail_pos - head_pos;
238 if ( left_cnt> max_cnt){
239 max_cnt = left_cnt;
240 if ((max_cnt & 0x1f) == 0)
241 printk("cy: got max %d", max_cnt);
242 }
243 if (left_cnt < ITEM_CNT_MASK)
244 {
245 break;
246 }
247 if (!g_scheduled)
248 {
249 g_scheduled = true;
250 schedule_work(&my_work);
251 }
252 waited = 1;
253 usleep_range(1000,1100);
254 }
255
256 if (i >= 40) {
257 printk("cy: write fail\n");
258 return -1;
259 }
260 else if (i > 1){
261 printk("cy: got full\n");
262 }
263
264 //printk("cy: my_ext4_file_write_iter %p\n", iocb->ki_filp->private_data);
265 if (iocb->ki_filp->private_data != NULL)
266 {
267 write_cnt = init_and_push_item(iocb->ki_filp->private_data, iocb, from);
268 g_hooked_tmp_file_writen = true;
269 }
270
271 // if (left_cnt > 64)
272 // usleep_range(7000,7100);
273 // else if (left_cnt > 32)
274 // usleep_range(5000,5100);
275 // else if (left_cnt > 8)
276 // usleep_range(3000,3100);
277 // else if (left_cnt > 1 && !waited)
278 // usleep_range(500,600);
279 return write_cnt;
280}
281
282static int my_ext4_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
283{
284 printk("cy: %s\n", __func__);
285 return org_operations.fsync(file, start, end, datasync);
286}
287
288static int my_ext4_release_file(struct inode *inode, struct file *filp)
289{
290 int i, ret;
291 // struct file *local_filp=NULL;
292 char buff[256];
293 char buff2[256];
294 char * file_name;
295 //printk("cy: %s\n", __func__);
296 if (filp == NULL)
297 return -1;
298 // dump_stack();
299 for (i=0; i<40;i++)
300 {
301 if (tail_pos == head_pos)
302 break;
303 usleep_range(300,350);
304 }
305
306 //printk("cy: close file wait count %d\n", i);
307 if (filp->private_data != NULL)
308 {
309 filp->private_data = 0;
310 }
311 ret = org_operations.release(inode, filp);
312 if (g_hooked_file_filp != NULL)
313 {
314 schedule_work(&rename_file_work);
315 }
316 return ret;
317}
318
319static void my_callback(struct work_struct *work)
320{
321 ssize_t ret;
322 loff_t local_pos = 0;
323 struct cached_items_type * p;
324 p = get_head_item();
325 // if (p != NULL)
326 // usleep_range(200,250);
327
328 while(p != NULL) {
329 local_pos = p->curr_offset;
330 ret = __kernel_write(p->filp, p->cached_buffer, p->cached_buffer_len, &local_pos);
331 //g_ki_pos = p->curr_offset + p->cached_buffer_len;
332 if (p->allocate_ptr)
333 {
334 kfree(p->allocate_ptr);
335 p->allocate_ptr = NULL;
336 p->cached_buffer = NULL;
337 }
338 else
339 {
340 buffer_tail_pos++;
341 p->cached_buffer = NULL;
342 }
343 p = get_head_item();
344 }
345 g_scheduled = false;
346}
347
348static void rename_file_callback(struct work_struct *work)
349{
350 int ret, i;
351 struct path old_path, new_path;
352 struct dentry *old_dentry, *new_dentry;
353 if (g_hooked_file_filp == NULL)
354 return;
355 printk("cy4: close ld file finish\n");
356 if (!g_hooked_tmp_file_writen)
357 {
358 ret = filp_close(g_hooked_file_filp, 0);
359 g_hooked_file_filp = NULL;
360 return;
361 }
362 printk("cy: head pos %d, tail pos %d\n", head_pos, tail_pos);
363 if (!g_scheduled) // write thread not running, check again
364 {
365 printk("cy: not g_scheduled\n");
366 my_callback(&my_work);
367 }
368 for (i=0; i<5000;i++)
369 {
370 if (head_pos == tail_pos)
371 {
372 break;
373 }
374 if (!g_scheduled)
375 {
376 printk("cy: not g_scheduled 2\n");
377 my_callback(&my_work);
378 break;
379 }
380 usleep_range(1000,1100);
381 if ((i & 0x3ff) == 0 )
382 printk("cy: wait file write done, sleep again\n");
383 }
384 printk("cy: wait times %d\n", i);
385 ret = filp_close(g_hooked_file_filp, 0);
386 g_hooked_file_filp = NULL;
387 ret = kern_path(g_hooked_tmp_file, LOOKUP_PARENT, &old_path);
388 if (ret != 0)
389 goto out2;
390 ret = kern_path(g_hooked_file_name, LOOKUP_PARENT, &new_path);
391 if (ret != 0)
392 goto out1;
393
394 old_dentry = old_path.dentry;
395 new_dentry = new_path.dentry;
396 if (old_dentry != NULL && new_dentry != NULL && old_path.dentry->d_parent != NULL && new_path.dentry->d_parent != NULL)
397 {
398 ret = vfs_rename(old_path.dentry->d_parent->d_inode, old_dentry, new_path.dentry->d_parent->d_inode, new_dentry, NULL, RENAME_EXCHANGE);
399 }
400 else
401 {
402 printk("cy: got null ptr\n");
403 }
404 path_put(&new_path);
405out1:
406 path_put(&old_path);
407out2:
408 g_hooked_tmp_file_writen = false;
409 printk("cy:rename file finish\n");
410}
411
412#define DEBUGFS_READ_FUNC(name) \
413 static ssize_t asr_dbgfs_##name##_read(struct file *file, \
414 char __user *user_buf, \
415 size_t count, loff_t *ppos);
416
417#define DEBUGFS_WRITE_FUNC(name) \
418 static ssize_t asr_dbgfs_##name##_write(struct file *file, \
419 const char __user *user_buf,\
420 size_t count, loff_t *ppos);
421
422
423#define DEBUGFS_ADD_FILE(name, parent, mode) do { \
424 if (!debugfs_create_file(#name, mode, parent, NULL, \
425 &asr_dbgfs_##name##_ops)) \
426 goto err; \
427} while (0)
428
429#define DEBUGFS_WRITE_FILE_OPS(name) \
430 DEBUGFS_WRITE_FUNC(name); \
431static const struct file_operations asr_dbgfs_##name##_ops = { \
432 .write = asr_dbgfs_##name##_write, \
433 .open = simple_open, \
434 .llseek = generic_file_llseek, \
435};
436
437#define DEBUGFS_READ_FILE_OPS(name) \
438 DEBUGFS_READ_FUNC(name); \
439static const struct file_operations asr_dbgfs_##name##_ops = { \
440 .read = asr_dbgfs_##name##_read, \
441 .open = simple_open, \
442 .llseek = generic_file_llseek, \
443};
444
445static void strip_enter(char * buf, int len){
446 int i;
447 for(i=0;i<len;i++) {
448 if (buf[i] == '\r' || buf[i] == '\n' || buf[i]=='\0') {
449 buf[i] = '\0';
450 return;
451 }
452 }
453}
454
455static ssize_t asr_dbgfs_add_hook_write(struct file *file,
456 const char __user *user_buf,
457 size_t count, loff_t *ppos)
458{
459 int i;
460 char buf[256]={0};
461 size_t len = min_t(size_t, sizeof(buf) - 1, count);
462 printk("cy: add hook count %d\n", count);
463 if (copy_from_user(buf, user_buf, len))
464 return -EFAULT;
465 strip_enter(buf, 256);
466 printk("cy: add hook buf %s\n", buf);
467 for(i=0;i<32;i++) {
468 if (hooked_files[i] == NULL) {
469 hooked_files[i] = kmalloc(count+1, GFP_KERNEL);
470 strcpy(hooked_files[i], buf);
471 g_hooked_file_cnt++;
472 break;
473 }
474 }
475 if (i >= 32)
476 return -EFAULT;
477 return count;
478}
479DEBUGFS_WRITE_FILE_OPS(add_hook);
480
481static ssize_t asr_dbgfs_del_hook_write(struct file *file,
482 const char __user *user_buf,
483 size_t count, loff_t *ppos)
484{
485 int i;
486 char buf[256]={0};
487 size_t len = min_t(size_t, sizeof(buf) - 1, count);
488 printk("cy: del hook count %d\n", count);
489 if (copy_from_user(buf, user_buf, len))
490 return -EFAULT;
491
492 strip_enter(buf, 256);
493 printk("cy: del hook buf %s\n", buf);
494 for(i=0;i<32;i++) {
495 if (hooked_files[i] != NULL && strcmp(hooked_files[i], buf) == 0) {
496 hooked_files[i] = NULL;
497 g_hooked_file_cnt--;
498 break;
499 }
500 }
501 if (i >= 32)
502 return -EFAULT;
503 return count;
504}
505DEBUGFS_WRITE_FILE_OPS(del_hook);
506
507static ssize_t asr_dbgfs_show_all_read(struct file *file,
508 char __user *user_buf,
509 size_t count, loff_t *ppos)
510{
511 int i, found, ret, read;
512 char *buf;
513 int bufsz = 256 * g_hooked_file_cnt;
514 buf = kmalloc(bufsz, GFP_ATOMIC);
515 if (buf == NULL)
516 return 0;
517 found = 0;
518 ret = 0;
519 for(i=0;i<32 && found < g_hooked_file_cnt;i++) {
520 if (hooked_files[i] != NULL) {
521 found++;
522 ret += scnprintf(&buf[ret], 258, "%s\n", hooked_files[i]);
523 }
524 }
525 read = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
526
527 kfree(buf);
528
529 return read;
530}
531DEBUGFS_READ_FILE_OPS(show_all);
532
533static struct dentry * hook_root=NULL;
534
535static int asr_dbgfs_register(void)
536{
537 if (!(hook_root = debugfs_create_dir("opt_cmd_36",NULL)))
538 return -1;
539 DEBUGFS_ADD_FILE(add_hook, hook_root, S_IWUSR | S_IRUSR);
540 DEBUGFS_ADD_FILE(del_hook, hook_root, S_IWUSR | S_IRUSR);
541 DEBUGFS_ADD_FILE(show_all, hook_root, S_IRUSR);
542 return 0;
543err:
544 debugfs_remove_recursive(hook_root);
545 return -1;
546}
547
548static void asr_dbgfs_unregister(void)
549{
550 if (hook_root != NULL)
551 {
552 debugfs_remove_recursive(hook_root);
553 hook_root = NULL;
554 }
555}
556
557static int __init opt_cmd_36_init(void)
558{
559 int ret, i;
560 unsigned long flags;
561 struct file *filp;
562 char * ptr;
563 char *filename = "/media/.test_create";
564 g_hooked_file_filp = NULL;
565 g_hooked_tmp_file_writen = false;
566
567 for(i=0; i<32;i++) {
568 if (hooked_files[i] != NULL) {
569 printk("cy: got %s\n", hooked_files[i]);
570 g_hooked_file_cnt++;
571 }
572 else if (strlen(opt_file_name) > 0)
573 {
574 hooked_files[i] = opt_file_name;
575 g_hooked_file_cnt++;
576 break;
577 }
578 }
579 filp = filp_open(filename, O_RDONLY | O_CREAT, 0644);
580 if (IS_ERR(filp) || filp->f_op == NULL) {
581 printk(KERN_ERR "Failed to open file: %ld\n", PTR_ERR(filp));
582 return -1;
583 }
584
585 printk("cy11: opt_cmd_36_init param [%s]\n", opt_file_name);
586 INIT_WORK(&my_work, my_callback);
587 INIT_WORK(&rename_file_work, rename_file_callback);
588
589 for(i=0;i<=BUF_CNT_MASK;i++)
590 {
591 g_buffers[i].ptr = kmalloc(32*PAGE_SIZE, GFP_KERNEL);
592 ptr = (char*)((((long long)g_buffers[i].ptr)/PAGE_SIZE + 1)*PAGE_SIZE);
593 g_buffers[i].cached_buffer = ptr;
594 //cached_items[i].org_ptr = kmalloc(32*PAGE_SIZE, GFP_KERNEL);
595 //ptr = (char*)((((long long)cached_items[i].org_ptr)/PAGE_SIZE + 1)*PAGE_SIZE);
596 //cached_items[i].cached_buffer = ptr;
597 }
598
599 spin_lock_irqsave(&my_lock, flags);
600 p_curr_file_operations = filp->f_op;
601
602 org_operations.llseek = p_curr_file_operations->llseek;
603 org_operations.read_iter = p_curr_file_operations->read_iter;
604 org_operations.write_iter = p_curr_file_operations->write_iter;
605 org_operations.unlocked_ioctl = p_curr_file_operations->unlocked_ioctl;
606#ifdef CONFIG_COMPAT
607 org_operations.compat_ioctl = p_curr_file_operations->compat_ioctl;
608#endif
609 org_operations.mmap = p_curr_file_operations->mmap;
610 org_operations.mmap_supported_flags = p_curr_file_operations->mmap_supported_flags;
611 org_operations.open = p_curr_file_operations->open;
612 org_operations.release = p_curr_file_operations->release;
613 org_operations.fsync = p_curr_file_operations->fsync;
614 org_operations.get_unmapped_area = p_curr_file_operations->get_unmapped_area;
615 org_operations.splice_read = p_curr_file_operations->splice_read;
616 org_operations.splice_write = p_curr_file_operations->splice_write;
617 org_operations.fallocate = p_curr_file_operations->fallocate;
618
619 hooked_operations.llseek = my_ext4_llseek;
620 //hooked_operations.write = hooked_write;
621 //hooked_operations.read_iter = my_ext4_file_read_iter;
622 hooked_operations.read_iter = p_curr_file_operations->read_iter;
623 hooked_operations.write_iter = my_ext4_file_write_iter;
624 //hooked_operations.write_iter = p_curr_file_operations->write_iter;
625 hooked_operations.unlocked_ioctl = p_curr_file_operations->unlocked_ioctl;
626#ifdef CONFIG_COMPAT
627 hooked_operations.compat_ioctl = p_curr_file_operations->compat_ioctl;
628#endif
629 hooked_operations.mmap = p_curr_file_operations->mmap;
630 hooked_operations.mmap_supported_flags = p_curr_file_operations->mmap_supported_flags;
631 hooked_operations.open = p_curr_file_operations->open;
632 //hooked_operations.release = p_curr_file_operations->release;
633 hooked_operations.release = my_ext4_release_file;
634 //hooked_operations.fsync = p_curr_file_operations->fsync;
635 hooked_operations.fsync = my_ext4_sync_file;
636 hooked_operations.get_unmapped_area = p_curr_file_operations->get_unmapped_area;
637 hooked_operations.splice_read = p_curr_file_operations->splice_read;
638 hooked_operations.splice_write = p_curr_file_operations->splice_write;
639 hooked_operations.fallocate = p_curr_file_operations->fallocate;
640
641 p_curr_file_operations->open = my_ext4_file_open;
642 spin_unlock_irqrestore(&my_lock, flags);
643
644 ret = filp_close(filp, 0);
645
646 asr_dbgfs_register();
647
648 pr_debug("init done\n");
649 return 0;
650
651}
652
653
654static void __exit opt_cmd_36_exit(void)
655{
656 int i;
657 unsigned long flags;
658 spin_lock_irqsave(&my_lock, flags);
659 p_curr_file_operations->open = org_operations.open;
660 spin_unlock_irqrestore(&my_lock, flags);
661
662 for(i=0;i<=BUF_CNT_MASK;i++)
663 {
664 // if (cached_items[i].org_ptr != NULL)
665 // kfree(cached_items[i].org_ptr);
666 if (g_buffers[i].ptr != NULL)
667 kfree(g_buffers[i].ptr);
668 }
669
670 asr_dbgfs_unregister();
671
672 pr_debug("exit done\n");
673}
674
675module_param_string(opt_file_name, opt_file_name, 256, 0);
676
677module_init(opt_cmd_36_init)
678module_exit(opt_cmd_36_exit)
679
680MODULE_LICENSE("GPL");