/* * linux/fs/proc/proc_avc.c * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef CONFIG_PROC_AVC #include #endif #define LOG_MAGIC 0x4d474f4c /* "LOGM" */ static unsigned int *sec_avc_log_ptr; static char *sec_avc_log_buf; static unsigned int sec_avc_log_size; int __init sec_avc_log_init(void) { unsigned int size = SZ_256K; unsigned int *sec_avc_log_mag; sec_avc_log_size = size; sec_avc_log_mag = kzalloc(sec_avc_log_size, GFP_NOWAIT); pr_info("allocating %u bytes at %p (%llx physical) for avc log\n", sec_avc_log_size, sec_avc_log_mag, __pa(sec_avc_log_buf)); sec_avc_log_ptr = sec_avc_log_mag + 4; sec_avc_log_buf = (char *)(sec_avc_log_mag + 8); if (*sec_avc_log_mag != LOG_MAGIC) { pr_info("%s: no old log found\n", __func__); *sec_avc_log_ptr = 0; *sec_avc_log_mag = LOG_MAGIC; } return 1; } #define BUF_SIZE 512 void sec_avc_log(char *fmt, ...) { va_list args; char buf[BUF_SIZE]; int len = 0; unsigned int idx; unsigned int size; /* In case of sec_avc_log_setup is failed */ if (!sec_avc_log_size) return; va_start(args, fmt); vsnprintf(buf, sizeof(buf), fmt, args); va_end(args); idx = *sec_avc_log_ptr; size = strlen(buf); if (idx + (size * 2) > sec_avc_log_size - 1) { len = scnprintf(&sec_avc_log_buf[0], size + 1, "%s\n", buf); *sec_avc_log_ptr = len; } else { len = scnprintf(&sec_avc_log_buf[idx], size + 1, "%s\n", buf); *sec_avc_log_ptr += len; } } static ssize_t sec_avc_log_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { char *page = NULL; ssize_t ret; int new_value; if (!sec_avc_log_buf) return 0; ret = -ENOMEM; if (count >= PAGE_SIZE) return ret; ret = -ENOMEM; page = (char *)get_zeroed_page(GFP_KERNEL); if (!page) return ret; ret = -EFAULT; if (copy_from_user(page, buf, count)) goto out; ret = -EINVAL; if (sscanf(page, "%u", &new_value) != 1) { pr_info("%s\n", page); /* print avc_log to sec_avc_log_buf */ sec_avc_log("%s", page); } ret = count; out: free_page((unsigned long)page); return ret; } static ssize_t sec_avc_log_read(struct file *file, char __user *buf, size_t len, loff_t *offset) { loff_t pos = *offset; ssize_t count; if (pos >= (*sec_avc_log_ptr & (sec_avc_log_size - 1))) return 0; count = min(len, (size_t)((*sec_avc_log_ptr & (sec_avc_log_size - 1)) - pos)); if (copy_to_user(buf, sec_avc_log_buf + pos, count)) return -EFAULT; *offset += count; return count; } static const struct file_operations avc_msg_file_ops = { .owner = THIS_MODULE, .read = sec_avc_log_read, .write = sec_avc_log_write, .llseek = generic_file_llseek, }; static int __init sec_avc_log_late_init(void) { struct proc_dir_entry *entry; if (sec_avc_log_buf == NULL) { pr_err("%s: sec_avc_log_buf not initialized.\n", __func__); return 0; } entry = proc_create_data("avc_msg", S_IFREG | 0x444, NULL, &avc_msg_file_ops, NULL); if (!entry) { pr_err("%s: failed to create proc entry\n", __func__); return 0; } proc_set_size(entry, sec_avc_log_size); return 0; } late_initcall(sec_avc_log_late_init); int __init sec_log_init(void) { #ifdef CONFIG_PROC_AVC sec_avc_log_init(); #endif return 0; } fs_initcall(sec_log_init);