FROMLIST: [PATCH v5 10/12] arm64: vdso: replace gettimeofday.S with global vgettimeof...
[GitHub/exynos8895/android_kernel_samsung_universal8895.git] / fs / dlog_hook.c
1 /*
2 * Copyright (C) 2012-2013 Samsung Electronics Co., Ltd.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include <linux/kernel.h>
19 #include <linux/version.h>
20 #include <linux/slab.h>
21 #include <linux/fs.h>
22 #include <linux/mount.h>
23 #include <linux/hashtable.h>
24 #include <linux/ctype.h>
25 #include <linux/module.h>
26 #include "mount.h"
27
28 #define DEFINE_DLOG(_name) extern int fslog_##_name(const char *fmt, ...)
29 DEFINE_DLOG(dlog_mm);
30 DEFINE_DLOG(dlog_efs);
31 DEFINE_DLOG(dlog_etc);
32 DEFINE_DLOG(dlog_rmdir);
33
34 #define EXT_SHIFT 7
35 #define MAX_EXT (1 << 7)
36 #define MAX_DEPTH 2
37
38 struct dlog_keyword {
39 struct hlist_node hlist;
40 const char *keyword;
41 };
42
43 struct dlog_keyword_hash_tbl {
44 DECLARE_HASHTABLE(table, 7);
45 };
46
47 enum {
48 DLOG_HT_EXTENSION = 0,
49 DLOG_HT_EXCEPTION,
50 DLOG_HT_MAX
51 };
52
53 enum {
54 DLOG_SUPP_PART_DATA = 0,
55 DLOG_SUPP_PART_EFS,
56 DLOG_SUPP_PART_MAX
57 };
58
59 enum {
60 DLOG_MM = 0,
61 DLOG_EFS,
62 DLOG_ETC,
63 DLOG_RMDIR
64 };
65
66 static struct dlog_keyword_hash_tbl ht[DLOG_HT_MAX];
67
68 static const char *support_part[] = {
69 "data", "efs", NULL,
70 };
71
72 static const char *extensions[] = {
73 /* image */
74 "arw", "bmp", "cr2", "dng", "gif",
75 "jpeg", "jpg", "nef", "nrw", "orf",
76 "pef", "png", "raf", "rw2", "srw",
77 "wbmp", "webp",
78 /* audio */
79 "3ga", "aac", "amr",
80 "awb", "dff", "dsf", "flac", "imy",
81 "m4a", "mid", "midi", "mka", "mp3",
82 "mpga", "mxmf", "oga", "ogg", "ota",
83 "rtttl", "rtx", "smf", "wav", "wma",
84 "xmf", "dcf",
85 /* video */
86 "3g2", "3gp", "3gpp", "3gpp2",
87 "ak3g", "asf", "avi", "divx", "flv",
88 "m2t", "m2ts", "m4v", "mkv", "mp4",
89 "mpeg", "mpg", "mts", "skm", "tp",
90 "trp", "ts", "webm", "wmv",
91 /* document */
92 "asc",
93 "csv", "doc", "docm", "docx", "dot",
94 "dotx", "htm", "html", "hwdt", "hwp",
95 "hwpx", "hwt", "memo", "pdf", "pot",
96 "potx", "pps", "ppsx", "ppt", "pptm",
97 "pptx", "rtf", "snb", "spd", "xls",
98 "xlsm", "xlsx", "xlt", "xltx", "xml",
99 NULL,
100 };
101
102 static const char *exceptions[] = {
103 /* exception extension */
104 "db-shm", "shm", "bak", "mbak", "gz",
105 "log", "swap", "dcs", "tmp", "temp",
106 "txt", NULL,
107 };
108
109 static const char **dlog_keyword_tbl[DLOG_HT_MAX] = {
110 extensions, exceptions
111 };
112
113 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0)
114 static inline unsigned int dlog_full_name_hash(const char *name, unsigned int len)
115 {
116 return full_name_hash((void *)0x0, name, len);
117 }
118 #else /* LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0) */
119 static inline unsigned int dlog_full_name_hash(const char *name, unsigned int len)
120 {
121 return full_name_hash(name, len);
122 }
123 #endif
124
125 bool is_ext(const char *name, const char token, struct dlog_keyword_hash_tbl *hash_tbl)
126 {
127 char *ext = strrchr(name, token);
128 struct dlog_keyword *hash_cur;
129 unsigned hash;
130 int i;
131 bool ret = false;
132
133 if (!ext || !ext[1])
134 return false;
135
136 ext = kstrdup(&ext[1], GFP_KERNEL);
137 if (!ext)
138 return false;
139
140 for (i = 0; ext[i]; i++)
141 ext[i] = tolower(ext[i]);
142 hash = dlog_full_name_hash(ext, strlen(ext));
143
144 hash_for_each_possible(hash_tbl->table, hash_cur, hlist, hash) {
145 if (!strcmp(ext, hash_cur->keyword)) {
146 ret = true;
147 break;
148 }
149 }
150 kfree(ext);
151
152 return ret;
153 }
154
155 int __init dlog_keyword_hash_init(void)
156 {
157 int i;
158 int tbl_idx = 0;
159
160 do {
161 hash_init(ht[tbl_idx].table);
162 for (i = 0; dlog_keyword_tbl[tbl_idx][i]; i++) {
163 struct dlog_keyword *hte;
164
165 hte = kzalloc(sizeof(struct dlog_keyword), GFP_KERNEL);
166 if (!hte)
167 return -ENOMEM;
168
169 INIT_HLIST_NODE(&hte->hlist);
170 hte->keyword = dlog_keyword_tbl[tbl_idx][i];
171 hash_add(ht[tbl_idx].table, &hte->hlist,
172 dlog_full_name_hash(hte->keyword, strlen(hte->keyword)));
173 }
174 tbl_idx++;
175 } while(tbl_idx < DLOG_HT_MAX);
176
177 return 0;
178 }
179 module_init(dlog_keyword_hash_init);
180
181 void __exit dlog_keyword_hash_exit(void)
182 {
183 int i;
184 int num_ht = 0;
185 struct dlog_keyword *hash_cur;
186
187 do {
188 hash_for_each(ht[num_ht].table, i, hash_cur, hlist)
189 kfree(hash_cur);
190 } while(++num_ht < DLOG_HT_MAX);
191
192 }
193 module_exit(dlog_keyword_hash_exit);
194
195 static int get_support_part_id(struct vfsmount *mnt)
196 {
197 int idx = 0;
198 struct mount *mount = real_mount(mnt);
199
200 /* check partition which need register delete log */
201 do {
202 if (!strcmp(mount->mnt_mountpoint->d_name.name, support_part[idx]))
203 return idx;
204 } while(support_part[++idx]);
205
206 return -1;
207 }
208
209 static int is_sdcard(struct vfsmount *mnt)
210 {
211 /* internal storage (external storage till Andorid 8.x) */
212 if (mnt->mnt_sb->s_magic == SDCARDFS_SUPER_MAGIC)
213 return true;
214 /* external storage from Android 9.x */
215 else if (mnt->mnt_sb->s_magic == SDFAT_SUPER_MAGIC)
216 return true;
217 else if (mnt->mnt_sb->s_magic == MSDOS_SUPER_MAGIC)
218 return true;
219
220 return false;
221 }
222
223 static void make_prefix(int part_id, char *prefix)
224 {
225 if (part_id == DLOG_SUPP_PART_DATA)
226 *prefix = 'd';
227 else
228 *prefix = 's';
229 }
230
231 static void store_log(struct dentry *dentry, struct inode *inode,
232 struct path *path, int type, int part_id)
233 {
234 kuid_t euid = current->cred->euid;
235 unsigned long ino = inode ? inode->i_ino : 0;
236 loff_t isize = inode ? inode->i_size : 0;
237 char prefix = 0;
238 char *buf, *full_path;
239 char unit = 'B';
240
241 buf = kzalloc(PATH_MAX, GFP_KERNEL);
242 if (!buf) {
243 printk(KERN_ERR "%s memory alloc failed : ENOMEM\n", __func__);
244 return;
245 }
246
247 full_path = dentry_path_raw(dentry, buf, PATH_MAX);
248 make_prefix(part_id, &prefix);
249 if (isize >> 10) {
250 isize >>= 10;
251 unit = 'K';
252 }
253
254 if (type == DLOG_MM) {
255 fslog_dlog_mm("[%c]\"%s\" (%u, %lu, %lu, %lld%c)\n", prefix, full_path,
256 euid, path->dentry->d_inode->i_ino, ino, isize, unit);
257 goto out;
258 }
259
260 if (type == DLOG_ETC) {
261 fslog_dlog_etc("[%c]\"%s\" (%u, %lu, %lu, %lld%c)\n", prefix, full_path,
262 euid, path->dentry->d_inode->i_ino, ino, isize, unit);
263 goto out;
264 }
265
266 if (type == DLOG_EFS) {
267 fslog_dlog_efs("\"%s\" (%lu, %lu, %lld%c)\n", full_path,
268 path->dentry->d_inode->i_ino, ino, isize, unit);
269 goto out;
270 }
271
272 if (type == DLOG_RMDIR)
273 fslog_dlog_rmdir("[%c]\"%s\" (%u, %lu)\n", prefix, full_path,
274 euid, path->dentry->d_inode->i_ino);
275 out:
276 kfree(buf);
277 }
278
279 void dlog_hook(struct dentry *dentry, struct inode *inode, struct path *path)
280 {
281 int part_id = get_support_part_id(path->mnt);
282
283 if ((part_id < 0) && !is_sdcard(path->mnt))
284 return;
285
286 /* for efs partition */
287 if (part_id == DLOG_SUPP_PART_EFS) {
288 store_log(dentry, inode, path, DLOG_EFS, part_id);
289 goto out;
290 }
291
292 /* for data partition`s only multimedia file */
293 if (is_ext(dentry->d_name.name, '.', &ht[DLOG_HT_EXTENSION])) {
294 store_log(dentry, inode, path, DLOG_MM, part_id);
295 goto out;
296 }
297
298 /* for data partition except multimedia file */
299 if (!is_ext(dentry->d_name.name, '.', &ht[DLOG_HT_EXCEPTION])
300 && !is_ext(dentry->d_name.name, '-', &ht[DLOG_HT_EXCEPTION]))
301 store_log(dentry, inode, path, DLOG_ETC, part_id);
302
303 out:
304 return;
305 }
306
307 static int get_dentry_depth(struct dentry *dentry)
308 {
309 int depth = 0;
310 struct dentry *tmp_de = dentry;
311
312 while (!IS_ROOT(tmp_de)) {
313 struct dentry *parent = tmp_de->d_parent;
314
315 depth++;
316 if (depth > MAX_DEPTH)
317 return -1;
318 tmp_de = parent;
319 }
320
321 return depth;
322 }
323
324 void dlog_hook_rmdir(struct dentry *dentry, struct path *path)
325 {
326 int depth = 0;
327 int part_id = get_support_part_id(path->mnt);
328
329 if (part_id != DLOG_SUPP_PART_DATA)
330 return;
331
332 depth = get_dentry_depth(dentry);
333 if (depth < 0)
334 return;
335
336 store_log(dentry, NULL, path, DLOG_RMDIR, part_id);
337
338 return;
339 }
340
341 MODULE_LICENSE("GPL");
342 MODULE_DESCRIPTION("Logging unlink file path");
343 MODULE_AUTHOR("Samsung Electronics Co., Ltd.");