security: samsung: defex_lsm: nuke
This commit is contained in:
parent
e6d3a12a1d
commit
c453e653ba
56 changed files with 0 additions and 8218 deletions
|
@ -7659,9 +7659,6 @@ CONFIG_INIT_ON_ALLOC_DEFAULT_ON=y
|
|||
# end of Memory initialization
|
||||
# end of Kernel hardening options
|
||||
|
||||
# CONFIG_SECURITY_DEFEX is not set
|
||||
# CONFIG_DEFEX_KERNEL_ONLY is not set
|
||||
# CONFIG_SECURITY_DEFEX_USER is not set
|
||||
# CONFIG_PROCA is not set
|
||||
# CONFIG_PROCA_GKI_10 is not set
|
||||
# CONFIG_PROCA_S_OS is not set
|
||||
|
|
|
@ -14,10 +14,6 @@
|
|||
#include <asm/thread_info.h>
|
||||
#include <asm/unistd.h>
|
||||
|
||||
#ifdef CONFIG_SECURITY_DEFEX
|
||||
#include <linux/defex.h>
|
||||
#endif
|
||||
|
||||
long compat_arm_syscall(struct pt_regs *regs, int scno);
|
||||
long sys_ni_syscall(void);
|
||||
|
||||
|
@ -26,10 +22,6 @@ static long do_ni_syscall(struct pt_regs *regs, int scno)
|
|||
#ifdef CONFIG_COMPAT
|
||||
long ret;
|
||||
if (is_compat_task()) {
|
||||
#ifdef CONFIG_SECURITY_DEFEX
|
||||
ret = defex_syscall_enter(scno, regs);
|
||||
if (!ret)
|
||||
#endif /* CONFIG_SECURITY_DEFEX */
|
||||
ret = compat_arm_syscall(regs, scno);
|
||||
if (ret != -ENOSYS)
|
||||
return ret;
|
||||
|
@ -53,10 +45,6 @@ static void invoke_syscall(struct pt_regs *regs, unsigned int scno,
|
|||
if (scno < sc_nr) {
|
||||
syscall_fn_t syscall_fn;
|
||||
syscall_fn = syscall_table[array_index_nospec(scno, sc_nr)];
|
||||
#ifdef CONFIG_SECURITY_DEFEX
|
||||
ret = defex_syscall_enter(scno, regs);
|
||||
if (!ret)
|
||||
#endif /* CONFIG_SECURITY_DEFEX */
|
||||
ret = __invoke_syscall(regs, syscall_fn);
|
||||
} else {
|
||||
ret = do_ni_syscall(regs, scno);
|
||||
|
|
13
fs/exec.c
13
fs/exec.c
|
@ -75,10 +75,6 @@
|
|||
|
||||
#include <trace/events/sched.h>
|
||||
|
||||
#ifdef CONFIG_SECURITY_DEFEX
|
||||
#include <linux/defex.h>
|
||||
#endif
|
||||
|
||||
EXPORT_TRACEPOINT_SYMBOL_GPL(task_rename);
|
||||
|
||||
static int bprm_creds_from_file(struct linux_binprm *bprm);
|
||||
|
@ -1822,15 +1818,6 @@ static int bprm_execve(struct linux_binprm *bprm,
|
|||
if (IS_ERR(file))
|
||||
goto out_unmark;
|
||||
|
||||
#ifdef CONFIG_SECURITY_DEFEX
|
||||
retval = task_defex_enforce(current, file, -__NR_execve);
|
||||
if (retval < 0) {
|
||||
bprm->file = file;
|
||||
retval = -EPERM;
|
||||
goto out_unmark;
|
||||
}
|
||||
#endif
|
||||
|
||||
sched_exec();
|
||||
|
||||
bprm->file = file;
|
||||
|
|
10
fs/open.c
10
fs/open.c
|
@ -36,10 +36,6 @@
|
|||
#include "internal.h"
|
||||
#include <trace/hooks/syscall_check.h>
|
||||
|
||||
#ifdef CONFIG_SECURITY_DEFEX
|
||||
#include <linux/defex.h>
|
||||
#endif
|
||||
|
||||
int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
|
||||
struct file *filp)
|
||||
{
|
||||
|
@ -1220,12 +1216,6 @@ static long do_sys_openat2(int dfd, const char __user *filename,
|
|||
if (fd >= 0) {
|
||||
struct file *f = do_filp_open(dfd, tmp, &op);
|
||||
|
||||
#ifdef CONFIG_SECURITY_DEFEX
|
||||
if (!IS_ERR(f) && task_defex_enforce(current, f, -__NR_openat)) {
|
||||
fput(f);
|
||||
f = ERR_PTR(-EPERM);
|
||||
}
|
||||
#endif
|
||||
if (IS_ERR(f)) {
|
||||
put_unused_fd(fd);
|
||||
fd = PTR_ERR(f);
|
||||
|
|
|
@ -29,10 +29,6 @@
|
|||
#include <linux/fscrypto_sdp_cache.h>
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SECURITY_DEFEX
|
||||
#include <linux/defex.h>
|
||||
#endif
|
||||
|
||||
const struct file_operations generic_ro_fops = {
|
||||
.llseek = generic_file_llseek,
|
||||
.read_iter = generic_file_read_iter,
|
||||
|
@ -604,10 +600,6 @@ ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_
|
|||
ret = rw_verify_area(WRITE, file, pos, count);
|
||||
if (ret)
|
||||
return ret;
|
||||
#ifdef CONFIG_SECURITY_DEFEX
|
||||
if (task_defex_enforce(current, file, -__NR_write))
|
||||
return -EPERM;
|
||||
#endif
|
||||
if (count > MAX_RW_COUNT)
|
||||
count = MAX_RW_COUNT;
|
||||
file_start_write(file);
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2015 Samsung Electronics Co., Ltd. All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef __CONFIG_SECURITY_DEFEX_H
|
||||
#define __CONFIG_SECURITY_DEFEX_H
|
||||
|
||||
/* Defex init API */
|
||||
int task_defex_enforce(struct task_struct *p, struct file *f, int syscall, ...);
|
||||
int task_defex_zero_creds(struct task_struct *tsk);
|
||||
asmlinkage int defex_syscall_enter(long int syscallno, struct pt_regs *regs);
|
||||
int task_defex_user_exec(const char *new_file);
|
||||
void __init defex_load_rules(void);
|
||||
#endif /* CONFIG_SECURITY_DEFEX_H */
|
|
@ -113,11 +113,6 @@
|
|||
#include <kunit/test.h>
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SECURITY_DEFEX
|
||||
#include <linux/defex.h>
|
||||
void __init __weak defex_load_rules(void) { }
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_RKP
|
||||
#include <linux/rkp.h>
|
||||
#endif
|
||||
|
@ -1587,7 +1582,4 @@ static noinline void __init kernel_init_freeable(void)
|
|||
*/
|
||||
|
||||
integrity_load_keys();
|
||||
#ifdef CONFIG_SECURITY_DEFEX
|
||||
defex_load_rules();
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -117,10 +117,6 @@ static __init int kernel_exit_sysfs_init(void)
|
|||
late_initcall(kernel_exit_sysfs_init);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SECURITY_DEFEX
|
||||
#include <linux/defex.h>
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_MEMORY_ZEROISATION)
|
||||
#include <trace/hooks/mz.h>
|
||||
#endif
|
||||
|
@ -776,10 +772,6 @@ void __noreturn do_exit(long code)
|
|||
struct task_struct *tsk = current;
|
||||
int group_dead;
|
||||
|
||||
#ifdef CONFIG_SECURITY_DEFEX
|
||||
task_defex_zero_creds(current);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* We can get here from a kernel oops, sometimes with preemption off.
|
||||
* Start by checking for critical errors.
|
||||
|
|
|
@ -113,10 +113,6 @@
|
|||
#undef CREATE_TRACE_POINTS
|
||||
#include <trace/hooks/sched.h>
|
||||
|
||||
#ifdef CONFIG_SECURITY_DEFEX
|
||||
#include <linux/defex.h>
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_KDP_CRED
|
||||
#include <linux/kdp.h>
|
||||
#endif
|
||||
|
@ -2654,10 +2650,6 @@ pid_t kernel_clone(struct kernel_clone_args *args)
|
|||
pid = get_task_pid(p, PIDTYPE_PID);
|
||||
nr = pid_vnr(pid);
|
||||
|
||||
#ifdef CONFIG_SECURITY_DEFEX
|
||||
task_defex_zero_creds(p);
|
||||
#endif
|
||||
|
||||
if (clone_flags & CLONE_PARENT_SETTID)
|
||||
put_user(nr, args->parent_tid);
|
||||
|
||||
|
|
14
kernel/sys.c
14
kernel/sys.c
|
@ -74,10 +74,6 @@
|
|||
#include <asm/io.h>
|
||||
#include <asm/unistd.h>
|
||||
|
||||
#ifdef CONFIG_SECURITY_DEFEX
|
||||
#include <linux/defex.h>
|
||||
#endif
|
||||
|
||||
#include "uid16.h"
|
||||
|
||||
#include <trace/hooks/sys.h>
|
||||
|
@ -846,11 +842,6 @@ long __sys_setfsuid(uid_t uid)
|
|||
if (!uid_valid(kuid))
|
||||
return old_fsuid;
|
||||
|
||||
#ifdef CONFIG_SECURITY_DEFEX
|
||||
if (task_defex_enforce(current, NULL, -__NR_setfsuid))
|
||||
return old_fsuid;
|
||||
#endif
|
||||
|
||||
new = prepare_creds();
|
||||
if (!new)
|
||||
return old_fsuid;
|
||||
|
@ -895,11 +886,6 @@ long __sys_setfsgid(gid_t gid)
|
|||
if (!gid_valid(kgid))
|
||||
return old_fsgid;
|
||||
|
||||
#ifdef CONFIG_SECURITY_DEFEX
|
||||
if (task_defex_enforce(current, NULL, -__NR_setfsgid))
|
||||
return old_fsgid;
|
||||
#endif
|
||||
|
||||
new = prepare_creds();
|
||||
if (!new)
|
||||
return old_fsgid;
|
||||
|
|
10
kernel/umh.c
10
kernel/umh.c
|
@ -30,10 +30,6 @@
|
|||
|
||||
#include <trace/events/module.h>
|
||||
|
||||
#ifdef CONFIG_SECURITY_DEFEX
|
||||
#include <linux/defex.h>
|
||||
#endif
|
||||
|
||||
#define CAP_BSET (void *)1
|
||||
#define CAP_PI (void *)2
|
||||
|
||||
|
@ -426,12 +422,6 @@ int call_usermodehelper_exec(struct subprocess_info *sub_info, int wait)
|
|||
if (strlen(sub_info->path) == 0)
|
||||
goto out;
|
||||
|
||||
#ifdef CONFIG_SECURITY_DEFEX
|
||||
if (task_defex_user_exec(sub_info->path)) {
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Set the completion pointer only if there is a waiter.
|
||||
* This makes it possible to use umh_complete to free
|
||||
|
|
|
@ -302,7 +302,6 @@ config SDP_KEY_DUMP
|
|||
|
||||
source "security/Kconfig.hardening"
|
||||
|
||||
source "security/samsung/defex_lsm/Kconfig" # ADDED BY LEGO AUTOMATICALLY: DO NOT SUBMIT
|
||||
source "security/samsung/proca/Kconfig" # ADDED BY LEGO AUTOMATICALLY: DO NOT SUBMIT
|
||||
source "security/samsung/proca/gaf/Kconfig" # ADDED BY LEGO AUTOMATICALLY: DO NOT SUBMIT
|
||||
source "security/samsung/mz/Kconfig" # ADDED BY LEGO AUTOMATICALLY: DO NOT SUBMIT
|
||||
|
|
|
@ -40,7 +40,6 @@ obj-$(CONFIG_INTEGRITY) += integrity/
|
|||
# KNOX DAR
|
||||
obj-$(CONFIG_SDP) += sdp/
|
||||
obj-$(CONFIG_SDP) += sdp/built-in.a
|
||||
obj-y += samsung/defex_lsm/ # ADDED BY LEGO AUTOMATICALLY: DO NOT SUBMIT
|
||||
obj-y += samsung/proca/ # ADDED BY LEGO AUTOMATICALLY: DO NOT SUBMIT
|
||||
obj-y += samsung/proca/gaf/ # ADDED BY LEGO AUTOMATICALLY: DO NOT SUBMIT
|
||||
obj-y += samsung/mz/ # ADDED BY LEGO AUTOMATICALLY: DO NOT SUBMIT
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
config SECURITY_DEFEX
|
||||
bool "Defex Support"
|
||||
depends on SECURITY && (!KCOV || SAMSUNG_PRODUCT_SHIP)
|
||||
select CRYPTO
|
||||
select CRYPTO_RSA
|
||||
select CRYPTO_SHA1
|
||||
select CRYPTO_SHA256
|
||||
select CRYPTO_HASH_INFO
|
||||
select INTEGRITY_SIGNATURE
|
||||
select INTEGRITY_ASYMMETRIC_KEYS
|
||||
default n
|
||||
help
|
||||
This selects the Defex support.
|
||||
If you are unsure how to answer this question, answer N.
|
||||
|
||||
config DEFEX_KERNEL_ONLY
|
||||
bool "Defex Kernel Only"
|
||||
depends on SECURITY_DEFEX
|
||||
default n
|
||||
help
|
||||
This lets defex know whether kernel-only build or not.
|
||||
Default value will be set to "y" if the build is kernel-only.
|
||||
And it will be changed to "n" by build.py at platform-build.
|
||||
|
||||
config SECURITY_DEFEX_USER
|
||||
bool "Defex USER build"
|
||||
depends on SECURITY_DEFEX
|
||||
default n
|
||||
help
|
||||
This lets defex to know whether USER build performed or not
|
||||
in case of TARGET_BUILD_VARIANT variable is empty.
|
|
@ -1,237 +0,0 @@
|
|||
#
|
||||
# Makefile for the Defex
|
||||
#
|
||||
|
||||
# Features to Enable
|
||||
PED_ENABLE=true
|
||||
SAFEPLACE_ENABLE=true
|
||||
IMMUTABLE_ENABLE=true
|
||||
LP_ENABLE=true
|
||||
UMH_RESTRICTION_ENABLE=true
|
||||
TRUSTED_MAP_ENABLE=false
|
||||
USER_BUILD=false
|
||||
|
||||
# Additional debug
|
||||
LOG_BUFFER_ENABLE=false
|
||||
SHOW_RULES_ENABLE=false
|
||||
|
||||
ifeq (,$(TARGET_BUILD_VARIANT))
|
||||
ifeq ($(CONFIG_SECURITY_DEFEX_USER),y)
|
||||
USER_BUILD := true
|
||||
endif
|
||||
else
|
||||
ifeq ($(TARGET_BUILD_VARIANT),user)
|
||||
USER_BUILD := true
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq ($(wildcard $(srctree)/include/crypto/internal/rsa.h),)
|
||||
$(warning [DEFEX] INTEGRITY_ENABLE)
|
||||
INTEGRITY_ENABLE=true
|
||||
endif
|
||||
|
||||
# caches to enable
|
||||
CACHES_ENABLE=true
|
||||
|
||||
# OEM Unlock dependency
|
||||
OEM_UNLOCK_DEPENDENCY=true
|
||||
|
||||
# use the ramdisk or system_root to store rules file
|
||||
RAMDISK_ENABLE=true
|
||||
|
||||
# do signing for rules
|
||||
SIGN_ENABLE=true
|
||||
|
||||
defex-y := core/defex_common.o
|
||||
defex-y += core/defex_lsm.o
|
||||
defex-y += core/defex_main.o
|
||||
defex-y += core/defex_get_mode.o
|
||||
defex-y += core/defex_rules_proc.o
|
||||
defex-y += core/defex_tailer.o
|
||||
defex-y += catch_engine/defex_catch_list.o
|
||||
defex-y += catch_engine/defex_ht.o
|
||||
defex-y += defex_rules.o
|
||||
defex-$(CONFIG_COMPAT) += catch_engine/defex_catch_list_compat.o
|
||||
|
||||
# Immutable Feature is applied with permissive mode first.
|
||||
DEFEX_DEFINES := -DDEFEX_PERMISSIVE_IM
|
||||
|
||||
# Integrity Feature is applied with permissive mode first.
|
||||
DEFEX_DEFINES += -DDEFEX_PERMISSIVE_INT
|
||||
|
||||
ifeq ($(CONFIG_DEFEX_KERNEL_ONLY), y)
|
||||
DEFEX_DEFINES += -DDEFEX_KERNEL_ONLY
|
||||
ifeq ($(CONFIG_SAMSUNG_PRODUCT_SHIP), y)
|
||||
$(warning [DEFEX] Kernel_only & Ship)
|
||||
else
|
||||
$(warning [DEFEX] Kernel_only & Noship)
|
||||
defex-y += debug/defex_debug.o
|
||||
defex-y += core/defex_sysfs.o
|
||||
DEFEX_DEFINES += -DDEFEX_PERMISSIVE_INT
|
||||
DEFEX_DEFINES += -DDEFEX_PERMISSIVE_SP
|
||||
DEFEX_DEFINES += -DDEFEX_PERMISSIVE_TM
|
||||
DEFEX_DEFINES += -DDEFEX_PERMISSIVE_IM
|
||||
DEFEX_DEFINES += -DDEFEX_PERMISSIVE_LP
|
||||
DEFEX_DEFINES += -DDEFEX_DEBUG_ENABLE
|
||||
ifeq ($(LOG_BUFFER_ENABLE), true)
|
||||
DEFEX_DEFINES += -DDEFEX_LOG_BUFFER_ENABLE
|
||||
endif
|
||||
ifeq ($(SHOW_RULES_ENABLE), true)
|
||||
defex-y += debug/defex_rules_show.o
|
||||
DEFEX_DEFINES += -DDEFEX_SHOW_RULES_ENABLE
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_SEC_FACTORY), y)
|
||||
DEFEX_DEFINES += -DDEFEX_FACTORY_ENABLE
|
||||
DEFEX_DEFINES += -DDEFEX_PERMISSIVE_LP
|
||||
endif
|
||||
|
||||
ifeq ($(PED_ENABLE), true)
|
||||
defex-y += feature_privilege_escalation_detection/defex_priv.o
|
||||
DEFEX_DEFINES += -DDEFEX_PED_ENABLE
|
||||
endif
|
||||
|
||||
ifeq ($(SAFEPLACE_ENABLE), true)
|
||||
defex-y += feature_safeplace/defex_safeplace.o
|
||||
DEFEX_DEFINES += -DDEFEX_SAFEPLACE_ENABLE
|
||||
endif
|
||||
|
||||
ifeq ($(INTEGRITY_ENABLE), true)
|
||||
defex-y += feature_safeplace/defex_integrity.o
|
||||
DEFEX_DEFINES += -DDEFEX_INTEGRITY_ENABLE
|
||||
endif
|
||||
|
||||
ifeq ($(IMMUTABLE_ENABLE), true)
|
||||
defex-y += feature_immutable/defex_immutable.o
|
||||
DEFEX_DEFINES += -DDEFEX_IMMUTABLE_ENABLE
|
||||
endif
|
||||
|
||||
ifeq ($(LP_ENABLE), true)
|
||||
DEFEX_DEFINES += -DDEFEX_LP_ENABLE
|
||||
endif
|
||||
|
||||
ifeq ($(UMH_RESTRICTION_ENABLE), true)
|
||||
DEFEX_DEFINES += -DDEFEX_UMH_RESTRICTION_ENABLE
|
||||
endif
|
||||
|
||||
ifeq ($(CACHES_ENABLE), true)
|
||||
defex-y += catch_engine/defex_caches.o
|
||||
DEFEX_DEFINES += -DDEFEX_CACHES_ENABLE
|
||||
endif
|
||||
|
||||
ifeq ($(OEM_UNLOCK_DEPENDENCY), true)
|
||||
DEFEX_DEFINES += -DDEFEX_DEPENDING_ON_OEMUNLOCK
|
||||
endif
|
||||
|
||||
ifeq ($(RAMDISK_ENABLE), true)
|
||||
DEFEX_DEFINES += -DDEFEX_RAMDISK_ENABLE
|
||||
ifeq ($(SIGN_ENABLE), true)
|
||||
defex-y += cert/defex_cert.o
|
||||
defex-y += cert/defex_sign.o
|
||||
DEFEX_DEFINES += -DDEFEX_SIGN_ENABLE
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(TRUSTED_MAP_ENABLE), true)
|
||||
DEFEX_DEFINES += -DDEFEX_TRUSTED_MAP_ENABLE
|
||||
DEFEX_DEFINES += -DDEFEX_PERMISSIVE_TM
|
||||
#DEFEX_DEFINES += -DDEFEX_TM_DEFAULT_POLICY_ENABLE
|
||||
defex-y += feature_trusted_map/defex_trusted_map.o
|
||||
defex-y += feature_trusted_map/dtm.o
|
||||
defex-y += feature_trusted_map/dtm_engine.o
|
||||
defex-y += feature_trusted_map/dtm_log.o
|
||||
defex-y += feature_trusted_map/dtm_utils.o
|
||||
defex-y += feature_trusted_map/ptree.o
|
||||
endif
|
||||
|
||||
ifeq ($(USER_BUILD), true)
|
||||
$(warning [DEFEX] DEBUG_DISABLE)
|
||||
ifeq ($(CONFIG_SECURITY_DSMS), y)
|
||||
DEFEX_DEFINES += -DDEFEX_DSMS_ENABLE
|
||||
endif
|
||||
else
|
||||
$(warning [DEFEX] DEBUG_ENABLE)
|
||||
defex-y += debug/defex_debug.o
|
||||
defex-y += core/defex_sysfs.o
|
||||
DEFEX_DEFINES += -DDEFEX_PERMISSIVE_INT
|
||||
DEFEX_DEFINES += -DDEFEX_PERMISSIVE_SP
|
||||
DEFEX_DEFINES += -DDEFEX_PERMISSIVE_TM
|
||||
DEFEX_DEFINES += -DDEFEX_PERMISSIVE_IM
|
||||
DEFEX_DEFINES += -DDEFEX_PERMISSIVE_LP
|
||||
DEFEX_DEFINES += -DDEFEX_DEBUG_ENABLE
|
||||
ifeq ($(LOG_BUFFER_ENABLE), true)
|
||||
DEFEX_DEFINES += -DDEFEX_LOG_BUFFER_ENABLE
|
||||
endif
|
||||
ifeq ($(SHOW_RULES_ENABLE), true)
|
||||
defex-y += debug/defex_rules_show.o
|
||||
DEFEX_DEFINES += -DDEFEX_SHOW_RULES_ENABLE
|
||||
endif
|
||||
endif
|
||||
|
||||
# kunit tests options:
|
||||
ifeq ($(CONFIG_SEC_KUNIT), y)
|
||||
GCOV_PROFILE := y
|
||||
DEFEX_DEFINES += -DDEFEX_KUNIT_ENABLED
|
||||
else
|
||||
DEFEX_DEFINES += -D__visible_for_testing=static
|
||||
endif
|
||||
|
||||
ccflags-y := -Wformat
|
||||
|
||||
EXTRA_CFLAGS += -I$(srctree)/$(src)
|
||||
EXTRA_AFLAGS += -Isecurity/samsung/defex_lsm
|
||||
EXTRA_CFLAGS += -I$(srctree)/$(src)/cert
|
||||
EXTRA_AFLAGS += -Isecurity/samsung/defex_lsm/cert
|
||||
|
||||
ifneq ($(wildcard $(srctree)/$(src)/pack_rules.c),)
|
||||
EXTRA_CFLAGS += $(DEFEX_DEFINES)
|
||||
EXTRA_AFLAGS += $(DEFEX_DEFINES)
|
||||
hostprogs := pack_rules
|
||||
hostprogs-y := pack_rules
|
||||
HOST_EXTRACFLAGS += $(DEFEX_DEFINES)
|
||||
clean-files := $(obj)/defex_packed_rules.inc
|
||||
DEPEND_LIST := $(obj)/pack_rules
|
||||
|
||||
quiet_cmd_pack = PACK $<
|
||||
cmd_pack = $(obj)/pack_rules -p $< $@ $(srctree)/$(src)/defex_packed_rules.bin
|
||||
|
||||
quiet_cmd_mkey = MAKEKEY $<
|
||||
cmd_mkey = cp -n $< $@ 2>/dev/null || true
|
||||
|
||||
$(obj)/core/defex_rules_proc.o: $(obj)/pack_rules $(obj)/defex_packed_rules.inc
|
||||
|
||||
$(obj)/cert/defex_cert.o: $(obj)/cert/pubkey_eng.der $(obj)/cert/pubkey_user.der
|
||||
|
||||
$(obj)/cert/pubkey_eng.der: $(srctree)/$(src)/cert/x509_five_eng.der
|
||||
$(call cmd,mkey)
|
||||
|
||||
$(obj)/cert/pubkey_user.der: $(srctree)/$(src)/cert/x509_five_user.der
|
||||
$(call cmd,mkey)
|
||||
|
||||
SOURCE_RULES := $(srctree)/$(src)/defex_rules.c
|
||||
ifneq ($(wildcard $(srctree)/$(src)/file_list),)
|
||||
$(warning '[DEFEX] file_list found')
|
||||
SOURCE_RULES := $(srctree)/$(src)/defex_rules_reduced.c
|
||||
DEPEND_LIST += $(SOURCE_RULES)
|
||||
DEPEND_LIST += $(srctree)/$(src)/file_list
|
||||
clean-files += $(DEPEND_LIST)
|
||||
|
||||
quiet_cmd_reduce = REDUCE $<
|
||||
cmd_reduce = $(obj)/pack_rules -r $< $@ $(srctree)/$(src)/file_list
|
||||
|
||||
$(srctree)/$(src)/defex_rules_reduced.c: $(srctree)/$(src)/defex_rules.c $(obj)/pack_rules
|
||||
$(call cmd,reduce)
|
||||
endif
|
||||
|
||||
$(obj)/defex_packed_rules.inc: $(SOURCE_RULES) $(DEPEND_LIST)
|
||||
$(call cmd,pack)
|
||||
@cp -n $(obj)/pack_rules $(srctree)/$(src)/pack_rules 2>/dev/null || true
|
||||
|
||||
else
|
||||
EXTRA_CFLAGS += $(DEFEX_DEFINES)
|
||||
EXTRA_AFLAGS += $(DEFEX_DEFINES)
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_SECURITY_DEFEX) := $(defex-y)
|
|
@ -1,177 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/file.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/unistd.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include "include/defex_caches.h"
|
||||
|
||||
__visible_for_testing struct defex_file_cache_list file_cache;
|
||||
|
||||
DEFINE_SPINLOCK(defex_caches_lock);
|
||||
|
||||
void defex_file_cache_init(void)
|
||||
{
|
||||
int i;
|
||||
struct defex_file_cache_entry *current_entry;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&defex_caches_lock, flags);
|
||||
for (i = 0; i < FILE_CACHE_SIZE; i++) {
|
||||
current_entry = &file_cache.entry[i];
|
||||
current_entry->next_entry = i + 1;
|
||||
current_entry->prev_entry = i - 1;
|
||||
current_entry->pid = -1;
|
||||
current_entry->file_addr = NULL;
|
||||
}
|
||||
|
||||
file_cache.first_entry = 0;
|
||||
file_cache.last_entry = FILE_CACHE_SIZE - 1;
|
||||
|
||||
file_cache.entry[file_cache.first_entry].prev_entry = file_cache.last_entry;
|
||||
file_cache.entry[file_cache.last_entry].next_entry = file_cache.first_entry;
|
||||
spin_unlock_irqrestore(&defex_caches_lock, flags);
|
||||
}
|
||||
|
||||
void defex_file_cache_add(int pid, struct file *file_addr)
|
||||
{
|
||||
struct defex_file_cache_entry *current_entry;
|
||||
struct file *old_file_addr;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&defex_caches_lock, flags);
|
||||
|
||||
current_entry = &file_cache.entry[file_cache.last_entry];
|
||||
|
||||
current_entry->pid = pid;
|
||||
|
||||
old_file_addr = current_entry->file_addr;
|
||||
|
||||
current_entry->file_addr = file_addr;
|
||||
current_entry->next_entry = file_cache.first_entry;
|
||||
|
||||
file_cache.first_entry = file_cache.last_entry;
|
||||
file_cache.last_entry = current_entry->prev_entry;
|
||||
|
||||
spin_unlock_irqrestore(&defex_caches_lock, flags);
|
||||
if (old_file_addr) {
|
||||
fput(old_file_addr);
|
||||
}
|
||||
}
|
||||
|
||||
void defex_file_cache_update(struct file *file_addr)
|
||||
{
|
||||
struct defex_file_cache_entry *current_entry;
|
||||
struct file *old_file_addr;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&defex_caches_lock, flags);
|
||||
current_entry = &file_cache.entry[file_cache.first_entry];
|
||||
old_file_addr = current_entry->file_addr;
|
||||
current_entry->file_addr = file_addr;
|
||||
spin_unlock_irqrestore(&defex_caches_lock, flags);
|
||||
if (old_file_addr)
|
||||
fput(old_file_addr);
|
||||
}
|
||||
|
||||
void defex_file_cache_delete(int pid)
|
||||
{
|
||||
int current_index, cache_found = 0;
|
||||
struct defex_file_cache_entry *current_entry;
|
||||
struct file *old_file_addr = NULL;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&defex_caches_lock, flags);
|
||||
|
||||
current_index = file_cache.first_entry;
|
||||
do {
|
||||
current_entry = &file_cache.entry[current_index];
|
||||
if (current_entry->pid == pid) {
|
||||
|
||||
if (current_index == file_cache.first_entry) {
|
||||
file_cache.first_entry = current_entry->next_entry;
|
||||
file_cache.last_entry = current_index;
|
||||
cache_found = 1;
|
||||
break;
|
||||
}
|
||||
if (current_index == file_cache.last_entry) {
|
||||
cache_found = 1;
|
||||
break;
|
||||
}
|
||||
file_cache.entry[current_entry->prev_entry].next_entry = current_entry->next_entry;
|
||||
file_cache.entry[current_entry->next_entry].prev_entry = current_entry->prev_entry;
|
||||
file_cache.entry[file_cache.first_entry].prev_entry = current_index;
|
||||
file_cache.entry[file_cache.last_entry].next_entry = current_index;
|
||||
|
||||
current_entry->next_entry = file_cache.first_entry;
|
||||
current_entry->prev_entry = file_cache.last_entry;
|
||||
|
||||
file_cache.last_entry = current_index;
|
||||
|
||||
cache_found = 1;
|
||||
break;
|
||||
}
|
||||
current_index = current_entry->next_entry;
|
||||
} while (current_index != file_cache.first_entry);
|
||||
|
||||
if (cache_found) {
|
||||
old_file_addr = current_entry->file_addr;
|
||||
current_entry->pid = -1;
|
||||
current_entry->file_addr = NULL;
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&defex_caches_lock, flags);
|
||||
if (old_file_addr)
|
||||
fput(old_file_addr);
|
||||
return;
|
||||
}
|
||||
|
||||
struct file *defex_file_cache_find(int pid)
|
||||
{
|
||||
int current_index, cache_found = 0;
|
||||
struct defex_file_cache_entry *current_entry;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&defex_caches_lock, flags);
|
||||
|
||||
current_index = file_cache.first_entry;
|
||||
do {
|
||||
current_entry = &file_cache.entry[current_index];
|
||||
if (current_entry->pid == pid) {
|
||||
if (current_index == file_cache.first_entry) {
|
||||
cache_found = 1;
|
||||
break;
|
||||
}
|
||||
if (current_index == file_cache.last_entry) {
|
||||
current_entry->next_entry = file_cache.first_entry;
|
||||
file_cache.first_entry = file_cache.last_entry;
|
||||
file_cache.last_entry = current_entry->prev_entry;
|
||||
cache_found = 1;
|
||||
break;
|
||||
}
|
||||
file_cache.entry[current_entry->prev_entry].next_entry = current_entry->next_entry;
|
||||
file_cache.entry[current_entry->next_entry].prev_entry = current_entry->prev_entry;
|
||||
file_cache.entry[file_cache.first_entry].prev_entry = current_index;
|
||||
file_cache.entry[file_cache.last_entry].next_entry = current_index;
|
||||
|
||||
current_entry->next_entry = file_cache.first_entry;
|
||||
current_entry->prev_entry = file_cache.last_entry;
|
||||
|
||||
file_cache.first_entry = current_index;
|
||||
|
||||
cache_found = 1;
|
||||
break;
|
||||
}
|
||||
current_index = current_entry->next_entry;
|
||||
} while (current_index != file_cache.first_entry);
|
||||
|
||||
spin_unlock_irqrestore(&defex_caches_lock, flags);
|
||||
|
||||
return (!cache_found)?NULL:current_entry->file_addr;
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/unistd.h>
|
||||
#include "include/defex_catch_list.h"
|
||||
|
||||
#ifdef DEFEX_KUNIT_ENABLED
|
||||
#ifndef __NR_syscalls
|
||||
#define __NR_syscalls 436
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define DEFEX_CATCH_COUNT __NR_syscalls
|
||||
const int defex_nr_syscalls = DEFEX_CATCH_COUNT;
|
||||
|
||||
#include "defex_catch_list.inc"
|
||||
|
||||
const struct local_syscall_struct *get_local_syscall(int syscall_no)
|
||||
{
|
||||
if ((unsigned int)syscall_no >= __NR_syscalls)
|
||||
return NULL;
|
||||
|
||||
if (!syscall_catch_arr[syscall_no].local_syscall && !syscall_catch_arr[syscall_no].err_code && syscall_no) {
|
||||
return &syscall_catch_arr[0];
|
||||
}
|
||||
|
||||
return &syscall_catch_arr[syscall_no];
|
||||
}
|
||||
|
||||
int syscall_local2global(int syscall_no)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < __NR_syscalls; i++) {
|
||||
if (syscall_catch_arr[i].local_syscall == syscall_no)
|
||||
return i;
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -1,575 +0,0 @@
|
|||
static const struct local_syscall_struct syscall_catch_arr[DEFEX_CATCH_COUNT] = {
|
||||
/* */
|
||||
[0] = {
|
||||
.local_syscall = 0,
|
||||
.err_code = -EPERM
|
||||
},
|
||||
|
||||
#ifdef __NR_rmdir
|
||||
SYSCALL_CATCH(rmdir, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_utimes
|
||||
SYSCALL_CATCH(utimes, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_stat
|
||||
SYSCALL_CATCH(stat, -EACCES),
|
||||
#endif
|
||||
#ifdef __NR_lstat
|
||||
SYSCALL_CATCH(lstat, -EACCES),
|
||||
#endif
|
||||
#ifdef __NR_umount
|
||||
SYSCALL_CATCH(umount, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_utime
|
||||
SYSCALL_CATCH(utime, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_futimesat
|
||||
SYSCALL_CATCH(futimesat, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_uselib
|
||||
SYSCALL_CATCH(uselib, -EACCES),
|
||||
#endif
|
||||
#ifdef __NR_send
|
||||
SYSCALL_CATCH(send, -EACCES),
|
||||
#endif
|
||||
#ifdef __NR_ustat
|
||||
SYSCALL_CATCH(ustat, -EFAULT),
|
||||
#endif
|
||||
#ifdef __NR_getdents
|
||||
SYSCALL_CATCH(getdents, -EFAULT),
|
||||
#endif
|
||||
#ifdef __NR_recv
|
||||
SYSCALL_CATCH(recv, -EFAULT),
|
||||
#endif
|
||||
#ifdef __NR_fork
|
||||
SYSCALL_CATCH(fork, -EINVAL),
|
||||
#endif
|
||||
#ifdef __NR_vfork
|
||||
SYSCALL_CATCH(vfork, -EINVAL),
|
||||
#endif
|
||||
#ifdef __NR_sigprocmask
|
||||
SYSCALL_CATCH(sigprocmask, -EFAULT),
|
||||
#endif
|
||||
#ifdef __NR_sigpending
|
||||
SYSCALL_CATCH(sigpending, -EFAULT),
|
||||
#endif
|
||||
#ifdef __NR_sigaction
|
||||
SYSCALL_CATCH(sigaction, -EFAULT),
|
||||
#endif
|
||||
#ifdef __NR_sigaltstack
|
||||
SYSCALL_CATCH(sigaltstack, -EFAULT),
|
||||
#endif
|
||||
#ifdef __NR_sigsuspend
|
||||
SYSCALL_CATCH(sigsuspend, -EFAULT),
|
||||
#endif
|
||||
#ifdef __NR_truncate64
|
||||
SYSCALL_CATCH(truncate64, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_ftruncate64
|
||||
SYSCALL_CATCH(ftruncate64, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_fstat64
|
||||
SYSCALL_CATCH(fstat64, -EACCES),
|
||||
#endif
|
||||
#ifdef __NR_fstatat64
|
||||
SYSCALL_CATCH(fstatat64, -EACCES),
|
||||
#endif
|
||||
#ifdef __NR_statfs64
|
||||
SYSCALL_CATCH(statfs64, -EACCES),
|
||||
#endif
|
||||
#ifdef __NR_stat64
|
||||
SYSCALL_CATCH(stat64, -EACCES),
|
||||
#endif
|
||||
#ifdef __NR_lstat64
|
||||
SYSCALL_CATCH(lstat64, -EACCES),
|
||||
#endif
|
||||
#ifdef __NR_eventfd
|
||||
SYSCALL_CATCH(eventfd, -EINVAL),
|
||||
#endif
|
||||
#ifdef __NR_epoll_create
|
||||
SYSCALL_CATCH(epoll_create, -EINVAL),
|
||||
#endif
|
||||
#ifdef __NR_shmget
|
||||
SYSCALL_CATCH(shmget, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_shmctl
|
||||
SYSCALL_CATCH(shmctl, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_semctl
|
||||
SYSCALL_CATCH(semctl, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_move_pages
|
||||
SYSCALL_CATCH(move_pages, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_lookup_dcookie
|
||||
SYSCALL_CATCH(lookup_dcookie, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_truncate
|
||||
SYSCALL_CATCH(truncate, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_ftruncate
|
||||
SYSCALL_CATCH(ftruncate, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_chdir
|
||||
SYSCALL_CATCH(chdir, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_chroot
|
||||
SYSCALL_CATCH(chroot, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_fchmod
|
||||
SYSCALL_CATCH(fchmod, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_fchmodat
|
||||
SYSCALL_CATCH(fchmodat, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_fchownat
|
||||
SYSCALL_CATCH(fchownat, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_fchown
|
||||
SYSCALL_CATCH(fchown, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_mknodat
|
||||
SYSCALL_CATCH(mknodat, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_mkdirat
|
||||
SYSCALL_CATCH(mkdirat, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_unlinkat
|
||||
SYSCALL_CATCH(unlinkat, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_symlinkat
|
||||
SYSCALL_CATCH(symlinkat, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_linkat
|
||||
SYSCALL_CATCH(linkat, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_renameat
|
||||
SYSCALL_CATCH(renameat, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_umount2
|
||||
SYSCALL_CATCH(umount2, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_mount
|
||||
SYSCALL_CATCH(mount, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_pivot_root
|
||||
SYSCALL_CATCH(pivot_root, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_utimensat
|
||||
SYSCALL_CATCH(utimensat, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_fcntl
|
||||
SYSCALL_CATCH(fcntl, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_kexec_load
|
||||
SYSCALL_CATCH(kexec_load, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_ptrace
|
||||
SYSCALL_CATCH(ptrace, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_setgroups
|
||||
SYSCALL_CATCH(setgroups, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_settimeofday
|
||||
SYSCALL_CATCH(settimeofday, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_delete_module
|
||||
SYSCALL_CATCH(delete_module, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_init_module
|
||||
SYSCALL_CATCH(init_module, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_capset
|
||||
SYSCALL_CATCH(capset, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_setpriority
|
||||
SYSCALL_CATCH(setpriority, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_setregid
|
||||
SYSCALL_CATCH(setregid, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_setfsuid
|
||||
SYSCALL_CATCH(setfsuid, 0), //-EPERM
|
||||
#endif
|
||||
#ifdef __NR_setfsgid
|
||||
SYSCALL_CATCH(setfsgid, 0), //-EPERM
|
||||
#endif
|
||||
#ifdef __NR_umask
|
||||
SYSCALL_CATCH(umask, 0), //-EPERM
|
||||
#endif
|
||||
#ifdef __NR_setgid
|
||||
SYSCALL_CATCH(setgid, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_setreuid
|
||||
SYSCALL_CATCH(setreuid, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_setuid
|
||||
SYSCALL_CATCH(setuid, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_setresuid
|
||||
SYSCALL_CATCH(setresuid, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_setresgid
|
||||
SYSCALL_CATCH(setresgid, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_setpgid
|
||||
SYSCALL_CATCH(setpgid, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_getsid
|
||||
SYSCALL_CATCH(getsid, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_setsid
|
||||
SYSCALL_CATCH(setsid, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_sethostname
|
||||
SYSCALL_CATCH(sethostname, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_setdomainname
|
||||
SYSCALL_CATCH(setdomainname, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_setrlimit
|
||||
SYSCALL_CATCH(setrlimit, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_prctl
|
||||
SYSCALL_CATCH(prctl, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_getcpu
|
||||
SYSCALL_CATCH(getcpu, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_kill
|
||||
SYSCALL_CATCH(kill, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_tgkill
|
||||
SYSCALL_CATCH(tgkill, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_tkill
|
||||
SYSCALL_CATCH(tkill, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_rt_tgsigqueueinfo
|
||||
SYSCALL_CATCH(rt_tgsigqueueinfo, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_rt_sigqueueinfo
|
||||
SYSCALL_CATCH(rt_sigqueueinfo, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_listen
|
||||
SYSCALL_CATCH(listen, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_accept
|
||||
SYSCALL_CATCH(accept, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_open
|
||||
SYSCALL_CATCH(open, 0), //-EPERM
|
||||
#endif
|
||||
#ifdef __NR_openat
|
||||
SYSCALL_CATCH(openat, 0), //-EPERM
|
||||
#endif
|
||||
#ifdef __NR_shutdown
|
||||
SYSCALL_CATCH(shutdown, -EBADF),
|
||||
#endif
|
||||
#ifdef __NR_shmat
|
||||
SYSCALL_CATCH(shmat, -EACCES),
|
||||
#endif
|
||||
#ifdef __NR_shmdt
|
||||
SYSCALL_CATCH(shmdt, -EACCES),
|
||||
#endif
|
||||
#ifdef __NR_semget
|
||||
SYSCALL_CATCH(semget, -EACCES),
|
||||
#endif
|
||||
#ifdef __NR_semop
|
||||
SYSCALL_CATCH(semop, -EACCES),
|
||||
#endif
|
||||
#ifdef __NR_faccessat
|
||||
SYSCALL_CATCH(faccessat, -EACCES),
|
||||
#endif
|
||||
#ifdef __NR_fchdir
|
||||
SYSCALL_CATCH(fchdir, -EACCES),
|
||||
#endif
|
||||
#ifdef __NR_fstat
|
||||
SYSCALL_CATCH(fstat, -EACCES),
|
||||
#endif
|
||||
#ifdef __NR_readlinkat
|
||||
SYSCALL_CATCH(readlinkat, -EACCES),
|
||||
#endif
|
||||
#ifdef __NR_statfs
|
||||
SYSCALL_CATCH(statfs, -EACCES),
|
||||
#endif
|
||||
#ifdef __NR_fstatfs
|
||||
SYSCALL_CATCH(fstatfs, -EACCES),
|
||||
#endif
|
||||
#ifdef __NR_getcwd
|
||||
SYSCALL_CATCH(getcwd, -EACCES),
|
||||
#endif
|
||||
#ifdef __NR_futex
|
||||
SYSCALL_CATCH(futex, -EACCES),
|
||||
#endif
|
||||
#ifdef __NR_perf_event_open
|
||||
SYSCALL_CATCH(perf_event_open, -EACCES),
|
||||
#endif
|
||||
#ifdef __NR_socket
|
||||
SYSCALL_CATCH(socket, -EACCES),
|
||||
#endif
|
||||
#ifdef __NR_bind
|
||||
SYSCALL_CATCH(bind, -EACCES),
|
||||
#endif
|
||||
#ifdef __NR_connect
|
||||
SYSCALL_CATCH(connect, -EACCES),
|
||||
#endif
|
||||
#ifdef __NR_sendto
|
||||
SYSCALL_CATCH(sendto, -EACCES),
|
||||
#endif
|
||||
#ifdef __NR_mprotect
|
||||
SYSCALL_CATCH(mprotect, -EACCES),
|
||||
#endif
|
||||
#ifdef __NR_mremap
|
||||
SYSCALL_CATCH(mremap, -EFAULT),
|
||||
#endif
|
||||
#ifdef __NR_pselect6
|
||||
SYSCALL_CATCH(pselect6, -EFAULT),
|
||||
#endif
|
||||
#ifdef __NR_ioctl
|
||||
SYSCALL_CATCH(ioctl, -EFAULT),
|
||||
#endif
|
||||
#ifdef __NR_ioprio_set
|
||||
SYSCALL_CATCH(ioprio_set, -EFAULT),
|
||||
#endif
|
||||
#ifdef __NR_pipe2
|
||||
SYSCALL_CATCH(pipe2, -EFAULT),
|
||||
#endif
|
||||
#ifdef __NR_getdents64
|
||||
SYSCALL_CATCH(getdents64, -EFAULT),
|
||||
#endif
|
||||
#ifdef __NR_setitimer
|
||||
SYSCALL_CATCH(setitimer, -EFAULT),
|
||||
#endif
|
||||
#ifdef __NR_capget
|
||||
SYSCALL_CATCH(capget, -EFAULT),
|
||||
#endif
|
||||
#ifdef __NR_getresuid
|
||||
SYSCALL_CATCH(getresuid, -EFAULT),
|
||||
#endif
|
||||
#ifdef __NR_getresgid
|
||||
SYSCALL_CATCH(getresgid, -EFAULT),
|
||||
#endif
|
||||
#ifdef __NR_rt_sigprocmask
|
||||
SYSCALL_CATCH(rt_sigprocmask, 0), //-EFAULT, Skip this syscall due to HTML5 score of Geekbench5.4
|
||||
#endif
|
||||
#ifdef __NR_socketpair
|
||||
SYSCALL_CATCH(socketpair, -EFAULT),
|
||||
#endif
|
||||
#ifdef __NR_getsockname
|
||||
SYSCALL_CATCH(getsockname, -EFAULT),
|
||||
#endif
|
||||
#ifdef __NR_getpeername
|
||||
SYSCALL_CATCH(getpeername, -EFAULT),
|
||||
#endif
|
||||
#ifdef __NR_recvfrom
|
||||
SYSCALL_CATCH(recvfrom, -EFAULT),
|
||||
#endif
|
||||
#ifdef __NR_setsockopt
|
||||
SYSCALL_CATCH(setsockopt, -EFAULT),
|
||||
#endif
|
||||
#ifdef __NR_sendmsg
|
||||
SYSCALL_CATCH(sendmsg, -EFAULT),
|
||||
#endif
|
||||
#ifdef __NR_recvmsg
|
||||
SYSCALL_CATCH(recvmsg, -EFAULT),
|
||||
#endif
|
||||
#ifdef __NR_rt_sigsuspend
|
||||
SYSCALL_CATCH(rt_sigsuspend, -EFAULT),
|
||||
#endif
|
||||
#ifdef __NR_rt_sigpending
|
||||
SYSCALL_CATCH(rt_sigpending, -EFAULT),
|
||||
#endif
|
||||
#ifdef __NR_rt_sigaction
|
||||
SYSCALL_CATCH(rt_sigaction, -EFAULT),
|
||||
#endif
|
||||
#ifdef __NR_remap_file_pages
|
||||
SYSCALL_CATCH(remap_file_pages, -EINVAL),
|
||||
#endif
|
||||
#ifdef __NR_ppoll
|
||||
SYSCALL_CATCH(ppoll, -EINVAL),
|
||||
#endif
|
||||
#ifdef __NR_dup
|
||||
SYSCALL_CATCH(dup, -EINVAL),
|
||||
#endif
|
||||
#ifdef __NR_dup3
|
||||
SYSCALL_CATCH(dup3, -EINVAL),
|
||||
#endif
|
||||
#ifdef __NR_eventfd2
|
||||
SYSCALL_CATCH(eventfd2, -EINVAL),
|
||||
#endif
|
||||
#ifdef __NR_timerfd_create
|
||||
SYSCALL_CATCH(timerfd_create, -EINVAL),
|
||||
#endif
|
||||
#ifdef __NR_timerfd_gettime
|
||||
SYSCALL_CATCH(timerfd_gettime, -EINVAL),
|
||||
#endif
|
||||
#ifdef __NR_timerfd_settime
|
||||
SYSCALL_CATCH(timerfd_settime, -EINVAL),
|
||||
#endif
|
||||
#ifdef __NR_epoll_create1
|
||||
SYSCALL_CATCH(epoll_create1, -EINVAL),
|
||||
#endif
|
||||
#ifdef __NR_rt_sigtimedwait
|
||||
SYSCALL_CATCH(rt_sigtimedwait, -EINVAL),
|
||||
#endif
|
||||
#ifdef __NR_setxattr
|
||||
SYSCALL_CATCH(setxattr, -EEXIST),
|
||||
#endif
|
||||
#ifdef __NR_lsetxattr
|
||||
SYSCALL_CATCH(lsetxattr, -EEXIST),
|
||||
#endif
|
||||
#ifdef __NR_fsetxattr
|
||||
SYSCALL_CATCH(fsetxattr, -EEXIST),
|
||||
#endif
|
||||
#ifdef __NR_removexattr
|
||||
SYSCALL_CATCH(removexattr, -EEXIST),
|
||||
#endif
|
||||
#ifdef __NR_lremovexattr
|
||||
SYSCALL_CATCH(lremovexattr, -EEXIST),
|
||||
#endif
|
||||
#ifdef __NR_fremovexattr
|
||||
SYSCALL_CATCH(fremovexattr, -EEXIST),
|
||||
#endif
|
||||
#ifdef __NR_inotify_init1
|
||||
SYSCALL_CATCH(inotify_init1, -EMFILE),
|
||||
#endif
|
||||
#ifdef __NR_clone
|
||||
SYSCALL_CATCH(clone, -EINVAL),
|
||||
#endif
|
||||
#ifdef __NR_execve
|
||||
SYSCALL_CATCH(execve, 0), //-EPERM
|
||||
#endif
|
||||
#ifdef __NR_write
|
||||
SYSCALL_CATCH(write, 0), //-EPERM
|
||||
#endif
|
||||
#ifdef __NR_writev
|
||||
SYSCALL_CATCH(writev, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_pwrite64
|
||||
SYSCALL_CATCH(pwrite64, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_pwritev
|
||||
SYSCALL_CATCH(pwritev, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_epoll_ctl
|
||||
SYSCALL_CATCH(epoll_ctl, -EINVAL),
|
||||
#endif
|
||||
#ifdef __NR_epoll_pwait
|
||||
SYSCALL_CATCH(epoll_pwait, -EINVAL),
|
||||
#endif
|
||||
#ifdef __NR_sendfile
|
||||
SYSCALL_CATCH(sendfile, -EFAULT),
|
||||
#endif
|
||||
#ifdef __NR_signalfd4
|
||||
SYSCALL_CATCH(signalfd4, -EFAULT),
|
||||
#endif
|
||||
#ifdef __NR_vmsplice
|
||||
SYSCALL_CATCH(vmsplice, -EINVAL),
|
||||
#endif
|
||||
#ifdef __NR_splice
|
||||
SYSCALL_CATCH(splice, -EINVAL),
|
||||
#endif
|
||||
#ifdef __NR_tee
|
||||
SYSCALL_CATCH(tee, -EINVAL),
|
||||
#endif
|
||||
#ifdef __NR_fsync
|
||||
SYSCALL_CATCH(fsync, -EINVAL),
|
||||
#endif
|
||||
#ifdef __NR_fdatasync
|
||||
SYSCALL_CATCH(fdatasync, -EINVAL),
|
||||
#endif
|
||||
#ifdef __NR_sync_file_range
|
||||
SYSCALL_CATCH(sync_file_range, -EINVAL),
|
||||
#endif
|
||||
#ifdef __NR_acct
|
||||
SYSCALL_CATCH(acct, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_sched_setparam
|
||||
SYSCALL_CATCH(sched_setparam, -EINVAL),
|
||||
#endif
|
||||
#ifdef __NR_sched_setscheduler
|
||||
SYSCALL_CATCH(sched_setscheduler, -EINVAL),
|
||||
#endif
|
||||
#ifdef __NR_sched_setaffinity
|
||||
SYSCALL_CATCH(sched_setaffinity, -EINVAL),
|
||||
#endif
|
||||
#ifdef __NR_reboot
|
||||
SYSCALL_CATCH(reboot, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_mq_timedsend
|
||||
SYSCALL_CATCH(mq_timedsend, -EINVAL),
|
||||
#endif
|
||||
#ifdef __NR_mq_timedreceive
|
||||
SYSCALL_CATCH(mq_timedreceive, -EBADF),
|
||||
#endif
|
||||
#ifdef __NR_msgrcv
|
||||
SYSCALL_CATCH(msgrcv, -EINVAL),
|
||||
#endif
|
||||
#ifdef __NR_msgsnd
|
||||
SYSCALL_CATCH(msgsnd, -EFAULT),
|
||||
#endif
|
||||
#ifdef __NR_semtimedop
|
||||
SYSCALL_CATCH(semtimedop, -EINVAL),
|
||||
#endif
|
||||
#ifdef __NR_add_key
|
||||
SYSCALL_CATCH(add_key, -EINVAL),
|
||||
#endif
|
||||
#ifdef __NR_request_key
|
||||
SYSCALL_CATCH(request_key, -EINVAL),
|
||||
#endif
|
||||
#ifdef __NR_keyctl
|
||||
SYSCALL_CATCH(keyctl, -EOPNOTSUPP),
|
||||
#endif
|
||||
#ifdef __NR_mmap
|
||||
SYSCALL_CATCH(mmap, -EINVAL),
|
||||
#endif
|
||||
#ifdef __NR_mincore
|
||||
SYSCALL_CATCH(mincore, -EINVAL),
|
||||
#endif
|
||||
#ifdef __NR_mbind
|
||||
SYSCALL_CATCH(mbind, -EINVAL),
|
||||
#endif
|
||||
#ifdef __NR_set_mempolicy
|
||||
SYSCALL_CATCH(set_mempolicy, -EINVAL),
|
||||
#endif
|
||||
#ifdef __NR_migrate_pages
|
||||
SYSCALL_CATCH(migrate_pages, -EINVAL),
|
||||
#endif
|
||||
#ifdef __NR_accept4
|
||||
SYSCALL_CATCH(accept4, -EINVAL),
|
||||
#endif
|
||||
#ifdef __NR_recvmmsg
|
||||
SYSCALL_CATCH(recvmmsg, -EINVAL),
|
||||
#endif
|
||||
#ifdef __NR_link
|
||||
SYSCALL_CATCH(link, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_unlink
|
||||
SYSCALL_CATCH(unlink, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_mknod
|
||||
SYSCALL_CATCH(mknod, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_chmod
|
||||
SYSCALL_CATCH(chmod, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_chown
|
||||
SYSCALL_CATCH(chown, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_mkdir
|
||||
SYSCALL_CATCH(mkdir, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_lchown
|
||||
SYSCALL_CATCH(lchown, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_rename
|
||||
SYSCALL_CATCH(rename, -EPERM),
|
||||
#endif
|
||||
#ifdef __NR_epoll_wait
|
||||
SYSCALL_CATCH(epoll_wait, -EINVAL),
|
||||
#endif
|
||||
#ifdef __NR_sysctl
|
||||
SYSCALL_CATCH(sysctl, -EFAULT),
|
||||
#endif
|
||||
};
|
|
@ -1,45 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <asm/unistd32.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/version.h>
|
||||
#include "include/defex_catch_list.h"
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 0, 0)
|
||||
#define __COMPAT_SYSCALL_NR
|
||||
#include <asm/unistd.h>
|
||||
#else
|
||||
#ifdef __NR_clone3
|
||||
#define __NR_compat_syscalls (__NR_clone3 + 10)
|
||||
#elif defined(__NR_rseq)
|
||||
#define __NR_compat_syscalls (__NR_rseq + 10)
|
||||
#elif defined(__NR_seccomp)
|
||||
#define __NR_compat_syscalls (__NR_seccomp + 10)
|
||||
#else
|
||||
#define __NR_compat_syscalls 400
|
||||
#endif
|
||||
#endif /* < KERNEL_VERSION(4, 0, 0) */
|
||||
|
||||
#define DEFEX_CATCH_COUNT __NR_compat_syscalls
|
||||
const int defex_nr_syscalls_compat = DEFEX_CATCH_COUNT;
|
||||
|
||||
#include "defex_catch_list.inc"
|
||||
|
||||
const struct local_syscall_struct *get_local_syscall_compat(int syscall_no)
|
||||
{
|
||||
if ((unsigned int)syscall_no >= __NR_compat_syscalls)
|
||||
return NULL;
|
||||
|
||||
if (!syscall_catch_arr[syscall_no].local_syscall && !syscall_catch_arr[syscall_no].err_code && syscall_no) {
|
||||
return &syscall_catch_arr[0];
|
||||
}
|
||||
|
||||
return &syscall_catch_arr[syscall_no];
|
||||
}
|
|
@ -1,389 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/version.h>
|
||||
#include "include/defex_catch_list.h"
|
||||
#include "include/defex_internal.h"
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
|
||||
#include <linux/sched/mm.h>
|
||||
#include <linux/sched/task.h>
|
||||
#endif
|
||||
|
||||
#define MAX_PID_32 32768
|
||||
#define DEFEX_MEM_CACHE_SIZE 32
|
||||
#define DEFEX_MEM_CACHE_COUNT 3
|
||||
#define CACHE_CRED_DATA 0
|
||||
#define CACHE_CRED_DATA_ID 1
|
||||
#define CACHE_HTABLE_ITEM 2
|
||||
|
||||
struct id_set {
|
||||
unsigned int uid, fsuid, egid;
|
||||
};
|
||||
|
||||
struct proc_cred_data {
|
||||
unsigned short cred_flags;
|
||||
unsigned short tcnt;
|
||||
struct id_set default_ids;
|
||||
struct id_set main_ids[];
|
||||
};
|
||||
|
||||
struct hash_item_struct {
|
||||
struct hlist_node node;
|
||||
struct proc_cred_data *cred_data;
|
||||
int id;
|
||||
};
|
||||
|
||||
struct mem_cache_list {
|
||||
atomic_t count;
|
||||
char name[8];
|
||||
struct kmem_cache *allocator;
|
||||
void *mem_cache_array[DEFEX_MEM_CACHE_SIZE];
|
||||
};
|
||||
|
||||
#ifdef DEFEX_PED_ENABLE
|
||||
DECLARE_HASHTABLE(creds_hash, 15);
|
||||
__visible_for_testing DEFINE_SPINLOCK(creds_hash_update_lock);
|
||||
static struct proc_cred_data *creds_fast_hash[MAX_PID_32 + 1];
|
||||
__visible_for_testing struct mem_cache_list mem_cache[DEFEX_MEM_CACHE_COUNT];
|
||||
static int creds_fast_hash_ready __ro_after_init;
|
||||
__visible_for_testing void mem_cache_alloc(void);
|
||||
|
||||
|
||||
void __init creds_fast_hash_init(void)
|
||||
{
|
||||
unsigned int i;
|
||||
static const int sizes[DEFEX_MEM_CACHE_COUNT] __initdata = {
|
||||
sizeof(struct proc_cred_data),
|
||||
sizeof(struct proc_cred_data) + sizeof(struct id_set),
|
||||
sizeof(struct hash_item_struct)
|
||||
};
|
||||
|
||||
hash_init(creds_hash);
|
||||
for (i = 0; i <= MAX_PID_32; i++)
|
||||
creds_fast_hash[i] = NULL;
|
||||
|
||||
for(i = 0; i < ARRAY_SIZE(sizes); i++) {
|
||||
snprintf(mem_cache[i].name, sizeof(mem_cache[i].name), "defex%d", i);
|
||||
mem_cache[i].allocator = kmem_cache_create(mem_cache[i].name, sizes[i], 0, 0, NULL);
|
||||
}
|
||||
|
||||
for(i = 0; i < (DEFEX_MEM_CACHE_SIZE / 2); i++)
|
||||
mem_cache_alloc();
|
||||
|
||||
creds_fast_hash_ready = 1;
|
||||
}
|
||||
|
||||
int is_task_creds_ready(void)
|
||||
{
|
||||
return creds_fast_hash_ready;
|
||||
}
|
||||
|
||||
__visible_for_testing inline void *mem_cache_get(int cache_number)
|
||||
{
|
||||
int n;
|
||||
n = atomic_read(&mem_cache[cache_number].count);
|
||||
if (n) {
|
||||
atomic_dec(&mem_cache[cache_number].count);
|
||||
return mem_cache[cache_number].mem_cache_array[n - 1];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
__visible_for_testing inline void *mem_cache_reclaim(int cache_number, void *ptr)
|
||||
{
|
||||
int n;
|
||||
n = atomic_read(&mem_cache[cache_number].count);
|
||||
if (n < DEFEX_MEM_CACHE_SIZE) {
|
||||
atomic_inc(&mem_cache[cache_number].count);
|
||||
mem_cache[cache_number].mem_cache_array[n] = ptr;
|
||||
ptr = NULL;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
__visible_for_testing void mem_cache_alloc(void)
|
||||
{
|
||||
int mem_allocated = 0;
|
||||
int i, n;
|
||||
unsigned long flags;
|
||||
void *mem_block[DEFEX_MEM_CACHE_COUNT];
|
||||
|
||||
for(i = 0; i < DEFEX_MEM_CACHE_COUNT; i++) {
|
||||
mem_block[i] = NULL;
|
||||
n = atomic_read(&mem_cache[i].count);
|
||||
if (n < (DEFEX_MEM_CACHE_SIZE / 2)) {
|
||||
mem_block[i] = kmem_cache_alloc(mem_cache[i].allocator, in_atomic() ? GFP_ATOMIC:GFP_KERNEL);
|
||||
mem_allocated++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!mem_allocated)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&creds_hash_update_lock, flags);
|
||||
for(i = 0; i < DEFEX_MEM_CACHE_COUNT; i++) {
|
||||
n = atomic_read(&mem_cache[i].count);
|
||||
if (mem_block[i] && n < DEFEX_MEM_CACHE_SIZE) {
|
||||
mem_cache[i].mem_cache_array[n] = mem_block[i];
|
||||
mem_block[i] = NULL;
|
||||
atomic_inc(&mem_cache[i].count);
|
||||
mem_allocated--;
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&creds_hash_update_lock, flags);
|
||||
|
||||
if (!mem_allocated)
|
||||
return;
|
||||
|
||||
for(i = 0; i < DEFEX_MEM_CACHE_COUNT; i++) {
|
||||
if (mem_block[i]) {
|
||||
kmem_cache_free(mem_cache[i].allocator, mem_block[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__visible_for_testing struct proc_cred_data *get_cred_data(int id)
|
||||
{
|
||||
struct proc_cred_data *cred_data = NULL;
|
||||
struct hash_item_struct *obj;
|
||||
|
||||
if (id < 0)
|
||||
return NULL;
|
||||
if (id <= MAX_PID_32) {
|
||||
cred_data = creds_fast_hash[id];
|
||||
} else {
|
||||
hash_for_each_possible(creds_hash, obj, node, id) {
|
||||
if (obj->id == id) {
|
||||
cred_data = obj->cred_data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return cred_data;
|
||||
}
|
||||
|
||||
__visible_for_testing struct proc_cred_data **get_cred_ptr(int id)
|
||||
{
|
||||
struct proc_cred_data **cred_ptr = NULL;
|
||||
struct hash_item_struct *obj;
|
||||
|
||||
if (id < 0)
|
||||
return NULL;
|
||||
if (id <= MAX_PID_32) {
|
||||
cred_ptr = &creds_fast_hash[id];
|
||||
} else {
|
||||
hash_for_each_possible(creds_hash, obj, node, id) {
|
||||
if (obj->id == id) {
|
||||
cred_ptr = &obj->cred_data;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return cred_ptr;
|
||||
}
|
||||
|
||||
__visible_for_testing void set_cred_data(int id, struct proc_cred_data **cred_ptr, struct proc_cred_data *cred_data)
|
||||
{
|
||||
struct hash_item_struct *obj;
|
||||
|
||||
if (id < 0)
|
||||
return;
|
||||
if (cred_ptr) {
|
||||
*cred_ptr = cred_data;
|
||||
} else {
|
||||
if (id > MAX_PID_32) {
|
||||
obj = mem_cache_get(CACHE_HTABLE_ITEM);
|
||||
if (!obj)
|
||||
return;
|
||||
obj->id = id;
|
||||
obj->cred_data = cred_data;
|
||||
hash_add(creds_hash, &obj->node, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void get_task_creds(struct task_struct *p, unsigned int *uid_ptr, unsigned int *fsuid_ptr, unsigned int *egid_ptr, unsigned short *cred_flags_ptr)
|
||||
{
|
||||
struct proc_cred_data *cred_data, *thread_cred_data;
|
||||
struct id_set *ids_ptr;
|
||||
unsigned int uid = 0, fsuid = 0, egid = 0;
|
||||
unsigned short cred_flags = CRED_FLAGS_PROOT;
|
||||
unsigned long flags;
|
||||
int tgid = p->tgid, pid = p->pid;
|
||||
|
||||
spin_lock_irqsave(&creds_hash_update_lock, flags);
|
||||
cred_data = get_cred_data(tgid);
|
||||
if (cred_data) {
|
||||
if (tgid == pid) {
|
||||
ids_ptr = (cred_data->cred_flags & CRED_FLAGS_MAIN_UPDATED) ? \
|
||||
(&cred_data->main_ids[0]) : (&cred_data->default_ids);
|
||||
} else {
|
||||
if (cred_data->cred_flags & CRED_FLAGS_SUB_UPDATED) {
|
||||
thread_cred_data = get_cred_data(pid);
|
||||
if (thread_cred_data)
|
||||
cred_data = thread_cred_data;
|
||||
}
|
||||
ids_ptr = &cred_data->default_ids;
|
||||
}
|
||||
GET_CREDS(ids_ptr, cred_data);
|
||||
}
|
||||
spin_unlock_irqrestore(&creds_hash_update_lock, flags);
|
||||
*uid_ptr = uid;
|
||||
*fsuid_ptr = fsuid;
|
||||
*egid_ptr = egid;
|
||||
*cred_flags_ptr = cred_flags;
|
||||
}
|
||||
|
||||
int set_task_creds(struct task_struct *p, unsigned int uid, unsigned int fsuid, unsigned int egid, unsigned short cred_flags)
|
||||
{
|
||||
struct proc_cred_data *cred_data = NULL, *tmp_data, **cred_ptr;
|
||||
struct id_set *ids_ptr;
|
||||
unsigned long flags;
|
||||
int err = -1, tgid = p->tgid, pid = p->pid;
|
||||
void *free_buff = NULL;
|
||||
|
||||
|
||||
mem_cache_alloc();
|
||||
spin_lock_irqsave(&creds_hash_update_lock, flags);
|
||||
|
||||
/* Search for main proces's data */
|
||||
cred_ptr = get_cred_ptr(tgid);
|
||||
cred_data = (cred_ptr) ? (*cred_ptr) : NULL;
|
||||
if (!cred_data) {
|
||||
/* Not found? Allocate a new data */
|
||||
cred_data = mem_cache_get(CACHE_CRED_DATA);
|
||||
if (!cred_data)
|
||||
goto set_finish;
|
||||
cred_data->cred_flags = 0;
|
||||
cred_data->tcnt = 1;
|
||||
set_cred_data(tgid, cred_ptr, cred_data);
|
||||
}
|
||||
ids_ptr = &cred_data->default_ids;
|
||||
|
||||
if (cred_data->tcnt >= 2) {
|
||||
if (tgid == pid) {
|
||||
/* Allocate extended data for main process, copy and remove old data */
|
||||
if (!(cred_data->cred_flags & CRED_FLAGS_MAIN_UPDATED)) {
|
||||
cred_data->cred_flags |= CRED_FLAGS_MAIN_UPDATED;
|
||||
tmp_data = mem_cache_get(CACHE_CRED_DATA_ID);
|
||||
if (!tmp_data)
|
||||
goto set_finish;
|
||||
*tmp_data = *cred_data;
|
||||
free_buff = mem_cache_reclaim(CACHE_CRED_DATA, cred_data);
|
||||
cred_data = tmp_data;
|
||||
set_cred_data(tgid, cred_ptr, cred_data);
|
||||
}
|
||||
ids_ptr = &cred_data->main_ids[0];
|
||||
} else {
|
||||
cred_data->cred_flags |= CRED_FLAGS_SUB_UPDATED;
|
||||
/* Search for thread's data. Allocate, if not found */
|
||||
cred_ptr = get_cred_ptr(pid);
|
||||
cred_data = (cred_ptr) ? (*cred_ptr) : NULL;
|
||||
if (!cred_data) {
|
||||
cred_data = mem_cache_get(CACHE_CRED_DATA);
|
||||
if (!cred_data)
|
||||
goto set_finish;
|
||||
set_cred_data(pid, cred_ptr, cred_data);
|
||||
}
|
||||
cred_data->cred_flags = 0;
|
||||
ids_ptr = &cred_data->default_ids;
|
||||
}
|
||||
}
|
||||
SET_CREDS(ids_ptr, cred_data);
|
||||
err = 0;
|
||||
|
||||
set_finish:
|
||||
spin_unlock_irqrestore(&creds_hash_update_lock, flags);
|
||||
/* Free the pending pointer */
|
||||
if (free_buff)
|
||||
kmem_cache_free(mem_cache[CACHE_CRED_DATA].allocator, free_buff);
|
||||
mem_cache_alloc();
|
||||
return err;
|
||||
}
|
||||
|
||||
void set_task_creds_tcnt(struct task_struct *p, int addition)
|
||||
{
|
||||
struct hash_item_struct *tgid_obj = NULL, *pid_obj = NULL;
|
||||
struct proc_cred_data **cred_ptr, *tgid_cred_data = NULL, *pid_cred_data = NULL;
|
||||
struct proc_cred_data *free_buff1 = NULL, *free_buff2 = NULL;
|
||||
int tgid = p->tgid, pid = p->pid;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&creds_hash_update_lock, flags);
|
||||
/* Remove the thread's data, if found */
|
||||
if (tgid != pid && addition == -1) {
|
||||
cred_ptr = get_cred_ptr(pid);
|
||||
pid_cred_data = (cred_ptr) ? (*cred_ptr) : NULL;
|
||||
if (pid_cred_data) {
|
||||
*cred_ptr = NULL;
|
||||
/* Return to pre-allocated pool, if possible */
|
||||
free_buff1 = mem_cache_reclaim(CACHE_CRED_DATA, pid_cred_data);
|
||||
}
|
||||
/* Remove the thread's hash container */
|
||||
if (cred_ptr && pid > MAX_PID_32) {
|
||||
pid_obj = container_of(cred_ptr, struct hash_item_struct, cred_data);
|
||||
hash_del(&pid_obj->node);
|
||||
/* Return to pre-allocated pool, if possible */
|
||||
pid_obj = mem_cache_reclaim(CACHE_HTABLE_ITEM, pid_obj);
|
||||
}
|
||||
}
|
||||
/* Search for the main process's data */
|
||||
cred_ptr = get_cred_ptr(tgid);
|
||||
tgid_cred_data = (cred_ptr) ? (*cred_ptr) : NULL;
|
||||
if (tgid_cred_data) {
|
||||
tgid_cred_data->tcnt += addition;
|
||||
/* No threads, remove process data */
|
||||
if (!tgid_cred_data->tcnt) {
|
||||
*cred_ptr = NULL;
|
||||
/* Return to pre-allocated pool, if possible */
|
||||
free_buff2 = mem_cache_reclaim((tgid_cred_data->cred_flags & CRED_FLAGS_MAIN_UPDATED) ? \
|
||||
CACHE_CRED_DATA_ID : CACHE_CRED_DATA, tgid_cred_data);
|
||||
/* Remove the process's hash container */
|
||||
if (tgid > MAX_PID_32) {
|
||||
tgid_obj = container_of(cred_ptr, struct hash_item_struct, cred_data);
|
||||
hash_del(&tgid_obj->node);
|
||||
/* Return to pre-allocated pool, if possible */
|
||||
tgid_obj = mem_cache_reclaim(CACHE_HTABLE_ITEM, tgid_obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&creds_hash_update_lock, flags);
|
||||
/* Free all pending pointers */
|
||||
if (free_buff1)
|
||||
kmem_cache_free(mem_cache[CACHE_CRED_DATA].allocator, free_buff1);
|
||||
if (free_buff2)
|
||||
kmem_cache_free(mem_cache[(free_buff2->cred_flags & CRED_FLAGS_MAIN_UPDATED) ? \
|
||||
CACHE_CRED_DATA_ID : CACHE_CRED_DATA].allocator, free_buff2);
|
||||
if (pid_obj)
|
||||
kmem_cache_free(mem_cache[CACHE_HTABLE_ITEM].allocator, pid_obj);
|
||||
if (tgid_obj)
|
||||
kmem_cache_free(mem_cache[CACHE_HTABLE_ITEM].allocator, tgid_obj);
|
||||
return;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int is_task_creds_ready(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void set_task_creds_tcnt(struct task_struct *p, int addition)
|
||||
{
|
||||
(void)p;
|
||||
(void)addition;
|
||||
}
|
||||
|
||||
#endif /* DEFEX_PED_ENABLE */
|
|
@ -1,33 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/version.h>
|
||||
|
||||
__INITRODATA
|
||||
|
||||
.align 8
|
||||
|
||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0) || !defined(VMLINUX_SYMBOL))
|
||||
#define VMLINUX_SYMBOL(name) name
|
||||
#endif
|
||||
|
||||
#define GLOBAL(name) \
|
||||
.globl VMLINUX_SYMBOL(name); \
|
||||
VMLINUX_SYMBOL(name):
|
||||
|
||||
.section ".ref.data", "aw"
|
||||
|
||||
GLOBAL(defex_public_key_start)
|
||||
#ifdef DEFEX_DEBUG_ENABLE
|
||||
.incbin "security/samsung/defex_lsm/cert/pubkey_eng.der"
|
||||
#else
|
||||
.incbin "security/samsung/defex_lsm/cert/pubkey_user.der"
|
||||
#endif
|
||||
GLOBAL(defex_public_key_end)
|
|
@ -1,242 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/cred.h>
|
||||
#include <linux/crypto.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/key.h>
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/version.h>
|
||||
#include <crypto/hash.h>
|
||||
#include <keys/asymmetric-type.h>
|
||||
#include "include/defex_debug.h"
|
||||
#include "include/defex_sign.h"
|
||||
|
||||
#ifdef DEFEX_KUNIT_ENABLED
|
||||
#include <kunit/mock.h>
|
||||
#endif
|
||||
|
||||
#define SHA256_DIGEST_SIZE 32
|
||||
|
||||
extern char defex_public_key_start[];
|
||||
extern char defex_public_key_end[];
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 7, 0)
|
||||
|
||||
__visible_for_testing int defex_public_key_verify_signature(unsigned char *pub_key,
|
||||
int pub_key_size,
|
||||
unsigned char *signature,
|
||||
unsigned char *hash_sha256)
|
||||
{
|
||||
(void)pub_key;
|
||||
(void)pub_key_size;
|
||||
(void)signature;
|
||||
(void)hash_sha256;
|
||||
/* Skip signarue check at kernel version < 3.7.0 */
|
||||
defex_log_warn("Skip signature check in current kernel version");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <crypto/public_key.h>
|
||||
|
||||
static struct key *defex_keyring;
|
||||
|
||||
__visible_for_testing struct key *defex_keyring_alloc(const char *description,
|
||||
kuid_t uid, kgid_t gid,
|
||||
const struct cred *cred,
|
||||
unsigned long flags)
|
||||
{
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 8, 0)
|
||||
return keyring_alloc(description, uid, gid, cred, flags, NULL)
|
||||
#elif LINUX_VERSION_CODE < KERNEL_VERSION(4, 7, 0)
|
||||
key_perm_t perm = ((KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW | KEY_USR_READ | KEY_USR_SEARCH);
|
||||
return keyring_alloc(description, uid, gid, cred, perm, flags, NULL);
|
||||
#else
|
||||
key_perm_t perm = ((KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW | KEY_USR_READ | KEY_USR_SEARCH);
|
||||
return keyring_alloc(description, uid, gid, cred, perm, flags, NULL, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
__visible_for_testing int defex_keyring_init(void)
|
||||
{
|
||||
int err = 0;
|
||||
const struct cred *cred = current_cred();
|
||||
static const char keyring_name[] = "defex_keyring";
|
||||
|
||||
if (defex_keyring)
|
||||
return err;
|
||||
|
||||
defex_keyring = defex_keyring_alloc(keyring_name, KUIDT_INIT(0), KGIDT_INIT(0),
|
||||
cred, KEY_ALLOC_NOT_IN_QUOTA);
|
||||
if (!defex_keyring) {
|
||||
err = -1;
|
||||
defex_log_info("Can't allocate %s keyring (NULL)", keyring_name);
|
||||
} else if (IS_ERR(defex_keyring)) {
|
||||
err = PTR_ERR(defex_keyring);
|
||||
defex_log_info("Can't allocate %s keyring, err=%d", keyring_name, err);
|
||||
defex_keyring = NULL;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
__visible_for_testing int defex_public_key_verify_signature(unsigned char *pub_key,
|
||||
int pub_key_size,
|
||||
unsigned char *signature,
|
||||
unsigned char *hash_sha256)
|
||||
{
|
||||
int ret = -1;
|
||||
key_ref_t key_ref;
|
||||
struct key *key;
|
||||
struct public_key_signature pks;
|
||||
static const char key_name[] = "defex_key";
|
||||
|
||||
if (defex_keyring_init() != 0)
|
||||
return ret;
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 3, 0)
|
||||
key_ref = keyring_search(make_key_ref(defex_keyring, 1), &key_type_asymmetric, key_name);
|
||||
#else
|
||||
key_ref = keyring_search(make_key_ref(defex_keyring, 1), &key_type_asymmetric, key_name, true);
|
||||
#endif
|
||||
if (IS_ERR(key_ref)) {
|
||||
key_ref = key_create_or_update(make_key_ref(defex_keyring, 1),
|
||||
"asymmetric",
|
||||
key_name,
|
||||
pub_key,
|
||||
pub_key_size,
|
||||
((KEY_POS_ALL & ~KEY_POS_SETATTR) | KEY_USR_VIEW | KEY_USR_READ),
|
||||
KEY_ALLOC_NOT_IN_QUOTA);
|
||||
}
|
||||
if (IS_ERR(key_ref)) {
|
||||
defex_log_err("Invalid key reference (%ld)", PTR_ERR(key_ref));
|
||||
return ret;
|
||||
}
|
||||
|
||||
key = key_ref_to_ptr(key_ref);
|
||||
|
||||
memset(&pks, 0, sizeof(pks));
|
||||
pks.digest = hash_sha256;
|
||||
pks.digest_size = SHA256_DIGEST_SIZE;
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 6, 0)
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0)
|
||||
pks.pkey_algo = PKEY_ALGO_RSA;
|
||||
#endif
|
||||
pks.pkey_hash_algo = HASH_ALGO_SHA256;
|
||||
pks.nr_mpi = 1;
|
||||
pks.rsa.s = mpi_read_raw_data(signature, SIGN_SIZE);
|
||||
if (pks.rsa.s)
|
||||
ret = verify_signature(key, &pks);
|
||||
mpi_free(pks.rsa.s);
|
||||
#else
|
||||
pks.pkey_algo = "rsa";
|
||||
pks.hash_algo = "sha256";
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)
|
||||
pks.encoding = "pkcs1";
|
||||
#endif
|
||||
pks.s = signature;
|
||||
pks.s_size = SIGN_SIZE;
|
||||
ret = verify_signature(key, &pks);
|
||||
#endif
|
||||
key_ref_put(key_ref);
|
||||
return ret;
|
||||
}
|
||||
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(3, 7, 0) */
|
||||
|
||||
int defex_calc_hash(const char *data, unsigned int size, unsigned char *hash)
|
||||
{
|
||||
struct crypto_shash *handle;
|
||||
struct shash_desc* shash;
|
||||
int err = -1;
|
||||
|
||||
handle = crypto_alloc_shash("sha256", 0, 0);
|
||||
if (IS_ERR_OR_NULL(handle)) {
|
||||
defex_log_err("Can't alloc sha256");
|
||||
return err;
|
||||
}
|
||||
|
||||
shash = kzalloc(sizeof(struct shash_desc) + crypto_shash_descsize(handle), GFP_KERNEL);
|
||||
if (!shash)
|
||||
goto clean_handle;
|
||||
|
||||
shash->tfm = handle;
|
||||
|
||||
do {
|
||||
err = crypto_shash_init(shash);
|
||||
if (err < 0)
|
||||
break;
|
||||
|
||||
err = crypto_shash_update(shash, data, size);
|
||||
if (err < 0)
|
||||
break;
|
||||
|
||||
err = crypto_shash_final(shash, hash);
|
||||
if (err < 0)
|
||||
break;
|
||||
} while(0);
|
||||
|
||||
kfree(shash);
|
||||
clean_handle:
|
||||
crypto_free_shash(handle);
|
||||
return err;
|
||||
}
|
||||
|
||||
int defex_rules_signature_check(const char *rules_buffer, unsigned int rules_data_size, unsigned int *rules_size)
|
||||
{
|
||||
int res = -1;
|
||||
unsigned int defex_public_key_size = (unsigned int)((defex_public_key_end - defex_public_key_start) & 0xffffffff);
|
||||
unsigned char *hash_sha256;
|
||||
unsigned char *hash_sha256_first;
|
||||
unsigned char *signature;
|
||||
unsigned char *pub_key;
|
||||
|
||||
if (rules_data_size < SIGN_SIZE)
|
||||
return res;
|
||||
hash_sha256_first = kmalloc(SHA256_DIGEST_SIZE, GFP_KERNEL);
|
||||
if (!hash_sha256_first)
|
||||
return res;
|
||||
hash_sha256 = kmalloc(SHA256_DIGEST_SIZE, GFP_KERNEL);
|
||||
if (!hash_sha256)
|
||||
goto clean_hash_sha256_first;
|
||||
signature = kmalloc(SIGN_SIZE, GFP_KERNEL);
|
||||
if (!signature)
|
||||
goto clean_hash_sha256;
|
||||
pub_key = kmalloc(defex_public_key_size, GFP_KERNEL);
|
||||
if (!pub_key)
|
||||
goto clean_signature;
|
||||
|
||||
memcpy(pub_key, defex_public_key_start, defex_public_key_size);
|
||||
memcpy(signature, (u8*)(rules_buffer + rules_data_size - SIGN_SIZE), SIGN_SIZE);
|
||||
|
||||
defex_calc_hash(rules_buffer, rules_data_size - SIGN_SIZE, hash_sha256_first);
|
||||
defex_calc_hash(hash_sha256_first, SHA256_DIGEST_SIZE, hash_sha256);
|
||||
|
||||
#ifdef DEFEX_DEBUG_ENABLE
|
||||
defex_log_info("Rules signature size = %d", SIGN_SIZE);
|
||||
blob("Rules signature dump:", signature, SIGN_SIZE, 16);
|
||||
defex_log_info("Key size = %d", defex_public_key_size);
|
||||
blob("Key dump:", pub_key, defex_public_key_size, 16);
|
||||
blob("Final hash dump:", hash_sha256, SHA256_DIGEST_SIZE, 16);
|
||||
#endif
|
||||
|
||||
res = defex_public_key_verify_signature(pub_key, defex_public_key_size, signature, hash_sha256);
|
||||
if (rules_size && !res)
|
||||
*rules_size = rules_data_size - SIGN_SIZE;
|
||||
kfree(pub_key);
|
||||
clean_signature:
|
||||
kfree(signature);
|
||||
clean_hash_sha256:
|
||||
kfree(hash_sha256);
|
||||
clean_hash_sha256_first:
|
||||
kfree(hash_sha256_first);
|
||||
return res;
|
||||
}
|
Binary file not shown.
Binary file not shown.
|
@ -1,367 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/cred.h>
|
||||
#include <linux/dcache.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/namei.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/unistd.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/vmalloc.h>
|
||||
|
||||
#include "include/defex_caches.h"
|
||||
#include "include/defex_catch_list.h"
|
||||
#include "include/defex_config.h"
|
||||
#include "include/defex_internal.h"
|
||||
#include "include/defex_rules.h"
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
|
||||
#include <linux/sched/mm.h>
|
||||
#include <linux/sched/task.h>
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
|
||||
#include "../security/integrity/integrity.h"
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 19, 0)
|
||||
|
||||
inline ssize_t __vfs_read(struct file *file, char __user *buf,
|
||||
size_t count, loff_t *pos)
|
||||
{
|
||||
ssize_t ret;
|
||||
|
||||
if (file->f_op->read)
|
||||
ret = file->f_op->read(file, buf, count, pos);
|
||||
else if (file->f_op->aio_read)
|
||||
ret = do_sync_read(file, buf, count, pos);
|
||||
else if (file->f_op->read_iter)
|
||||
ret = new_sync_read(file, buf, count, pos);
|
||||
else
|
||||
ret = -EINVAL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0)
|
||||
#define GET_KERNEL_DS KERNEL_DS
|
||||
#else
|
||||
#define GET_KERNEL_DS get_ds()
|
||||
#endif
|
||||
|
||||
struct file *local_fopen(const char *fname, int flags, umode_t mode)
|
||||
{
|
||||
struct file *f;
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)
|
||||
mm_segment_t old_fs;
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)
|
||||
old_fs = get_fs();
|
||||
set_fs(GET_KERNEL_DS);
|
||||
#endif
|
||||
f = filp_open(fname, flags, mode);
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)
|
||||
set_fs(old_fs);
|
||||
#endif
|
||||
return f;
|
||||
}
|
||||
|
||||
int local_fread(struct file *f, loff_t offset, void *ptr, unsigned long bytes)
|
||||
{
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)
|
||||
mm_segment_t old_fs;
|
||||
char __user *buf = (char __user *)ptr;
|
||||
#endif
|
||||
ssize_t ret;
|
||||
|
||||
if (!(f->f_mode & FMODE_READ))
|
||||
return -EBADF;
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)
|
||||
old_fs = get_fs();
|
||||
set_fs(GET_KERNEL_DS);
|
||||
ret = vfs_read(f, buf, bytes, &offset);
|
||||
set_fs(old_fs);
|
||||
#else
|
||||
ret = (ssize_t)integrity_kernel_read(f, offset, ptr, bytes);
|
||||
#endif
|
||||
|
||||
return (int)ret;
|
||||
}
|
||||
|
||||
const char unknown_file[] = "<unknown filename>";
|
||||
|
||||
__visible_for_testing bool check_slab_ptr(void *ptr)
|
||||
{
|
||||
struct page *page;
|
||||
|
||||
if (IS_ERR_OR_NULL(ptr) || ptr < (void *)PAGE_SIZE || !virt_addr_valid(ptr))
|
||||
return false;
|
||||
page = virt_to_head_page(ptr);
|
||||
return PageSlab(page);
|
||||
}
|
||||
|
||||
int init_defex_context(struct defex_context *dc, int syscall, struct task_struct *p, struct file *f)
|
||||
{
|
||||
memset(dc, 0, offsetof(struct defex_context, cred));
|
||||
if (check_slab_ptr(f)) {
|
||||
get_file(f);
|
||||
dc->target_file = f;
|
||||
}
|
||||
dc->syscall_no = syscall;
|
||||
dc->task = p;
|
||||
if (p == current)
|
||||
dc->cred = (struct cred *)current_cred();
|
||||
if (!dc->cred)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void release_defex_context(struct defex_context *dc)
|
||||
{
|
||||
kfree(dc->process_name_buff);
|
||||
kfree(dc->target_name_buff);
|
||||
if (dc->target_file)
|
||||
fput(dc->target_file);
|
||||
#ifndef DEFEX_CACHES_ENABLE
|
||||
if (dc->process_file)
|
||||
fput(dc->process_file);
|
||||
#endif /* DEFEX_CACHES_ENABLE */
|
||||
}
|
||||
|
||||
struct file *get_dc_process_file(struct defex_context *dc)
|
||||
{
|
||||
if (!dc->process_file)
|
||||
dc->process_file = defex_get_source_file(dc->task);
|
||||
return dc->process_file;
|
||||
}
|
||||
|
||||
const struct path *get_dc_process_dpath(struct defex_context *dc)
|
||||
{
|
||||
const struct path *dpath;
|
||||
struct file *exe_file = NULL;
|
||||
|
||||
if (dc->process_dpath)
|
||||
return dc->process_dpath;
|
||||
|
||||
exe_file = get_dc_process_file(dc);
|
||||
if (!IS_ERR_OR_NULL(exe_file)) {
|
||||
dpath = &exe_file->f_path;
|
||||
if (dpath->dentry && dpath->dentry->d_inode) {
|
||||
dc->process_dpath = dpath;
|
||||
return dpath;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *get_dc_process_name(struct defex_context *dc)
|
||||
{
|
||||
const struct path *dpath;
|
||||
char *path = NULL;
|
||||
|
||||
if (!dc->process_name) {
|
||||
dpath = get_dc_process_dpath(dc);
|
||||
if (dpath) {
|
||||
dc->process_name_buff = kmalloc(PATH_MAX, GFP_KERNEL);
|
||||
if (dc->process_name_buff)
|
||||
path = d_path(dpath, dc->process_name_buff, PATH_MAX);
|
||||
}
|
||||
dc->process_name = (IS_ERR_OR_NULL(path)) ? (char *)unknown_file : path;
|
||||
}
|
||||
return dc->process_name;
|
||||
}
|
||||
|
||||
const struct path *get_dc_target_dpath(struct defex_context *dc)
|
||||
{
|
||||
const struct path *dpath;
|
||||
|
||||
if (dc->target_dpath && check_slab_ptr((void *)dc->target_dpath))
|
||||
return dc->target_dpath;
|
||||
|
||||
if (dc->target_file) {
|
||||
dpath = &(dc->target_file->f_path);
|
||||
if (check_slab_ptr((void *)dpath) && dpath->dentry && dpath->dentry->d_inode) {
|
||||
dc->target_dpath = dpath;
|
||||
return dpath;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *get_dc_target_name(struct defex_context *dc)
|
||||
{
|
||||
const struct path *dpath;
|
||||
char *path = NULL;
|
||||
|
||||
if (!dc->target_name) {
|
||||
dpath = get_dc_target_dpath(dc);
|
||||
if (dpath) {
|
||||
dc->target_name_buff = kmalloc(PATH_MAX, GFP_KERNEL);
|
||||
if (dc->target_name_buff)
|
||||
path = d_path(dpath, dc->target_name_buff, PATH_MAX);
|
||||
}
|
||||
dc->target_name = (IS_ERR_OR_NULL(path)) ? (char *)unknown_file : path;
|
||||
}
|
||||
return dc->target_name;
|
||||
}
|
||||
|
||||
struct file *defex_get_source_file(struct task_struct *p)
|
||||
{
|
||||
struct file *file_addr = NULL;
|
||||
struct mm_struct *proc_mm;
|
||||
|
||||
#ifdef DEFEX_CACHES_ENABLE
|
||||
bool self;
|
||||
file_addr = defex_file_cache_find(p->pid);
|
||||
|
||||
if (!file_addr) {
|
||||
proc_mm = get_task_mm(p);
|
||||
if (!proc_mm)
|
||||
return NULL;
|
||||
file_addr = get_mm_exe_file(proc_mm);
|
||||
mmput(proc_mm);
|
||||
if (!file_addr)
|
||||
return NULL;
|
||||
defex_file_cache_add(p->pid, file_addr);
|
||||
} else {
|
||||
self = (p == current);
|
||||
proc_mm = (self)?p->mm:get_task_mm(p);
|
||||
if (!proc_mm)
|
||||
return NULL;
|
||||
if (self)
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 8, 0)
|
||||
if (!down_read_trylock(&proc_mm->mmap_sem))
|
||||
return NULL;
|
||||
#else
|
||||
if (!down_read_trylock(&proc_mm->mmap_lock))
|
||||
return NULL;
|
||||
#endif
|
||||
if (file_addr != proc_mm->exe_file) {
|
||||
file_addr = proc_mm->exe_file;
|
||||
if (!file_addr)
|
||||
goto clean_mm;
|
||||
get_file(file_addr);
|
||||
defex_file_cache_update(file_addr);
|
||||
}
|
||||
clean_mm:
|
||||
if (self)
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 8, 0)
|
||||
up_read(&proc_mm->mmap_sem);
|
||||
#else
|
||||
up_read(&proc_mm->mmap_lock);
|
||||
#endif
|
||||
else
|
||||
mmput(proc_mm);
|
||||
}
|
||||
#else
|
||||
|
||||
proc_mm = get_task_mm(p);
|
||||
if (!proc_mm)
|
||||
return NULL;
|
||||
file_addr = get_mm_exe_file(proc_mm);
|
||||
mmput(proc_mm);
|
||||
#endif /* DEFEX_CACHES_ENABLE */
|
||||
return file_addr;
|
||||
}
|
||||
|
||||
char *defex_get_filename(struct task_struct *p)
|
||||
{
|
||||
struct file *exe_file = NULL;
|
||||
const struct path *dpath = NULL;
|
||||
char *path = NULL, *buff = NULL;
|
||||
char *filename = NULL;
|
||||
|
||||
exe_file = defex_get_source_file(p);
|
||||
if (IS_ERR_OR_NULL(exe_file))
|
||||
goto out_filename;
|
||||
|
||||
dpath = &exe_file->f_path;
|
||||
if (!dpath->dentry || !dpath->dentry->d_inode) {
|
||||
fput(exe_file);
|
||||
goto out_filename;
|
||||
}
|
||||
path_get(dpath);
|
||||
|
||||
buff = kmalloc(PATH_MAX, GFP_KERNEL);
|
||||
if (buff)
|
||||
path = d_path(dpath, buff, PATH_MAX);
|
||||
path_put(dpath);
|
||||
|
||||
#ifndef DEFEX_CACHES_ENABLE
|
||||
fput(exe_file);
|
||||
#endif /* DEFEX_CACHES_ENABLE */
|
||||
|
||||
out_filename:
|
||||
if (path && !IS_ERR(path))
|
||||
filename = kstrdup(path, GFP_KERNEL);
|
||||
|
||||
if (!filename)
|
||||
filename = (char *)unknown_file;
|
||||
|
||||
if (buff)
|
||||
kfree(buff);
|
||||
return filename;
|
||||
}
|
||||
|
||||
/* Resolve the filename to absolute path, follow the links
|
||||
name - input file name
|
||||
out_buff - output pointer to the allocated buffer (should be freed)
|
||||
Returns: pointer to resolved filename or NULL
|
||||
*/
|
||||
char* defex_resolve_filename(const char *name, char **out_buff)
|
||||
{
|
||||
char *target_file = NULL, *buff = NULL;
|
||||
struct path path;
|
||||
|
||||
if (*out_buff)
|
||||
buff = *out_buff;
|
||||
else
|
||||
buff = kmalloc(PATH_MAX, GFP_KERNEL);
|
||||
if (buff) {
|
||||
if (!kern_path(name, LOOKUP_FOLLOW, &path)) {
|
||||
target_file = d_path(&path, buff, PATH_MAX);
|
||||
path_put(&path);
|
||||
}
|
||||
if (IS_ERR_OR_NULL(target_file)) {
|
||||
kfree(buff);
|
||||
buff = NULL;
|
||||
target_file = NULL;
|
||||
}
|
||||
}
|
||||
*out_buff = buff;
|
||||
return target_file;
|
||||
}
|
||||
|
||||
int defex_files_identical(const struct file *f1, const struct file *f2)
|
||||
{
|
||||
const struct path *dpath1, *dpath2;
|
||||
const struct inode *inode1, *inode2;
|
||||
|
||||
if (f1 && f2) {
|
||||
dpath1 = &f1->f_path;
|
||||
dpath2 = &f2->f_path;
|
||||
if (dpath1->dentry && dpath2->dentry) {
|
||||
inode1 = dpath1->dentry->d_inode;
|
||||
inode2 = dpath2->dentry->d_inode;
|
||||
return (inode1 == inode2);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -1,76 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/defex.h>
|
||||
#include "include/defex_internal.h"
|
||||
|
||||
int defex_get_features(void)
|
||||
{
|
||||
int features = 0;
|
||||
#ifdef DEFEX_PED_ENABLE
|
||||
#if !defined(DEFEX_PERMISSIVE_PED)
|
||||
features |= GLOBAL_PED_STATUS;
|
||||
#else
|
||||
if (global_privesc_status != 0)
|
||||
features |= FEATURE_CHECK_CREDS;
|
||||
if (global_privesc_status == 2)
|
||||
features |= FEATURE_CHECK_CREDS_SOFT;
|
||||
#endif /* DEFEX_PERMISSIVE_PED */
|
||||
#endif /* DEFEX_PED_ENABLE */
|
||||
|
||||
#ifdef DEFEX_INTEGRITY_ENABLE
|
||||
#if !defined(DEFEX_PERMISSIVE_INT)
|
||||
features |= GLOBAL_INTEGRITY_STATUS;
|
||||
#else
|
||||
if (global_integrity_status != 0)
|
||||
features |= FEATURE_INTEGRITY;
|
||||
if (global_integrity_status == 2)
|
||||
features |= FEATURE_INTEGRITY_SOFT;
|
||||
#endif /* DEFEX_PERMISSIVE_INT */
|
||||
#endif /* DEFEX_INTEGRITY_ENABLE */
|
||||
|
||||
#ifdef DEFEX_SAFEPLACE_ENABLE
|
||||
#if !defined(DEFEX_PERMISSIVE_SP)
|
||||
features |= GLOBAL_SAFEPLACE_STATUS;
|
||||
#else
|
||||
if (global_safeplace_status != 0)
|
||||
features |= FEATURE_SAFEPLACE;
|
||||
if (global_safeplace_status == 2)
|
||||
features |= FEATURE_SAFEPLACE_SOFT;
|
||||
#endif /* DEFEX_PERMISSIVE_SP */
|
||||
#endif /* DEFEX_SAFEPLACE_ENABLE */
|
||||
|
||||
#ifdef DEFEX_TRUSTED_MAP_ENABLE
|
||||
#if !defined(DEFEX_PERMISSIVE_TM)
|
||||
features |= GLOBAL_TRUSTED_MAP_STATUS;
|
||||
#else
|
||||
if (global_trusted_map_status != 0)
|
||||
features |= FEATURE_TRUSTED_MAP;
|
||||
if (global_trusted_map_status & DEFEX_TM_PERMISSIVE_MODE)
|
||||
features |= FEATURE_TRUSTED_MAP_SOFT;
|
||||
#endif /* DEFEX_PERMISSIVE_TM */
|
||||
#endif /* DEFEX_TRUSTED_MAP_ENABLE */
|
||||
|
||||
#ifdef DEFEX_IMMUTABLE_ENABLE
|
||||
#if !defined(DEFEX_PERMISSIVE_IM)
|
||||
features |= GLOBAL_IMMUTABLE_STATUS;
|
||||
#else
|
||||
if (global_immutable_status != 0)
|
||||
features |= FEATURE_IMMUTABLE;
|
||||
if (global_immutable_status == 2)
|
||||
features |= FEATURE_IMMUTABLE_SOFT;
|
||||
#endif /* DEFEX_PERMISSIVE_IM */
|
||||
#endif /* DEFEX_IMMUTABLE_ENABLE */
|
||||
return features;
|
||||
}
|
|
@ -1,162 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/unistd.h>
|
||||
#include <linux/version.h>
|
||||
#include "include/defex_caches.h"
|
||||
#include "include/defex_catch_list.h"
|
||||
#include "include/defex_debug.h"
|
||||
#include "include/defex_internal.h"
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
|
||||
#include <linux/bootconfig.h>
|
||||
#endif
|
||||
|
||||
MODULE_DESCRIPTION("Defex Linux Security Module");
|
||||
|
||||
bool boot_state_recovery __ro_after_init;
|
||||
|
||||
#ifdef DEFEX_DEPENDING_ON_OEMUNLOCK
|
||||
bool boot_state_unlocked __ro_after_init;
|
||||
int warranty_bit __ro_after_init;
|
||||
#endif /* DEFEX_DEPENDING_ON_OEMUNLOCK */
|
||||
|
||||
asmlinkage int defex_syscall_enter(long int syscallno, struct pt_regs *regs);
|
||||
asmlinkage int (* const defex_syscall_catch_enter)(long int syscallno, struct pt_regs *regs) = defex_syscall_enter;
|
||||
static int defex_init_done __initdata;
|
||||
|
||||
asmlinkage int defex_syscall_enter(long int syscallno, struct pt_regs *regs)
|
||||
{
|
||||
long err;
|
||||
const struct local_syscall_struct *item;
|
||||
|
||||
if (!current)
|
||||
return 0;
|
||||
|
||||
#if !defined(__arm__) && defined(CONFIG_COMPAT)
|
||||
if (regs->pstate & PSR_MODE32_BIT)
|
||||
item = get_local_syscall_compat(syscallno);
|
||||
else
|
||||
#endif /* __arm__ && CONFIG_COMPAT */
|
||||
item = get_local_syscall(syscallno);
|
||||
|
||||
if (!item)
|
||||
return 0;
|
||||
|
||||
err = item->err_code;
|
||||
if (err) {
|
||||
if (task_defex_enforce(current, NULL, item->local_syscall))
|
||||
return err;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEFEX_DEPENDING_ON_OEMUNLOCK
|
||||
__visible_for_testing int __init verifiedboot_state_setup(char *str)
|
||||
{
|
||||
static const char unlocked[] = "orange";
|
||||
|
||||
if (str && !strncmp(str, unlocked, sizeof(unlocked))) {
|
||||
boot_state_unlocked = true;
|
||||
defex_log_crit("Device is unlocked and DEFEX will be disabled");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
__visible_for_testing int __init warrantybit_setup(char *str)
|
||||
{
|
||||
if (get_option(&str, &warranty_bit))
|
||||
defex_log_crit("Warranty bit setup");
|
||||
return 0;
|
||||
}
|
||||
|
||||
__setup("androidboot.verifiedbootstate=", verifiedboot_state_setup);
|
||||
__setup("androidboot.warranty_bit=", warrantybit_setup);
|
||||
#endif /* DEFEX_DEPENDING_ON_OEMUNLOCK */
|
||||
|
||||
__visible_for_testing int __init bootstate_recovery_setup(char *str)
|
||||
{
|
||||
if (str && *str == '2') {
|
||||
boot_state_recovery = true;
|
||||
defex_log_crit("Recovery mode setup");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
__setup("bootmode=", bootstate_recovery_setup);
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
|
||||
void __init defex_bootconfig_setup(void)
|
||||
{
|
||||
char *value;
|
||||
|
||||
#ifdef DEFEX_DEPENDING_ON_OEMUNLOCK
|
||||
value = (char *)xbc_find_value("androidboot.verifiedbootstate", NULL);
|
||||
verifiedboot_state_setup(value);
|
||||
|
||||
value = (char *)xbc_find_value("androidboot.warranty_bit", NULL);
|
||||
warrantybit_setup(value);
|
||||
#endif /* DEFEX_DEPENDING_ON_OEMUNLOCK */
|
||||
|
||||
value = (char *)xbc_find_value("androidboot.boot_recovery", NULL);
|
||||
bootstate_recovery_setup(value);
|
||||
}
|
||||
#endif /* LINUX_VERSION_CODE */
|
||||
|
||||
|
||||
//INIT/////////////////////////////////////////////////////////////////////////
|
||||
__visible_for_testing int __init defex_lsm_init(void)
|
||||
{
|
||||
#ifdef DEFEX_DEBUG_ENABLE
|
||||
int ret;
|
||||
#endif /* DEFEX_DEBUG_ENABLE */
|
||||
|
||||
#ifdef DEFEX_CACHES_ENABLE
|
||||
defex_file_cache_init();
|
||||
#endif /* DEFEX_CACHES_ENABLE */
|
||||
|
||||
#ifdef DEFEX_PED_ENABLE
|
||||
creds_fast_hash_init();
|
||||
#endif /* DEFEX_PED_ENABLE */
|
||||
|
||||
#ifdef DEFEX_DEBUG_ENABLE
|
||||
ret = defex_init_sysfs();
|
||||
if (ret) {
|
||||
defex_log_crit("LSM defex_init_sysfs() failed!");
|
||||
return ret;
|
||||
}
|
||||
#endif /* DEFEX_DEBUG_ENABLE */
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
|
||||
defex_bootconfig_setup();
|
||||
#endif /* LINUX_VERSION_CODE */
|
||||
|
||||
defex_log_info("LSM started");
|
||||
#ifdef DEFEX_LP_ENABLE
|
||||
defex_log_info("ADB LP Enabled");
|
||||
#endif /* DEFEX_LP_ENABLE */
|
||||
defex_init_done = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
__visible_for_testing int __init defex_lsm_load(void)
|
||||
{
|
||||
if (!boot_state_unlocked && defex_init_done)
|
||||
do_load_rules();
|
||||
return 0;
|
||||
}
|
||||
|
||||
module_init(defex_lsm_init);
|
||||
late_initcall(defex_lsm_load);
|
|
@ -1,730 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <asm/barrier.h>
|
||||
#include <linux/binfmts.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/const.h>
|
||||
#ifdef DEFEX_DSMS_ENABLE
|
||||
#include <linux/dsms.h>
|
||||
#endif
|
||||
#include <linux/file.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/namei.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/stddef.h>
|
||||
#ifdef DEFEX_DSMS_ENABLE
|
||||
#include <linux/string.h>
|
||||
#endif
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/unistd.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include "include/defex_caches.h"
|
||||
#include "include/defex_catch_list.h"
|
||||
#include "include/defex_config.h"
|
||||
#include "include/defex_debug.h"
|
||||
#include "include/defex_internal.h"
|
||||
#include "include/defex_rules.h"
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
|
||||
#include <linux/sched/mm.h>
|
||||
#include <linux/sched/task.h>
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0)
|
||||
#define is_task_used(tsk) refcount_read(&(tsk)->usage)
|
||||
#else
|
||||
#define is_task_used(tsk) atomic_read(&(tsk)->usage)
|
||||
#endif
|
||||
|
||||
|
||||
__visible_for_testing struct task_struct *get_parent_task(const struct task_struct *p)
|
||||
{
|
||||
struct task_struct *parent = NULL;
|
||||
|
||||
read_lock(&tasklist_lock);
|
||||
parent = p->parent;
|
||||
if (parent)
|
||||
get_task_struct(parent);
|
||||
read_unlock(&tasklist_lock);
|
||||
return parent;
|
||||
}
|
||||
|
||||
#ifdef DEFEX_DSMS_ENABLE
|
||||
|
||||
# define PED_VIOLATION "DFX1"
|
||||
# define SAFEPLACE_VIOLATION "DFX2"
|
||||
# define INTEGRITY_VIOLATION "DFX3"
|
||||
# define IMMUTABLE_VIOLATION "DFX4"
|
||||
# define MESSAGE_BUFFER_SIZE 200
|
||||
# define STORED_CREDS_SIZE 100
|
||||
|
||||
__visible_for_testing void defex_report_violation(const char *violation, uint64_t counter,
|
||||
struct defex_context *dc, uid_t stored_uid, uid_t stored_fsuid, uid_t stored_egid, int case_num)
|
||||
{
|
||||
int usermode_result;
|
||||
char message[MESSAGE_BUFFER_SIZE + 1];
|
||||
|
||||
struct task_struct *parent = NULL, *p = dc->task;
|
||||
const uid_t uid = uid_get_value(dc->cred->uid);
|
||||
const uid_t euid = uid_get_value(dc->cred->euid);
|
||||
const uid_t fsuid = uid_get_value(dc->cred->fsuid);
|
||||
const uid_t egid = uid_get_value(dc->cred->egid);
|
||||
const char *process_name = p->comm;
|
||||
const char *prt_process_name = NULL;
|
||||
const char *program_path = get_dc_process_name(dc);
|
||||
char *prt_program_path = NULL;
|
||||
char *file_path = NULL;
|
||||
char stored_creds[STORED_CREDS_SIZE + 1];
|
||||
|
||||
parent = get_parent_task(p);
|
||||
if (!parent)
|
||||
return;
|
||||
|
||||
prt_process_name = parent->comm;
|
||||
prt_program_path = defex_get_filename(parent);
|
||||
|
||||
if (dc->target_file && !case_num) {
|
||||
file_path = get_dc_target_name(dc);
|
||||
} else {
|
||||
snprintf(stored_creds, sizeof(stored_creds),
|
||||
"[%ld, %ld, %ld]", (long)stored_uid, (long)stored_fsuid, (long)stored_egid);
|
||||
stored_creds[sizeof(stored_creds) - 1] = 0;
|
||||
}
|
||||
snprintf(message, sizeof(message), "%d, %d, sc=%d, tsk=%s(%s), %s(%s), [%ld %ld %ld %ld], %s%s, %d",
|
||||
warranty_bit, boot_state_unlocked, dc->syscall_no, process_name, program_path, prt_process_name,
|
||||
prt_program_path, (long)uid, (long)euid, (long)fsuid, (long)egid,
|
||||
(file_path ? "file=" : "stored "), (file_path ? file_path : stored_creds), case_num);
|
||||
message[sizeof(message) - 1] = 0;
|
||||
|
||||
usermode_result = dsms_send_message(violation, message, counter);
|
||||
#ifdef DEFEX_DEBUG_ENABLE
|
||||
defex_log_err("Violation : feature=%s value=%ld, detail=[%s]", violation, (long)counter, message);
|
||||
defex_log_err("Result : %d", usermode_result);
|
||||
#endif /* DEFEX_DEBUG_ENABLE */
|
||||
|
||||
safe_str_free(prt_program_path);
|
||||
put_task_struct(parent);
|
||||
}
|
||||
#endif /* DEFEX_DSMS_ENABLE */
|
||||
|
||||
#if defined(DEFEX_SAFEPLACE_ENABLE) || defined(DEFEX_TRUSTED_MAP_ENABLE) || defined(DEFEX_INTEGRITY_ENABLE)
|
||||
__visible_for_testing long kill_process(struct task_struct *p)
|
||||
{
|
||||
read_lock(&tasklist_lock);
|
||||
send_sig(SIGKILL, p, 0);
|
||||
read_unlock(&tasklist_lock);
|
||||
return 0;
|
||||
}
|
||||
#endif /* DEFEX_SAFEPLACE_ENABLE || DEFEX_TRUSTED_MAP_ENABLE || DEFEX_INTEGRITY_ENABLE */
|
||||
|
||||
#ifdef DEFEX_PED_ENABLE
|
||||
__visible_for_testing long kill_process_group(int tgid, int pid)
|
||||
{
|
||||
struct task_struct *p;
|
||||
read_lock(&tasklist_lock);
|
||||
for_each_process(p) {
|
||||
if (p->tgid == tgid)
|
||||
send_sig(SIGKILL, p, 0);
|
||||
}
|
||||
send_sig(SIGKILL, current, 0);
|
||||
read_unlock(&tasklist_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
__visible_for_testing int check_incfs(struct defex_context *dc)
|
||||
{
|
||||
char *new_file;
|
||||
struct file *f = dc->target_file;
|
||||
static const char incfs_path[] = "/data/incremental/";
|
||||
|
||||
if (f) {
|
||||
new_file = get_dc_target_name(dc);
|
||||
if (!strncmp(new_file, incfs_path, sizeof(incfs_path) - 1)) {
|
||||
#ifdef DEFEX_DEBUG_ENABLE
|
||||
defex_log_crit("Allow IncFS access");
|
||||
#endif /* DEFEX_DEBUG_ENABLE */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
__visible_for_testing int task_defex_is_secured(struct defex_context *dc)
|
||||
{
|
||||
struct file *exe_file = get_dc_process_file(dc);
|
||||
char *proc_name = get_dc_process_name(dc);
|
||||
int is_secured = 0;
|
||||
|
||||
if (!get_dc_process_dpath(dc))
|
||||
return is_secured;
|
||||
is_secured = !rules_lookup(proc_name, feature_ped_exception, exe_file, NULL);
|
||||
return is_secured;
|
||||
}
|
||||
|
||||
__visible_for_testing int at_same_group(unsigned int uid1, unsigned int uid2)
|
||||
{
|
||||
/* allow the weaken privilege */
|
||||
if (uid1 >= 10000 && uid2 < 10000) return 1;
|
||||
/* allow traverse in the same class */
|
||||
if ((uid1 / 1000) == (uid2 / 1000)) return 1;
|
||||
/* allow traverse to isolated ranges */
|
||||
if (uid1 >= 90000) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
__visible_for_testing int at_same_group_gid(unsigned int gid1, unsigned int gid2)
|
||||
{
|
||||
/* allow the weaken privilege */
|
||||
if (gid1 >= 10000 && gid2 < 10000) return 1;
|
||||
/* allow traverse in the same class */
|
||||
if ((gid1 / 1000) == (gid2 / 1000)) return 1;
|
||||
/* allow traverse to isolated ranges */
|
||||
if (gid1 >= 90000) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef DEFEX_LP_ENABLE
|
||||
/* Lower Permission feature decision function */
|
||||
__visible_for_testing int lower_adb_permission(struct defex_context *dc, unsigned short cred_flags)
|
||||
{
|
||||
char *parent_file;
|
||||
struct task_struct *parent = NULL, *p = dc->task;
|
||||
#ifndef DEFEX_PERMISSIVE_LP
|
||||
struct cred *shellcred;
|
||||
static const char adbd_str[] = "/apex/com.android.adbd/bin/adbd";
|
||||
#endif /* DEFEX_PERMISSIVE_LP */
|
||||
int ret = 0;
|
||||
|
||||
parent = get_parent_task(p);
|
||||
if (!parent || p->pid == 1 || parent->pid == 1)
|
||||
goto out;
|
||||
|
||||
parent_file = defex_get_filename(parent);
|
||||
|
||||
#ifndef DEFEX_PERMISSIVE_LP
|
||||
if (!strncmp(parent_file, adbd_str, sizeof(adbd_str))) {
|
||||
shellcred = prepare_creds();
|
||||
defex_log_crit("ADB with root");
|
||||
if (!shellcred) {
|
||||
defex_log_crit("Prepare_creds fail");
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
uid_set_value(shellcred->uid, 2000);
|
||||
uid_set_value(shellcred->suid, 2000);
|
||||
uid_set_value(shellcred->euid, 2000);
|
||||
uid_set_value(shellcred->fsuid, 2000);
|
||||
uid_set_value(shellcred->gid, 2000);
|
||||
uid_set_value(shellcred->sgid, 2000);
|
||||
uid_set_value(shellcred->egid, 2000);
|
||||
uid_set_value(shellcred->fsgid, 2000);
|
||||
commit_creds(shellcred);
|
||||
dc->cred = (struct cred *)current_cred(); //shellcred;
|
||||
set_task_creds(p, 2000, 2000, 2000, cred_flags);
|
||||
|
||||
ret = 1;
|
||||
}
|
||||
#endif /* DEFEX_PERMISSIVE_LP */
|
||||
|
||||
safe_str_free(parent_file);
|
||||
out:
|
||||
if (parent)
|
||||
put_task_struct(parent);
|
||||
return ret;
|
||||
}
|
||||
#endif /* DEFEX_LP_ENABLE */
|
||||
|
||||
/* Cred. violation feature decision function */
|
||||
#define AID_MEDIA_RW 1023
|
||||
#define AID_MEDIA_OBB 1059
|
||||
#define AID_SYSTEM 1000
|
||||
|
||||
__visible_for_testing int task_defex_check_creds(struct defex_context *dc)
|
||||
{
|
||||
char *path = NULL;
|
||||
int check_deeper, case_num;
|
||||
unsigned int cur_uid, cur_euid, cur_fsuid, cur_egid;
|
||||
unsigned int ref_uid, ref_fsuid, ref_egid;
|
||||
struct task_struct *parent, *p = dc->task;
|
||||
unsigned short cred_flags;
|
||||
const struct cred *parent_cred;
|
||||
static const unsigned int dead_uid = 0xDEADBEAF;
|
||||
|
||||
if (!is_task_creds_ready() || !p->cred)
|
||||
goto out;
|
||||
|
||||
get_task_creds(p, &ref_uid, &ref_fsuid, &ref_egid, &cred_flags);
|
||||
|
||||
cur_uid = uid_get_value(dc->cred->uid);
|
||||
cur_euid = uid_get_value(dc->cred->euid);
|
||||
cur_fsuid = uid_get_value(dc->cred->fsuid);
|
||||
cur_egid = uid_get_value(dc->cred->egid);
|
||||
|
||||
if (!ref_uid) {
|
||||
if (p->tgid != p->pid && p->tgid != 1 && p->real_parent->pid != 1) {
|
||||
path = get_dc_process_name(dc);
|
||||
defex_log_crit("[6]: cred wasn't stored [task=%s, filename=%s, uid=%d, tgid=%u, pid=%u, ppid=%u]",
|
||||
p->comm, path, cur_uid, p->tgid, p->pid, p->real_parent->pid);
|
||||
defex_log_crit("[6]: stored [euid=%d fsuid=%d egid=%d] current [uid=%d euid=%d fsuid=%d egid=%d]",
|
||||
ref_uid, ref_fsuid, ref_egid, cur_uid, cur_euid, cur_fsuid, cur_egid);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
parent = get_parent_task(p);
|
||||
if (parent) {
|
||||
parent_cred = get_task_cred(parent);
|
||||
if (CHECK_ROOT_CREDS(parent_cred))
|
||||
cred_flags |= CRED_FLAGS_PROOT;
|
||||
put_cred(parent_cred);
|
||||
put_task_struct(parent);
|
||||
}
|
||||
|
||||
if (CHECK_ROOT_CREDS(dc->cred)) {
|
||||
#ifdef DEFEX_LP_ENABLE
|
||||
if (!lower_adb_permission(dc, cred_flags))
|
||||
#endif /* DEFEX_LP_ENABLE */
|
||||
{
|
||||
set_task_creds(p, 1, 1, 1, cred_flags);
|
||||
}
|
||||
}
|
||||
else
|
||||
set_task_creds(p, cur_euid, cur_fsuid, cur_egid, cred_flags);
|
||||
} else if (ref_uid == 1) {
|
||||
if (!CHECK_ROOT_CREDS(dc->cred))
|
||||
set_task_creds(p, cur_euid, cur_fsuid, cur_egid, cred_flags);
|
||||
} else if (ref_uid == dead_uid) {
|
||||
path = get_dc_process_name(dc);
|
||||
defex_log_crit("[5]: process wasn't killed [task=%s, filename=%s, uid=%d, tgid=%u, pid=%u, ppid=%u]",
|
||||
p->comm, path, cur_uid, p->tgid, p->pid, p->real_parent->pid);
|
||||
defex_log_crit("[5]: stored [euid=%d fsuid=%d egid=%d] current [uid=%d euid=%d fsuid=%d egid=%d]",
|
||||
ref_uid, ref_fsuid, ref_egid, cur_uid, cur_euid, cur_fsuid, cur_egid);
|
||||
goto exit;
|
||||
} else {
|
||||
check_deeper = 0;
|
||||
/* temporary allow fsuid changes to "media_rw" */
|
||||
if ( (cur_uid != ref_uid) ||
|
||||
(cur_euid != ref_uid) ||
|
||||
(cur_egid != ref_egid) ||
|
||||
!((cur_fsuid == ref_fsuid) ||
|
||||
(cur_fsuid == ref_uid) ||
|
||||
(cur_fsuid%100000 == AID_SYSTEM) ||
|
||||
(cur_fsuid%100000 == AID_MEDIA_RW) ||
|
||||
(cur_fsuid%100000 == AID_MEDIA_OBB)) ) {
|
||||
check_deeper = 1;
|
||||
if (CHECK_ROOT_CREDS(dc->cred))
|
||||
set_task_creds(p, 1, 1, 1, cred_flags);
|
||||
else
|
||||
set_task_creds(p, cur_euid, cur_fsuid, cur_egid, cred_flags);
|
||||
}
|
||||
if (check_deeper &&
|
||||
(!at_same_group(cur_uid, ref_uid) ||
|
||||
!at_same_group(cur_euid, ref_uid) ||
|
||||
!at_same_group_gid(cur_egid, ref_egid) ||
|
||||
!at_same_group(cur_fsuid, ref_fsuid)) &&
|
||||
task_defex_is_secured(dc)) {
|
||||
case_num = ((p->tgid == p->pid) ? 1 : 2);
|
||||
goto trigger_violation;
|
||||
}
|
||||
}
|
||||
|
||||
if (CHECK_ROOT_CREDS(dc->cred) && !(cred_flags & CRED_FLAGS_PROOT) && task_defex_is_secured(dc)) {
|
||||
if (p->tgid != p->pid) {
|
||||
case_num = 3;
|
||||
goto trigger_violation;
|
||||
}
|
||||
case_num = 4;
|
||||
goto trigger_violation;
|
||||
}
|
||||
|
||||
out:
|
||||
return DEFEX_ALLOW;
|
||||
|
||||
trigger_violation:
|
||||
if (check_incfs(dc))
|
||||
return DEFEX_ALLOW;
|
||||
set_task_creds(p, dead_uid, dead_uid, dead_uid, cred_flags);
|
||||
path = get_dc_process_name(dc);
|
||||
defex_log_crit("[%d]: credential violation [task=%s, filename=%s, uid=%d, tgid=%u, pid=%u, ppid=%u]",
|
||||
case_num, p->comm, path, cur_uid, p->tgid, p->pid, p->real_parent->pid);
|
||||
defex_log_crit("[%d]: stored [euid=%d fsuid=%d egid=%d] current [uid=%d euid=%d fsuid=%d egid=%d]",
|
||||
case_num, ref_uid, ref_fsuid, ref_egid, cur_uid, cur_euid, cur_fsuid, cur_egid);
|
||||
|
||||
#ifdef DEFEX_DSMS_ENABLE
|
||||
defex_report_violation(PED_VIOLATION, 0, dc, ref_uid, ref_fsuid, ref_egid, case_num);
|
||||
#endif /* DEFEX_DSMS_ENABLE */
|
||||
|
||||
exit:
|
||||
return -DEFEX_DENY;
|
||||
}
|
||||
#endif /* DEFEX_PED_ENABLE */
|
||||
|
||||
#ifdef DEFEX_INTEGRITY_ENABLE
|
||||
__visible_for_testing int task_defex_integrity(struct defex_context *dc)
|
||||
{
|
||||
int ret = DEFEX_ALLOW, is_violation = 0;
|
||||
char *proc_file, *new_file;
|
||||
struct task_struct *p = dc->task;
|
||||
|
||||
if (!get_dc_target_dpath(dc))
|
||||
goto out;
|
||||
|
||||
new_file = get_dc_target_name(dc);
|
||||
is_violation = rules_lookup(new_file, feature_integrity_check, dc->target_file, NULL);
|
||||
|
||||
if (is_violation == DEFEX_INTEGRITY_FAIL) {
|
||||
ret = -DEFEX_DENY;
|
||||
proc_file = get_dc_process_name(dc);
|
||||
|
||||
defex_log_crit("Integrity violation [task=%s (%s), child=%s, uid=%d]",
|
||||
p->comm, proc_file, new_file, uid_get_value(dc->cred->uid));
|
||||
#ifdef DEFEX_DSMS_ENABLE
|
||||
defex_report_violation(INTEGRITY_VIOLATION, 0, dc, 0, 0, 0, 0);
|
||||
#endif /* DEFEX_DSMS_ENABLE */
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
#endif /* DEFEX_INTEGRITY_ENABLE */
|
||||
|
||||
#ifdef DEFEX_SAFEPLACE_ENABLE
|
||||
/* Safeplace feature decision function */
|
||||
__visible_for_testing int task_defex_safeplace(struct defex_context *dc)
|
||||
{
|
||||
int ret = DEFEX_ALLOW, is_violation = 0;
|
||||
char *proc_file, *new_file;
|
||||
struct task_struct *p = dc->task;
|
||||
|
||||
if (!CHECK_ROOT_CREDS(dc->cred))
|
||||
goto out;
|
||||
|
||||
if (!get_dc_target_dpath(dc))
|
||||
goto out;
|
||||
|
||||
new_file = get_dc_target_name(dc);
|
||||
is_violation = !rules_lookup(new_file, feature_safeplace_path, dc->target_file, NULL);
|
||||
|
||||
if (is_violation) {
|
||||
ret = -DEFEX_DENY;
|
||||
proc_file = get_dc_process_name(dc);
|
||||
|
||||
defex_log_crit("Safeplace violation [task=%s (%s), child=%s, uid=%d]",
|
||||
p->comm, proc_file, new_file, uid_get_value(dc->cred->uid));
|
||||
#ifdef DEFEX_DSMS_ENABLE
|
||||
defex_report_violation(SAFEPLACE_VIOLATION, 0, dc, 0, 0, 0, 0);
|
||||
#endif /* DEFEX_DSMS_ENABLE */
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
#endif /* DEFEX_SAFEPLACE_ENABLE */
|
||||
|
||||
#ifdef DEFEX_TRUSTED_MAP_ENABLE
|
||||
/* Trusted map feature decision function */
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 9, 0)
|
||||
__visible_for_testing int task_defex_trusted_map(struct defex_context *dc, va_list ap)
|
||||
{
|
||||
int ret = DEFEX_ALLOW, argc;
|
||||
struct linux_binprm *bprm;
|
||||
|
||||
if (!CHECK_ROOT_CREDS(&dc->cred))
|
||||
goto out;
|
||||
|
||||
bprm = va_arg(ap, struct linux_binprm *);
|
||||
argc = bprm->argc;
|
||||
#ifdef DEFEX_DEBUG_ENABLE
|
||||
if (argc <= 0)
|
||||
defex_log_crit("[DTM] Invalid trusted map arguments - check integration on fs/exec.c (argc %d)", argc);
|
||||
#endif
|
||||
|
||||
ret = defex_trusted_map_lookup(dc, argc, bprm);
|
||||
if (defex_tm_mode_enabled(DEFEX_TM_PERMISSIVE_MODE))
|
||||
ret = DEFEX_ALLOW;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
__visible_for_testing int task_defex_trusted_map(struct defex_context *dc, va_list ap)
|
||||
{
|
||||
int ret = DEFEX_ALLOW, argc;
|
||||
void *argv;
|
||||
|
||||
if (!CHECK_ROOT_CREDS(dc->cred))
|
||||
goto out;
|
||||
|
||||
argc = va_arg(ap, int);
|
||||
argv = va_arg(ap, void *);
|
||||
#ifdef DEFEX_DEBUG_ENABLE
|
||||
if (argc <= 0)
|
||||
defex_log_crit(
|
||||
"[DTM] Invalid trusted map arguments - check integration on fs/exec.c (argc %d)", argc);
|
||||
#endif
|
||||
|
||||
ret = defex_trusted_map_lookup(dc, argc, argv);
|
||||
if (defex_tm_mode_enabled(DEFEX_TM_PERMISSIVE_MODE))
|
||||
ret = DEFEX_ALLOW;
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
#endif /* DEFEX_TRUSTED_MAP_ENABLE */
|
||||
|
||||
#ifdef DEFEX_IMMUTABLE_ENABLE
|
||||
|
||||
/* Immutable feature decision function */
|
||||
__visible_for_testing int task_defex_src_exception(struct defex_context *dc)
|
||||
{
|
||||
struct file *exe_file = get_dc_process_file(dc);
|
||||
char *target_name, *proc_name = get_dc_process_name(dc);
|
||||
int offset, allow = 1;
|
||||
struct rule_item_struct *found_item = NULL;
|
||||
|
||||
if (!get_dc_process_dpath(dc))
|
||||
return allow;
|
||||
|
||||
exe_file = get_dc_process_file(dc);
|
||||
allow = rules_lookup(proc_name, feature_immutable_src_exception, exe_file, &found_item);
|
||||
if (allow && found_item &&
|
||||
(found_item->feature_type & feature_is_file) &&
|
||||
found_item->next_level) {
|
||||
target_name = get_dc_target_name(dc);
|
||||
offset = rules_lookup(target_name, feature_immutable_dst_exception, dc->target_file, NULL);
|
||||
allow = (offset == found_item->next_level);
|
||||
}
|
||||
return allow;
|
||||
}
|
||||
|
||||
/* Immutable feature decision function */
|
||||
__visible_for_testing int task_defex_immutable(struct defex_context *dc, int attribute)
|
||||
{
|
||||
int ret = DEFEX_ALLOW, is_violation = 0;
|
||||
char *proc_file, *new_file;
|
||||
struct task_struct *p = dc->task;
|
||||
|
||||
if (!get_dc_target_dpath(dc))
|
||||
goto out;
|
||||
|
||||
new_file = get_dc_target_name(dc);
|
||||
is_violation = rules_lookup(new_file, attribute, dc->target_file, NULL);
|
||||
|
||||
if (is_violation) {
|
||||
/* Check the Source exception and self-access */
|
||||
if (attribute == feature_immutable_path_open &&
|
||||
(task_defex_src_exception(dc) ||
|
||||
defex_files_identical(get_dc_process_file(dc), dc->target_file)))
|
||||
goto out;
|
||||
|
||||
ret = -DEFEX_DENY;
|
||||
proc_file = get_dc_process_name(dc);
|
||||
defex_log_crit("Immutable %s violation [task=%s (%s), access to:%s]",
|
||||
(attribute==feature_immutable_path_open)?"open":"write", p->comm, proc_file, new_file);
|
||||
#ifdef DEFEX_DSMS_ENABLE
|
||||
defex_report_violation(IMMUTABLE_VIOLATION, 0, dc, 0, 0, 0, 0);
|
||||
#endif /* DEFEX_DSMS_ENABLE */
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
#endif /* DEFEX_IMMUTABLE_ENABLE */
|
||||
|
||||
/* Main decision function */
|
||||
int task_defex_enforce(struct task_struct *p, struct file *f, int syscall, ...)
|
||||
{
|
||||
int ret = DEFEX_ALLOW;
|
||||
int feature_flag;
|
||||
const struct local_syscall_struct *item;
|
||||
struct defex_context dc;
|
||||
#ifdef DEFEX_TRUSTED_MAP_ENABLE
|
||||
va_list ap;
|
||||
#endif
|
||||
|
||||
if (boot_state_unlocked)
|
||||
return ret;
|
||||
|
||||
if (!p || p->pid == 1 || !p->mm || !is_task_used(p))
|
||||
return ret;
|
||||
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 14, 0))
|
||||
if ((p->state & (__TASK_STOPPED | TASK_DEAD)) || (p->exit_state & (EXIT_ZOMBIE | EXIT_DEAD)))
|
||||
#else
|
||||
if ((p->__state & (__TASK_STOPPED | TASK_DEAD)) || (p->exit_state & (EXIT_ZOMBIE | EXIT_DEAD)))
|
||||
#endif
|
||||
return ret;
|
||||
|
||||
if (syscall < 0) {
|
||||
item = get_local_syscall(-syscall);
|
||||
if (!item)
|
||||
return ret;
|
||||
syscall = item->local_syscall;
|
||||
}
|
||||
|
||||
feature_flag = defex_get_features();
|
||||
get_task_struct(p);
|
||||
if (!init_defex_context(&dc, syscall, p, f))
|
||||
goto do_allow;
|
||||
|
||||
#ifdef DEFEX_PED_ENABLE
|
||||
/* Credential escalation feature */
|
||||
if (feature_flag & FEATURE_CHECK_CREDS) {
|
||||
ret = task_defex_check_creds(&dc);
|
||||
if (ret) {
|
||||
if (!(feature_flag & FEATURE_CHECK_CREDS_SOFT)) {
|
||||
release_defex_context(&dc);
|
||||
kill_process_group(p->tgid, p->pid);
|
||||
put_task_struct(p);
|
||||
return -DEFEX_DENY;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* DEFEX_PED_ENABLE */
|
||||
|
||||
#ifdef DEFEX_INTEGRITY_ENABLE
|
||||
/* Integrity feature */
|
||||
if (feature_flag & FEATURE_INTEGRITY) {
|
||||
if (syscall == __DEFEX_execve) {
|
||||
ret = task_defex_integrity(&dc);
|
||||
if (ret == -DEFEX_DENY) {
|
||||
if (!(feature_flag & FEATURE_INTEGRITY_SOFT)) {
|
||||
kill_process(p);
|
||||
goto do_deny;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* DEFEX_INTEGRITY_ENABLE */
|
||||
|
||||
#ifdef DEFEX_SAFEPLACE_ENABLE
|
||||
/* Safeplace feature */
|
||||
if (feature_flag & FEATURE_SAFEPLACE) {
|
||||
if (syscall == __DEFEX_execve) {
|
||||
ret = task_defex_safeplace(&dc);
|
||||
if (ret == -DEFEX_DENY) {
|
||||
if (!(feature_flag & FEATURE_SAFEPLACE_SOFT)) {
|
||||
kill_process(p);
|
||||
goto do_deny;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* DEFEX_SAFEPLACE_ENABLE */
|
||||
|
||||
#ifdef DEFEX_IMMUTABLE_ENABLE
|
||||
/* Immutable feature */
|
||||
if (feature_flag & FEATURE_IMMUTABLE) {
|
||||
if (syscall == __DEFEX_openat || syscall == __DEFEX_write) {
|
||||
ret = task_defex_immutable(&dc,
|
||||
(syscall == __DEFEX_openat)?feature_immutable_path_open:feature_immutable_path_write);
|
||||
if (ret == -DEFEX_DENY) {
|
||||
if (!(feature_flag & FEATURE_IMMUTABLE_SOFT)) {
|
||||
goto do_deny;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* DEFEX_IMMUTABLE_ENABLE */
|
||||
|
||||
#ifdef DEFEX_TRUSTED_MAP_ENABLE
|
||||
/* Trusted map feature */
|
||||
if (feature_flag & FEATURE_TRUSTED_MAP) {
|
||||
if (syscall == __DEFEX_execve) {
|
||||
va_start(ap, syscall);
|
||||
ret = task_defex_trusted_map(&dc, ap);
|
||||
va_end(ap);
|
||||
if (ret == -DEFEX_DENY) {
|
||||
if (!(feature_flag & FEATURE_TRUSTED_MAP_SOFT)) {
|
||||
kill_process(p);
|
||||
goto do_deny;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* DEFEX_TRUSTED_MAP_ENABLE */
|
||||
do_allow:
|
||||
release_defex_context(&dc);
|
||||
put_task_struct(p);
|
||||
return DEFEX_ALLOW;
|
||||
do_deny:
|
||||
release_defex_context(&dc);
|
||||
put_task_struct(p);
|
||||
return -DEFEX_DENY;
|
||||
}
|
||||
|
||||
int task_defex_zero_creds(struct task_struct *tsk)
|
||||
{
|
||||
int is_fork = -1;
|
||||
if (tsk->flags & (PF_KTHREAD | PF_WQ_WORKER)) {
|
||||
return 0;
|
||||
}
|
||||
if (is_task_creds_ready()) {
|
||||
is_fork = ((tsk->flags & PF_FORKNOEXEC) && (!tsk->on_rq));
|
||||
#ifdef TASK_NEW
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 14, 0))
|
||||
if (!is_fork && (tsk->state & TASK_NEW))
|
||||
#else
|
||||
if (!is_fork && (tsk->__state & TASK_NEW))
|
||||
#endif
|
||||
is_fork = 1;
|
||||
#endif /* TASK_NEW */
|
||||
set_task_creds_tcnt(tsk, is_fork?1:-1);
|
||||
}
|
||||
|
||||
#ifdef DEFEX_CACHES_ENABLE
|
||||
defex_file_cache_delete(tsk->pid);
|
||||
#endif /* DEFEX_CACHES_ENABLE */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int task_defex_user_exec(const char *new_file)
|
||||
{
|
||||
#ifdef DEFEX_UMH_RESTRICTION_ENABLE
|
||||
int res = DEFEX_ALLOW, is_violation;
|
||||
struct file *fp = NULL;
|
||||
static unsigned int rules_load_cnt;
|
||||
|
||||
if (boot_state_unlocked)
|
||||
return DEFEX_ALLOW;
|
||||
|
||||
if (!check_rules_ready()) {
|
||||
if (rules_load_cnt++%100 == 0)
|
||||
defex_log_warn("Rules not ready");
|
||||
goto umh_out;
|
||||
}
|
||||
|
||||
if (current == NULL || current->fs == NULL) {
|
||||
goto umh_out;
|
||||
}
|
||||
|
||||
fp = local_fopen(new_file, O_RDONLY, 0);
|
||||
if (IS_ERR(fp) || (fp == NULL)) {
|
||||
res = DEFEX_DENY;
|
||||
goto umh_out;
|
||||
} else {
|
||||
filp_close(fp, NULL);
|
||||
}
|
||||
|
||||
is_violation = !rules_lookup(new_file, feature_umhbin_path, NULL, NULL);
|
||||
if (is_violation) {
|
||||
defex_log_warn("UMH Exec Denied: %s", new_file);
|
||||
res = DEFEX_DENY;
|
||||
goto umh_out;
|
||||
}
|
||||
|
||||
umh_out:
|
||||
return res;
|
||||
#else
|
||||
return DEFEX_ALLOW;
|
||||
#endif /* DEFEX_UMH_RESTRICTION_ENABLE */
|
||||
}
|
|
@ -1,704 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/dcache.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/namei.h>
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/version.h>
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
|
||||
#include <linux/mm.h>
|
||||
#endif /* < KERNEL_VERSION(4, 12, 0) */
|
||||
|
||||
#include "include/defex_debug.h"
|
||||
#include "include/defex_internal.h"
|
||||
#include "include/defex_rules.h"
|
||||
#include "include/defex_sign.h"
|
||||
#ifdef DEFEX_TRUSTED_MAP_ENABLE
|
||||
#include "include/defex_tailer.h"
|
||||
#include "include/ptree.h"
|
||||
#endif
|
||||
|
||||
#define LOAD_FLAG_DPOLICY 0x01
|
||||
#define LOAD_FLAG_DPOLICY_SYSTEM 0x02
|
||||
#define LOAD_FLAG_SYSTEM_FIRST 0x04
|
||||
#define LOAD_FLAG_TIMEOUT 0x08
|
||||
#define LOAD_FLAG_RECOVERY 0x10
|
||||
|
||||
#define DEFEX_RULES_ARRAY_SIZE_MIN 64
|
||||
#define DEFEX_RULES_ARRAY_SIZE_FIXED (32 * 1024)
|
||||
#define DEFEX_RULES_ARRAY_SIZE_MAX (256 * 1024)
|
||||
|
||||
|
||||
/*
|
||||
* Variant 1: Platform build, use static packed rules array
|
||||
*/
|
||||
#include "defex_packed_rules.inc"
|
||||
|
||||
#ifdef DEFEX_RAMDISK_ENABLE
|
||||
/*
|
||||
* Variant 2: Platform build, load rules from kernel ramdisk or system partition
|
||||
*/
|
||||
#ifdef DEFEX_SIGN_ENABLE
|
||||
#include "include/defex_sign.h"
|
||||
#endif
|
||||
#if (DEFEX_RULES_ARRAY_SIZE < 8)
|
||||
#undef DEFEX_RULES_ARRAY_SIZE
|
||||
#define DEFEX_RULES_ARRAY_SIZE DEFEX_RULES_ARRAY_SIZE_MIN
|
||||
#endif
|
||||
#ifdef DEFEX_KERNEL_ONLY
|
||||
#undef DEFEX_RULES_ARRAY_SIZE
|
||||
#define DEFEX_RULES_ARRAY_SIZE DEFEX_RULES_ARRAY_SIZE_MAX
|
||||
__visible_for_testing unsigned char packed_rules_primary[DEFEX_RULES_ARRAY_SIZE] = {0};
|
||||
#else
|
||||
#if (DEFEX_RULES_ARRAY_SIZE < DEFEX_RULES_ARRAY_SIZE_FIXED)
|
||||
#undef DEFEX_RULES_ARRAY_SIZE
|
||||
#define DEFEX_RULES_ARRAY_SIZE DEFEX_RULES_ARRAY_SIZE_FIXED
|
||||
#endif
|
||||
__visible_for_testing unsigned char packed_rules_primary[DEFEX_RULES_ARRAY_SIZE] __ro_after_init = {0};
|
||||
#endif /* DEFEX_KERNEL_ONLY */
|
||||
static unsigned char *packed_rules_secondary;
|
||||
#ifdef DEFEX_TRUSTED_MAP_ENABLE
|
||||
struct PPTree dtm_tree;
|
||||
#endif
|
||||
|
||||
#endif /* DEFEX_RAMDISK_ENABLE */
|
||||
|
||||
#ifdef DEFEX_TRUSTED_MAP_ENABLE
|
||||
/* In loaded policy, title of DTM's section; set by tailer -t in buildscript/build_external/defex. */
|
||||
#define DEFEX_DTM_SECTION_NAME "dtm_rules"
|
||||
#endif
|
||||
|
||||
#ifdef DEFEX_INTEGRITY_ENABLE
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <crypto/hash.h>
|
||||
#include <crypto/public_key.h>
|
||||
#include <crypto/internal/rsa.h>
|
||||
#include "../../integrity/integrity.h"
|
||||
#define SHA256_DIGEST_SIZE 32
|
||||
#endif /* DEFEX_INTEGRITY_ENABLE */
|
||||
|
||||
struct rules_file_struct {
|
||||
char *name;
|
||||
int flags;
|
||||
};
|
||||
|
||||
static const struct rules_file_struct rules_files[4] = {
|
||||
{ "/dpolicy", LOAD_FLAG_DPOLICY },
|
||||
{ "/first_stage_ramdisk/dpolicy", LOAD_FLAG_DPOLICY },
|
||||
{ "/vendor/etc/dpolicy", LOAD_FLAG_DPOLICY },
|
||||
{ "/dpolicy_system", LOAD_FLAG_DPOLICY_SYSTEM }
|
||||
};
|
||||
static volatile unsigned int load_flags;
|
||||
static DEFINE_SPINLOCK(rules_data_lock);
|
||||
|
||||
static unsigned int get_load_flags(void)
|
||||
{
|
||||
unsigned int data;
|
||||
spin_lock(&rules_data_lock);
|
||||
data = load_flags;
|
||||
spin_unlock(&rules_data_lock);
|
||||
return data;
|
||||
}
|
||||
|
||||
static unsigned int update_load_flags(unsigned int new_flags)
|
||||
{
|
||||
unsigned int data;
|
||||
spin_lock(&rules_data_lock);
|
||||
data = load_flags;
|
||||
data |= new_flags;
|
||||
load_flags = data;
|
||||
spin_unlock(&rules_data_lock);
|
||||
return data;
|
||||
}
|
||||
|
||||
__visible_for_testing unsigned long get_current_sec(void)
|
||||
{
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 11, 0)
|
||||
return get_seconds();
|
||||
#else
|
||||
return ktime_get_seconds();
|
||||
#endif
|
||||
}
|
||||
|
||||
__visible_for_testing char *get_rules_ptr(int is_system)
|
||||
{
|
||||
char *ptr;
|
||||
|
||||
spin_lock(&rules_data_lock);
|
||||
if (load_flags & LOAD_FLAG_SYSTEM_FIRST)
|
||||
is_system = !is_system;
|
||||
ptr = is_system ? (char *)packed_rules_secondary : (char *)packed_rules_primary;
|
||||
spin_unlock(&rules_data_lock);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
__visible_for_testing int get_rules_size(int is_system)
|
||||
{
|
||||
struct rule_item_struct *rules_ptr = (struct rule_item_struct *)get_rules_ptr(is_system);
|
||||
|
||||
return rules_ptr ? rules_ptr->data_size : 0;
|
||||
}
|
||||
|
||||
int check_rules_ready(void)
|
||||
{
|
||||
struct rule_item_struct *base = (struct rule_item_struct *)packed_rules_primary;
|
||||
|
||||
return (!base || !base->data_size)?0:1;
|
||||
}
|
||||
|
||||
__visible_for_testing int check_system_mount(void)
|
||||
{
|
||||
static int mount_system_root = -1;
|
||||
struct file *fp;
|
||||
|
||||
if (mount_system_root < 0) {
|
||||
fp = local_fopen("/sbin/recovery", O_RDONLY, 0);
|
||||
if (IS_ERR(fp))
|
||||
fp = local_fopen("/system/bin/recovery", O_RDONLY, 0);
|
||||
|
||||
if (!IS_ERR(fp)) {
|
||||
defex_log_crit("Recovery mode");
|
||||
filp_close(fp, NULL);
|
||||
update_load_flags(LOAD_FLAG_RECOVERY);
|
||||
} else {
|
||||
defex_log_crit("Normal mode");
|
||||
}
|
||||
|
||||
mount_system_root = 0;
|
||||
fp = local_fopen("/system_root", O_DIRECTORY | O_PATH, 0);
|
||||
if (!IS_ERR(fp)) {
|
||||
filp_close(fp, NULL);
|
||||
mount_system_root = 1;
|
||||
defex_log_crit("System_root=TRUE");
|
||||
} else {
|
||||
defex_log_crit("System_root=FALSE");
|
||||
}
|
||||
}
|
||||
return (mount_system_root > 0);
|
||||
}
|
||||
|
||||
#ifdef DEFEX_INTEGRITY_ENABLE
|
||||
__visible_for_testing int defex_check_integrity(struct file *f, unsigned char *hash)
|
||||
{
|
||||
struct crypto_shash *handle = NULL;
|
||||
struct shash_desc *shash = NULL;
|
||||
static const unsigned char buff_zero[SHA256_DIGEST_SIZE] = {0};
|
||||
unsigned char hash_sha256[SHA256_DIGEST_SIZE];
|
||||
unsigned char *buff = NULL;
|
||||
size_t buff_size = PAGE_SIZE;
|
||||
loff_t file_size = 0;
|
||||
int ret = 0, err = 0, read_size = 0;
|
||||
|
||||
// A saved hash is zero, skip integrity check
|
||||
if (!memcmp(buff_zero, hash, SHA256_DIGEST_SIZE))
|
||||
return ret;
|
||||
|
||||
if (IS_ERR(f))
|
||||
goto hash_error;
|
||||
|
||||
handle = crypto_alloc_shash("sha256", 0, 0);
|
||||
if (IS_ERR(handle)) {
|
||||
err = PTR_ERR(handle);
|
||||
defex_log_err("Can't alloc sha256, error : %d", err);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
|
||||
shash = (struct shash_desc *)kvzalloc(sizeof(struct shash_desc) + crypto_shash_descsize(handle), GFP_KERNEL);
|
||||
#else
|
||||
shash = kzalloc(sizeof(struct shash_desc) + crypto_shash_descsize(handle), GFP_KERNEL);
|
||||
#endif /* < KERNEL_VERSION(4, 12, 0) */
|
||||
|
||||
if (shash == NULL)
|
||||
goto hash_error;
|
||||
|
||||
shash->tfm = handle;
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
|
||||
buff = kvmalloc(buff_size, GFP_KERNEL);
|
||||
#else
|
||||
buff = kmalloc(buff_size, GFP_KERNEL);
|
||||
#endif /* < KERNEL_VERSION(4, 12, 0) */
|
||||
|
||||
if (buff == NULL)
|
||||
goto hash_error;
|
||||
|
||||
err = crypto_shash_init(shash);
|
||||
if (err < 0)
|
||||
goto hash_error;
|
||||
|
||||
|
||||
while (1) {
|
||||
read_size = local_fread(f, file_size, (char *)buff, buff_size);
|
||||
if (read_size < 0)
|
||||
goto hash_error;
|
||||
if (read_size == 0)
|
||||
break;
|
||||
file_size += read_size;
|
||||
err = crypto_shash_update(shash, buff, read_size);
|
||||
if (err < 0)
|
||||
goto hash_error;
|
||||
}
|
||||
|
||||
err = crypto_shash_final(shash, hash_sha256);
|
||||
if (err < 0)
|
||||
goto hash_error;
|
||||
|
||||
ret = memcmp(hash_sha256, hash, SHA256_DIGEST_SIZE);
|
||||
|
||||
goto hash_exit;
|
||||
|
||||
hash_error:
|
||||
ret = -1;
|
||||
hash_exit:
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 12, 0)
|
||||
kvfree(buff);
|
||||
kvfree(shash);
|
||||
#else
|
||||
kfree(buff);
|
||||
kfree(shash);
|
||||
#endif /* < KERNEL_VERSION(4, 12, 0) */
|
||||
|
||||
if (handle)
|
||||
crypto_free_shash(handle);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
__visible_for_testing int defex_integrity_default(const char *file_path)
|
||||
{
|
||||
static const char integrity_default[] = "/system/bin/install-recovery.sh";
|
||||
|
||||
return strncmp(integrity_default, file_path, sizeof(integrity_default));
|
||||
}
|
||||
|
||||
#endif /* DEFEX_INTEGRITY_ENABLE */
|
||||
|
||||
#if defined(DEFEX_RAMDISK_ENABLE)
|
||||
|
||||
#ifdef DEFEX_TRUSTED_MAP_ENABLE
|
||||
static const unsigned char *find_policy_section(const char *name, const char *data, int data_size, long *section_size)
|
||||
{
|
||||
return data_size > 0 ? defex_tailerp_find(data, data_size, name, section_size) : 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
__visible_for_testing int check_rule_structure(unsigned char *data_buff)
|
||||
{
|
||||
struct rule_item_struct *rules_ptr = (struct rule_item_struct *)data_buff;
|
||||
int res = 0;
|
||||
const int req_size = sizeof(struct rule_item_struct) + rules_ptr->size;
|
||||
|
||||
#ifdef DEFEX_INTEGRITY_ENABLE
|
||||
const int integrity_state = 1;
|
||||
#else
|
||||
const int integrity_state = 0;
|
||||
#endif /* DEFEX_INTEGRITY_ENABLE */
|
||||
if (rules_ptr->next_level != req_size || memcmp(rules_ptr->name, "DEFEX_RULES_FILE", 16) != 0) {
|
||||
defex_log_err("Rules structure is wrong. Integrity state: %d", integrity_state);
|
||||
res = -1;
|
||||
} else {
|
||||
defex_log_info("Rules structure is OK. Integrity state: %d", integrity_state);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
__visible_for_testing int load_rules_common(struct file *f, int flags)
|
||||
{
|
||||
int res = -1, data_size, rules_size;
|
||||
unsigned char *data_buff = NULL;
|
||||
|
||||
data_size = i_size_read(file_inode(f));
|
||||
if (data_size <= 0 || data_size > DEFEX_RULES_ARRAY_SIZE_MAX)
|
||||
goto do_clean;
|
||||
data_buff = vmalloc(data_size);
|
||||
if (!data_buff)
|
||||
goto do_clean;
|
||||
|
||||
rules_size = local_fread(f, 0, data_buff, data_size);
|
||||
if (rules_size <= 0) {
|
||||
defex_log_err("Failed to read rules file (%d)", rules_size);
|
||||
goto do_clean;
|
||||
}
|
||||
defex_log_info("Read %d bytes", rules_size);
|
||||
|
||||
#ifdef DEFEX_SIGN_ENABLE
|
||||
res = defex_rules_signature_check((char *)data_buff, (unsigned int)rules_size, (unsigned int *)&rules_size);
|
||||
|
||||
if (!res)
|
||||
defex_log_info("Rules signature verified successfully");
|
||||
else
|
||||
defex_log_err("Rules signature incorrect!!!");
|
||||
#else
|
||||
res = 0;
|
||||
#endif
|
||||
|
||||
if (!res)
|
||||
res = check_rule_structure(data_buff);
|
||||
|
||||
if (!res) {
|
||||
const unsigned char *policy_data = NULL; /* where additional features like DTM could look for policy data */
|
||||
if (!(get_load_flags() & (LOAD_FLAG_DPOLICY | LOAD_FLAG_DPOLICY_SYSTEM))) {
|
||||
if (rules_size > sizeof(packed_rules_primary)) {
|
||||
res = -1;
|
||||
goto do_clean;
|
||||
}
|
||||
spin_lock(&rules_data_lock);
|
||||
memcpy(packed_rules_primary, data_buff, rules_size);
|
||||
spin_unlock(&rules_data_lock);
|
||||
policy_data = packed_rules_primary;
|
||||
if (flags & LOAD_FLAG_DPOLICY_SYSTEM)
|
||||
update_load_flags(LOAD_FLAG_SYSTEM_FIRST);
|
||||
defex_log_info("Primary rules have been stored");
|
||||
} else {
|
||||
if (rules_size > 0) {
|
||||
spin_lock(&rules_data_lock);
|
||||
packed_rules_secondary = data_buff;
|
||||
data_buff = NULL;
|
||||
spin_unlock(&rules_data_lock);
|
||||
policy_data = packed_rules_secondary;
|
||||
defex_log_info("Secondary rules have been stored");
|
||||
}
|
||||
}
|
||||
#ifdef DEFEX_SHOW_RULES_ENABLE
|
||||
if (policy_data)
|
||||
defex_show_structure((void *)policy_data, rules_size);
|
||||
#endif /* DEFEX_SHOW_RULES_ENABLE */
|
||||
#ifdef DEFEX_TRUSTED_MAP_ENABLE
|
||||
if (policy_data && !dtm_tree.data) { /* DTM not yet initialized */
|
||||
const unsigned char *dtm_section = find_policy_section(DEFEX_DTM_SECTION_NAME,
|
||||
policy_data, rules_size, 0);
|
||||
if (dtm_section)
|
||||
pptree_set_data(&dtm_tree, dtm_section);
|
||||
}
|
||||
#endif
|
||||
update_load_flags(flags);
|
||||
res = rules_size;
|
||||
}
|
||||
|
||||
do_clean:
|
||||
filp_close(f, NULL);
|
||||
vfree(data_buff);
|
||||
return res;
|
||||
}
|
||||
|
||||
int validate_file(const char *file_path)
|
||||
{
|
||||
struct path a_path;
|
||||
struct super_block *sb = NULL;
|
||||
struct dentry *root_dentry;
|
||||
int err, ret = 0;
|
||||
|
||||
err = kern_path(file_path, 0, &a_path);
|
||||
if (err)
|
||||
return ret;
|
||||
sb = a_path.dentry->d_sb;
|
||||
if (!sb)
|
||||
goto do_clean;
|
||||
if (!sb->s_type)
|
||||
goto do_clean;
|
||||
if (!sb->s_type->name || !sb->s_type->name[0])
|
||||
goto do_clean;
|
||||
root_dentry = dget(sb->s_root);
|
||||
if (!root_dentry)
|
||||
goto do_clean;
|
||||
dput(root_dentry);
|
||||
ret = 1;
|
||||
do_clean:
|
||||
path_put(&a_path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int load_rules_thread(void *params)
|
||||
{
|
||||
const unsigned int load_both_mask = (LOAD_FLAG_DPOLICY | LOAD_FLAG_DPOLICY_SYSTEM);
|
||||
struct file *f = NULL;
|
||||
int f_index;
|
||||
const struct rules_file_struct *item;
|
||||
unsigned long start_time, cur_time, last_time = 0;
|
||||
int load_counter = 0;
|
||||
|
||||
(void)params;
|
||||
|
||||
start_time = get_current_sec();
|
||||
while (!kthread_should_stop()) {
|
||||
cur_time = get_current_sec();
|
||||
if ((cur_time - last_time) < 5) {
|
||||
if (msleep_interruptible(1000) != 0)
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
last_time = cur_time;
|
||||
|
||||
if ((cur_time - start_time) > 600) {
|
||||
update_load_flags(LOAD_FLAG_TIMEOUT);
|
||||
defex_log_warn("Late load timeout. Try counter = %d", load_counter);
|
||||
break;
|
||||
}
|
||||
load_counter++;
|
||||
|
||||
for (f_index = 0; f_index < ARRAY_SIZE(rules_files); f_index++) {
|
||||
item = &rules_files[f_index];
|
||||
if (!(get_load_flags() & item->flags) && validate_file(item->name)) {
|
||||
f = local_fopen(item->name, O_RDONLY, 0);
|
||||
if (!IS_ERR_OR_NULL(f)) {
|
||||
defex_log_info("Late load rules file: %s", item->name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (IS_ERR_OR_NULL(f)) {
|
||||
#ifdef DEFEX_KERNEL_ONLY
|
||||
defex_log_err("Failed to open rules file (%ld)", (long)PTR_ERR(f));
|
||||
#endif /* DEFEX_KERNEL_ONLY */
|
||||
} else
|
||||
load_rules_common(f, item->flags);
|
||||
if ((get_load_flags() & load_both_mask) == load_both_mask)
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int load_rules_late(int forced_load)
|
||||
{
|
||||
int res = 0;
|
||||
static atomic_t load_lock = ATOMIC_INIT(1);
|
||||
static int first_entry;
|
||||
struct task_struct *thread_ptr;
|
||||
|
||||
if (get_load_flags() & LOAD_FLAG_TIMEOUT)
|
||||
return -1;
|
||||
|
||||
if (!atomic_dec_and_test(&load_lock)) {
|
||||
atomic_inc(&load_lock);
|
||||
return res;
|
||||
}
|
||||
|
||||
/* The first try to load, initialize time values and start the kernel thread */
|
||||
if (!first_entry) {
|
||||
first_entry = 1;
|
||||
thread_ptr = kthread_create(load_rules_thread, NULL, "defex_load_thread");
|
||||
if (IS_ERR_OR_NULL(thread_ptr)) {
|
||||
res = -1;
|
||||
update_load_flags(LOAD_FLAG_TIMEOUT);
|
||||
goto do_exit;
|
||||
}
|
||||
wake_up_process(thread_ptr);
|
||||
}
|
||||
|
||||
do_exit:
|
||||
atomic_inc(&load_lock);
|
||||
return res;
|
||||
}
|
||||
|
||||
int __init do_load_rules(void)
|
||||
{
|
||||
struct file *f = NULL;
|
||||
int res = -1;
|
||||
unsigned int f_index = 0;
|
||||
const struct rules_file_struct *item;
|
||||
|
||||
if (boot_state_recovery)
|
||||
update_load_flags(LOAD_FLAG_RECOVERY);
|
||||
|
||||
load_next:
|
||||
while (f_index < ARRAY_SIZE(rules_files)) {
|
||||
item = &rules_files[f_index];
|
||||
if (!(get_load_flags() & item->flags)) {
|
||||
f = local_fopen(item->name, O_RDONLY, 0);
|
||||
if (!IS_ERR_OR_NULL(f)) {
|
||||
defex_log_info("Load rules file: %s", item->name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
f_index++;
|
||||
};
|
||||
|
||||
if (f_index == ARRAY_SIZE(rules_files)) {
|
||||
if (get_load_flags() & (LOAD_FLAG_DPOLICY_SYSTEM | LOAD_FLAG_DPOLICY))
|
||||
return 0;
|
||||
defex_log_err("Failed to open rules file (%ld)", (long)PTR_ERR(f));
|
||||
|
||||
#ifdef DEFEX_KERNEL_ONLY
|
||||
if (get_load_flags() & LOAD_FLAG_RECOVERY)
|
||||
res = 0;
|
||||
#endif /* DEFEX_KERNEL_ONLY */
|
||||
return res;
|
||||
}
|
||||
|
||||
res = load_rules_common(f, item->flags);
|
||||
res = (res < 0) ? res : 0;
|
||||
|
||||
#ifdef DEFEX_KERNEL_ONLY
|
||||
if ((get_load_flags() & LOAD_FLAG_RECOVERY) && res != 0) {
|
||||
res = 0;
|
||||
defex_log_info("Kernel Only & recovery mode, rules loading is passed");
|
||||
}
|
||||
#endif
|
||||
if (++f_index < ARRAY_SIZE(rules_files))
|
||||
goto load_next;
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif /* DEFEX_RAMDISK_ENABLE */
|
||||
|
||||
__visible_for_testing struct rule_item_struct *lookup_dir(struct rule_item_struct *base,
|
||||
const char *name,
|
||||
int l,
|
||||
int attribute,
|
||||
char *base_start)
|
||||
{
|
||||
struct rule_item_struct *item = NULL, *tmp_item_attr = NULL, *tmp_item_rec = NULL;
|
||||
unsigned int offset, feature;
|
||||
unsigned int feature_mask = attribute & (~feature_for_recovery);
|
||||
unsigned int recovery_mask = attribute & feature_for_recovery;
|
||||
|
||||
if (!base || !base_start)
|
||||
return item;
|
||||
offset = base->next_level;
|
||||
item = GET_ITEM_PTR(offset, base_start);
|
||||
while (offset) {
|
||||
if (item->size == l && !memcmp(name, item->name, l)) {
|
||||
feature = item->feature_type;
|
||||
if (!(feature & feature_is_file))
|
||||
return item;
|
||||
if ((feature & feature_mask) == feature_mask)
|
||||
tmp_item_attr = item;
|
||||
if ((feature & feature_for_recovery) == recovery_mask)
|
||||
tmp_item_rec = item;
|
||||
if (tmp_item_attr && tmp_item_attr == tmp_item_rec)
|
||||
break;
|
||||
}
|
||||
offset = item->next_file;
|
||||
item = GET_ITEM_PTR(offset, base_start);
|
||||
}
|
||||
return (tmp_item_attr) ? tmp_item_attr : tmp_item_rec;
|
||||
}
|
||||
|
||||
__visible_for_testing int lookup_tree(const char *file_path,
|
||||
int attribute,
|
||||
struct file *f,
|
||||
struct rule_item_struct **found_item)
|
||||
{
|
||||
const char *ptr, *next_separator;
|
||||
struct rule_item_struct *base, *cur_item = NULL;
|
||||
char *base_start;
|
||||
int l, is_system, forced_load = 0;
|
||||
const int is_recovery = (get_load_flags() & LOAD_FLAG_RECOVERY) ? feature_for_recovery : 0;
|
||||
const unsigned int load_both_mask = (LOAD_FLAG_DPOLICY | LOAD_FLAG_DPOLICY_SYSTEM);
|
||||
int iterator = 0;
|
||||
|
||||
if (found_item)
|
||||
*found_item = NULL;
|
||||
|
||||
if (!file_path || *file_path != '/')
|
||||
return 0;
|
||||
|
||||
is_system = ((strncmp("/system/", file_path, 8) == 0) ||
|
||||
(strncmp("/product/", file_path, 9) == 0) ||
|
||||
(strncmp("/apex/", file_path, 6) == 0) ||
|
||||
(strncmp("/system_ext/", file_path, 12) == 0) ||
|
||||
(strncmp("/postinstall/system/", file_path, 20) == 0)) ? 1 : 0;
|
||||
|
||||
if ((get_load_flags() & load_both_mask) != load_both_mask &&
|
||||
!(get_load_flags() & LOAD_FLAG_TIMEOUT)) {
|
||||
/* allow all requests if rules were not loaded for Recovery mode */
|
||||
if (!load_rules_late(forced_load) || is_recovery)
|
||||
return (attribute == feature_ped_exception ||
|
||||
attribute == feature_umhbin_path ||
|
||||
attribute == feature_safeplace_path) ? 1 : 0;
|
||||
}
|
||||
|
||||
try_not_system:
|
||||
|
||||
base_start = get_rules_ptr(get_rules_size(is_system) ? is_system : (!is_system));
|
||||
base = (struct rule_item_struct *)base_start;
|
||||
|
||||
if (!base || !base->data_size) {
|
||||
/* block all requests if rules were not loaded */
|
||||
return 0;
|
||||
}
|
||||
|
||||
ptr = file_path + 1;
|
||||
do {
|
||||
next_separator = strchr(ptr, '/');
|
||||
if (!next_separator)
|
||||
l = strlen(ptr);
|
||||
else
|
||||
l = next_separator - ptr;
|
||||
if (!l)
|
||||
return 0;
|
||||
cur_item = lookup_dir(base, ptr, l, attribute | is_recovery, base_start);
|
||||
if (!cur_item)
|
||||
break;
|
||||
|
||||
ptr += l;
|
||||
if (next_separator)
|
||||
ptr++;
|
||||
|
||||
if (cur_item->feature_type & attribute) {
|
||||
#ifdef DEFEX_INTEGRITY_ENABLE
|
||||
/* Integrity acceptable only for files */
|
||||
if ((cur_item->feature_type & feature_integrity_check) &&
|
||||
(cur_item->feature_type & feature_is_file) && f) {
|
||||
if (defex_integrity_default(file_path)
|
||||
&& defex_check_integrity(f, cur_item->integrity))
|
||||
return DEFEX_INTEGRITY_FAIL;
|
||||
}
|
||||
#endif /* DEFEX_INTEGRITY_ENABLE */
|
||||
if (attribute & (feature_immutable_path_open | feature_immutable_path_write)
|
||||
&& !(cur_item->feature_type & feature_is_file)) {
|
||||
/* Allow open the folder by default */
|
||||
if (!*ptr)
|
||||
return 0;
|
||||
}
|
||||
if (found_item)
|
||||
*found_item = cur_item;
|
||||
return GET_ITEM_OFFSET(cur_item, base_start);
|
||||
}
|
||||
base = cur_item;
|
||||
} while (*ptr);
|
||||
if ((get_load_flags() & load_both_mask) == load_both_mask && ++iterator < 2) {
|
||||
is_system = !is_system;
|
||||
goto try_not_system;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rules_lookup(const char *target_file, int attribute, struct file *f, struct rule_item_struct **found_item)
|
||||
{
|
||||
int ret = 0;
|
||||
#if (defined(DEFEX_SAFEPLACE_ENABLE) || defined(DEFEX_IMMUTABLE_ENABLE) || defined(DEFEX_PED_ENABLE))
|
||||
static const char system_root_txt[] = "/system_root";
|
||||
|
||||
if (check_system_mount() &&
|
||||
!strncmp(target_file, system_root_txt, sizeof(system_root_txt) - 1))
|
||||
target_file += (sizeof(system_root_txt) - 1);
|
||||
|
||||
ret = lookup_tree(target_file, attribute, f, found_item);
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
void __init defex_load_rules(void)
|
||||
{
|
||||
#if defined(DEFEX_RAMDISK_ENABLE)
|
||||
if (!boot_state_unlocked && do_load_rules() != 0) {
|
||||
#if !(defined(DEFEX_DEBUG_ENABLE) || defined(DEFEX_KERNEL_ONLY))
|
||||
panic("[DEFEX] Signature mismatch.\n");
|
||||
#endif
|
||||
}
|
||||
#endif /* DEFEX_RAMDISK_ENABLE */
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/async.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/initrd.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/version.h>
|
||||
|
||||
#include "include/defex_debug.h"
|
||||
#include "include/defex_internal.h"
|
||||
#include "include/defex_rules.h"
|
||||
|
||||
static struct kset *defex_kset;
|
||||
|
||||
int __init defex_init_sysfs(void)
|
||||
{
|
||||
defex_kset = kset_create_and_add("defex", NULL, NULL);
|
||||
if (!defex_kset)
|
||||
return -ENOMEM;
|
||||
|
||||
#if defined(DEFEX_DEBUG_ENABLE)
|
||||
if (defex_create_debug(defex_kset) != DEFEX_OK)
|
||||
goto kset_error;
|
||||
#endif /* DEFEX_DEBUG_ENABLE */
|
||||
|
||||
return 0;
|
||||
|
||||
kset_error:
|
||||
kset_unregister(defex_kset);
|
||||
defex_kset = NULL;
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
|
@ -1,98 +0,0 @@
|
|||
/* Routines for handling archival-like files where each new contents is
|
||||
* appended and linked backwards - memory-only variants.
|
||||
*/
|
||||
|
||||
#include <linux/string.h>
|
||||
#include "include/defex_tailer.h"
|
||||
|
||||
/* Reads int from 4-byte big-endian */
|
||||
static int be2int(const unsigned char *p)
|
||||
{
|
||||
return (*p << 24) + (p[1] << 16) + (p[2] << 8) + p[3];
|
||||
}
|
||||
|
||||
long defex_tailerp_has_suffix(const unsigned char *p, long size)
|
||||
{
|
||||
return !p || size < TAIL_MAGIC_LEN + 8 + 1 + 2 ||
|
||||
memcmp(p + size - TAIL_MAGIC_LEN, TAIL_MAGIC, TAIL_MAGIC_LEN)
|
||||
? 0 : size - TAIL_MAGIC_LEN;
|
||||
}
|
||||
|
||||
int defex_tailerp_iterate(const unsigned char *p, long size,
|
||||
int (*task)(const char *title, int titleLen,
|
||||
const unsigned char *start, long size,
|
||||
void *data),
|
||||
void *data)
|
||||
{
|
||||
long start, offset = defex_tailerp_has_suffix(p, size);
|
||||
char buffer[TAIL_MAX_TITLE_LENGTH];
|
||||
|
||||
if (!offset)
|
||||
return 0;
|
||||
for (offset -= 2; ; offset = start - 2) {
|
||||
int i, ttlLength;
|
||||
long size;
|
||||
|
||||
/* Possibly change behavior depending on version
|
||||
* (p[offset] and p[offset + 1])
|
||||
*/
|
||||
ttlLength = p[--offset];
|
||||
if (offset - 4 - 4 - ttlLength < 0)
|
||||
return -1;
|
||||
memcpy(buffer, p + (offset -= ttlLength), ttlLength);
|
||||
size = be2int(p + (offset -= 4));
|
||||
start = be2int(p + (offset -= 4));
|
||||
if (task) {
|
||||
i = (*task)(buffer, ttlLength,
|
||||
p + start, size, data);
|
||||
if (i < 0)
|
||||
return i;
|
||||
}
|
||||
if (!start)
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Auxiliary data for finding an entry */
|
||||
struct find_data {
|
||||
const char *title;
|
||||
int titleLen;
|
||||
int found;
|
||||
const unsigned char *start;
|
||||
long size;
|
||||
};
|
||||
|
||||
static int tailerp_iteratefind(const char *title, int titleLen,
|
||||
const unsigned char *start, long size,
|
||||
void *data)
|
||||
{
|
||||
struct find_data *fd = (struct find_data *)data;
|
||||
|
||||
if (fd->titleLen == titleLen &&
|
||||
!memcmp(title, fd->title, titleLen)) {
|
||||
fd->found = 1;
|
||||
fd->start = start;
|
||||
fd->size = size;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const unsigned char *defex_tailerp_find(const unsigned char *p, long size,
|
||||
const char *title, long *sizep)
|
||||
{
|
||||
struct find_data fd;
|
||||
|
||||
fd.title = title;
|
||||
fd.titleLen = strlen(title);
|
||||
fd.found = 0;
|
||||
if (!defex_tailerp_iterate(p, size, tailerp_iteratefind, &fd))
|
||||
return 0;
|
||||
if (fd.found) {
|
||||
if (sizep)
|
||||
*sizep = fd.size;
|
||||
return fd.start;
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -1,411 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/cred.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kobject.h>
|
||||
#ifdef DEFEX_LOG_BUFFER_ENABLE
|
||||
#include <linux/ktime.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/rculist.h>
|
||||
#endif /* DEFEX_LOG_BUFFER_ENABLE */
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#ifdef DEFEX_LOG_BUFFER_ENABLE
|
||||
#include <linux/spinlock.h>
|
||||
#endif /* DEFEX_LOG_BUFFER_ENABLE */
|
||||
#include <linux/string.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include "include/defex_debug.h"
|
||||
#include "include/defex_internal.h"
|
||||
|
||||
static int last_cmd;
|
||||
|
||||
#ifdef DEFEX_LOG_BUFFER_ENABLE
|
||||
unsigned char *log_buf;
|
||||
DEFINE_SPINLOCK(log_buf_lock);
|
||||
static unsigned int log_buf_in_index, log_buf_out_index;
|
||||
static unsigned long log_buf_size, log_buf_mask;
|
||||
|
||||
static int log_buf_init(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
log_buf_size = DEFEX_LOG_BUF_SIZE;
|
||||
do {
|
||||
log_buf = vmalloc(log_buf_size);
|
||||
if (log_buf)
|
||||
break;
|
||||
log_buf_size >>= 1;
|
||||
} while (log_buf_size > PAGE_SIZE);
|
||||
if (!log_buf)
|
||||
ret = -1;
|
||||
|
||||
log_buf_in_index = 0;
|
||||
log_buf_out_index = 0;
|
||||
log_buf_mask = log_buf_size - 1;
|
||||
|
||||
defex_log_info("Log buffer size set to %ld bytes", log_buf_size);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int log_buffer_put(const char *msg, int msg_len)
|
||||
{
|
||||
char c;
|
||||
int avail, ret = -1;
|
||||
|
||||
if (!log_buf_size)
|
||||
return ret;
|
||||
|
||||
spin_lock(&log_buf_lock);
|
||||
avail = log_buf_size - ((log_buf_in_index - log_buf_out_index) & log_buf_mask);
|
||||
if (avail > msg_len) {
|
||||
do {
|
||||
c = *msg++;
|
||||
log_buf[log_buf_in_index++] = c;
|
||||
log_buf_in_index &= log_buf_mask;
|
||||
} while (--msg_len);
|
||||
if (c != '\n') {
|
||||
log_buf[log_buf_in_index++] = '\n';
|
||||
log_buf_in_index &= log_buf_mask;
|
||||
}
|
||||
ret = 0;
|
||||
}
|
||||
spin_unlock(&log_buf_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int log_buffer_get(char *str, int buff_size)
|
||||
{
|
||||
char value;
|
||||
int index = 0;
|
||||
unsigned int log_buf_out_local;
|
||||
|
||||
if (log_buf_in_index == log_buf_out_index || buff_size < 2)
|
||||
return 0;
|
||||
|
||||
spin_lock(&log_buf_lock);
|
||||
log_buf_out_local = log_buf_out_index;
|
||||
do {
|
||||
value = log_buf[log_buf_out_local++];
|
||||
str[index++] = value;
|
||||
log_buf_out_local &= log_buf_mask;
|
||||
if (value == '\n') {
|
||||
str[index] = 0;
|
||||
log_buf_out_index = log_buf_out_local;
|
||||
spin_unlock(&log_buf_lock);
|
||||
return index;
|
||||
}
|
||||
} while (--buff_size > 1 && (log_buf_in_index != log_buf_out_local));
|
||||
spin_unlock(&log_buf_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void log_buffer_flush(void)
|
||||
{
|
||||
char msg[MAX_LEN];
|
||||
int msg_len;
|
||||
|
||||
pr_info("%s== Buffer flushing begin ==", DEFEX_LOG_TAG);
|
||||
|
||||
do {
|
||||
msg_len = log_buffer_get(&msg[0], MAX_LEN);
|
||||
if (msg_len)
|
||||
pr_info("%s", msg);
|
||||
} while (msg_len);
|
||||
|
||||
pr_info("%s== Buffer flushing end ==", DEFEX_LOG_TAG);
|
||||
}
|
||||
#endif /* DEFEX_LOG_BUFFER_ENABLE */
|
||||
|
||||
void defex_print_msg(const enum defex_log_level msg_type, const char *format, ...)
|
||||
{
|
||||
char msg[MAX_LEN];
|
||||
int msg_len, ktime_msg_len = 0;
|
||||
va_list aptr;
|
||||
static const char header[] = DEFEX_LOG_TAG;
|
||||
|
||||
#ifdef DEFEX_LOG_BUFFER_ENABLE
|
||||
if ((msg_type != MSG_TIMEOFF) && (msg_type != MSG_BLOB)) {
|
||||
ktime_t cur_time = ktime_get_boottime();
|
||||
|
||||
ktime_msg_len = snprintf(msg, MAX_LEN,
|
||||
"[% 4lld.%04lld] ", cur_time/1000000000, (cur_time%1000000000)/100000);
|
||||
}
|
||||
#endif /* DEFEX_LOG_BUFFER_ENABLE */
|
||||
|
||||
va_start(aptr, format);
|
||||
msg_len = vsnprintf(msg + ktime_msg_len, MAX_LEN - ktime_msg_len, format, aptr);
|
||||
va_end(aptr);
|
||||
#ifdef DEFEX_LOG_BUFFER_ENABLE
|
||||
if (DEFEX_LOG_LEVEL_MASK & msg_type)
|
||||
if (!log_buffer_put(msg, msg_len + ktime_msg_len))
|
||||
return;
|
||||
#endif /* DEFEX_LOG_BUFFER_ENABLE */
|
||||
switch (msg_type) {
|
||||
case MSG_CRIT:
|
||||
pr_crit("%s%s\n", header, msg + ktime_msg_len);
|
||||
break;
|
||||
case MSG_ERR:
|
||||
pr_err("%s%s\n", header, msg + ktime_msg_len);
|
||||
break;
|
||||
case MSG_WARN:
|
||||
pr_warn("%s%s\n", header, msg + ktime_msg_len);
|
||||
break;
|
||||
case MSG_INFO:
|
||||
case MSG_TIMEOFF:
|
||||
pr_info("%s%s\n", header, msg + ktime_msg_len);
|
||||
break;
|
||||
case MSG_DEBUG:
|
||||
pr_debug("%s%s\n", header, msg + ktime_msg_len);
|
||||
break;
|
||||
case MSG_BLOB:
|
||||
pr_crit("%s\n", msg + ktime_msg_len);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void blob(const char *title, const char *buffer, const size_t bufLen, const int lineSize)
|
||||
{
|
||||
size_t i = 0, line;
|
||||
size_t j = 0, len = bufLen;
|
||||
int offset;
|
||||
char c, stringToPrint[MAX_DATA_LEN];
|
||||
|
||||
defex_log_blob("%s", title);
|
||||
|
||||
do {
|
||||
line = (len > lineSize)?lineSize:len;
|
||||
offset = 0;
|
||||
offset += snprintf(stringToPrint + offset, MAX_DATA_LEN - offset, "| 0x%08lX | ", i);
|
||||
|
||||
for (j = 0; j < line; j++)
|
||||
offset += snprintf(stringToPrint + offset, MAX_DATA_LEN - offset, "%02X ",
|
||||
(unsigned char)buffer[i + j]);
|
||||
if (line < lineSize) {
|
||||
for (j = 0; j < lineSize - line; j++)
|
||||
offset += snprintf(stringToPrint + offset, MAX_DATA_LEN - offset, " ");
|
||||
}
|
||||
offset += snprintf(stringToPrint + offset, MAX_DATA_LEN - offset, "| ");
|
||||
|
||||
for (j = 0; j < line; j++) {
|
||||
c = buffer[i + j];
|
||||
c = (c < 0x20) || (c >= 0x7F)?'.':c;
|
||||
offset += snprintf(stringToPrint + offset, MAX_DATA_LEN - offset, "%c", c);
|
||||
}
|
||||
if (line < lineSize) {
|
||||
for (j = 0; j < lineSize - line; j++)
|
||||
offset += snprintf(stringToPrint + offset, MAX_DATA_LEN - offset, " ");
|
||||
}
|
||||
|
||||
snprintf(stringToPrint + offset, MAX_DATA_LEN - offset, " |");
|
||||
defex_log_blob("%s", stringToPrint);
|
||||
memset(stringToPrint, 0, MAX_DATA_LEN);
|
||||
i += line;
|
||||
len -= line;
|
||||
} while (len);
|
||||
}
|
||||
|
||||
__visible_for_testing int set_user(struct cred *new_cred)
|
||||
{
|
||||
struct user_struct *new_user;
|
||||
|
||||
new_user = alloc_uid(new_cred->uid);
|
||||
if (!new_user)
|
||||
return -EAGAIN;
|
||||
|
||||
free_uid(new_cred->user);
|
||||
new_cred->user = new_user;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* target_id = (0 - set all uids, 1 - set fsuid, 2 - set all gids)
|
||||
*/
|
||||
__visible_for_testing int set_cred(int target_id, int new_val)
|
||||
{
|
||||
struct user_namespace *ns = current_user_ns();
|
||||
const struct cred *old_cred;
|
||||
struct cred *new_cred;
|
||||
kuid_t kuid;
|
||||
kgid_t kgid;
|
||||
uid_t new_uid;
|
||||
gid_t new_gid;
|
||||
|
||||
new_cred = prepare_creds();
|
||||
if (!new_cred)
|
||||
return -ENOMEM;
|
||||
old_cred = current_cred();
|
||||
|
||||
switch (target_id) {
|
||||
case 0:
|
||||
new_uid = new_val;
|
||||
kuid = make_kuid(ns, new_uid);
|
||||
if (!uid_valid(kuid))
|
||||
goto do_abort;
|
||||
new_cred->uid = new_cred->euid = new_cred->suid = new_cred->fsuid = kuid;
|
||||
if (!uid_eq(new_cred->uid, old_cred->uid)) {
|
||||
if (set_user(new_cred) < 0)
|
||||
goto do_abort;
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
new_uid = new_val;
|
||||
kuid = make_kuid(ns, new_uid);
|
||||
if (!uid_valid(kuid))
|
||||
goto do_abort;
|
||||
new_cred->fsuid = kuid;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
new_gid = new_val;
|
||||
kgid = make_kgid(ns, new_gid);
|
||||
if (!gid_valid(kgid))
|
||||
goto do_abort;
|
||||
new_cred->gid = new_cred->egid = new_cred->sgid = new_cred->fsgid = kgid;
|
||||
break;
|
||||
}
|
||||
return commit_creds(new_cred);
|
||||
|
||||
do_abort:
|
||||
abort_creds(new_cred);
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
__visible_for_testing ssize_t debug_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count)
|
||||
{
|
||||
struct task_struct *p = current;
|
||||
int i, l, new_val = -1;
|
||||
int ret = 0;
|
||||
|
||||
static const char *prefix[] = {
|
||||
"uid=",
|
||||
"fsuid=",
|
||||
"gid=",
|
||||
"pe_status=",
|
||||
"im_status=",
|
||||
"sp_status=",
|
||||
"int_status=",
|
||||
"get_log"
|
||||
};
|
||||
|
||||
if (!buf || !p)
|
||||
return -EINVAL;
|
||||
|
||||
for (i = 0; i < sizeof(prefix) / sizeof(prefix[0]); i++) {
|
||||
l = strlen(prefix[i]);
|
||||
if (!strncmp(buf, prefix[i], l))
|
||||
break;
|
||||
}
|
||||
if (i == (sizeof(prefix) / sizeof(prefix[0])))
|
||||
return -EINVAL;
|
||||
|
||||
switch (i) {
|
||||
case DBG_SETUID ... DBG_SETGID:
|
||||
ret = kstrtoint(buf + l, 10, &new_val);
|
||||
if (ret != 0)
|
||||
return -EINVAL;
|
||||
ret = set_cred(i, new_val);
|
||||
break;
|
||||
case DBG_SET_PE_STATUS:
|
||||
#ifdef DEFEX_PED_ENABLE
|
||||
privesc_status_store(buf + l);
|
||||
#endif /* DEFEX_PED_ENABLE */
|
||||
break;
|
||||
case DBG_SET_IM_STATUS:
|
||||
#ifdef DEFEX_IMMUTABLE_ENABLE
|
||||
immutable_status_store(buf + l);
|
||||
#endif /* DEFEX_IMMUTABLE_ENABLE */
|
||||
break;
|
||||
case DBG_SET_SP_STATUS:
|
||||
#ifdef DEFEX_SAFEPLACE_ENABLE
|
||||
safeplace_status_store(buf + l);
|
||||
#endif /* DEFEX_SAFEPLACE_ENABLE */
|
||||
break;
|
||||
case DBG_SET_INT_STATUS:
|
||||
#ifdef DEFEX_INTEGRITY_ENABLE
|
||||
integrity_status_store(buf + l);
|
||||
#endif /* DEFEX_INTEGRITY_ENABLE */
|
||||
break;
|
||||
case DBG_GET_LOG:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
last_cmd = i;
|
||||
return (!ret)?count:ret;
|
||||
}
|
||||
|
||||
__visible_for_testing ssize_t debug_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
|
||||
{
|
||||
struct task_struct *p = current;
|
||||
int res = 0;
|
||||
#ifdef DEFEX_LOG_BUFFER_ENABLE
|
||||
int buff_size, msg_len;
|
||||
#endif /* DEFEX_LOG_BUFFER_ENABLE */
|
||||
|
||||
if (!p)
|
||||
return 0;
|
||||
|
||||
switch (last_cmd) {
|
||||
case DBG_SETUID ... DBG_SETGID:
|
||||
res = snprintf(buf, MAX_LEN + 1, "pid=%d\nuid=%d\ngid=%d\neuid=%d\negid=%d\n",
|
||||
p->pid,
|
||||
uid_get_value(p->cred->uid),
|
||||
uid_get_value(p->cred->gid),
|
||||
uid_get_value(p->cred->euid),
|
||||
uid_get_value(p->cred->egid));
|
||||
break;
|
||||
case DBG_GET_LOG:
|
||||
#ifdef DEFEX_LOG_BUFFER_ENABLE
|
||||
buff_size = PAGE_SIZE;
|
||||
do {
|
||||
msg_len = log_buffer_get(&buf[res], buff_size);
|
||||
res += msg_len;
|
||||
buff_size -= msg_len;
|
||||
} while (msg_len && buff_size >= MAX_LEN);
|
||||
if (!msg_len)
|
||||
res += snprintf(&buf[res], buff_size, "=== EOF ===\n");
|
||||
else
|
||||
res += snprintf(&buf[res], buff_size, "=== %lu bytes left ===\n",
|
||||
(unsigned long)(log_buf_in_index - log_buf_out_index) & DEFEX_LOG_BUF_MASK);
|
||||
#else
|
||||
res = snprintf(buf, MAX_LEN + 1, "Log buffer disabled...\n");
|
||||
#endif /* DEFEX_LOG_BUFFER_ENABLE */
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
__visible_for_testing struct kobj_attribute debug_attribute = __ATTR(debug, 0660, debug_show, debug_store);
|
||||
|
||||
int defex_create_debug(struct kset *defex_kset)
|
||||
{
|
||||
int retval;
|
||||
|
||||
#ifdef DEFEX_LOG_BUFFER_ENABLE
|
||||
retval = log_buf_init();
|
||||
if (retval)
|
||||
defex_log_err("Log buffer init failed. Log output only via /dev/kmsg");
|
||||
else
|
||||
defex_log_info("Logging started...");
|
||||
#endif /* DEFEX_LOG_BUFFER_ENABLE */
|
||||
last_cmd = DBG_GET_LOG;
|
||||
|
||||
retval = sysfs_create_file(&defex_kset->kobj, &debug_attribute.attr);
|
||||
if (retval)
|
||||
return DEFEX_NOK;
|
||||
|
||||
kobject_uevent(&defex_kset->kobj, KOBJ_ADD);
|
||||
return DEFEX_OK;
|
||||
}
|
|
@ -1,177 +0,0 @@
|
|||
#include <linux/kobject.h>
|
||||
|
||||
#include "include/defex_debug.h"
|
||||
#include "include/defex_rules.h"
|
||||
|
||||
const char header_name[16] = {"DEFEX_RULES_FILE"};
|
||||
struct rule_item_struct *defex_packed_rules;
|
||||
static char work_path[512];
|
||||
static int packfiles_size, global_data_size;
|
||||
|
||||
|
||||
const struct feature_match_entry feature_match[] = {
|
||||
{"feature_safeplace_path", feature_safeplace_path},
|
||||
{"feature_ped_exception", feature_ped_exception},
|
||||
{"feature_immutable_path_open", feature_immutable_path_open},
|
||||
{"feature_immutable_path_write", feature_immutable_path_write},
|
||||
{"feature_immutable_src_exception", feature_immutable_src_exception},
|
||||
{"feature_immutable_dst_exception", feature_immutable_dst_exception},
|
||||
{"feature_umhbin_path", feature_umhbin_path},
|
||||
{"feature_integrity_check", feature_integrity_check},
|
||||
};
|
||||
|
||||
static void feature_to_str(char *str, unsigned short flags)
|
||||
{
|
||||
int i;
|
||||
|
||||
str[0] = 0;
|
||||
for (i = 0; i < ARRAY_SIZE(feature_match); i++)
|
||||
if (flags & feature_match[i].feature_num) {
|
||||
if (str[0])
|
||||
strcat(str, ", ");
|
||||
strcat(str, feature_match[i].feature_name);
|
||||
}
|
||||
if (flags & feature_for_recovery) {
|
||||
if (str[0])
|
||||
strcat(str, ", ");
|
||||
strcat(str, "feature_for_recovery");
|
||||
}
|
||||
}
|
||||
|
||||
static int check_array_size(struct rule_item_struct *ptr)
|
||||
{
|
||||
unsigned long offset = (unsigned long)ptr - (unsigned long)defex_packed_rules;
|
||||
int min_size = (global_data_size < packfiles_size)?global_data_size:packfiles_size;
|
||||
|
||||
offset += sizeof(struct rule_item_struct);
|
||||
|
||||
if (offset > min_size)
|
||||
return 1;
|
||||
|
||||
offset += ptr->size;
|
||||
if (offset > min_size)
|
||||
return 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_items(struct rule_item_struct *base, int path_length, int level)
|
||||
{
|
||||
int l, err, ret = 0, is_rule_part2;
|
||||
unsigned int offset;
|
||||
struct rule_item_struct *child_item;
|
||||
static char feature_list[128];
|
||||
|
||||
if (level > 8) {
|
||||
defex_log_timeoff("Level is too deep");
|
||||
return -1;
|
||||
|
||||
}
|
||||
if (path_length > (sizeof(work_path) - 128)) {
|
||||
defex_log_timeoff("Work path is too long");
|
||||
return -1;
|
||||
}
|
||||
while (base) {
|
||||
err = check_array_size(base);
|
||||
if (err) {
|
||||
defex_log_timeoff("%s/<?> - out of array bounds", work_path);
|
||||
return -1;
|
||||
}
|
||||
l = base->size;
|
||||
if (!l) {
|
||||
defex_log_timeoff("WARNING: Name field is incorrect, structure error!");
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
memcpy(work_path + path_length, base->name, l);
|
||||
l += path_length;
|
||||
work_path[l] = 0;
|
||||
offset = base->next_level;
|
||||
is_rule_part2 = (offset && (base->feature_type & feature_is_file) &&
|
||||
(base->feature_type & feature_immutable_src_exception));
|
||||
|
||||
if (offset && !is_rule_part2) {
|
||||
if (base->feature_type & feature_is_file) {
|
||||
defex_log_timeoff("%s - is a file, but has children, structure error!", work_path);
|
||||
ret = -1;
|
||||
} else if (base->feature_type != 0) {
|
||||
feature_to_str(feature_list, base->feature_type);
|
||||
defex_log_blob("%s%c - %s", work_path,
|
||||
((base->feature_type & feature_is_file)?' ':'/'), feature_list);
|
||||
}
|
||||
child_item = GET_ITEM_PTR(offset, defex_packed_rules);
|
||||
work_path[l++] = '/';
|
||||
work_path[l] = 0;
|
||||
err = check_array_size(child_item);
|
||||
if (!err) {
|
||||
err = parse_items(child_item, l, level + 1);
|
||||
if (err != 0)
|
||||
return err;
|
||||
} else {
|
||||
defex_log_timeoff("%s/<?> - out of array bounds", work_path);
|
||||
ret = -1;
|
||||
}
|
||||
} else {
|
||||
feature_to_str(feature_list, base->feature_type);
|
||||
defex_log_blob("%s%c%s - %s", work_path,
|
||||
((base->feature_type & feature_is_file)?' ':'/'),
|
||||
(is_rule_part2)?":<SECOND PART>":"", feature_list);
|
||||
}
|
||||
work_path[path_length] = 0;
|
||||
offset = base->next_file;
|
||||
base = (offset)?GET_ITEM_PTR(offset, defex_packed_rules):NULL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int defex_show_structure(void *packed_rules, int rules_size)
|
||||
{
|
||||
struct rule_item_struct *base;
|
||||
int res, offset;
|
||||
int first_item_size = sizeof(struct rule_item_struct) + sizeof(header_name);
|
||||
|
||||
defex_packed_rules = (struct rule_item_struct *)packed_rules;
|
||||
|
||||
work_path[0] = '/';
|
||||
work_path[1] = 0;
|
||||
|
||||
packfiles_size = rules_size;
|
||||
global_data_size = defex_packed_rules->data_size;
|
||||
|
||||
defex_log_timeoff("Rules binary size: %d", packfiles_size);
|
||||
defex_log_timeoff("Rules internal data size: %d", global_data_size);
|
||||
|
||||
if (global_data_size > packfiles_size)
|
||||
defex_log_timeoff("WARNING: Internal size is bigger than binary size, possible structure error!");
|
||||
|
||||
if (packfiles_size < first_item_size) {
|
||||
defex_log_timeoff("ERROR: Too short binary size, can't continue!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (global_data_size < first_item_size)
|
||||
defex_log_timeoff("WARNING: Too short data size, possible structure error!");
|
||||
|
||||
if (defex_packed_rules->size != sizeof(header_name))
|
||||
defex_log_timeoff("WARNING: incorrect size field (%d), possible structure error!",
|
||||
(int)defex_packed_rules->size);
|
||||
|
||||
if (memcmp(header_name, defex_packed_rules->name, sizeof(header_name)) != 0)
|
||||
defex_log_timeoff("WARNING: incorrect name field, possible structure error!");
|
||||
|
||||
defex_log_timeoff("File List:\n");
|
||||
offset = defex_packed_rules->next_level;
|
||||
base = (offset)?GET_ITEM_PTR(offset, defex_packed_rules):NULL;
|
||||
if (!base) {
|
||||
defex_log_timeoff("- empty list\n");
|
||||
return 0;
|
||||
} else if (check_array_size(base)) {
|
||||
defex_log_timeoff("- list is out of array bounds!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = parse_items(base, 1, 1);
|
||||
defex_log_timeoff("== End of File List ==");
|
||||
return res;
|
||||
}
|
||||
|
|
@ -1,285 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#if 0
|
||||
/* Rules start after this line */
|
||||
|
||||
{feature_ped_exception,"/system/bin/run-as"}, /* DEFAULT */
|
||||
{feature_ped_exception,"/system/bin/dumpstate"}, /* DEFAULT */
|
||||
{feature_safeplace_path,"/init"},
|
||||
{feature_safeplace_path,"/system/bin/init"},
|
||||
{feature_safeplace_path,"/system/bin/app_process32"},
|
||||
{feature_safeplace_path,"/system/bin/app_process64"},
|
||||
{feature_safeplace_path,"/system/bin/blkid"},
|
||||
{feature_safeplace_path,"/system/bin/clatd"},
|
||||
{feature_safeplace_path,"/system/bin/cmd"},
|
||||
{feature_safeplace_path,"/system/bin/corehelper.sh"},
|
||||
{feature_safeplace_path,"/system/bin/crash_dump32"},
|
||||
{feature_safeplace_path,"/system/bin/crash_dump64"},
|
||||
{feature_safeplace_path,"/system/bin/debuggerd"},
|
||||
{feature_safeplace_path,"/system/bin/dnsmasq"},
|
||||
{feature_safeplace_path,"/system/bin/dsms"},
|
||||
{feature_safeplace_path,"/system/bin/dumpstate"},
|
||||
{feature_safeplace_path,"/system/bin/fsck.vfat"},
|
||||
{feature_safeplace_path,"/system/bin/fsck.exfat"},
|
||||
{feature_safeplace_path,"/system/bin/gatekeeperd"},
|
||||
{feature_safeplace_path,"/system/bin/healthd"},
|
||||
{feature_safeplace_path,"/system/bin/installd"},
|
||||
{feature_safeplace_path,"/system/bin/iod"},
|
||||
{feature_safeplace_path,"/system/bin/ip"},
|
||||
{feature_safeplace_path,"/system/bin/iptables"},
|
||||
{feature_safeplace_path,"/system/bin/iptables-restore"},
|
||||
{feature_safeplace_path,"/system/bin/ip6tables"},
|
||||
{feature_safeplace_path,"/system/bin/ip6tables-restore"},
|
||||
{feature_safeplace_path,"/system/bin/lmkd"},
|
||||
{feature_safeplace_path,"/system/bin/lshal"},
|
||||
{feature_safeplace_path,"/system/bin/mdf_fota"},
|
||||
{feature_safeplace_path,"/system/bin/mkfs.vfat"},
|
||||
{feature_safeplace_path,"/system/bin/mkfs.exfat"},
|
||||
{feature_safeplace_path,"/system/bin/netd"},
|
||||
{feature_safeplace_path,"/system/bin/nst"},
|
||||
{feature_safeplace_path,"/system/bin/perfmond"},
|
||||
{feature_safeplace_path,"/system/bin/perfprofd"},
|
||||
{feature_safeplace_path,"/system/bin/sgdisk"},
|
||||
{feature_safeplace_path,"/system/bin/sh"},
|
||||
{feature_safeplace_path,"/system/bin/ss"},
|
||||
{feature_safeplace_path,"/system/bin/storaged"},
|
||||
{feature_safeplace_path,"/system/bin/tc"},
|
||||
{feature_safeplace_path,"/system/bin/uncrypt"},
|
||||
{feature_safeplace_path,"/system/bin/vold"},
|
||||
{feature_safeplace_path,"/system/bin/webview_zygote32"},
|
||||
{feature_safeplace_path,"/system/bin/grep"},
|
||||
{feature_safeplace_path,"/system/bin/e2fsck"},
|
||||
{feature_safeplace_path,"/system/bin/scs"},
|
||||
{feature_safeplace_path,"/system/bin/vdc"},
|
||||
{feature_safeplace_path,"/system/bin/vaultkeeperd"},
|
||||
{feature_safeplace_path,"/system/bin/prepare_param.sh"},
|
||||
{feature_safeplace_path,"/system/bin/smdexe"},
|
||||
{feature_safeplace_path,"/system/bin/diagexe"},
|
||||
{feature_safeplace_path,"/system/bin/ddexe"},
|
||||
{feature_safeplace_path,"/system/bin/connfwexe"},
|
||||
{feature_safeplace_path,"/system/bin/at_distributor"},
|
||||
{feature_safeplace_path,"/system/bin/sdcard"},
|
||||
{feature_safeplace_path,"/system/bin/resetreason"},
|
||||
{feature_safeplace_path,"/system/bin/lpm"},
|
||||
{feature_safeplace_path,"/system/bin/resize2fs"},
|
||||
{feature_safeplace_path,"/system/bin/tune2fs"},
|
||||
{feature_safeplace_path,"/system/bin/patchoat"},
|
||||
{feature_safeplace_path,"/system/bin/knox_changer"},
|
||||
{feature_safeplace_path,"/system/bin/knox_changer_recovery"},
|
||||
{feature_safeplace_path,"/sbin/sswap"},
|
||||
{feature_safeplace_path,"/sbin/cbd"},
|
||||
{feature_safeplace_path,"/sbin/adbd"},
|
||||
{feature_safeplace_path,"/sbin/recovery"},
|
||||
{feature_safeplace_path,"/sbin/mke2fs_static"},
|
||||
{feature_safeplace_path,"/vendor/bin/hw/wpa_supplicant"},
|
||||
{feature_safeplace_path,"/vendor/bin/hw/macloader"},
|
||||
{feature_safeplace_path,"/vendor/bin/hw/mfgloader"},
|
||||
{feature_safeplace_path,"/sbin/dm_verity_hash"},
|
||||
{feature_safeplace_path,"/sbin/dm_verity_signature_checker"},
|
||||
{feature_safeplace_path,"/vendor/bin/qseecomd"},
|
||||
{feature_safeplace_path,"/system/bin/vold_prepare_subdirs"},
|
||||
{feature_safeplace_path,"/vendor/bin/init.qcom.early_boot.sh"},
|
||||
{feature_safeplace_path,"/vendor/bin/toybox_vendor"},
|
||||
{feature_safeplace_path,"/vendor/bin/toolbox"},
|
||||
{feature_safeplace_path,"/vendor/bin/hw/android.hardware.usb@1.1-service.wahoo"},
|
||||
{feature_safeplace_path,"/vendor/bin/hw/vendor.qti.hardware.iop@2.0-service"},
|
||||
{feature_safeplace_path,"/vendor/bin/hw/vendor.qti.hardware.perf@1.0-service"},
|
||||
{feature_safeplace_path,"/vendor/bin/init.qcom.class_core.sh"},
|
||||
{feature_safeplace_path,"/vendor/bin/irsc_util"},
|
||||
{feature_safeplace_path,"/vendor/bin/rmt_storage"},
|
||||
{feature_safeplace_path,"/system/bin/toybox"},
|
||||
{feature_safeplace_path,"/vendor/bin/init.qcom.usb.sh"},
|
||||
{feature_safeplace_path,"/vendor/bin/tftp_server"},
|
||||
{feature_safeplace_path,"/vendor/bin/init.qcom.sensors.sh"},
|
||||
{feature_safeplace_path,"/system/bin/insthk"},
|
||||
{feature_safeplace_path,"/vendor/bin/init.class_main.sh"},
|
||||
{feature_safeplace_path,"/vendor/bin/time_daemon"},
|
||||
{feature_safeplace_path,"/vendor/bin/thermal-engine"},
|
||||
{feature_safeplace_path,"/vendor/bin/thermal-engine-v2"},
|
||||
{feature_safeplace_path,"/system/bin/sec_diag_uart_log"},
|
||||
{feature_safeplace_path,"/vendor/bin/init.qcom.sh"},
|
||||
{feature_safeplace_path,"/system/bin/usbd"},
|
||||
{feature_safeplace_path,"/vendor/bin/init.qcom.post_boot.sh"},
|
||||
{feature_safeplace_path,"/system/bin/adbd"},
|
||||
{feature_safeplace_path,"/system/bin/atrace"},
|
||||
{feature_safeplace_path,"/system/bin/fsdbg"},
|
||||
{feature_safeplace_path,"/system/bin/dumpsys"},
|
||||
{feature_safeplace_path,"/system/bin/logcat"},
|
||||
{feature_safeplace_path,"/system/bin/toolbox"},
|
||||
{feature_safeplace_path,"/system/bin/mke2fs"},
|
||||
{feature_safeplace_path,"/vendor/bin/cbd"},
|
||||
{feature_safeplace_path,"/vendor/bin/adsprpcd"},
|
||||
{feature_safeplace_path,"/sbin/e2fsdroid_static"},
|
||||
{feature_safeplace_path,"/system/bin/e2fsdroid"},
|
||||
{feature_safeplace_path,"/system/bin/fsck.f2fs"},
|
||||
{feature_safeplace_path,"/system/bin/make_f2fs"},
|
||||
{feature_safeplace_path,"/system/bin/sload_f2fs"},
|
||||
{feature_safeplace_path,"/system/bin/bpfloader"},
|
||||
{feature_safeplace_path,"/system/bin/wait_for_keymaster"},
|
||||
{feature_safeplace_path,"/system/bin/secdiscard"},
|
||||
{feature_safeplace_path,"/system/bin/idledefrag"},
|
||||
{feature_safeplace_path,"/vendor/bin/init.mdm.sh"},
|
||||
{feature_safeplace_path,"/vendor/bin/mdm_helper"},
|
||||
{feature_safeplace_path,"/vendor/bin/ks"},
|
||||
{feature_safeplace_path,"/vendor/bin/sh"},
|
||||
{feature_safeplace_path,"/system/bin/e4defrag"},
|
||||
{feature_safeplace_path,"/sbin/dm_verity_tz_cmd"},
|
||||
{feature_safeplace_path,"/sbin/mcDriverDaemon_static"},
|
||||
{feature_safeplace_path,"/sbin/qseecomfsd"},
|
||||
{feature_safeplace_path,"/sbin/tzdaemon_recovery"},
|
||||
{feature_safeplace_path,"/vendor/bin/hvdcp_opti"},
|
||||
{feature_safeplace_path,"/sbin/mkfs.f2fs"},
|
||||
{feature_safeplace_path,"/sbin/sload.f2fs"},
|
||||
{feature_safeplace_path,"/system/bin/secilc"},
|
||||
{feature_safeplace_path,"/system/bin/apexd"},
|
||||
{feature_safeplace_path,"/system/bin/art_apex_boot_integrity"},
|
||||
{feature_safeplace_path,"/system/bin/gsid"},
|
||||
{feature_safeplace_path,"/system/bin/idmap2"},
|
||||
{feature_safeplace_path,"/system/bin/charger"},
|
||||
{feature_safeplace_path,"/system/bin/recovery"},
|
||||
{feature_safeplace_path,"/system/bin/watchdogd"},
|
||||
{feature_safeplace_path,"/vendor/bin/hw/vendor.qti.hardware.perf@2.0-service"},
|
||||
{feature_safeplace_path,"/system/bin/netutils-wrapper-1.0"},
|
||||
{feature_safeplace_path,"/system/bin/bugreport"},
|
||||
{feature_safeplace_path,"/system/bin/minadbd"},
|
||||
{feature_safeplace_path,"/system/bin/migrate_legacy_obb_data.sh"},
|
||||
{feature_safeplace_path,"/vendor/bin/shsusrd"},
|
||||
{feature_safeplace_path,"/system/bin/defrag_f2fs"},
|
||||
{feature_safeplace_path,"/system/bin/fastbootd"},
|
||||
{feature_safeplace_path,"/system/bin/sbm"},
|
||||
{feature_safeplace_path,"/vendor/bin/hw/vendor.qti.hardware.perf@2.1-service"},
|
||||
{feature_safeplace_path,"/vendor/bin/hw/vendor.qti.hardware.perf@2.2-service"},
|
||||
{feature_safeplace_path,"/vendor/bin/grep"},
|
||||
{feature_safeplace_path,"/vendor/bin/memlogd"},
|
||||
{feature_safeplace_path,"/vendor/bin/init.insmod.sh"},
|
||||
{feature_safeplace_path,"/vendor/bin/hw/android.hardware.usb@1.3-service.coral"},
|
||||
{feature_safeplace_path,"/vendor/bin/hw/vendor.qti.hardware.perf-hal-service"},
|
||||
{feature_safeplace_path,"/vendor/bin/iod"},
|
||||
{feature_safeplace_path,"/vendor/bin/dsmsca"},
|
||||
{feature_safeplace_path,"/vendor/bin/hqread"},
|
||||
{feature_safeplace_path,"/system/bin/hqcpsnbin"},
|
||||
{feature_safeplace_path,"/system/bin/awk"},
|
||||
{feature_safeplace_path,"/system/bin/bc"},
|
||||
{feature_safeplace_path,"/system/bin/service"},
|
||||
{feature_safeplace_path,"/system/bin/rdxd"},
|
||||
{feature_safeplace_path,"/system/bin/ztd"},
|
||||
{feature_safeplace_path,"/system/system_ext/bin/dpmd"},
|
||||
{feature_safeplace_path,"/vendor/bin/init.qti.dcvs.sh"},
|
||||
{feature_safeplace_path,"/vendor/bin/vendor_modprobe.sh"},
|
||||
{feature_safeplace_path,"/vendor/bin/init.qti.qcv.sh"},
|
||||
{feature_safeplace_path,"/vendor/bin/init.qcom.crashdata.sh"},
|
||||
{feature_safeplace_path,"/vendor/bin/energy-awareness"},
|
||||
{feature_safeplace_path,"/vendor/bin/qcom-system-daemon"},
|
||||
{feature_safeplace_path,"/vendor/bin/init.qti.kernel.sh"},
|
||||
{feature_safeplace_path,"/vendor/bin/init.kernel.post_boot.sh"},
|
||||
{feature_safeplace_path,"/vendor/bin/init.kernel.post_boot-lahaina.sh"},
|
||||
{feature_safeplace_path,"/vendor/bin/init.qti.early_init.sh"},
|
||||
{feature_safeplace_path,"/vendor/bin/init.qti.keymaster.sh"},
|
||||
{feature_safeplace_path,"/vendor/bin/init.qti.write.sh"},
|
||||
{feature_safeplace_path,"/vendor/bin/vmmgr"},
|
||||
{feature_safeplace_path,"/product/bin/qvirtmgr"},
|
||||
{feature_safeplace_path,"/system_ext/bin/qcrosvm"},
|
||||
{feature_safeplace_path,"/vendor/bin/ssr_setup"},
|
||||
{feature_safeplace_path,"/product/bin/vendor.qti.qvirt-service_rs"},
|
||||
{feature_safeplace_path,"/product/bin/vendor.qti.qvirt-service"},
|
||||
{feature_safeplace_path,"/vendor/bin/hw/vendor.qti.hardware.debugutils-service"},
|
||||
{feature_safeplace_path,"/vendor/bin/hw/vendor.qti.hardware.perf2-hal-service"},
|
||||
{feature_safeplace_path,"/vendor/bin/hw/vendor.qti.hardware.limits@1.2-service"},
|
||||
{feature_safeplace_path,"/vendor/bin/thermal_manager"},
|
||||
{feature_safeplace_path,"/vendor/bin/nvram_daemon"},
|
||||
{feature_safeplace_path,"/vendor/bin/hw/vendor.mediatek.hardware.nvram@1.1-service"},
|
||||
{feature_safeplace_path,"/vendor/bin/aee_aedv"},
|
||||
{feature_safeplace_path,"/vendor/bin/aee_aedv64"},
|
||||
{feature_safeplace_path,"/vendor/bin/meta_tst"},
|
||||
{feature_safeplace_path,"/vendor/bin/thermal_core"},
|
||||
{feature_safeplace_path,"/system/bin/linkerconfig"},
|
||||
{feature_safeplace_path,"/system/bin/snapshotctl"},
|
||||
{feature_safeplace_path,"/system/bin/boringssl_self_test32"},
|
||||
{feature_safeplace_path,"/system/bin/boringssl_self_test64"},
|
||||
{feature_safeplace_path,"/vendor/bin/boringssl_self_test32"},
|
||||
{feature_safeplace_path,"/vendor/bin/boringssl_self_test64"},
|
||||
{feature_safeplace_path,"/apex/com.android.adbd/bin/adbd"},
|
||||
{feature_safeplace_path,"/apex/com.android.sdkext/bin/derive_sdk"},
|
||||
{feature_safeplace_path,"/apex/com.android.conscrypt/bin/boringssl_self_test32"},
|
||||
{feature_safeplace_path,"/apex/com.android.conscrypt/bin/boringssl_self_test64"},
|
||||
{feature_safeplace_path,"/system/bin/applypatch"},
|
||||
{feature_safeplace_path,"/vendor/bin/applypatch"},
|
||||
{feature_safeplace_path,"/system/bin/clean_scratch_files"},
|
||||
{feature_safeplace_path,"/system/bin/fsverity"},
|
||||
{feature_safeplace_path,"/system/bin/fsverity_init"},
|
||||
{feature_safeplace_path,"/system/xbin/librank"},
|
||||
{feature_safeplace_path,"/system/xbin/procrank"},
|
||||
{feature_safeplace_path,"/system/xbin/showmap"},
|
||||
{feature_safeplace_path,"/system/bin/librank"},
|
||||
{feature_safeplace_path,"/system/bin/procrank"},
|
||||
{feature_safeplace_path,"/system/bin/showmap"},
|
||||
{feature_safeplace_path,"/product/bin/dmabuf_dump"},
|
||||
{feature_safeplace_path,"/system/bin/dmabuf_dump"},
|
||||
{feature_safeplace_path,"/apex/com.android.runtime/bin/spqr"},
|
||||
{feature_safeplace_path,"/system/bin/perfetto"},
|
||||
{feature_safeplace_path,"/system/bin/update_verifier"},
|
||||
{feature_safeplace_path,"/system/bin/bootstrap/linkerconfig"},
|
||||
{feature_safeplace_path,"/apex/com.android.runtime/bin/linkerconfig"},
|
||||
{feature_safeplace_path,"/system/bin/otapreopt_slot"},
|
||||
{feature_safeplace_path,"/apex/com.android.art/bin/dex2oat32"},
|
||||
{feature_safeplace_path,"/apex/com.android.art/bin/dex2oat64"},
|
||||
{feature_safeplace_path,"/system/bin/incident"},
|
||||
{feature_safeplace_path,"/system/bin/odsign"},
|
||||
{feature_safeplace_path,"/apex/com.android.art/bin/odrefresh"},
|
||||
{feature_safeplace_path,"/apex/com.android.art/bin/artd"},
|
||||
{feature_safeplace_path,"/apex/com.android.runtime/bin/crash_dump32"},
|
||||
{feature_safeplace_path,"/apex/com.android.runtime/bin/crash_dump64"},
|
||||
{feature_safeplace_path,"/system/bin/lpdump"},
|
||||
{feature_safeplace_path,"/system/bin/extra_free_kbytes.sh"},
|
||||
{feature_safeplace_path,"/system/bin/bpfloader"},
|
||||
{feature_safeplace_path,"/system/bin/btfloader"},
|
||||
{feature_safeplace_path,"/vendor/bin/system_dlkm_modprobe.sh"},
|
||||
{feature_safeplace_path,"/apex/com.android.art/bin/art_boot"},
|
||||
{feature_safeplace_path,"/tmp/update_binary;updater_intermediates/updater;obj/EXECUTABLES"},
|
||||
{feature_safeplace_path,"/tmp/update-binary"},
|
||||
{feature_safeplace_path,"/system/bin/install-recovery.sh"}, /* DEFAULT */
|
||||
{feature_safeplace_path,"/vendor/bin/install-recovery.sh"}, /* DEFAULT */
|
||||
{feature_safeplace_path,"/system/bin/bpfloader"}, /* DEFAULT */
|
||||
{feature_immutable_path_write,"/system/"}, /* DEFAULT */
|
||||
{feature_immutable_path_write,"/vendor/"}, /* DEFAULT */
|
||||
{feature_immutable_path_open,"/system/bin/"}, /* DEFAULT */
|
||||
{feature_immutable_path_open,"/vendor/bin/"}, /* DEFAULT */
|
||||
{feature_immutable_src_exception,"/system/bin/icd"},
|
||||
{feature_immutable_src_exception,"/system/bin/iof"},
|
||||
{feature_immutable_src_exception,"/system/bin/sh"},
|
||||
{feature_immutable_src_exception,"/system/bin/app_process32"},
|
||||
{feature_immutable_src_exception,"/system/bin/app_process64"},
|
||||
{feature_immutable_src_exception,"/system/bin/crash_dump32"},
|
||||
{feature_immutable_src_exception,"/system/bin/crash_dump64"},
|
||||
{feature_immutable_src_exception,"/system/bin/mediaextractor"},
|
||||
{feature_immutable_src_exception,"/system/bin/surfaceflinger"},
|
||||
{feature_immutable_src_exception,"/vendor/bin/sh"},
|
||||
{feature_immutable_src_exception,"/vendor/bin/hw/android.hardware.media.omx@1.0-service"},
|
||||
{feature_immutable_src_exception,"/vendor/bin/snap_utility_32"},
|
||||
{feature_immutable_src_exception,"/vendor/bin/snap_utility_64"},
|
||||
{feature_immutable_src_exception,"/vendor/bin/icd_vendor"},
|
||||
{feature_immutable_src_exception,"/vendor/bin/iof_vendor"},
|
||||
{feature_immutable_src_exception,"/init"},
|
||||
{feature_immutable_src_exception,"/system/bin/init"},
|
||||
{feature_immutable_src_exception,"/system/bin/lshal"},
|
||||
{feature_immutable_src_exception,"/apex/com.android.runtime/bin/crash_dump32"}, /* DEFAULT */
|
||||
{feature_immutable_src_exception,"/apex/com.android.runtime/bin/crash_dump64"}, /* DEFAULT */
|
||||
{feature_immutable_src_exception,"/data/local/tests/unrestricted/CtsBionicTestCases/arm64/CtsBionicTestCases"}, /* DEFAULT */
|
||||
{feature_immutable_src_exception,"/data/local/tests/unrestricted/CtsBionicTestCases/arm/CtsBionicTestCases"}, /* DEFAULT */
|
||||
{feature_integrity_check,"/vendor/bin/hw/android.hardware.gatekeeper@1.0-service"},
|
||||
{feature_integrity_check,"/vendor/bin/hw/android.hardware.keymaster@4.0-service"},
|
||||
{feature_integrity_check,"/vendor/bin/hw/android.hardware.security.keymint-service"},
|
||||
{feature_integrity_check,"/vendor/bin/hw/vendor.samsung.hardware.tlc.kg@1.0-service"},
|
||||
{feature_integrity_check,"/vendor/bin/hw/vendor.samsung.hardware.security.wsm-service"},
|
||||
{feature_integrity_check,"/vendor/bin/vendor.samsung.hardware.security.wsm@1.0-service"},
|
||||
{feature_integrity_check,"/vendor/bin/vaultkeeperd"},
|
||||
{feature_integrity_check,"/vendor/bin/hw/vendor.samsung.hardware.tlc.kg@1.1-service"},
|
||||
/* Rules will be added here */
|
||||
/* Never modify the above line. Rules will be added for buildtime */
|
||||
#endif /* if 0 */
|
|
@ -1,36 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include "include/defex_internal.h"
|
||||
|
||||
#ifdef DEFEX_PERMISSIVE_IM
|
||||
unsigned char global_immutable_status = 2;
|
||||
#else
|
||||
unsigned char global_immutable_status = 1;
|
||||
#endif /* DEFEX_PERMISSIVE_IM */
|
||||
|
||||
int immutable_status_store(const char *status_str)
|
||||
{
|
||||
int ret;
|
||||
unsigned int status;
|
||||
|
||||
if (!status_str)
|
||||
return -EINVAL;
|
||||
|
||||
ret = kstrtouint(status_str, 10, &status);
|
||||
if (ret != 0 || status > 2)
|
||||
return -EINVAL;
|
||||
|
||||
global_immutable_status = status;
|
||||
return 0;
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include "include/defex_internal.h"
|
||||
|
||||
#ifdef DEFEX_PERMISSIVE_PED
|
||||
unsigned char global_privesc_status = 2;
|
||||
#else
|
||||
unsigned char global_privesc_status = 1;
|
||||
#endif /* DEFEX_PERMISSIVE_PED */
|
||||
|
||||
int privesc_status_store(const char *status_str)
|
||||
{
|
||||
int ret;
|
||||
unsigned int status;
|
||||
|
||||
if (!status_str)
|
||||
return -EINVAL;
|
||||
|
||||
ret = kstrtouint(status_str, 10, &status);
|
||||
if (ret != 0 || status > 2)
|
||||
return -EINVAL;
|
||||
global_privesc_status = status;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include "include/defex_internal.h"
|
||||
|
||||
#ifdef DEFEX_PERMISSIVE_INT
|
||||
unsigned char global_integrity_status = 2;
|
||||
#else
|
||||
unsigned char global_integrity_status = 1;
|
||||
#endif /* DEFEX_PERMISSIVE_INT */
|
||||
|
||||
int integrity_status_store(const char *status_str)
|
||||
{
|
||||
int ret;
|
||||
unsigned int status;
|
||||
|
||||
if (!status_str)
|
||||
return -EINVAL;
|
||||
|
||||
ret = kstrtouint(status_str, 10, &status);
|
||||
if (ret != 0 || status > 2)
|
||||
return -EINVAL;
|
||||
|
||||
global_integrity_status = status;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include "include/defex_internal.h"
|
||||
|
||||
#ifdef DEFEX_PERMISSIVE_SP
|
||||
unsigned char global_safeplace_status = 2;
|
||||
#else
|
||||
unsigned char global_safeplace_status = 1;
|
||||
#endif /* DEFEX_PERMISSIVE_SP */
|
||||
|
||||
int safeplace_status_store(const char *status_str)
|
||||
{
|
||||
int ret;
|
||||
unsigned int status;
|
||||
|
||||
if (!status_str)
|
||||
return -EINVAL;
|
||||
|
||||
ret = kstrtouint(status_str, 10, &status);
|
||||
if (ret != 0 || status > 2)
|
||||
return -EINVAL;
|
||||
|
||||
global_safeplace_status = status;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include "include/defex_internal.h"
|
||||
|
||||
unsigned char global_trusted_map_status = DEFEX_TM_ENFORCING_MODE
|
||||
#ifdef DEFEX_PERMISSIVE_TM
|
||||
| DEFEX_TM_PERMISSIVE_MODE
|
||||
#endif
|
||||
| DEFEX_TM_DEBUG_VIOLATIONS
|
||||
;
|
|
@ -1,206 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2020-2022 Samsung Electronics Co., Ltd. All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/compat.h>
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/version.h>
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
|
||||
#include <linux/sched/task.h>
|
||||
#endif
|
||||
|
||||
#include "include/dtm.h"
|
||||
#include "include/dtm_engine.h"
|
||||
#include "include/dtm_log.h"
|
||||
#include "include/dtm_utils.h"
|
||||
|
||||
/* From fs/exec.c: SM8150_Q, SM8250_Q, SM8250_R, exynos9820, exynos9830 */
|
||||
struct user_arg_ptr {
|
||||
#ifdef CONFIG_COMPAT
|
||||
bool is_compat;
|
||||
#endif
|
||||
union {
|
||||
const char __user *const __user *native;
|
||||
#ifdef CONFIG_COMPAT
|
||||
const compat_uptr_t __user *compat;
|
||||
#endif
|
||||
} ptr;
|
||||
};
|
||||
|
||||
/* From fs/exec.c: SM8150_Q, SM8250_Q, SM8250_R, exynos9820, exynos9830 */
|
||||
static const char __user *get_user_arg_ptr(struct user_arg_ptr argv, int nr)
|
||||
{
|
||||
const char __user *native;
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
if (unlikely(argv.is_compat)) {
|
||||
compat_uptr_t compat;
|
||||
|
||||
if (get_user(compat, argv.ptr.compat + nr))
|
||||
return ERR_PTR(-EFAULT);
|
||||
|
||||
return compat_ptr(compat);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (get_user(native, argv.ptr.native + nr))
|
||||
return ERR_PTR(-EFAULT);
|
||||
|
||||
return native;
|
||||
}
|
||||
|
||||
static void dtm_kfree_args(struct dtm_context *context)
|
||||
{
|
||||
const char **argv;
|
||||
int arg, to_free;
|
||||
|
||||
if (unlikely(!is_dtm_context_valid(context)))
|
||||
return;
|
||||
argv = context->callee_argv;
|
||||
arg = min_t(int, context->callee_argc, DTM_MAX_ARGC);
|
||||
to_free = context->callee_copied_argc;
|
||||
context->callee_copied_argc = 0;
|
||||
while (--arg >= 0 && to_free > 0) {
|
||||
if (!argv[arg])
|
||||
continue;
|
||||
kfree(argv[arg]);
|
||||
to_free--;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Gets call argument value, copying from user if needed.
|
||||
*/
|
||||
const char *dtm_get_callee_arg(struct dtm_context *context, int arg_index)
|
||||
{
|
||||
struct user_arg_ptr argv;
|
||||
const char __user *user_str;
|
||||
char *copy;
|
||||
int max_argc, arg_len, copy_len;
|
||||
|
||||
if (unlikely(!is_dtm_context_valid(context)))
|
||||
return NULL;
|
||||
max_argc = min_t(int, context->callee_argc, DTM_MAX_ARGC);
|
||||
if (unlikely((arg_index < 0) || (arg_index >= max_argc)))
|
||||
return NULL;
|
||||
if (context->callee_argv[arg_index])
|
||||
return context->callee_argv[arg_index];
|
||||
|
||||
argv = *(struct user_arg_ptr *)context->callee_argv_ref;
|
||||
user_str = get_user_arg_ptr(argv, arg_index);
|
||||
if (IS_ERR(user_str))
|
||||
return NULL;
|
||||
|
||||
arg_len = strnlen_user(user_str, MAX_ARG_STRLEN);
|
||||
if (unlikely(!arg_len))
|
||||
return NULL;
|
||||
|
||||
copy_len = min_t(int, arg_len, DTM_MAX_ARG_STRLEN);
|
||||
copy = kzalloc(copy_len, GFP_KERNEL);
|
||||
if (unlikely(!copy))
|
||||
return NULL;
|
||||
|
||||
if (unlikely(copy_from_user(copy, user_str, copy_len)))
|
||||
goto out_free_copy;
|
||||
copy[copy_len - 1] = '\0';
|
||||
|
||||
context->callee_argv[arg_index] = copy;
|
||||
context->callee_copied_argc++;
|
||||
context->callee_copied_args_len += copy_len;
|
||||
context->callee_total_args_len += arg_len;
|
||||
return copy;
|
||||
|
||||
out_free_copy:
|
||||
kfree(copy);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initializes dtm context data structure.
|
||||
*/
|
||||
__visible_for_testing bool dtm_context_get(struct dtm_context *context,
|
||||
struct defex_context *defex_context,
|
||||
int callee_argc,
|
||||
void *callee_argv_ref)
|
||||
{
|
||||
memset(context, 0, sizeof(*context));
|
||||
context->defex_context = defex_context;
|
||||
context->callee_argc = callee_argc;
|
||||
context->callee_argv_ref = callee_argv_ref;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Releases resources associated to dtm context.
|
||||
*/
|
||||
__visible_for_testing void dtm_context_put(struct dtm_context *context)
|
||||
{
|
||||
dtm_kfree_args(context);
|
||||
}
|
||||
|
||||
/*
|
||||
* Gets program name for current call.
|
||||
*/
|
||||
const char *dtm_get_program_name(struct dtm_context *context)
|
||||
{
|
||||
if (unlikely(!is_dtm_context_valid(context)))
|
||||
return NULL;
|
||||
if (context->program_name)
|
||||
return context->program_name;
|
||||
context->program_name = dtm_get_callee_arg(context, 0);
|
||||
if (context->program_name == NULL)
|
||||
context->program_name = DTM_UNKNOWN;
|
||||
return context->program_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets stdin mode bit for current call.
|
||||
*/
|
||||
int dtm_get_stdin_mode_bit(struct dtm_context *context)
|
||||
{
|
||||
if (unlikely(!context))
|
||||
return DTM_FD_MODE_ERROR;
|
||||
if (!context->stdin_mode_bit)
|
||||
context->stdin_mode_bit = dtm_get_fd_mode_bit(0);
|
||||
return context->stdin_mode_bit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets stdin mode for current call.
|
||||
*/
|
||||
const char *dtm_get_stdin_mode(struct dtm_context *context)
|
||||
{
|
||||
if (unlikely(!context))
|
||||
return NULL;
|
||||
if (!context->stdin_mode)
|
||||
context->stdin_mode = dtm_get_fd_mode_bit_name(
|
||||
dtm_get_stdin_mode_bit(context));
|
||||
return context->stdin_mode;
|
||||
}
|
||||
|
||||
int defex_trusted_map_lookup(struct defex_context *defex_context,
|
||||
int callee_argc, void *callee_argv_ref)
|
||||
{
|
||||
int ret = DTM_DENY;
|
||||
struct dtm_context context;
|
||||
|
||||
if (unlikely(!defex_context || !(defex_context->task)))
|
||||
goto out;
|
||||
if (unlikely(!dtm_context_get(&context, defex_context, callee_argc, callee_argv_ref)))
|
||||
goto out;
|
||||
ret = dtm_enforce(&context);
|
||||
dtm_context_put(&context);
|
||||
out:
|
||||
return ret;
|
||||
}
|
|
@ -1,195 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2020-2022 Samsung Electronics Co., Ltd. All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "include/defex_debug.h"
|
||||
#include "include/defex_rules.h"
|
||||
#include "include/dtm.h"
|
||||
#include "include/dtm_engine.h"
|
||||
#include "include/dtm_log.h"
|
||||
#include "include/dtm_utils.h"
|
||||
#include "include/ptree.h"
|
||||
|
||||
#define DTM_ANY_VALUE "*" /* wildcard value for files and arguments */
|
||||
#if defined(DEFEX_TM_DEFAULT_POLICY_ENABLE) || defined(DEFEX_KERNEL_ONLY)
|
||||
/* Kernel-only builds don't use DEFEX's dynamic policy loading mechanism. */
|
||||
#define USE_EMBEDDED_POLICY
|
||||
static struct PPTree embedded_header;
|
||||
/* File with hardcoded policy */
|
||||
#include "dtm_engine_defaultpolicy.h"
|
||||
#endif
|
||||
|
||||
#ifdef DEFEX_KUNIT_ENABLED
|
||||
static struct PPTree override_header, *pptree_override;
|
||||
|
||||
void dtm_engine_override_data(const unsigned char *p)
|
||||
{
|
||||
if (p) {
|
||||
defex_log_warn("Dtm_engine data overridden");
|
||||
pptree_set_data(pptree_override = &override_header, p);
|
||||
} else {
|
||||
defex_log_warn("Dtm_engine override data back to normal");
|
||||
pptree_override = 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static int dtm_check_stdin(struct dtm_context *context, int allowed_stdin_modes)
|
||||
{
|
||||
if (unlikely(!(dtm_get_stdin_mode_bit(context) & allowed_stdin_modes))) {
|
||||
dtm_report_violation(DTM_STDIN_VIOLATION, context);
|
||||
return DTM_DENY;
|
||||
}
|
||||
return DTM_ALLOW;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enforces DTM policy for an exec system call.
|
||||
*/
|
||||
int dtm_enforce(struct dtm_context *context)
|
||||
{
|
||||
const char *callee_path, *caller_path;
|
||||
const char *program_name;
|
||||
int ret, argc, call_argc;
|
||||
const char *argument_value;
|
||||
struct PPTree *pptree; /* effective header of policy rules */
|
||||
struct PPTreeContext pp_ctx; /* context for policy search */
|
||||
static char first_run = 1; /* flag for one-time policy actions */
|
||||
|
||||
if (first_run) {
|
||||
if (dtm_tree.data)
|
||||
defex_log_info("DTM engine: policy found");
|
||||
else
|
||||
defex_log_warn("DTM engine: dynamic policy not loaded");
|
||||
first_run = 0;
|
||||
#ifdef USE_EMBEDDED_POLICY
|
||||
pptree_set_data(&embedded_header, dtm_engine_defaultpolicy);
|
||||
#endif
|
||||
}
|
||||
|
||||
defex_log_info("Pid : %d %d", current->tgid, current->pid);
|
||||
|
||||
if (!context || unlikely(!is_dtm_context_valid(context))) {
|
||||
defex_log_info("(0) TMED no or invalid context");
|
||||
return DTM_DENY;
|
||||
}
|
||||
/* Check callee */
|
||||
callee_path = dtm_get_callee_path(context);
|
||||
if (unlikely(!callee_path)) {
|
||||
defex_log_info("(1) TMED null callee");
|
||||
return DTM_DENY;
|
||||
}
|
||||
|
||||
#ifdef DEFEX_KUNIT_ENABLED
|
||||
if (pptree_override) /* test code has opportunity to use test policy instead */
|
||||
pptree = pptree_override;
|
||||
else
|
||||
#endif
|
||||
#ifdef USE_EMBEDDED_POLICY /* try dynamic policy first, use embedded if not found */
|
||||
pptree = dtm_tree.data ? &dtm_tree : &embedded_header;
|
||||
#else /* only dynamically loaded policy is acceptable */
|
||||
pptree = &dtm_tree;
|
||||
#endif
|
||||
if (!pptree->data) { /* Should never happen */
|
||||
defex_log_warn("(0) DTM engine: neither dynamic nor hardcoded rules loaded");
|
||||
return DTM_ALLOW;
|
||||
}
|
||||
memset(&pp_ctx, 0, sizeof(pp_ctx));
|
||||
if (!(pptree_find_path(pptree,
|
||||
*callee_path == '/' ?
|
||||
callee_path + 1 : callee_path, '/', &pp_ctx) &&
|
||||
(pp_ctx.types & PTREE_DATA_PATH))) {
|
||||
defex_log_info("(2) TME callee '%s' not found", callee_path);
|
||||
return DTM_ALLOW;
|
||||
}
|
||||
/* Check caller */
|
||||
caller_path = dtm_get_caller_path(context);
|
||||
if (unlikely(!caller_path)) {
|
||||
defex_log_info("(3) TMED callee '%s': null caller", callee_path);
|
||||
return DTM_DENY;
|
||||
}
|
||||
if (!(pptree_find_path(pptree, caller_path + 1, '/', &pp_ctx) &&
|
||||
(pp_ctx.types & PTREE_DATA_PATH))) {
|
||||
defex_log_info("(4) TMED callee '%s': caller '%s' not found",
|
||||
callee_path, caller_path);
|
||||
dtm_report_violation(DTM_CALLER_VIOLATION, context);
|
||||
return DTM_DENY;
|
||||
}
|
||||
/* Check program, if any */
|
||||
program_name = dtm_get_program_name(context);
|
||||
if (!program_name) {
|
||||
defex_log_info("(5) TMED callee '%s', caller '%s': null program",
|
||||
callee_path, caller_path);
|
||||
return DTM_DENY;
|
||||
}
|
||||
pp_ctx.types |= PTREE_FIND_PEEK;
|
||||
if (pptree_child_count(pptree, &pp_ctx) == 1 &&
|
||||
pptree_find_path(pptree, DTM_ANY_VALUE, 0, &pp_ctx)) {
|
||||
defex_log_info("[TME callee '%s', caller '%s': program may be '*...'",
|
||||
callee_path, caller_path);
|
||||
pp_ctx.types |= PTREE_FIND_PEEKED;
|
||||
pptree_find_path(pptree, 0, 0, &pp_ctx);
|
||||
} else {
|
||||
pp_ctx.types &= ~PTREE_FIND_PEEK;
|
||||
if (!(pptree_find_path(pptree, program_name, 0, &pp_ctx) &&
|
||||
(pp_ctx.types & PTREE_DATA_INT2))) {
|
||||
defex_log_info("(6) TMED callee '%s', caller '%s': program '%s' not found",
|
||||
callee_path, caller_path, program_name);
|
||||
dtm_report_violation(DTM_PROGRAM_VIOLATION, context);
|
||||
return DTM_DENY;
|
||||
}
|
||||
}
|
||||
/* Check standard input mode */
|
||||
if (pp_ctx.types & PTREE_DATA_INT2) {
|
||||
ret = dtm_check_stdin(context, pp_ctx.value.int2);
|
||||
if (unlikely(ret != DTM_ALLOW)) {
|
||||
defex_log_info("(7) TMED callee '%s', caller '%s', program '%s': stdin mode %d, should be %d",
|
||||
callee_path, caller_path,
|
||||
program_name ? program_name : "(null)",
|
||||
dtm_get_stdin_mode_bit(context), pp_ctx.value.int2);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
/* Check program arguments, if any */
|
||||
pp_ctx.types |= PTREE_FIND_CONTINUE;
|
||||
for (call_argc = context->callee_argc, argc = 1;
|
||||
argc <= call_argc && pptree_child_count(pptree, &pp_ctx);
|
||||
++argc) {
|
||||
pp_ctx.types |= PTREE_FIND_PEEK;
|
||||
if (pptree_find_path(pptree, DTM_ANY_VALUE, 0, &pp_ctx)) {
|
||||
defex_log_info("(8) TME callee '%s', caller '%s', program '%s': any arguments accepted",
|
||||
callee_path, caller_path, program_name);
|
||||
return DTM_ALLOW;
|
||||
}
|
||||
pp_ctx.types &= PTREE_FIND_PEEKED;
|
||||
pp_ctx.types |= PTREE_FIND_CONTINUE;
|
||||
argument_value = dtm_get_callee_arg(context, argc);
|
||||
if (!pptree_find_path(pptree, argument_value, 0, &pp_ctx)) {
|
||||
defex_log_info(
|
||||
"(9) TMED callee '%s', caller '%s', program '%s': argument '%s' (%d of %d) not found",
|
||||
callee_path, caller_path, program_name,
|
||||
argument_value ? argument_value : "(null)",
|
||||
argc, call_argc);
|
||||
dtm_report_violation(DTM_ARGUMENTS_VIOLATION, context);
|
||||
return DTM_DENY;
|
||||
}
|
||||
if (pp_ctx.value.bits) {
|
||||
defex_log_info("(10) TME callee '%s', caller '%s', program '%s': argument '%s' accepts '*'",
|
||||
callee_path, caller_path, program_name,
|
||||
argument_value ? argument_value : "(null)");
|
||||
return DTM_ALLOW;
|
||||
}
|
||||
}
|
||||
if (call_argc && argc > call_argc)
|
||||
defex_log_info("TME callee '%s', caller '%s', program '%s': all %d argument(s) checked",
|
||||
callee_path, caller_path, program_name, call_argc);
|
||||
return DTM_ALLOW;
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
static unsigned char dtm_engine_defaultpolicy[] = {
|
||||
80,80,84,114,101,101,45,1,0,0,0,0,1,0,0,0,0,1,0,0,0,
|
||||
0,1,0,0,0,0,1,0,1,1,0,0,
|
||||
};
|
|
@ -1,115 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2020-2022 Samsung Electronics Co., Ltd. All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/printk.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#include "include/dtm.h"
|
||||
#include "include/dtm_log.h"
|
||||
#include "include/dtm_utils.h"
|
||||
|
||||
#define DTM_MAX_LOG_SIZE (1024)
|
||||
#define DTM_MAX_DETAIL_SIZE (1024)
|
||||
|
||||
#ifdef DEFEX_DSMS_ENABLE
|
||||
#include <linux/dsms.h>
|
||||
#else
|
||||
#define DSMS_SUCCESS (0)
|
||||
#define dsms_send_message(feature_code, message, value) (DSMS_SUCCESS)
|
||||
#endif
|
||||
|
||||
static inline bool should_send_dsms_event(void)
|
||||
{
|
||||
#ifdef DEFEX_DSMS_ENABLE
|
||||
return IS_ENABLED(CONFIG_SECURITY_DSMS);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
__visible_for_testing void dtm_append_argv(char *message, size_t size,
|
||||
char separator,
|
||||
int argc, const char **argv)
|
||||
{
|
||||
const char *from;
|
||||
char *to;
|
||||
size_t len;
|
||||
int arg, available;
|
||||
|
||||
if (!message || size <= 0 || !separator)
|
||||
return;
|
||||
if (argc <= 0 || !argv || !argv[0])
|
||||
return;
|
||||
|
||||
arg = 0;
|
||||
len = strnlen(message, size);
|
||||
available = size - len - 1;
|
||||
to = message + len;
|
||||
while (arg < argc && available > 0) {
|
||||
from = argv[arg++];
|
||||
if (!from)
|
||||
from = "(null)";
|
||||
len = strnlen(from, available);
|
||||
strncpy(to, from, len);
|
||||
to += len;
|
||||
available -= len;
|
||||
if (available-- > 0)
|
||||
*to++ = separator;
|
||||
}
|
||||
*to = 0;
|
||||
}
|
||||
|
||||
__visible_for_testing void dtm_prepare_message(char *message, size_t size,
|
||||
const char *where, const char *sep,
|
||||
struct dtm_context *context)
|
||||
{
|
||||
int total_argc, max_argc, arg;
|
||||
|
||||
/* load all arguments to update attributes and fill arg values */
|
||||
total_argc = context->callee_argc;
|
||||
max_argc = min_t(int, total_argc, ARRAY_SIZE(context->callee_argv));
|
||||
if (context->callee_copied_argc != max_argc)
|
||||
for (arg = 0; arg < max_argc; arg++)
|
||||
if (!context->callee_argv[arg])
|
||||
dtm_get_callee_arg(context, arg);
|
||||
|
||||
snprintf(message, size, "%s%s%d:%d:%ld:%ld:%s:%s:%s:", where, sep,
|
||||
context->callee_copied_argc, total_argc,
|
||||
context->callee_copied_args_len, context->callee_total_args_len,
|
||||
dtm_get_caller_path(context), dtm_get_callee_path(context),
|
||||
dtm_get_stdin_mode(context));
|
||||
dtm_append_argv(message, size, ':', max_argc, context->callee_argv);
|
||||
}
|
||||
|
||||
#ifdef DEFEX_DEBUG_ENABLE
|
||||
void dtm_debug_call(const char *where, struct dtm_context *context)
|
||||
{
|
||||
char message[DTM_MAX_LOG_SIZE];
|
||||
|
||||
dtm_prepare_message(message, sizeof(message), where, ": ", context);
|
||||
DTM_LOG_DEBUG("%s", message);
|
||||
}
|
||||
#endif
|
||||
|
||||
noinline void dtm_report_violation(const char *feature_code,
|
||||
struct dtm_context *context)
|
||||
{
|
||||
char message[DTM_MAX_DETAIL_SIZE + 1];
|
||||
int ret;
|
||||
|
||||
dtm_prepare_message(message, sizeof(message), "", "", context);
|
||||
DTM_DEBUG(VIOLATIONS, "[%s]%s", feature_code, message);
|
||||
if (should_send_dsms_event()) {
|
||||
ret = dsms_send_message(feature_code, message, 0);
|
||||
if (unlikely(ret != DSMS_SUCCESS))
|
||||
DTM_LOG_ERROR("Error %d while sending DSMS report", ret);
|
||||
}
|
||||
}
|
|
@ -1,137 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2020-2022 Samsung Electronics Co., Ltd. All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/compiler.h>
|
||||
#include <linux/cred.h>
|
||||
#include <linux/dcache.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/namei.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/path.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/stat.h>
|
||||
#include <linux/uidgid.h>
|
||||
#include <linux/version.h>
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
|
||||
#include <linux/sched/mm.h>
|
||||
#endif
|
||||
|
||||
#include "include/dtm.h"
|
||||
#include "include/dtm_log.h"
|
||||
#include "include/dtm_utils.h"
|
||||
|
||||
const char * const DTM_UNKNOWN = "<unknown>";
|
||||
|
||||
static inline int dtm_get_file_attr(struct path *path, struct kstat *stat)
|
||||
{
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)
|
||||
return vfs_getattr(path, stat, STATX_BASIC_STATS, 0);
|
||||
#else
|
||||
return vfs_getattr(path, stat);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Gets mode bit value for a file status.
|
||||
*/
|
||||
int dtm_get_stat_mode_bit(struct kstat *stat)
|
||||
{
|
||||
int mode, mode_bit;
|
||||
|
||||
if (!stat)
|
||||
return DTM_FD_MODE_ERROR;
|
||||
|
||||
mode = (stat->mode) & S_IFMT;
|
||||
switch (mode) {
|
||||
case S_IFBLK:
|
||||
mode_bit = DTM_FD_MODE_BLK;
|
||||
break;
|
||||
case S_IFCHR:
|
||||
mode_bit = DTM_FD_MODE_CHR;
|
||||
break;
|
||||
case S_IFDIR:
|
||||
mode_bit = DTM_FD_MODE_DIR;
|
||||
break;
|
||||
case S_IFIFO:
|
||||
mode_bit = DTM_FD_MODE_FIFO;
|
||||
break;
|
||||
case S_IFLNK:
|
||||
mode_bit = DTM_FD_MODE_LNK;
|
||||
break;
|
||||
case S_IFREG:
|
||||
mode_bit = DTM_FD_MODE_REG;
|
||||
break;
|
||||
case S_IFSOCK:
|
||||
mode_bit = DTM_FD_MODE_SOCK;
|
||||
break;
|
||||
default:
|
||||
mode_bit = DTM_FD_MODE_UNKNOWN;
|
||||
DTM_LOG_ERROR("Unknown stat mode %d", mode);
|
||||
}
|
||||
return mode_bit;
|
||||
}
|
||||
|
||||
/*
|
||||
* Gets mode bit value for a file descriptor.
|
||||
*/
|
||||
int dtm_get_fd_mode_bit(int fd)
|
||||
{
|
||||
struct kstat stat;
|
||||
struct fd sf;
|
||||
int error;
|
||||
|
||||
if (fd < 0)
|
||||
return DTM_FD_MODE_ERROR;
|
||||
|
||||
sf = fdget_raw(fd);
|
||||
if (unlikely(!sf.file))
|
||||
return DTM_FD_MODE_CLOSED;
|
||||
|
||||
error = dtm_get_file_attr(&sf.file->f_path, &stat);
|
||||
fdput(sf);
|
||||
if (unlikely(error < 0))
|
||||
return DTM_FD_MODE_ERROR;
|
||||
|
||||
return dtm_get_stat_mode_bit(&stat);
|
||||
}
|
||||
|
||||
/*
|
||||
* Gets printable name for a fd mode bit value.
|
||||
*/
|
||||
const char *dtm_get_fd_mode_bit_name(int mode_bit)
|
||||
{
|
||||
switch (mode_bit) {
|
||||
case DTM_FD_MODE_NONE:
|
||||
return "NONE";
|
||||
case DTM_FD_MODE_BLK:
|
||||
return "BLK";
|
||||
case DTM_FD_MODE_CHR:
|
||||
return "CHR";
|
||||
case DTM_FD_MODE_DIR:
|
||||
return "DIR";
|
||||
case DTM_FD_MODE_FIFO:
|
||||
return "FIFO";
|
||||
case DTM_FD_MODE_LNK:
|
||||
return "LNK";
|
||||
case DTM_FD_MODE_REG:
|
||||
return "REG";
|
||||
case DTM_FD_MODE_SOCK:
|
||||
return "SOCK";
|
||||
case DTM_FD_MODE_CLOSED:
|
||||
return "CLOSED";
|
||||
case DTM_FD_MODE_ERROR:
|
||||
return "ERROR";
|
||||
case DTM_FD_MODE_UNKNOWN:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
DTM_LOG_ERROR("Unexpected mode bit %d", mode_bit);
|
||||
return "INVALID";
|
||||
}
|
|
@ -1,475 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2021-2022 Samsung Electronics Co., Ltd. All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include "include/defex_debug.h"
|
||||
#include "include/ptree.h"
|
||||
|
||||
/* Functions for "using" (i.e., loading and searching) p-tree in portable
|
||||
* variant.
|
||||
*/
|
||||
|
||||
/* Big-endian uchar -> int */
|
||||
static unsigned int charp2UInt(const unsigned char *p, int size)
|
||||
{
|
||||
unsigned int i = *p;
|
||||
|
||||
if (size > 1) {
|
||||
i = (i << 8) | p[1];
|
||||
if (size > 2) {
|
||||
i = (i << 8) | p[2];
|
||||
if (size > 3)
|
||||
i = (i << 8) | p[3];
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
/* Checks magic number, loads important constants from prologue
|
||||
*/
|
||||
static int pptree_set_header(struct PPTree *tree)
|
||||
{
|
||||
const unsigned char *pp = tree->data;
|
||||
|
||||
/* Only PPTREE_MAGIC_FIXEDSIZE bytes are mandatory, remaining
|
||||
* two can encode version information for compatibility
|
||||
*/
|
||||
if (strncmp((char *)pp, PPTREE_MAGIC, PPTREE_MAGIC_FIXEDSIZE)) {
|
||||
defex_log_warn("Ptree: Bad magic number");
|
||||
return -1;
|
||||
}
|
||||
pp += PPTREE_MAGIC_FIXEDSIZE + 2;
|
||||
tree->sTable.fullSize = charp2UInt(pp, UPPER_COUNT_SIZE);
|
||||
pp += UPPER_COUNT_SIZE;
|
||||
tree->sTable.size = charp2UInt(pp, UPPER_COUNT_SIZE);
|
||||
pp += UPPER_COUNT_SIZE;
|
||||
tree->sTable.indexSize = charp2UInt(pp++, 1);
|
||||
tree->sTable.table = pp;
|
||||
pp += tree->sTable.fullSize;
|
||||
|
||||
tree->bTable.fullSize = charp2UInt(pp, UPPER_COUNT_SIZE);
|
||||
pp += UPPER_COUNT_SIZE;
|
||||
tree->bTable.size = charp2UInt(pp, UPPER_COUNT_SIZE);
|
||||
pp += UPPER_COUNT_SIZE;
|
||||
tree->bTable.indexSize = charp2UInt(pp++, 1);
|
||||
tree->bTable.table = pp;
|
||||
pp += tree->bTable.fullSize;
|
||||
|
||||
tree->nodes.childCountSize = charp2UInt(pp++, 1);
|
||||
tree->nodes.offsetSize = charp2UInt(pp++, 1);
|
||||
tree->nodes.root = pp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pptree_set_data(struct PPTree *tree, const unsigned char *data)
|
||||
{
|
||||
tree->data = data;
|
||||
tree->allocated = 0;
|
||||
return pptree_set_header(tree);
|
||||
}
|
||||
|
||||
void pptree_free(struct PPTree *tree)
|
||||
{
|
||||
if (tree->allocated && tree->data) {
|
||||
kfree((void *)tree->data);
|
||||
tree->data = 0;
|
||||
tree->allocated = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Gets a string (either a component of a search key or data associated
|
||||
* with an item) given index
|
||||
*/
|
||||
static const unsigned char *pptree_string(const struct PPTree *tree, int i)
|
||||
{
|
||||
const unsigned char *sTable = tree->sTable.table;
|
||||
int index, bcs = tree->sTable.indexSize;
|
||||
|
||||
if (i < 0 || i >= tree->sTable.size) {
|
||||
defex_log_warn("Ptree: bad string index: %d (max %d)", i, tree->sTable.size);
|
||||
return 0;
|
||||
}
|
||||
index = charp2UInt(sTable + i * bcs, bcs);
|
||||
return sTable + (1 + tree->sTable.size) * bcs + index;
|
||||
}
|
||||
|
||||
/* Gets a bytearray given index */
|
||||
static const unsigned char *pptree_bytearray(const struct PPTree *tree, int i,
|
||||
int *length)
|
||||
{
|
||||
const unsigned char *bTable = tree->bTable.table;
|
||||
int index, indexNext, bcs = tree->bTable.indexSize;
|
||||
|
||||
if (i < 0 || i >= tree->bTable.size) {
|
||||
defex_log_warn("Ptree: Bad bytearray index: %d (max %d)", i, tree->bTable.size);
|
||||
if (length)
|
||||
*length = 0;
|
||||
return "";
|
||||
}
|
||||
index = charp2UInt(bTable + i * bcs, bcs);
|
||||
if (length) {
|
||||
indexNext = charp2UInt(bTable + (i + 1) * bcs, bcs);
|
||||
*length = indexNext - index;
|
||||
}
|
||||
return bTable + (1 + tree->bTable.size) * bcs + index;
|
||||
}
|
||||
|
||||
/* Given a pointer to the start of a tree node, load important values
|
||||
* and advance pointer to the start of item index.
|
||||
*/
|
||||
static void load_node_prologue(const struct PPTree *tree,
|
||||
const unsigned char **p,
|
||||
unsigned int *itemSize,
|
||||
unsigned int *dataTypes,
|
||||
unsigned int *childCount)
|
||||
{
|
||||
/* <dtTypes> is the |-ing of data masks of all items in this node,
|
||||
* thus all possible data types associated to items.
|
||||
* By extension, it determines <itSize>, which is the size in bytes
|
||||
* of all items in this node.
|
||||
*/
|
||||
int dtTypes = charp2UInt((*p)++, 1),
|
||||
itSize = tree->sTable.indexSize + tree->nodes.offsetSize;
|
||||
if (dtTypes && itSize) {
|
||||
++itSize;
|
||||
if (dtTypes & PTREE_DATA_BYTES)
|
||||
itSize += tree->bTable.indexSize;
|
||||
if (dtTypes & PTREE_DATA_STRING)
|
||||
itSize += tree->sTable.indexSize;
|
||||
if (dtTypes & PTREE_DATA_INT1)
|
||||
itSize++;
|
||||
if (dtTypes & PTREE_DATA_INT2)
|
||||
itSize += 2;
|
||||
if (dtTypes & PTREE_DATA_INT4)
|
||||
itSize += 4;
|
||||
if (dtTypes & PTREE_DATA_PATH)
|
||||
itSize += tree->nodes.offsetSize;
|
||||
}
|
||||
if (childCount)
|
||||
*childCount = charp2UInt(*p, tree->nodes.childCountSize);
|
||||
*p += tree->nodes.childCountSize;
|
||||
if (dataTypes)
|
||||
*dataTypes = dtTypes;
|
||||
if (itemSize)
|
||||
*itemSize = itSize;
|
||||
}
|
||||
|
||||
/* Calculate offset from root node. It depends on a previous search, if any */
|
||||
static int pptree_get_offset(const struct PPTree *tree,
|
||||
struct PPTreeContext *ctx)
|
||||
{
|
||||
return ctx ?
|
||||
/* Continue from the result of a previous search? */
|
||||
(ctx->types & PTREE_FIND_CONTINUE) && ctx->last ?
|
||||
ctx->last - tree->nodes.root :
|
||||
/* Continue from subpath of a previous search, if any? */
|
||||
ctx->types & PTREE_DATA_PATH ?
|
||||
ctx->value.childPath :
|
||||
0 :
|
||||
0; /* No context, use root itself */
|
||||
}
|
||||
|
||||
/* Load item-related data. <p> should be pointing to data type byte */
|
||||
static const unsigned char *pptree_get_itemData(const struct PPTree *tree,
|
||||
const unsigned char *p,
|
||||
int dataTypes,
|
||||
struct PPTreeContext *ctx)
|
||||
{
|
||||
memset(&ctx->value, 0, sizeof(ctx->value));
|
||||
ctx->types = (ctx->types & ~PTREE_DATA_MASK) | charp2UInt(p++, 1);
|
||||
if (dataTypes & PTREE_DATA_BYTES) {
|
||||
if (ctx->types & PTREE_DATA_BYTES)
|
||||
ctx->value.bytearray.bytes =
|
||||
pptree_bytearray(tree,
|
||||
charp2UInt(p,
|
||||
tree->bTable.indexSize),
|
||||
&ctx->value.bytearray.length);
|
||||
p += tree->bTable.indexSize;
|
||||
}
|
||||
if (dataTypes & PTREE_DATA_STRING) {
|
||||
if (ctx->types & PTREE_DATA_STRING)
|
||||
ctx->value.string =
|
||||
(const char *)
|
||||
pptree_string(tree,
|
||||
charp2UInt(p,
|
||||
tree->sTable.indexSize));
|
||||
p += tree->sTable.indexSize;
|
||||
}
|
||||
if (dataTypes & PTREE_DATA_BITA)
|
||||
ctx->value.bits = (ctx->types & PTREE_DATA_BITA) &&
|
||||
(ctx->types & PTREE_DATA_BITA_MASK)
|
||||
? 1 : 0;
|
||||
if (dataTypes & PTREE_DATA_INT1) {
|
||||
if (ctx->types & PTREE_DATA_INT1)
|
||||
ctx->value.int1 = charp2UInt(p, 1);
|
||||
++p;
|
||||
}
|
||||
if (dataTypes & PTREE_DATA_INT2) {
|
||||
if (ctx->types & PTREE_DATA_INT2)
|
||||
ctx->value.int2 = charp2UInt(p, 2);
|
||||
p += 2;
|
||||
}
|
||||
if (dataTypes & PTREE_DATA_INT4) {
|
||||
if (ctx->types & PTREE_DATA_INT4)
|
||||
ctx->value.int4 = charp2UInt(p, 4);
|
||||
p += 4;
|
||||
}
|
||||
if (dataTypes & PTREE_DATA_PATH) {
|
||||
if (ctx->types & PTREE_DATA_PATH)
|
||||
ctx->value.childPath =
|
||||
charp2UInt(p, tree->nodes.offsetSize);
|
||||
p += tree->nodes.offsetSize;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
int pptree_find(const struct PPTree *tree, const char **path, int pathLen,
|
||||
struct PPTreeContext *ctx)
|
||||
{
|
||||
int depth;
|
||||
unsigned int dataTypes = 0;
|
||||
const unsigned char *pFound = 0,
|
||||
*p = tree->nodes.root + pptree_get_offset(tree, ctx);
|
||||
|
||||
if (ctx->types & PTREE_FIND_PEEKED) {
|
||||
/* If a previous call used PTREE_FIND_PEEK ignore <path>,
|
||||
* only advance context's offset
|
||||
*/
|
||||
if (ctx->lastPeeked) {
|
||||
ctx->last = ctx->lastPeeked;
|
||||
ctx->lastPeeked = 0;
|
||||
return 1;
|
||||
}
|
||||
ctx->types &= ~(PTREE_FIND_PEEK | PTREE_FIND_PEEKED);
|
||||
}
|
||||
if (pathLen < 1)
|
||||
return 0;
|
||||
for (depth = 0; depth < pathLen; ++depth) {
|
||||
const char *s;
|
||||
int rCmp, sIndex, i;
|
||||
unsigned int itemSize, childCount;
|
||||
|
||||
load_node_prologue(tree, &p, &itemSize, &dataTypes, &childCount);
|
||||
rCmp = -1;
|
||||
if (childCount < 5) { /* linear ordered search */
|
||||
for (i = 0; i < childCount; ++i) {
|
||||
sIndex = charp2UInt(p + i * itemSize,
|
||||
tree->sTable.indexSize);
|
||||
rCmp = strncmp(path[depth],
|
||||
(const char *)
|
||||
pptree_string(tree, sIndex),
|
||||
PTREE_FINDPATH_MAX);
|
||||
if (!rCmp)
|
||||
break;
|
||||
if (rCmp < 0)
|
||||
return 0;
|
||||
}
|
||||
if (i == childCount)
|
||||
return 0;
|
||||
} else { /* binary search */
|
||||
int l = 0, r = childCount - 1;
|
||||
|
||||
while (l <= r) {
|
||||
i = l + (r - l) / 2;
|
||||
sIndex = charp2UInt(p + i * itemSize,
|
||||
tree->sTable.indexSize);
|
||||
s = (const char *)pptree_string(tree, sIndex);
|
||||
rCmp = strncmp(path[depth], s,
|
||||
PTREE_FINDPATH_MAX);
|
||||
if (rCmp < 0)
|
||||
r = i - 1;
|
||||
else
|
||||
if (rCmp)
|
||||
l = i + 1;
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (rCmp)
|
||||
return 0;
|
||||
}
|
||||
pFound = p + i * itemSize + tree->sTable.indexSize;
|
||||
p = tree->nodes.root + charp2UInt(pFound,
|
||||
tree->nodes.offsetSize);
|
||||
}
|
||||
if (ctx) {
|
||||
if (ctx->types & PTREE_FIND_PEEK)
|
||||
/* Don't advance context, just store it here */
|
||||
ctx->lastPeeked = p;
|
||||
else {
|
||||
ctx->last = p;
|
||||
ctx->lastPeeked = 0;
|
||||
}
|
||||
if (dataTypes)
|
||||
pptree_get_itemData(tree,
|
||||
pFound + tree->nodes.offsetSize,
|
||||
dataTypes, ctx);
|
||||
else
|
||||
/* Clear all bits for associated data */
|
||||
ctx->types &= ~PTREE_DATA_MASK;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int pptree_find_path(const struct PPTree *tree, const char *path, char delim,
|
||||
struct PPTreeContext *ctx)
|
||||
{
|
||||
int i, itemCount, findRes, flags = ctx->types;
|
||||
char *ppath, *p, **pathItems;
|
||||
const char *q, *pathItems1[1];
|
||||
|
||||
if (!path)
|
||||
return 0;
|
||||
/* Convenience: split <path> in components, invoke pptree_find */
|
||||
if (ctx->types & PTREE_FIND_PEEKED) {
|
||||
/* No path array to fill, just use last result */
|
||||
pathItems = 0;
|
||||
itemCount = 0;
|
||||
} else {
|
||||
if (!delim) {
|
||||
/* Special case, consider the whole string as
|
||||
* a single component
|
||||
*/
|
||||
pathItems = (char **)pathItems1;
|
||||
pathItems1[0] = path;
|
||||
itemCount = 1;
|
||||
} else {
|
||||
ppath = kstrndup(path, PTREE_FINDPATH_MAX, GFP_KERNEL);
|
||||
if (!ppath)
|
||||
return 0;
|
||||
for (itemCount = *path ? 1 : 0, q = path; *q; ++q)
|
||||
if (*q == delim)
|
||||
++itemCount;
|
||||
pathItems = kmalloc((itemCount ? itemCount : 1) *
|
||||
sizeof(const char *),
|
||||
GFP_KERNEL);
|
||||
if (!pathItems) {
|
||||
kfree((void *)ppath);
|
||||
return 0;
|
||||
}
|
||||
*pathItems = ppath;
|
||||
for (i = 1, p = ppath; *p; ++p)
|
||||
if (*p == delim) {
|
||||
*p = 0;
|
||||
if (i < itemCount)
|
||||
pathItems[i++] = p + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
findRes = pptree_find(tree, (const char **)pathItems, itemCount, ctx);
|
||||
if (!(flags & PTREE_FIND_PEEKED) && delim) {
|
||||
kfree((void *) pathItems);
|
||||
kfree((void *) ppath);
|
||||
}
|
||||
return findRes;
|
||||
}
|
||||
|
||||
int pptree_child_count(const struct PPTree *tree,
|
||||
struct PPTreeContext *ctx)
|
||||
{
|
||||
const unsigned char *p = tree->nodes.root +
|
||||
pptree_get_offset(tree, ctx);
|
||||
unsigned int childCount;
|
||||
|
||||
load_node_prologue(tree, &p, 0, 0, &childCount);
|
||||
return childCount;
|
||||
}
|
||||
|
||||
int pptree_iterate_children(const struct PPTree *tree,
|
||||
struct PPTreeContext *ctx,
|
||||
int (*f)(const struct PPTree *tree,
|
||||
const char *name,
|
||||
const struct PPTreeContext *itemData,
|
||||
void *data),
|
||||
void *data)
|
||||
{
|
||||
const unsigned char *p;
|
||||
unsigned int i, childCount, itemSize, dataTypes, sIndex;
|
||||
int ret;
|
||||
|
||||
if (!f)
|
||||
return 0;
|
||||
p = tree->nodes.root + pptree_get_offset(tree, ctx);
|
||||
load_node_prologue(tree, &p, &itemSize, &dataTypes, &childCount);
|
||||
for (ret = i = 0; i < childCount; ++i) {
|
||||
struct PPTreeContext itemData;
|
||||
|
||||
sIndex = charp2UInt(p, tree->sTable.indexSize);
|
||||
if (dataTypes)
|
||||
pptree_get_itemData(tree,
|
||||
p + tree->nodes.offsetSize +
|
||||
tree->nodes.offsetSize,
|
||||
dataTypes, &itemData);
|
||||
else
|
||||
itemData.types = 0;
|
||||
ret = (*f)(tree, (const char *)pptree_string(tree, sIndex),
|
||||
&itemData, data);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
p += itemSize;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Recursively traverses all children in subpath of a node given
|
||||
* by <tree>+<offset>, invoking <f> on all paths ending on a leaf.
|
||||
* Returns last result of <f>. Stops prematurely if <f> returns nonzero.
|
||||
*/
|
||||
static int pptree_iterate_subpaths(const struct PPTree *tree,
|
||||
int offset, int pathDepth,
|
||||
int (*f)(const struct PPTree *tree,
|
||||
const char **path,
|
||||
int pathLen, void *data),
|
||||
const char **path, int maxDepth,
|
||||
void *data)
|
||||
{
|
||||
const unsigned char *p = tree->nodes.root + offset;
|
||||
unsigned int i, childCount, itemSize, dataTypes;
|
||||
|
||||
load_node_prologue(tree, &p, &itemSize, &dataTypes, &childCount);
|
||||
for (i = 0; i < childCount; ++i) {
|
||||
const unsigned char *pp = p + i * itemSize;
|
||||
int sIndex, childIndex, j;
|
||||
|
||||
sIndex = charp2UInt(pp, tree->sTable.indexSize);
|
||||
pp += tree->sTable.indexSize;
|
||||
childIndex = charp2UInt(pp, tree->nodes.offsetSize);
|
||||
pp += tree->nodes.offsetSize;
|
||||
path[pathDepth] = (const char *)pptree_string(tree, sIndex);
|
||||
if (childIndex) {
|
||||
if (pathDepth < maxDepth) {
|
||||
j = pptree_iterate_subpaths(tree, childIndex,
|
||||
pathDepth + 1, f,
|
||||
path, maxDepth,
|
||||
data);
|
||||
if (j)
|
||||
return j;
|
||||
}
|
||||
} else
|
||||
if (f) {
|
||||
int j = (*f)(tree, path, pathDepth + 1, data);
|
||||
|
||||
if (j)
|
||||
return j;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pptree_iterate_paths(const struct PPTree *tree,
|
||||
struct PPTreeContext *ctx,
|
||||
int (*f)(const struct PPTree *tree,
|
||||
const char **path,
|
||||
int pathLen, void *data),
|
||||
const char **path, int maxPathLen,
|
||||
void *data)
|
||||
{
|
||||
return pptree_iterate_subpaths(tree, pptree_get_offset(tree, ctx),
|
||||
0, f, path, maxPathLen, data);
|
||||
}
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef __DEFEX_CACHES_H
|
||||
#define __DEFEX_CACHES_H
|
||||
|
||||
#include "defex_config.h"
|
||||
#include "defex_internal.h"
|
||||
|
||||
#define FILE_CACHE_SIZE 0x40
|
||||
|
||||
struct defex_file_cache_entry {
|
||||
int prev_entry;
|
||||
int next_entry;
|
||||
int pid;
|
||||
struct file *file_addr;
|
||||
};
|
||||
|
||||
struct defex_file_cache_list {
|
||||
struct defex_file_cache_entry entry[FILE_CACHE_SIZE];
|
||||
int first_entry;
|
||||
int last_entry;
|
||||
};
|
||||
|
||||
void defex_file_cache_init(void);
|
||||
void defex_file_cache_add(int pid, struct file *file_addr);
|
||||
void defex_file_cache_update(struct file *file_addr);
|
||||
void defex_file_cache_delete(int pid);
|
||||
struct file *defex_file_cache_find(int pid);
|
||||
|
||||
#endif /* __DEFEX_CACHES_H */
|
|
@ -1,229 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef __CONFIG_SECURITY_DEFEX_CATCH_LIST_H
|
||||
#define __CONFIG_SECURITY_DEFEX_CATCH_LIST_H
|
||||
|
||||
#include "defex_config.h"
|
||||
|
||||
//DEFINES//////////////////////////////////////////////////////////////////////
|
||||
#define defex_do_str(s) #s
|
||||
#define defex_make_str(s) defex_do_str(s)
|
||||
|
||||
#define SYSCALL_CATCH(name, errno) \
|
||||
[__NR_##name] = { \
|
||||
.local_syscall = __DEFEX_##name, \
|
||||
.err_code = (errno) \
|
||||
}
|
||||
|
||||
enum defex_local_syscall {
|
||||
__DEFEX_empty = 0,
|
||||
__DEFEX_rmdir,
|
||||
__DEFEX_utimes,
|
||||
__DEFEX_stat,
|
||||
__DEFEX_lstat,
|
||||
__DEFEX_umount,
|
||||
__DEFEX_utime,
|
||||
__DEFEX_futimesat,
|
||||
__DEFEX_uselib,
|
||||
__DEFEX_send,
|
||||
__DEFEX_ustat,
|
||||
__DEFEX_getdents,
|
||||
__DEFEX_recv,
|
||||
__DEFEX_fork,
|
||||
__DEFEX_vfork,
|
||||
__DEFEX_sigprocmask,
|
||||
__DEFEX_sigpending,
|
||||
__DEFEX_sigaction,
|
||||
__DEFEX_sigaltstack,
|
||||
__DEFEX_sigsuspend,
|
||||
__DEFEX_truncate64,
|
||||
__DEFEX_ftruncate64,
|
||||
__DEFEX_fstat64,
|
||||
__DEFEX_fstatat64,
|
||||
__DEFEX_statfs64,
|
||||
__DEFEX_stat64,
|
||||
__DEFEX_lstat64,
|
||||
__DEFEX_eventfd,
|
||||
__DEFEX_epoll_create,
|
||||
__DEFEX_shmget,
|
||||
__DEFEX_shmctl,
|
||||
__DEFEX_semctl,
|
||||
__DEFEX_move_pages,
|
||||
__DEFEX_lookup_dcookie,
|
||||
__DEFEX_truncate,
|
||||
__DEFEX_ftruncate,
|
||||
__DEFEX_chdir,
|
||||
__DEFEX_chroot,
|
||||
__DEFEX_fchmod,
|
||||
__DEFEX_fchmodat,
|
||||
__DEFEX_fchownat,
|
||||
__DEFEX_fchown,
|
||||
__DEFEX_open, // -> included to the source
|
||||
__DEFEX_openat, // -> included to the source
|
||||
__DEFEX_write, // -> included to the source
|
||||
__DEFEX_writev,
|
||||
__DEFEX_pwrite64,
|
||||
__DEFEX_pwritev,
|
||||
__DEFEX_sendfile,
|
||||
__DEFEX_signalfd4,
|
||||
__DEFEX_vmsplice,
|
||||
__DEFEX_splice,
|
||||
__DEFEX_tee,
|
||||
__DEFEX_fsync,
|
||||
__DEFEX_fdatasync,
|
||||
__DEFEX_sync_file_range,
|
||||
__DEFEX_acct,
|
||||
__DEFEX_sched_setparam,
|
||||
__DEFEX_sched_setscheduler,
|
||||
__DEFEX_sched_setaffinity,
|
||||
__DEFEX_reboot,
|
||||
__DEFEX_mq_timedsend,
|
||||
__DEFEX_mq_timedreceive,
|
||||
__DEFEX_msgrcv,
|
||||
__DEFEX_msgsnd,
|
||||
__DEFEX_semtimedop,
|
||||
__DEFEX_add_key,
|
||||
__DEFEX_request_key,
|
||||
__DEFEX_keyctl,
|
||||
__DEFEX_mmap,
|
||||
__DEFEX_mincore,
|
||||
__DEFEX_mbind,
|
||||
__DEFEX_set_mempolicy,
|
||||
__DEFEX_migrate_pages,
|
||||
__DEFEX_accept4,
|
||||
__DEFEX_recvmmsg,
|
||||
__DEFEX_link,
|
||||
__DEFEX_unlink,
|
||||
__DEFEX_mknod,
|
||||
__DEFEX_chmod,
|
||||
__DEFEX_chown,
|
||||
__DEFEX_mknodat,
|
||||
__DEFEX_mkdirat,
|
||||
__DEFEX_unlinkat,
|
||||
__DEFEX_symlinkat,
|
||||
__DEFEX_linkat,
|
||||
__DEFEX_mkdir,
|
||||
__DEFEX_lchown,
|
||||
__DEFEX_rename,
|
||||
__DEFEX_epoll_wait,
|
||||
__DEFEX_sysctl,
|
||||
__DEFEX_renameat,
|
||||
__DEFEX_umount2,
|
||||
__DEFEX_mount,
|
||||
__DEFEX_pivot_root,
|
||||
__DEFEX_utimensat,
|
||||
__DEFEX_fcntl,
|
||||
__DEFEX_kexec_load,
|
||||
__DEFEX_ptrace,
|
||||
__DEFEX_setgroups,
|
||||
__DEFEX_settimeofday,
|
||||
__DEFEX_delete_module,
|
||||
__DEFEX_init_module,
|
||||
__DEFEX_capset,
|
||||
__DEFEX_setpriority,
|
||||
__DEFEX_setregid,
|
||||
__DEFEX_setgid,
|
||||
__DEFEX_setreuid,
|
||||
__DEFEX_setuid,
|
||||
__DEFEX_setresuid,
|
||||
__DEFEX_setresgid,
|
||||
__DEFEX_setpgid,
|
||||
__DEFEX_setfsuid, // -> included to the source
|
||||
__DEFEX_setfsgid, // -> included to the source
|
||||
__DEFEX_getsid,
|
||||
__DEFEX_setsid,
|
||||
__DEFEX_sethostname,
|
||||
__DEFEX_setdomainname,
|
||||
__DEFEX_setrlimit,
|
||||
__DEFEX_umask, // -> included to the source
|
||||
__DEFEX_prctl,
|
||||
__DEFEX_getcpu,
|
||||
__DEFEX_kill,
|
||||
__DEFEX_tgkill,
|
||||
__DEFEX_tkill,
|
||||
__DEFEX_rt_tgsigqueueinfo,
|
||||
__DEFEX_rt_sigqueueinfo,
|
||||
__DEFEX_listen,
|
||||
__DEFEX_accept,
|
||||
__DEFEX_shutdown,
|
||||
__DEFEX_shmat,
|
||||
__DEFEX_shmdt,
|
||||
__DEFEX_semget,
|
||||
__DEFEX_semop,
|
||||
__DEFEX_faccessat,
|
||||
__DEFEX_fchdir,
|
||||
__DEFEX_fstat,
|
||||
__DEFEX_readlinkat,
|
||||
__DEFEX_statfs,
|
||||
__DEFEX_fstatfs,
|
||||
__DEFEX_getcwd,
|
||||
__DEFEX_futex,
|
||||
__DEFEX_perf_event_open,
|
||||
__DEFEX_socket,
|
||||
__DEFEX_bind,
|
||||
__DEFEX_connect,
|
||||
__DEFEX_sendto,
|
||||
__DEFEX_mprotect,
|
||||
__DEFEX_mremap,
|
||||
__DEFEX_pselect6,
|
||||
__DEFEX_ioctl,
|
||||
__DEFEX_ioprio_set,
|
||||
__DEFEX_pipe2,
|
||||
__DEFEX_getdents64,
|
||||
__DEFEX_setitimer,
|
||||
__DEFEX_capget,
|
||||
__DEFEX_getresuid,
|
||||
__DEFEX_getresgid,
|
||||
__DEFEX_rt_sigprocmask,
|
||||
__DEFEX_socketpair,
|
||||
__DEFEX_getsockname,
|
||||
__DEFEX_getpeername,
|
||||
__DEFEX_recvfrom,
|
||||
__DEFEX_setsockopt,
|
||||
__DEFEX_sendmsg,
|
||||
__DEFEX_recvmsg,
|
||||
__DEFEX_socketcall,
|
||||
__DEFEX_rt_sigsuspend,
|
||||
__DEFEX_rt_sigpending,
|
||||
__DEFEX_rt_sigaction,
|
||||
__DEFEX_signal,
|
||||
__DEFEX_remap_file_pages,
|
||||
__DEFEX_ppoll,
|
||||
__DEFEX_dup,
|
||||
__DEFEX_dup3,
|
||||
__DEFEX_eventfd2,
|
||||
__DEFEX_timerfd_create,
|
||||
__DEFEX_timerfd_gettime,
|
||||
__DEFEX_timerfd_settime,
|
||||
__DEFEX_epoll_create1,
|
||||
__DEFEX_epoll_ctl,
|
||||
__DEFEX_epoll_pwait,
|
||||
__DEFEX_rt_sigtimedwait,
|
||||
__DEFEX_clone,
|
||||
__DEFEX_execve, // -> included to the source
|
||||
__DEFEX_setxattr,
|
||||
__DEFEX_lsetxattr,
|
||||
__DEFEX_fsetxattr,
|
||||
__DEFEX_removexattr,
|
||||
__DEFEX_lremovexattr,
|
||||
__DEFEX_fremovexattr,
|
||||
__DEFEX_inotify_init1,
|
||||
__DEFEX_syscalls,
|
||||
};
|
||||
|
||||
struct local_syscall_struct {
|
||||
enum defex_local_syscall local_syscall;
|
||||
long int err_code;
|
||||
};
|
||||
|
||||
const struct local_syscall_struct *get_local_syscall(int syscall_no);
|
||||
const struct local_syscall_struct *get_local_syscall_compat(int syscall_no);
|
||||
int syscall_local2global(int syscall_no);
|
||||
|
||||
#endif /* __CONFIG_SECURITY_DEFEX_CATCH_LIST_H */
|
|
@ -1,56 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef __CONFIG_SECURITY_DEFEX_CONFIG_H
|
||||
#define __CONFIG_SECURITY_DEFEX_CONFIG_H
|
||||
|
||||
/* MAX VALUES */
|
||||
#define MAX_LEN 256
|
||||
#define MAX_EXCEPTIONS 1024
|
||||
#define MAX_PROTECTED 1024
|
||||
|
||||
#ifdef DEFEX_PERMISSIVE_PED
|
||||
#define GLOBAL_PED_STATUS (FEATURE_CHECK_CREDS | FEATURE_CHECK_CREDS_SOFT)
|
||||
#else
|
||||
#define GLOBAL_PED_STATUS FEATURE_CHECK_CREDS
|
||||
#endif
|
||||
|
||||
#ifdef DEFEX_PERMISSIVE_INT
|
||||
#define GLOBAL_INTEGRITY_STATUS (FEATURE_INTEGRITY | FEATURE_INTEGRITY_SOFT)
|
||||
#else
|
||||
#define GLOBAL_INTEGRITY_STATUS FEATURE_INTEGRITY
|
||||
#endif
|
||||
|
||||
#ifdef DEFEX_PERMISSIVE_SP
|
||||
#define GLOBAL_SAFEPLACE_STATUS (FEATURE_SAFEPLACE | FEATURE_SAFEPLACE_SOFT)
|
||||
#else
|
||||
#define GLOBAL_SAFEPLACE_STATUS FEATURE_SAFEPLACE
|
||||
#endif
|
||||
|
||||
#ifdef DEFEX_PERMISSIVE_TM
|
||||
#define GLOBAL_TRUSTED_MAP_STATUS (FEATURE_TRUSTED_MAP | FEATURE_TRUSTED_MAP_SOFT)
|
||||
#else
|
||||
#define GLOBAL_TRUSTED_MAP_STATUS FEATURE_TRUSTED_MAP
|
||||
#endif
|
||||
|
||||
#ifdef DEFEX_PERMISSIVE_IM
|
||||
#define GLOBAL_IMMUTABLE_STATUS (FEATURE_IMMUTABLE | FEATURE_IMMUTABLE_SOFT)
|
||||
#else
|
||||
#define GLOBAL_IMMUTABLE_STATUS FEATURE_IMMUTABLE
|
||||
#endif
|
||||
|
||||
/* Uncomment for Kernels, that require it */
|
||||
#define STRICT_UID_TYPE_CHECKS 1
|
||||
|
||||
#if defined(DEFEX_PED_ENABLE) || defined(DEFEX_SAFEPLACE_ENABLE) || defined(DEFEX_TRUSTED_MAP_ENABLE) || defined(DEFEX_IMMUTABLE_ENABLE)
|
||||
#define DEFEX_FEATURE_ENABLE
|
||||
#endif /* DEFEX_PED_ENABLE || DEFEX_SAFEPLACE_ENABLE || DEFEX_TRUSTED_MAP_ENABLE || DEFEX_IMMUTABLE_ENABLE */
|
||||
|
||||
int defex_get_features(void);
|
||||
|
||||
#endif /* CONFIG_SECURITY_DEFEX_CONFIG_H */
|
|
@ -1,70 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef __DEFEX_DEBUG_H
|
||||
#define __DEFEX_DEBUG_H
|
||||
|
||||
#define DBG_SETUID 0
|
||||
#define DBG_SET_FSUID 1
|
||||
#define DBG_SETGID 2
|
||||
|
||||
#define DBG_SET_PE_STATUS 3
|
||||
#define DBG_SET_IM_STATUS 4
|
||||
#define DBG_SET_SP_STATUS 5
|
||||
#define DBG_SET_INT_STATUS 6
|
||||
#define DBG_GET_LOG 7
|
||||
|
||||
#define MAX_DATA_LEN 300
|
||||
|
||||
#define DEFEX_LOG_TAG "[DEFEX] "
|
||||
#define DEFEX_LOG_BUF_SIZE (PAGE_SIZE << 0)
|
||||
#define DEFEX_LOG_BUF_MASK (DEFEX_LOG_BUF_SIZE - 1)
|
||||
#define DEFEX_LOG_LEVEL_MASK (MSG_CRIT | MSG_ERR | MSG_WARN | MSG_INFO | MSG_DEBUG | MSG_TIMEOFF | MSG_BLOB)
|
||||
|
||||
enum defex_log_level {
|
||||
MSG_CRIT = 1,
|
||||
MSG_ERR = 2,
|
||||
MSG_WARN = 4,
|
||||
MSG_INFO = 8,
|
||||
MSG_DEBUG = 16,
|
||||
MSG_TIMEOFF = 32,
|
||||
MSG_BLOB = 64
|
||||
};
|
||||
|
||||
int defex_create_debug(struct kset *defex_kset);
|
||||
|
||||
void blob(const char *title, const char *buffer, const size_t bufLen, const int lineSize);
|
||||
|
||||
#ifdef DEFEX_DEBUG_ENABLE
|
||||
#define defex_log_crit(fmt, ...) defex_print_msg(MSG_CRIT, fmt, ##__VA_ARGS__)
|
||||
#define defex_log_err(fmt, ...) defex_print_msg(MSG_ERR, fmt, ##__VA_ARGS__)
|
||||
#define defex_log_warn(fmt, ...) defex_print_msg(MSG_WARN, fmt, ##__VA_ARGS__)
|
||||
#define defex_log_info(fmt, ...) defex_print_msg(MSG_INFO, fmt, ##__VA_ARGS__)
|
||||
#define defex_log_debug(fmt, ...) defex_print_msg(MSG_DEBUG, fmt, ##__VA_ARGS__)
|
||||
#define defex_log_timeoff(fmt, ...) defex_print_msg(MSG_TIMEOFF, fmt, ##__VA_ARGS__)
|
||||
#define defex_log_blob(fmt, ...) defex_print_msg(MSG_BLOB, fmt, ##__VA_ARGS__)
|
||||
void defex_print_msg(const enum defex_log_level msg_type, const char *format, ...);
|
||||
#else
|
||||
#define defex_log_crit(fmt, ...) pr_crit(DEFEX_LOG_TAG fmt "\n", ##__VA_ARGS__)
|
||||
#define defex_log_err(fmt, ...) pr_err(DEFEX_LOG_TAG fmt "\n", ##__VA_ARGS__)
|
||||
#define defex_log_warn(fmt, ...) pr_warn(DEFEX_LOG_TAG fmt "\n", ##__VA_ARGS__)
|
||||
#define defex_log_info(fmt, ...) pr_info(DEFEX_LOG_TAG fmt "\n", ##__VA_ARGS__)
|
||||
#define defex_log_debug(fmt, ...) pr_debug(DEFEX_LOG_TAG fmt "\n", ##__VA_ARGS__)
|
||||
#define defex_log_timeoff(fmt, ...) pr_info(DEFEX_LOG_TAG fmt "\n", ##__VA_ARGS__)
|
||||
#define defex_log_blob(fmt, ...) pr_crit(fmt "\n", ##__VA_ARGS__)
|
||||
#endif /* DEFEX_DEBUG_ENABLE */
|
||||
|
||||
#ifdef DEFEX_LOG_BUFFER_ENABLE
|
||||
void log_buffer_flush(void);
|
||||
#endif /* DEFEX_LOG_BUFFER_ENABLE */
|
||||
|
||||
#ifdef DEFEX_SHOW_RULES_ENABLE
|
||||
int defex_show_structure(void *packed_rules, int rules_size);
|
||||
#endif /* DEFEX_SHOW_RULES_ENABLE */
|
||||
|
||||
#endif /* __DEFEX_DEBUG_H */
|
|
@ -1,231 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef __CONFIG_SECURITY_DEFEX_INTERNAL_H
|
||||
#define __CONFIG_SECURITY_DEFEX_INTERNAL_H
|
||||
|
||||
#include <linux/cred.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/hashtable.h>
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/defex.h>
|
||||
#include "defex_config.h"
|
||||
|
||||
#ifdef DEFEX_KUNIT_ENABLED
|
||||
#include <kunit/mock.h>
|
||||
#endif
|
||||
|
||||
#define DEFEX_MAJOR_VERSION 2
|
||||
#define DEFEX_MINOR_VERSION 6
|
||||
#define DEFEX_REVISION "rel"
|
||||
|
||||
/* DEFEX Features */
|
||||
#define FEATURE_NONE 0
|
||||
#define FEATURE_CHECK_CREDS (1 << 0)
|
||||
#define FEATURE_CHECK_CREDS_SOFT (1 << 1)
|
||||
#define FEATURE_JAILHOUSE (1 << 2) /* reserved for future use */
|
||||
#define FEATURE_JAILHOUSE_SOFT (1 << 3) /* reserved for future use */
|
||||
#define FEATURE_RESTRICT_SYSCALL (1 << 4) /* reserved for future use */
|
||||
#define FEATURE_RESTRICT_SYSCALL_SOFT (1 << 5) /* reserved for future use */
|
||||
#define FEATURE_IMMUTABLE (1 << 6)
|
||||
#define FEATURE_IMMUTABLE_SOFT (1 << 7)
|
||||
#define FEATURE_SAFEPLACE (1 << 8)
|
||||
#define FEATURE_SAFEPLACE_SOFT (1 << 9)
|
||||
#define FEATURE_FIVE (1 << 10) /* reserved for future use */
|
||||
#define FEATURE_FIVE_SOFT (1 << 11) /* reserved for future use */
|
||||
#define FEATURE_TRUSTED_MAP (1 << 12)
|
||||
#define FEATURE_TRUSTED_MAP_SOFT (1 << 13)
|
||||
#define FEATURE_INTEGRITY (1 << 14)
|
||||
#define FEATURE_INTEGRITY_SOFT (1 << 15)
|
||||
|
||||
#define FEATURE_CLEAR_ALL (0xFF0000)
|
||||
|
||||
#define DEFEX_ALLOW 0
|
||||
#define DEFEX_DENY 1
|
||||
|
||||
#define DEFEX_OK 0
|
||||
#define DEFEX_NOK 1
|
||||
|
||||
#define DEFEX_STARTED 1
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Integrity feature */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
#define DEFEX_INTEGRITY_FAIL (1 << 1)
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* PrivEsc feature */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
#ifdef STRICT_UID_TYPE_CHECKS
|
||||
#define CHECK_ROOT_CREDS(x) (uid_eq((x)->uid, GLOBAL_ROOT_UID) || \
|
||||
gid_eq((x)->gid, GLOBAL_ROOT_GID) || \
|
||||
uid_eq((x)->euid, GLOBAL_ROOT_UID) || \
|
||||
gid_eq((x)->egid, GLOBAL_ROOT_GID))
|
||||
|
||||
#define GLOBAL_SYS_UID KUIDT_INIT(1000)
|
||||
#define GLOBAL_SYS_GID KGIDT_INIT(1000)
|
||||
|
||||
#define CHECK_SYS_CREDS(x) (uid_eq((x)->uid, GLOBAL_SYS_UID) || \
|
||||
gid_eq((x)->gid, GLOBAL_SYS_GID) || \
|
||||
uid_eq((x)->euid, GLOBAL_SYS_UID) || \
|
||||
gid_eq((x)->egid, GLOBAL_SYS_GID))
|
||||
|
||||
#define uid_get_value(x) (x.val)
|
||||
#define uid_set_value(x, v) x.val = v
|
||||
|
||||
#else
|
||||
#define CHECK_ROOT_CREDS(x) (((x)->uid == 0) || ((x)->gid == 0) || \
|
||||
((x)->euid == 0) || ((x)->egid == 0))
|
||||
#define uid_get_value(x) (x)
|
||||
#define uid_set_value(x, v) (x = v)
|
||||
#endif /* STRICT_UID_TYPE_CHECKS */
|
||||
|
||||
#define CRED_FLAGS_PROOT (1 << 0) /* parent is root */
|
||||
#define CRED_FLAGS_MAIN_UPDATED (1 << 1) /* main thread's permission updated */
|
||||
#define CRED_FLAGS_SUB_UPDATED (1 << 2) /* sub thread's permission updated */
|
||||
|
||||
#define GET_CREDS(ids_ptr, cred_data_ptr) do { uid = (ids_ptr)->uid; \
|
||||
fsuid = (ids_ptr)->fsuid; \
|
||||
egid = (ids_ptr)->egid; \
|
||||
cred_flags = (cred_data_ptr)->cred_flags; } while(0)
|
||||
|
||||
#define SET_CREDS(ids_ptr, cred_data_ptr) do { (ids_ptr)->uid = uid; \
|
||||
(ids_ptr)->fsuid = fsuid; \
|
||||
(ids_ptr)->egid = egid; \
|
||||
(cred_data_ptr)->cred_flags |= cred_flags; } while(0)
|
||||
|
||||
extern unsigned char global_privesc_status;
|
||||
|
||||
void get_task_creds(struct task_struct *p, unsigned int *uid_ptr, unsigned int *fsuid_ptr, unsigned int *egid_ptr, unsigned short *cred_flags_ptr);
|
||||
int set_task_creds(struct task_struct *p, unsigned int uid, unsigned int fsuid, unsigned int egid, unsigned short cred_flags);
|
||||
void set_task_creds_tcnt(struct task_struct *p, int addition);
|
||||
int is_task_creds_ready(void);
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Integrity feature */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
extern unsigned char global_integrity_status;
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* SafePlace feature */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
extern unsigned char global_safeplace_status;
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Immutable feature */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
extern unsigned char global_immutable_status;
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Trusted Map feature */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
extern unsigned char global_trusted_map_status;
|
||||
|
||||
enum trusted_map_status {
|
||||
DEFEX_TM_ENFORCING_MODE = (1 << 0),
|
||||
DEFEX_TM_PERMISSIVE_MODE = (1 << 1),
|
||||
DEFEX_TM_DEBUG_VIOLATIONS = (1 << 2),
|
||||
DEFEX_TM_DEBUG_CALLS = (1 << 3),
|
||||
DEFEX_TM_LAST_STATUS = (1 << 4) - 1
|
||||
};
|
||||
|
||||
static inline int defex_tm_mode_enabled(int mode_flag)
|
||||
{
|
||||
return global_trusted_map_status & mode_flag;
|
||||
}
|
||||
|
||||
struct defex_context;
|
||||
int defex_trusted_map_lookup(struct defex_context *dc, int argc, void *argv);
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Common Helper API */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
struct defex_context {
|
||||
int syscall_no;
|
||||
struct task_struct *task;
|
||||
struct file *process_file;
|
||||
struct file *target_file;
|
||||
const struct path *process_dpath;
|
||||
const struct path *target_dpath;
|
||||
char *process_name;
|
||||
char *target_name;
|
||||
char *target_name_buff;
|
||||
char *process_name_buff;
|
||||
|
||||
/* NB: cred must be the last field */
|
||||
struct cred *cred;
|
||||
};
|
||||
|
||||
extern const char unknown_file[];
|
||||
struct rule_item_struct;
|
||||
|
||||
struct file *local_fopen(const char *fname, int flags, umode_t mode);
|
||||
int local_fread(struct file *f, loff_t offset, void *ptr, unsigned long bytes);
|
||||
int init_defex_context(struct defex_context *dc, int syscall, struct task_struct *p, struct file *f);
|
||||
void release_defex_context(struct defex_context *dc);
|
||||
struct file *get_dc_process_file(struct defex_context *dc);
|
||||
const struct path *get_dc_process_dpath(struct defex_context *dc);
|
||||
char *get_dc_process_name(struct defex_context *dc);
|
||||
const struct path *get_dc_target_dpath(struct defex_context *dc);
|
||||
char *get_dc_target_name(struct defex_context *dc);
|
||||
struct file *defex_get_source_file(struct task_struct *p);
|
||||
char *defex_get_filename(struct task_struct *p);
|
||||
char* defex_resolve_filename(const char *name, char **out_buff);
|
||||
int defex_files_identical(const struct file *f1, const struct file *f2);
|
||||
static inline void safe_str_free(void *ptr)
|
||||
{
|
||||
if (ptr && ptr != unknown_file)
|
||||
kfree(ptr);
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Defex lookup API */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
int rules_lookup(const char *target_file, int attribute, struct file *f, struct rule_item_struct **found_item);
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Defex init API */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
int __init defex_init_sysfs(void);
|
||||
void __init creds_fast_hash_init(void);
|
||||
int __init do_load_rules(void);
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Defex debug API */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
int immutable_status_store(const char *status_str);
|
||||
int privesc_status_store(const char *status_str);
|
||||
int safeplace_status_store(const char *status_str);
|
||||
int integrity_status_store(const char *status_str);
|
||||
|
||||
extern bool boot_state_recovery __ro_after_init;
|
||||
#ifdef DEFEX_DEPENDING_ON_OEMUNLOCK
|
||||
extern bool boot_state_unlocked __ro_after_init;
|
||||
extern int warranty_bit __ro_after_init;
|
||||
#else
|
||||
#define boot_state_unlocked (0)
|
||||
#define warranty_bit (0)
|
||||
#endif /* DEFEX_DEPENDING_ON_OEMUNLOCK */
|
||||
|
||||
#endif /* CONFIG_SECURITY_DEFEX_INTERNAL_H */
|
|
@ -1,74 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef __DEFEX_RULES_H
|
||||
#define __DEFEX_RULES_H
|
||||
|
||||
#ifdef DEFEX_TRUSTED_MAP_ENABLE
|
||||
#include "ptree.h"
|
||||
#endif
|
||||
|
||||
#define STATIC_RULES_MAX_STR 32
|
||||
#define INTEGRITY_LENGTH 32
|
||||
#define FEATURE_NAME_MAX_STR 32
|
||||
|
||||
#define GET_ITEM_OFFSET(item_ptr, base_ptr) (((char *)item_ptr) - ((char *)base_ptr))
|
||||
#define GET_ITEM_PTR(offset, base_ptr) ((struct rule_item_struct *)(((char *)base_ptr) + (offset)))
|
||||
|
||||
enum feature_types {
|
||||
feature_is_file = 1,
|
||||
feature_for_recovery = 2,
|
||||
feature_ped_path = 4,
|
||||
feature_ped_exception = 8,
|
||||
feature_ped_status = 16,
|
||||
feature_safeplace_path = 32,
|
||||
feature_safeplace_status = 64,
|
||||
feature_immutable_path_open = 128,
|
||||
feature_immutable_path_write = 256,
|
||||
feature_immutable_src_exception = 512,
|
||||
feature_immutable_status = 1024,
|
||||
feature_umhbin_path = 2048,
|
||||
feature_trusted_map_status = 4096,
|
||||
feature_integrity_check = 8192,
|
||||
feature_immutable_dst_exception = 16384
|
||||
};
|
||||
|
||||
struct feature_match_entry {
|
||||
char feature_name[FEATURE_NAME_MAX_STR];
|
||||
int feature_num;
|
||||
};
|
||||
|
||||
struct static_rule {
|
||||
unsigned int feature_type;
|
||||
char rule[STATIC_RULES_MAX_STR];
|
||||
};
|
||||
|
||||
struct rule_item_struct {
|
||||
unsigned short int next_level;
|
||||
union {
|
||||
struct {
|
||||
unsigned short int next_file;
|
||||
unsigned short int feature_type;
|
||||
} __attribute__((packed));
|
||||
unsigned int data_size;
|
||||
} __attribute__((packed));
|
||||
unsigned char size;
|
||||
#ifdef DEFEX_INTEGRITY_ENABLE
|
||||
unsigned char integrity[INTEGRITY_LENGTH];
|
||||
#endif /* DEFEX_INTEGRITY_ENABLE */
|
||||
char name[0];
|
||||
} __attribute__((packed));
|
||||
|
||||
int check_rules_ready(void);
|
||||
|
||||
#ifdef DEFEX_TRUSTED_MAP_ENABLE
|
||||
/* "Header" for DTM's dynamically loaded policy */
|
||||
extern struct PPTree dtm_tree;
|
||||
#endif
|
||||
|
||||
#endif /* __DEFEX_RULES_H */
|
|
@ -1,16 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef __DEFEX_SIGN_H
|
||||
#define __DEFEX_SIGN_H
|
||||
|
||||
#define SIGN_SIZE 256
|
||||
|
||||
int defex_rules_signature_check(const char *rules_buffer, unsigned int rules_data_size, unsigned int *rules_size);
|
||||
|
||||
#endif /* __DEFEX_SIGN_H */
|
|
@ -1,57 +0,0 @@
|
|||
#ifndef __INCLUDE_TAILER_H__
|
||||
#define __INCLUDE_TAILER_H__
|
||||
|
||||
/* Functions for managing a "tailer file", which is similar to a tar
|
||||
* archive but, in order to support ordinary unadorned files
|
||||
* - stores metainformation after each archived file
|
||||
* - stores a single magic number at the very end.
|
||||
*/
|
||||
|
||||
/* Magic number, occurs only once at the end of tailer file. Should it
|
||||
* change, be sure to update TAIL_MAGIC_LEN
|
||||
*/
|
||||
#define TAIL_MAGIC "#TAIL_GUARD#"
|
||||
#define TAIL_MAGIC_LEN 12
|
||||
/* Maximum length of title associated with a stored file. Arbitrary, but
|
||||
* should it increase, metainfo size (currently 1 byte) must change
|
||||
* accordingly
|
||||
*/
|
||||
#define TAIL_MAX_TITLE_LENGTH 255
|
||||
|
||||
/* Each file's metainfo entry comprises (version 1,0):
|
||||
* - offset where actual contents start: 4-byte big-endian
|
||||
* - size of contents in bytes: 4-byte big-endian
|
||||
* - title, up to TAIL_MAX_TITLE_LENGTH bytes, non 0-terminated
|
||||
* - title length, 1 byte
|
||||
* - major/minor version number, 1 byte each
|
||||
*
|
||||
* A tailer file is either an unadorned one or a linked list of content+
|
||||
* metainfo entries which goes backwards from the magic number.
|
||||
*/
|
||||
|
||||
/* Functions for handling tailer data as memory buffers */
|
||||
|
||||
/* If a memory buffer <p> with <size> given ends with the tailer magic
|
||||
* suffix, returns its offset, else returns -1
|
||||
*/
|
||||
extern long defex_tailerp_has_suffix(const unsigned char *p, long size);
|
||||
/* Given buffer <p> of <size> given, returns address of last occurrence
|
||||
* of contents of given <title> (and if <sizep> sets *<sizep> to
|
||||
* contents size), or 0 if <p> is unadorned has no such
|
||||
* occurrences
|
||||
*/
|
||||
extern const unsigned char *defex_tailerp_find(const unsigned char *p, long size,
|
||||
const char *title, long *sizep);
|
||||
/* Given buffer <p> with <size> bytes, returns 0 if unadorned. Else,
|
||||
* executes <task> for each entry, from last to first, passing arguments
|
||||
* <title> (unterminated), title length, absolute <start> address and
|
||||
* <size> in bytes, plus <data>. Terminates immediately if <task> returns
|
||||
* negative. Returns last result of <task>.
|
||||
*/
|
||||
extern int defex_tailerp_iterate(const unsigned char *p, long size,
|
||||
int (*task)(const char *title, int titleLen,
|
||||
const unsigned char *start,
|
||||
long size, void *data),
|
||||
void *data);
|
||||
|
||||
#endif
|
|
@ -1,87 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _DEFEX_TEST_H
|
||||
#define _DEFEX_TEST_H
|
||||
#ifdef DEFEX_KUNIT_ENABLED
|
||||
#include <kunit/mock.h>
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/sysfs.h>
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* defex_debug */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
extern struct kobj_attribute debug_attribute;
|
||||
|
||||
extern int set_user(struct cred *new_cred);
|
||||
extern int set_cred(int target_id, int new_val);
|
||||
extern ssize_t debug_store(struct kobject *kobj, struct kobj_attribute *attr,
|
||||
const char *buf, size_t count);
|
||||
extern ssize_t debug_show(struct kobject *kobj, struct kobj_attribute *attr,
|
||||
char *buf);
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* defex_immutable */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
extern int immutable_status_store(const char *status_str);
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* defex_priv */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
extern int privesc_status_store(const char *status_str);
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* defex_safeplace */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
extern int safeplace_status_store(const char *status_str);
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* defex_main */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
|
||||
struct defex_context;
|
||||
|
||||
extern struct task_struct *get_parent_task(const struct task_struct *p);
|
||||
|
||||
#ifdef DEFEX_DSMS_ENABLE
|
||||
extern void defex_report_violation(const char *violation, uint64_t counter, struct defex_context *dc,
|
||||
uid_t stored_uid, uid_t stored_fsuid, uid_t stored_egid, int case_num);
|
||||
#endif
|
||||
|
||||
#ifdef DEFEX_SAFEPLACE_ENABLE
|
||||
extern long kill_process(struct task_struct *p);
|
||||
#endif
|
||||
|
||||
#ifdef DEFEX_PED_ENABLE
|
||||
extern long kill_process_group(struct task_struct *p, int tgid, int pid);
|
||||
extern int task_defex_is_secured(struct defex_context *dc);
|
||||
extern int at_same_group(unsigned int uid1, unsigned int uid2);
|
||||
extern int at_same_group_gid(unsigned int gid1, unsigned int gid2);
|
||||
|
||||
#ifdef DEFEX_LP_ENABLE
|
||||
extern int lower_adb_permission(struct defex_context *dc, unsigned short cred_flags);
|
||||
#endif /* DEFEX_LP_ENABLE */
|
||||
extern int task_defex_check_creds(struct defex_context *dc);
|
||||
#endif /* DEFEX_PED_ENABLE */
|
||||
|
||||
#ifdef DEFEX_SAFEPLACE_ENABLE
|
||||
extern int task_defex_safeplace(struct defex_context *dc);
|
||||
#endif /* DEFEX_SAFEPLACE_ENABLE */
|
||||
|
||||
#ifdef DEFEX_IMMUTABLE_ENABLE
|
||||
extern int task_defex_src_exception(struct defex_context *dc);
|
||||
extern int task_defex_immutable(struct defex_context *dc, int attribute);
|
||||
#endif /* DEFEX_IMMUTABLE_ENABLE */
|
||||
|
||||
#endif /* DEFEX_KUNIT_ENABLED */
|
||||
#endif /* _DEFEX_TEST_H */
|
|
@ -1,171 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2021-2022 Samsung Electronics Co., Ltd. All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef __PTREE_H__
|
||||
|
||||
/* A "P-tree" is a n-ary search tree whose keys are strings. A p-tree
|
||||
* node may be associated with data like a string, a byte array or
|
||||
* an entry point for an additional search (unrelated to the node's
|
||||
* children).
|
||||
*
|
||||
* P-trees are represented in two variants:
|
||||
* - a "build" data structure with traditional structs and pointers, used for
|
||||
* building, converting, merging or exporting
|
||||
* - a "portable" format packed with integer indices instead of pointers,
|
||||
* stored as a byte array and used (read-only) by target applications.
|
||||
* In both, all strings are stored at a dictionary and represented in nodes
|
||||
* by indices, therefore child data have constant size; in addition, child
|
||||
* lists are sorted, allowing efficient search.
|
||||
*/
|
||||
|
||||
/* Masks for data types. Should any be created, PTREE_DATA_MASK must
|
||||
* be updated accordingly
|
||||
*/
|
||||
#define PTREE_DATA_BYTES 1 /* byte array */
|
||||
#define PTREE_DATA_STRING 2 /* zero-terminated string */
|
||||
#define PTREE_DATA_PATH 4 /* subpath */
|
||||
#define PTREE_DATA_INT1 8 /* byte */
|
||||
#define PTREE_DATA_INT2 16 /* 2-byte short */
|
||||
#define PTREE_DATA_INT4 32 /* 4-byte int */
|
||||
#define PTREE_DATA_BITA 64 /* bit */
|
||||
/* Bit A is stored directly in the bit below */
|
||||
#define PTREE_DATA_BITA_MASK 128
|
||||
|
||||
#define PTREE_DATA_MASK 255 /* ORs all PTREE_DATA masks */
|
||||
|
||||
/* Modifiers for search behavior */
|
||||
#define PTREE_FIND_CONTINUE 256 /* pptree_find should continue from
|
||||
* previous result, if any
|
||||
*/
|
||||
#define PTREE_FIND_PEEK 512 /* a successful search does not advance
|
||||
* the context, therefore the next search
|
||||
* will start from the same point
|
||||
*/
|
||||
#define PTREE_FIND_PEEKED 1024 /* go to where a previous search would have
|
||||
* gone had it not used PTREE_FIND_PEEKED
|
||||
*/
|
||||
|
||||
/* ***************************************************************************
|
||||
* Declarations needed for _using_ exported P-trees
|
||||
* ***************************************************************************/
|
||||
|
||||
/* Header for portable P-tree. This is not the binary format, rather after
|
||||
* loading it caches the tree's details.
|
||||
*/
|
||||
struct PPTree {
|
||||
const unsigned char *data;
|
||||
struct {
|
||||
int fullSize;
|
||||
int size;
|
||||
char indexSize;
|
||||
const unsigned char *table;
|
||||
} sTable;
|
||||
struct {
|
||||
int fullSize;
|
||||
int size;
|
||||
char indexSize;
|
||||
const unsigned char *table;
|
||||
} bTable;
|
||||
struct {
|
||||
char offsetSize;
|
||||
char childCountSize;
|
||||
const unsigned char *root;
|
||||
} nodes;
|
||||
char allocated;
|
||||
};
|
||||
|
||||
/* Magic number (fixed portion, plus two version bytes) */
|
||||
#define PPTREE_MAGIC "PPTree-\1\0"
|
||||
#define PPTREE_MAGIC_FIXEDSIZE 7
|
||||
|
||||
/* Sets a byte array as a p-tree's data. Returns 0 if successful. */
|
||||
extern int pptree_set_data(struct PPTree *tree, const unsigned char *data);
|
||||
/* Releases pptree data, if needed */
|
||||
extern void pptree_free(struct PPTree *tree);
|
||||
|
||||
/* Context data for portable p-tree operations, especially searching.
|
||||
* Used for both input (key data) and output (result's place and data)
|
||||
* Search starts from root, or,
|
||||
* if .types is PPTREE_DATA_PATH and there's a subpath, from .value.childPath
|
||||
* if .types is PPTREE_FIND_CONTINUE, from latest sucessful search
|
||||
* If .types contains PTREE_DATA_PEEK, context does not advance even if
|
||||
* search is successful. It will advance (and no search will be done) if next
|
||||
* search include PTREE_DATA_PEEKED.
|
||||
*/
|
||||
struct PPTreeContext {
|
||||
int types;
|
||||
struct {
|
||||
struct {
|
||||
const unsigned char *bytes;
|
||||
int length;
|
||||
} bytearray;
|
||||
const char *string;
|
||||
int childPath;
|
||||
int int1;
|
||||
int int2;
|
||||
int int4;
|
||||
unsigned char bits;
|
||||
} value;
|
||||
const unsigned char *last, *lastPeeked;
|
||||
unsigned int childCount;
|
||||
};
|
||||
/* Search for given path. Return 0 if not found, 1 otherwise
|
||||
* (and fills in *ctx).
|
||||
* See PPTreeContext for where the search starts.
|
||||
*/
|
||||
extern int pptree_find(const struct PPTree *tree,
|
||||
const char **path, int pathLen,
|
||||
struct PPTreeContext *ctx);
|
||||
/* Maximum key length, mostly an arbitrary limit against DoS */
|
||||
#define PTREE_FINDPATH_MAX 8000
|
||||
/* Search for a given path.
|
||||
* Similar to pptree_find, but splits <path> at every occurrence of <delim>
|
||||
* (unless delim is 0). In kernelspace, returns 0 if <path> length exceeds
|
||||
* PTREE_FINDPATH_MAX.
|
||||
*/
|
||||
extern int pptree_find_path(const struct PPTree *tree, const char *path,
|
||||
char delim, struct PPTreeContext *ctx);
|
||||
/* Returns number of children.
|
||||
* See PPTreeContext for which is the parent node.
|
||||
*/
|
||||
extern int pptree_child_count(const struct PPTree *tree,
|
||||
struct PPTreeContext *ctx);
|
||||
/* Iterates on immediate children.
|
||||
* See PPTreeContext for iteration root.
|
||||
* Executes <f> for all children until <f> returns nonzero. Returns
|
||||
* last return of <f>.
|
||||
*/
|
||||
extern int pptree_iterate_children(const struct PPTree *tree,
|
||||
struct PPTreeContext *ctx,
|
||||
int (*f)(const struct PPTree *tree,
|
||||
const char *name,
|
||||
const struct PPTreeContext *itemData,
|
||||
void *data),
|
||||
void *data);
|
||||
|
||||
/* Iterate on subpaths.
|
||||
* See PPTreeContext for iteration root.
|
||||
* Executes <f> for all subpaths ending on a leaf, stopping if <f>
|
||||
* returns nonzero.
|
||||
* Returns last result of <f>
|
||||
*/
|
||||
extern int pptree_iterate_paths(const struct PPTree *tree,
|
||||
struct PPTreeContext *ctx,
|
||||
int (*f)(const struct PPTree *tree,
|
||||
const char **path,
|
||||
int pathLen, void *data),
|
||||
const char **path, int maxDepth,
|
||||
void *data);
|
||||
/* Dumps to stdout in human-readable format */
|
||||
extern void pptree_dump(const struct PPTree *tree);
|
||||
|
||||
/* Maximum number of bytes for counters (practical reasonable limit) */
|
||||
#define UPPER_COUNT_SIZE 4
|
||||
|
||||
#define __PTREE_H__
|
||||
#endif
|
|
@ -1,941 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2
|
||||
* as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include "include/defex_rules.h"
|
||||
|
||||
#define SAFE_STRCOPY(dst, src) do { strncpy(dst, src, sizeof(dst)); dst[sizeof(dst) - 1] = 0; } while (0)
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||
#endif /* ARRAY_SIZE */
|
||||
|
||||
const struct feature_match_entry feature_match[] = {
|
||||
{"feature_safeplace_path", feature_safeplace_path},
|
||||
{"feature_ped_exception", feature_ped_exception},
|
||||
{"feature_immutable_path_open", feature_immutable_path_open},
|
||||
{"feature_immutable_path_write", feature_immutable_path_write},
|
||||
{"feature_immutable_src_exception", feature_immutable_src_exception},
|
||||
{"feature_immutable_dst_exception", feature_immutable_dst_exception},
|
||||
{"feature_umhbin_path", feature_umhbin_path},
|
||||
{"feature_integrity_check", feature_integrity_check},
|
||||
};
|
||||
|
||||
struct file_list_item {
|
||||
char file_name[PATH_MAX];
|
||||
#ifdef DEFEX_INTEGRITY_ENABLE
|
||||
char integrity[INTEGRITY_LENGTH * 2 + 1];
|
||||
#endif /* DEFEX_INTEGRITY_ENABLE */
|
||||
int is_recovery;
|
||||
};
|
||||
|
||||
struct rule_item_struct *defex_packed_rules;
|
||||
int packfiles_count, packfiles_size;
|
||||
|
||||
struct file_list_item *file_list = NULL;
|
||||
int file_list_count = 0;
|
||||
|
||||
#ifndef DEFEX_DEBUG_ENABLE
|
||||
int debug_ifdef_is_active = 0;
|
||||
void process_debug_ifdef(const char *src_str);
|
||||
#endif
|
||||
|
||||
/* Show rules vars */
|
||||
const char header_name[16] = {"DEFEX_RULES_FILE"};
|
||||
static char work_path[512];
|
||||
static int global_data_size;
|
||||
|
||||
/* Suplementary functions for packing rules */
|
||||
struct rule_item_struct *create_file_item(const char *name, int l);
|
||||
struct rule_item_struct *add_file_item(struct rule_item_struct *base, const char *name, int l);
|
||||
struct rule_item_struct *lookup_dir(struct rule_item_struct *base, const char *name, int l, int for_recovery);
|
||||
struct rule_item_struct *add_file_path(const char *file_path, int for_recovery);
|
||||
void add_rule(const char *part1, const char *part2, int for_recovery,
|
||||
enum feature_types feature, const char *integrity);
|
||||
void addline2tree(char *src_line, enum feature_types feature);
|
||||
char *extract_rule_text(const char *src_line);
|
||||
int lookup_tree(const char *file_path, int attribute, int for_recovery);
|
||||
int store_tree(FILE *f, FILE *f_bin);
|
||||
|
||||
#ifdef DEFEX_INTEGRITY_ENABLE
|
||||
/* Transfer string to hex */
|
||||
char null_integrity[INTEGRITY_LENGTH * 2 + 1];
|
||||
unsigned char ascii_to_hex(char input);
|
||||
int string_to_hex(const char *input, size_t inputLen, unsigned char *output);
|
||||
#endif /* DEFEX_INTEGRITY_ENABLE */
|
||||
|
||||
/* Suplementary functions for reducing rules */
|
||||
int str_to_feature(const char *str);
|
||||
int remove_substr(char *str, const char *part);
|
||||
void trim_cr_lf(char *str);
|
||||
char* remove_redundant_chars(char *str);
|
||||
int check_path_in_use(const char *path);
|
||||
int load_file_list(const char *name);
|
||||
int lookup_file_list(const char *rule, int for_recovery);
|
||||
|
||||
/* Suplementary functions for showing rules */
|
||||
void feature_to_str(char *str, unsigned short flags);
|
||||
int check_array_size(struct rule_item_struct *ptr);
|
||||
int parse_items(struct rule_item_struct *base, int path_length, int level);
|
||||
int defex_show_structure(void *packed_rules, int rules_size);
|
||||
|
||||
/* Main processing functions */
|
||||
int reduce_rules(const char *source_rules_file, const char *reduced_rules_file, const char *list_file);
|
||||
int pack_rules(const char *source_rules_file, const char *packed_rules_file, const char *packed_rules_binfile);
|
||||
int parse_packed_bin_file(const char *source_bin_file);
|
||||
|
||||
int str_to_feature(const char *str)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(feature_match); i++) {
|
||||
if (strstr(str, feature_match[i].feature_name))
|
||||
return feature_match[i].feature_num;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void feature_to_str(char *str, unsigned short flags)
|
||||
{
|
||||
int i;
|
||||
|
||||
str[0] = 0;
|
||||
for (i = 0; i < ARRAY_SIZE(feature_match); i++)
|
||||
if (flags & feature_match[i].feature_num) {
|
||||
if (str[0])
|
||||
strcat(str, ", ");
|
||||
strcat(str, feature_match[i].feature_name);
|
||||
}
|
||||
if (flags & feature_for_recovery) {
|
||||
if (str[0])
|
||||
strcat(str, ", ");
|
||||
strcat(str, "feature_for_recovery");
|
||||
}
|
||||
}
|
||||
|
||||
int remove_substr(char *str, const char *part)
|
||||
{
|
||||
int l, part_l, found = 0;
|
||||
char *ptr;
|
||||
|
||||
l = strnlen(str, PATH_MAX - 1);
|
||||
ptr = strstr(str, part);
|
||||
if (ptr) {
|
||||
part_l = strnlen(part, 32) - 1;
|
||||
memmove(ptr, ptr + part_l, l - (ptr - str) - part_l + 1);
|
||||
found = 1;
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
void trim_cr_lf(char *str)
|
||||
{
|
||||
char *ptr;
|
||||
/* remove CR or LF at the end */
|
||||
ptr = strchr(str, '\r');
|
||||
if (ptr)
|
||||
*ptr = 0;
|
||||
ptr = strchr(str, '\n');
|
||||
if (ptr)
|
||||
*ptr = 0;
|
||||
}
|
||||
|
||||
char *remove_redundant_chars(char *str)
|
||||
{
|
||||
int l;
|
||||
|
||||
/* skip hash values in the begin */
|
||||
str += 65;
|
||||
trim_cr_lf(str);
|
||||
l = strnlen(str, PATH_MAX - 1);
|
||||
/* remove starting dot or space */
|
||||
while (l && (*str == '.' || *str == ' '))
|
||||
str++;
|
||||
return str;
|
||||
}
|
||||
|
||||
int check_path_in_use(const char *path)
|
||||
{
|
||||
int i;
|
||||
static const char * const path_list[] = {
|
||||
"/root/",
|
||||
"/product",
|
||||
"/recovery/",
|
||||
"/system/",
|
||||
"/tmp/",
|
||||
"/vendor/",
|
||||
#if defined(DEFEX_FACTORY_ENABLE)
|
||||
"/data/",
|
||||
#endif
|
||||
"/apex/",
|
||||
"/system_ext/",
|
||||
"/postinstall/"
|
||||
};
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(path_list); i++) {
|
||||
if (!strncmp(path, path_list[i], strnlen(path_list[i], PATH_MAX)))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct rule_item_struct *create_file_item(const char *name, int l)
|
||||
{
|
||||
struct rule_item_struct *item;
|
||||
unsigned int offset;
|
||||
|
||||
if (!name)
|
||||
l = 0;
|
||||
offset = packfiles_size;
|
||||
packfiles_size += (sizeof(struct rule_item_struct) + l);
|
||||
packfiles_count++;
|
||||
item = GET_ITEM_PTR(offset, defex_packed_rules);
|
||||
item->next_file = 0;
|
||||
item->next_level = 0;
|
||||
item->feature_type = 0;
|
||||
item->size = l;
|
||||
#ifdef DEFEX_INTEGRITY_ENABLE
|
||||
memset(item->integrity, 0, INTEGRITY_LENGTH);
|
||||
#endif /* DEFEX_INTEGRITY_ENABLE */
|
||||
if (l)
|
||||
memcpy(item->name, name, l);
|
||||
return item;
|
||||
}
|
||||
|
||||
struct rule_item_struct *add_file_item(struct rule_item_struct *base, const char *name, int l)
|
||||
{
|
||||
struct rule_item_struct *item, *new_item = NULL;
|
||||
|
||||
if (!base)
|
||||
return new_item;
|
||||
|
||||
new_item = create_file_item(name, l);
|
||||
if (!base->next_level) {
|
||||
base->next_level = GET_ITEM_OFFSET(new_item, defex_packed_rules);
|
||||
} else {
|
||||
item = GET_ITEM_PTR(base->next_level, defex_packed_rules);
|
||||
while (item->next_file)
|
||||
item = GET_ITEM_PTR(item->next_file, defex_packed_rules);
|
||||
item->next_file = GET_ITEM_OFFSET(new_item, defex_packed_rules);
|
||||
}
|
||||
return new_item;
|
||||
}
|
||||
|
||||
struct rule_item_struct *lookup_dir(struct rule_item_struct *base, const char *name, int l, int for_recovery)
|
||||
{
|
||||
struct rule_item_struct *item = NULL;
|
||||
unsigned int offset;
|
||||
|
||||
if (!base || !base->next_level)
|
||||
return item;
|
||||
item = GET_ITEM_PTR(base->next_level, defex_packed_rules);
|
||||
do {
|
||||
if ((!(item->feature_type & feature_is_file)
|
||||
|| (!!(item->feature_type & feature_for_recovery)) == for_recovery)
|
||||
&& item->size == l
|
||||
&& !memcmp(name, item->name, l)) return item;
|
||||
offset = item->next_file;
|
||||
item = GET_ITEM_PTR(offset, defex_packed_rules);
|
||||
} while (offset);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct rule_item_struct *add_file_path(const char *file_path, int for_recovery)
|
||||
{
|
||||
const char *ptr, *next_separator;
|
||||
struct rule_item_struct *base, *cur_item = NULL;
|
||||
int l;
|
||||
|
||||
if (!file_path || *file_path != '/')
|
||||
return NULL;
|
||||
if (!defex_packed_rules) {
|
||||
packfiles_count = 0;
|
||||
packfiles_size = 0;
|
||||
defex_packed_rules = calloc(sizeof(struct rule_item_struct), 100 * 1024);
|
||||
if (!defex_packed_rules) {
|
||||
printf("WARNING: Can not create the new item!\n");
|
||||
exit(-1);
|
||||
}
|
||||
create_file_item(header_name, sizeof(header_name));
|
||||
}
|
||||
base = defex_packed_rules;
|
||||
ptr = file_path + 1;
|
||||
do {
|
||||
next_separator = strchr(ptr, '/');
|
||||
if (!next_separator)
|
||||
l = strlen(ptr);
|
||||
else
|
||||
l = next_separator - ptr;
|
||||
if (!l)
|
||||
return NULL; /* two slashes in sequence */
|
||||
cur_item = lookup_dir(base, ptr, l, for_recovery);
|
||||
if (!cur_item) {
|
||||
cur_item = add_file_item(base, ptr, l);
|
||||
/* slash wasn't found, it's a file */
|
||||
if (!next_separator) {
|
||||
cur_item->feature_type |= feature_is_file;
|
||||
if (for_recovery)
|
||||
cur_item->feature_type |= feature_for_recovery;
|
||||
}
|
||||
}
|
||||
base = cur_item;
|
||||
ptr += l;
|
||||
if (next_separator)
|
||||
ptr++;
|
||||
} while (*ptr);
|
||||
return cur_item;
|
||||
}
|
||||
|
||||
int lookup_tree(const char *file_path, int attribute, int for_recovery)
|
||||
{
|
||||
const char *ptr, *next_separator;
|
||||
struct rule_item_struct *base, *cur_item = NULL;
|
||||
int l;
|
||||
|
||||
if (!file_path || *file_path != '/' || !defex_packed_rules)
|
||||
return 0;
|
||||
base = defex_packed_rules;
|
||||
ptr = file_path + 1;
|
||||
do {
|
||||
next_separator = strchr(ptr, '/');
|
||||
if (!next_separator)
|
||||
l = strlen(ptr);
|
||||
else
|
||||
l = next_separator - ptr;
|
||||
if (!l)
|
||||
return 0;
|
||||
cur_item = lookup_dir(base, ptr, l, for_recovery);
|
||||
if (!cur_item)
|
||||
break;
|
||||
if (cur_item->feature_type & attribute)
|
||||
return 1;
|
||||
base = cur_item;
|
||||
ptr += l;
|
||||
if (next_separator)
|
||||
ptr++;
|
||||
} while (*ptr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *extract_rule_text(const char *src_line)
|
||||
{
|
||||
char *start_ptr, *end_ptr;
|
||||
|
||||
start_ptr = strchr(src_line, '\"');
|
||||
if (start_ptr) {
|
||||
start_ptr++;
|
||||
end_ptr = strchr(start_ptr, '\"');
|
||||
if (end_ptr) {
|
||||
*end_ptr = 0;
|
||||
return start_ptr;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef DEFEX_INTEGRITY_ENABLE
|
||||
unsigned char ascii_to_hex(char input)
|
||||
{
|
||||
if (input >= 0x30 && input <= 0x39)
|
||||
return (unsigned char)input - 0x30;
|
||||
else if (input >= 0x41 && input <= 0x46)
|
||||
return (unsigned char)input - 0x37;
|
||||
else if (input >= 0x61 && input <= 0x66)
|
||||
return (unsigned char)input - 0x57;
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
int string_to_hex(const char *input, size_t inputLen, unsigned char *output)
|
||||
{
|
||||
unsigned char convert1, convert2;
|
||||
size_t i;
|
||||
|
||||
if (input == NULL || output == NULL)
|
||||
return 0;
|
||||
|
||||
/* Check input is a paired value. */
|
||||
if (inputLen % 2 != 0)
|
||||
return 0;
|
||||
|
||||
/* divide length by 2 */
|
||||
inputLen >>= 1;
|
||||
memset(output, 0, inputLen);
|
||||
|
||||
/* Convert ascii code to hexa. */
|
||||
for (i = 0; i < inputLen; i++) {
|
||||
convert1 = ascii_to_hex(input[2*i]);
|
||||
convert2 = ascii_to_hex(input[2*i+1]);
|
||||
|
||||
if (convert1 == 0xFF || convert2 == 0xFF)
|
||||
return 0;
|
||||
|
||||
output[i] = (char)((convert1 << 4) | convert2);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#endif /* DEFEX_INTEGRITY_ENABLE */
|
||||
|
||||
void add_rule(const char *part1, const char *part2, int for_recovery, enum feature_types feature, const char *integrity)
|
||||
{
|
||||
struct rule_item_struct *item_part1 = NULL, *item_part2;
|
||||
|
||||
(void)integrity;
|
||||
if (part1) {
|
||||
item_part1 = add_file_path(part1, for_recovery);
|
||||
if (item_part1) {
|
||||
item_part1->feature_type |= feature;
|
||||
if (part2 && item_part1->feature_type & feature_is_file) {
|
||||
item_part2 = add_file_path(part2, 0);
|
||||
if (item_part2)
|
||||
item_part2->feature_type |= feature_immutable_dst_exception;
|
||||
|
||||
/* add the reference from part1 to part2 */
|
||||
if (item_part2)
|
||||
item_part1->next_level = GET_ITEM_OFFSET(item_part2, defex_packed_rules);
|
||||
}
|
||||
#ifdef DEFEX_INTEGRITY_ENABLE
|
||||
if (integrity)
|
||||
string_to_hex(integrity + 1, INTEGRITY_LENGTH * 2, item_part1->integrity);
|
||||
#endif /* DEFEX_INTEGRITY_ENABLE */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void addline2tree(char *src_line, enum feature_types feature)
|
||||
{
|
||||
char *part1, *part2;
|
||||
char *n_sign = NULL, *r_sign = NULL;
|
||||
char *integrity;
|
||||
|
||||
(void)integrity;
|
||||
/* extract the first part */
|
||||
part1 = extract_rule_text(src_line);
|
||||
if (!part1)
|
||||
return;
|
||||
/* extract the second part after ':' symbol (immutable_dst_exception rule) */
|
||||
part2 = strchr(part1, ':');
|
||||
if (part2) {
|
||||
*part2 = 0;
|
||||
++part2;
|
||||
}
|
||||
|
||||
#ifdef DEFEX_INTEGRITY_ENABLE
|
||||
integrity = strchr((part2) ? part2 : part1, '\0') + 1;
|
||||
integrity = extract_rule_text(integrity);
|
||||
if (integrity) {
|
||||
n_sign = strchr(integrity, 'N');
|
||||
r_sign = strchr(integrity, 'R');
|
||||
}
|
||||
#endif /* DEFEX_INTEGRITY_ENABLE */
|
||||
|
||||
if (n_sign || !r_sign)
|
||||
add_rule(part1, part2, 0, feature, n_sign);
|
||||
|
||||
if (r_sign)
|
||||
add_rule(part1, part2, 1, feature, r_sign);
|
||||
}
|
||||
|
||||
int store_tree(FILE *f, FILE *f_bin)
|
||||
{
|
||||
unsigned char *ptr = (unsigned char *)defex_packed_rules;
|
||||
static char work_str[4096];
|
||||
int i, offset = 0, index = 0;
|
||||
|
||||
if (packfiles_size)
|
||||
defex_packed_rules->data_size = packfiles_size;
|
||||
|
||||
work_str[0] = 0;
|
||||
fprintf(f, "#ifndef DEFEX_RAMDISK_ENABLE\n\n");
|
||||
fprintf(f, "const unsigned char defex_packed_rules[] = {\n");
|
||||
for (i = 0; i < packfiles_size; i++) {
|
||||
if (index)
|
||||
offset += snprintf(work_str + offset, sizeof(work_str) - offset, ", ");
|
||||
offset += snprintf(work_str + offset, sizeof(work_str) - offset, "0x%02x", ptr[i]);
|
||||
index++;
|
||||
if (index == 16) {
|
||||
fprintf(f, "\t%s,\n", work_str);
|
||||
index = 0;
|
||||
offset = 0;
|
||||
}
|
||||
}
|
||||
if (index)
|
||||
fprintf(f, "\t%s\n", work_str);
|
||||
fprintf(f, "};\n");
|
||||
fprintf(f, "\n#endif /* DEFEX_RAMDISK_ENABLE */\n\n");
|
||||
fprintf(f, "#define DEFEX_RULES_ARRAY_SIZE\t\t%d\n", packfiles_size);
|
||||
if (f_bin)
|
||||
fwrite(defex_packed_rules, 1, packfiles_size, f_bin);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int load_file_list(const char *name)
|
||||
{
|
||||
int found;
|
||||
char *str;
|
||||
FILE *lst_file = NULL;
|
||||
struct file_list_item *file_list_new;
|
||||
static char work_str[PATH_MAX*2];
|
||||
|
||||
lst_file = fopen(name, "r");
|
||||
if (!lst_file)
|
||||
return -1;
|
||||
|
||||
while (!feof(lst_file)) {
|
||||
if (!fgets(work_str, sizeof(work_str), lst_file))
|
||||
break;
|
||||
str = remove_redundant_chars(work_str);
|
||||
if (*str == '/' && check_path_in_use(str)) {
|
||||
remove_substr(str, "/root/");
|
||||
found = remove_substr(str, "/recovery/");
|
||||
file_list_count++;
|
||||
file_list_new = realloc(file_list, sizeof(struct file_list_item) * file_list_count);
|
||||
if (!file_list_new) {
|
||||
free(file_list);
|
||||
printf("WARNING: Can not allocate the filelist item!\n");
|
||||
exit(-1);
|
||||
}
|
||||
file_list = file_list_new;
|
||||
#ifdef DEFEX_INTEGRITY_ENABLE
|
||||
strncpy(file_list[file_list_count - 1].integrity, work_str, INTEGRITY_LENGTH * 2);
|
||||
file_list[file_list_count - 1].integrity[INTEGRITY_LENGTH * 2] = 0;
|
||||
#endif /* DEFEX_INTEGRITY_ENABLE */
|
||||
SAFE_STRCOPY(file_list[file_list_count - 1].file_name, str);
|
||||
file_list[file_list_count - 1].is_recovery = found;
|
||||
}
|
||||
}
|
||||
fclose(lst_file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int lookup_file_list(const char *rule, int for_recovery)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < file_list_count; i++) {
|
||||
if (file_list[i].is_recovery == for_recovery
|
||||
&& !strncmp(file_list[i].file_name, rule, strnlen(rule, PATH_MAX))
|
||||
&& !strncmp(file_list[i].file_name, rule, strnlen(file_list[i].file_name, PATH_MAX)))
|
||||
return i+1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef DEFEX_DEBUG_ENABLE
|
||||
void process_debug_ifdef(const char *src_str)
|
||||
{
|
||||
char *ptr;
|
||||
ptr = strstr(src_str, "#ifdef DEFEX_DEBUG_ENABLE");
|
||||
if (ptr) {
|
||||
while (ptr > src_str) {
|
||||
ptr--;
|
||||
if (*ptr != ' ' && *ptr != '\t')
|
||||
return;
|
||||
}
|
||||
debug_ifdef_is_active = 1;
|
||||
return;
|
||||
}
|
||||
ptr = strstr(src_str, "#endif");
|
||||
if (ptr && debug_ifdef_is_active) {
|
||||
while (ptr > src_str) {
|
||||
ptr--;
|
||||
if (*ptr != ' ' && *ptr != '\t')
|
||||
return;
|
||||
}
|
||||
debug_ifdef_is_active = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int reduce_rules(const char *source_rules_file, const char *reduced_rules_file, const char *list_file)
|
||||
{
|
||||
int ret_val = -1;
|
||||
int found_normal = 0, found_recovery = 0;
|
||||
char *rule, *colon_ptr;
|
||||
static char work_str[PATH_MAX*2], tmp_str[PATH_MAX*2], rule_part1[PATH_MAX*2];
|
||||
FILE *src_file = NULL, *dst_file = NULL;
|
||||
#ifdef DEFEX_INTEGRITY_ENABLE
|
||||
char *line_end, *integrity_normal;
|
||||
char *integrity_recovery;
|
||||
#endif /* DEFEX_INTEGRITY_ENABLE */
|
||||
|
||||
src_file = fopen(source_rules_file, "r");
|
||||
if (!src_file)
|
||||
return -1;
|
||||
dst_file = fopen(reduced_rules_file, "wt");
|
||||
if (!dst_file)
|
||||
goto do_close2;
|
||||
|
||||
if (load_file_list(list_file) != 0)
|
||||
goto do_close1;
|
||||
|
||||
#ifdef DEFEX_INTEGRITY_ENABLE
|
||||
memset(null_integrity, '0', sizeof(null_integrity) - 1);
|
||||
null_integrity[sizeof(null_integrity) - 1] = 0;
|
||||
#endif /* DEFEX_INTEGRITY_ENABLE */
|
||||
|
||||
while (!feof(src_file)) {
|
||||
if (!fgets(work_str, sizeof(work_str), src_file))
|
||||
break;
|
||||
|
||||
if (str_to_feature(work_str)) {
|
||||
trim_cr_lf(work_str);
|
||||
SAFE_STRCOPY(tmp_str, work_str);
|
||||
rule = extract_rule_text(tmp_str);
|
||||
SAFE_STRCOPY(rule_part1, rule);
|
||||
colon_ptr = strchr(rule_part1, ':');
|
||||
if (colon_ptr)
|
||||
*colon_ptr = 0;
|
||||
found_normal = lookup_file_list(rule_part1, 0);
|
||||
found_recovery = lookup_file_list(rule_part1, 1);
|
||||
if (rule && !found_normal && !found_recovery && !strstr(work_str, "/* DEFAULT */")) {
|
||||
printf("removed rule: %s\n", rule);
|
||||
continue;
|
||||
}
|
||||
#ifdef DEFEX_INTEGRITY_ENABLE
|
||||
integrity_normal = null_integrity;
|
||||
integrity_recovery = null_integrity;
|
||||
if (found_normal)
|
||||
integrity_normal = file_list[found_normal - 1].integrity;
|
||||
if (found_recovery)
|
||||
integrity_recovery = file_list[found_recovery - 1].integrity;
|
||||
|
||||
line_end = strstr(work_str, "},");
|
||||
if (line_end) {
|
||||
*line_end = 0;
|
||||
line_end += 2;
|
||||
}
|
||||
|
||||
/* Add hash vale after each file path */
|
||||
if (found_normal || (!found_normal && !found_recovery))
|
||||
printf("remained rule: %s, %s %s\n",
|
||||
rule, integrity_normal, (line_end != NULL)?line_end:"");
|
||||
if (found_recovery)
|
||||
printf("remained rule: %s, %s %s (R)\n",
|
||||
rule, integrity_recovery, (line_end != NULL)?line_end:"");
|
||||
|
||||
fprintf(dst_file, "%s,\"", work_str);
|
||||
if (found_normal)
|
||||
fprintf(dst_file, "N%s", integrity_normal);
|
||||
if (found_recovery)
|
||||
fprintf(dst_file, "R%s", integrity_recovery);
|
||||
|
||||
fprintf(dst_file, "\"}, %s\n", (line_end != NULL)?line_end:"");
|
||||
|
||||
#else
|
||||
printf("remained rule: %s\n", work_str);
|
||||
fputs(work_str, dst_file);
|
||||
fputs("\n", dst_file);
|
||||
#endif /* DEFEX_INTEGRITY_ENABLE */
|
||||
} else
|
||||
fputs(work_str, dst_file);
|
||||
}
|
||||
ret_val = 0;
|
||||
do_close1:
|
||||
fclose(dst_file);
|
||||
do_close2:
|
||||
fclose(src_file);
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
int pack_rules(const char *source_rules_file, const char *packed_rules_file, const char *packed_rules_binfile)
|
||||
{
|
||||
int ret_val = -1;
|
||||
int feature;
|
||||
FILE *src_file = NULL, *dst_file = NULL, *dst_binfile = NULL;
|
||||
static char work_str[PATH_MAX*2];
|
||||
|
||||
src_file = fopen(source_rules_file, "r");
|
||||
if (!src_file) {
|
||||
printf("Failed to open %s, %s\n", source_rules_file, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
dst_file = fopen(packed_rules_file, "wt");
|
||||
if (!dst_file) {
|
||||
printf("Failed to open %s, %s\n", packed_rules_file, strerror(errno));
|
||||
goto do_close2;
|
||||
}
|
||||
if (packed_rules_binfile) {
|
||||
dst_binfile = fopen(packed_rules_binfile, "wt");
|
||||
if (!dst_binfile)
|
||||
printf("Failed to open %s, %s - Ignore\n", packed_rules_binfile, strerror(errno));
|
||||
}
|
||||
|
||||
while (!feof(src_file)) {
|
||||
if (!fgets(work_str, sizeof(work_str), src_file))
|
||||
break;
|
||||
#ifndef DEFEX_DEBUG_ENABLE
|
||||
process_debug_ifdef(work_str);
|
||||
if (!debug_ifdef_is_active) {
|
||||
#endif
|
||||
feature = str_to_feature(work_str);
|
||||
if (feature) {
|
||||
addline2tree(work_str, feature);
|
||||
continue;
|
||||
}
|
||||
#ifndef DEFEX_DEBUG_ENABLE
|
||||
}
|
||||
#endif
|
||||
}
|
||||
store_tree(dst_file, dst_binfile);
|
||||
if (!packfiles_count)
|
||||
printf("WARNING: Defex packed rules tree is empty!\n");
|
||||
ret_val = 0;
|
||||
if (dst_binfile)
|
||||
fclose(dst_binfile);
|
||||
fclose(dst_file);
|
||||
do_close2:
|
||||
fclose(src_file);
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
int check_array_size(struct rule_item_struct *ptr)
|
||||
{
|
||||
unsigned long offset = (unsigned long)ptr - (unsigned long)defex_packed_rules;
|
||||
int min_size = (global_data_size < packfiles_size)?global_data_size:packfiles_size;
|
||||
|
||||
offset += sizeof(struct rule_item_struct);
|
||||
|
||||
if (offset > min_size)
|
||||
return 1;
|
||||
|
||||
offset += ptr->size;
|
||||
if (offset > min_size)
|
||||
return 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int parse_items(struct rule_item_struct *base, int path_length, int level)
|
||||
{
|
||||
int l, err, ret = 0, is_rule_part2;
|
||||
unsigned int offset;
|
||||
struct rule_item_struct *child_item;
|
||||
static char feature_list[128];
|
||||
|
||||
if (level > 8) {
|
||||
printf("Level is too deep\n");
|
||||
return -1;
|
||||
|
||||
}
|
||||
if (path_length > (sizeof(work_path) - 128)) {
|
||||
printf("Work path is too long\n");
|
||||
return -1;
|
||||
}
|
||||
while (base) {
|
||||
err = check_array_size(base);
|
||||
if (err) {
|
||||
printf("%s/<?> - out of array bounds\n", work_path);
|
||||
return -1;
|
||||
}
|
||||
l = base->size;
|
||||
if (!l) {
|
||||
printf("WARNING: Name field is incorrect, structure error!\n");
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
memcpy(work_path + path_length, base->name, l);
|
||||
l += path_length;
|
||||
work_path[l] = 0;
|
||||
offset = base->next_level;
|
||||
/* check whether the rule has the second part (immutable_dst_exception) */
|
||||
is_rule_part2 = (offset && (base->feature_type & feature_is_file) &&
|
||||
(base->feature_type & feature_immutable_src_exception));
|
||||
|
||||
if (offset && !is_rule_part2) {
|
||||
if (base->feature_type & feature_is_file) {
|
||||
printf("%s - is a file, but has children, structure error!\n", work_path);
|
||||
ret = -1;
|
||||
} else if (base->feature_type != 0) {
|
||||
feature_to_str(feature_list, base->feature_type);
|
||||
printf("%s%c - %s\n", work_path,
|
||||
((base->feature_type & feature_is_file)?' ':'/'), feature_list);
|
||||
}
|
||||
child_item = GET_ITEM_PTR(offset, defex_packed_rules);
|
||||
work_path[l++] = '/';
|
||||
work_path[l] = 0;
|
||||
err = check_array_size(child_item);
|
||||
if (!err) {
|
||||
err = parse_items(child_item, l, level + 1);
|
||||
if (err != 0)
|
||||
return err;
|
||||
} else {
|
||||
printf("%s/<?> - out of array bounds\n", work_path);
|
||||
ret = -1;
|
||||
}
|
||||
} else {
|
||||
feature_to_str(feature_list, base->feature_type);
|
||||
printf("%s%c%s - %s\n", work_path,
|
||||
((base->feature_type & feature_is_file)?' ':'/'),
|
||||
(is_rule_part2)?":<SECOND PART>":"", feature_list);
|
||||
}
|
||||
work_path[path_length] = 0;
|
||||
offset = base->next_file;
|
||||
base = (offset)?GET_ITEM_PTR(offset, defex_packed_rules):NULL;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int defex_show_structure(void *packed_rules, int rules_size)
|
||||
{
|
||||
struct rule_item_struct *base;
|
||||
int res, offset;
|
||||
int first_item_size = sizeof(struct rule_item_struct) + sizeof(header_name);
|
||||
|
||||
defex_packed_rules = (struct rule_item_struct *)packed_rules;
|
||||
|
||||
work_path[0] = '/';
|
||||
work_path[1] = 0;
|
||||
|
||||
packfiles_size = rules_size;
|
||||
global_data_size = defex_packed_rules->data_size;
|
||||
|
||||
printf("Rules binary size: %d\n", packfiles_size);
|
||||
printf("Rules internal data size: %d\n", global_data_size);
|
||||
|
||||
if (global_data_size > packfiles_size)
|
||||
printf("WARNING: Internal size is bigger than binary size, possible structure error!\n");
|
||||
|
||||
if (packfiles_size < first_item_size) {
|
||||
printf("ERROR: Too short binary size, can't continue!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (global_data_size < first_item_size)
|
||||
printf("WARNING: Too short data size, possible structure error!\n");
|
||||
|
||||
if ((int)(defex_packed_rules->size) != sizeof(header_name))
|
||||
printf("WARNING: incorrect size field (%d), possible structure error!\n",
|
||||
(int)defex_packed_rules->size);
|
||||
|
||||
|
||||
if (memcmp(header_name, defex_packed_rules->name, sizeof(header_name)) != 0)
|
||||
printf("WARNING: incorrect name field, possible structure error!\n");
|
||||
|
||||
printf("File List:\n");
|
||||
offset = defex_packed_rules->next_level;
|
||||
base = (offset)?GET_ITEM_PTR(offset, defex_packed_rules):NULL;
|
||||
|
||||
if ((long unsigned int)base < (long unsigned int)packed_rules ||
|
||||
(long unsigned int)base > (long unsigned int)base + rules_size) {
|
||||
printf("- empty list\n");
|
||||
return 0;
|
||||
} else if (check_array_size(base)) {
|
||||
printf("- list is out of array bounds!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = parse_items(base, 1, 1);
|
||||
printf("== End of File List ==\n");
|
||||
return res;
|
||||
}
|
||||
|
||||
int parse_packed_bin_file(const char *source_bin_file)
|
||||
{
|
||||
struct stat sb;
|
||||
FILE *policy_file = NULL;
|
||||
int policy_size;
|
||||
unsigned char *policy_data = NULL;
|
||||
|
||||
if (stat(source_bin_file, &sb) == -1) {
|
||||
perror("Error");
|
||||
return -1;
|
||||
}
|
||||
|
||||
policy_size = sb.st_size;
|
||||
|
||||
printf("Try to parse file: %s\n", source_bin_file);
|
||||
|
||||
policy_file = fopen(source_bin_file, "r");
|
||||
if (policy_file == NULL) {
|
||||
perror("Error");
|
||||
return -1;
|
||||
}
|
||||
|
||||
policy_data = malloc(policy_size);
|
||||
|
||||
if (policy_data == NULL) {
|
||||
perror("Error");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if ((fread(policy_data, policy_size, 1, policy_file)) != 1) {
|
||||
perror("Error");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
defex_show_structure((void *)policy_data, policy_size);
|
||||
|
||||
exit:
|
||||
free(policy_data);
|
||||
fclose(policy_file);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
static char param[4][PATH_MAX];
|
||||
char *src_file = NULL, *packed_file = NULL, *packed_bin_file = NULL;
|
||||
char *reduced_file = NULL, *list_file = NULL;
|
||||
int i;
|
||||
|
||||
if (argc == 3) {
|
||||
if (!strncmp(argv[1], "-s", 2)) {
|
||||
SAFE_STRCOPY(param[0], argv[2]);
|
||||
src_file = param[0];
|
||||
parse_packed_bin_file(src_file);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (argc < 4 || argc > 5) {
|
||||
printf("Invalid number of arguments\n");
|
||||
goto show_help;
|
||||
}
|
||||
|
||||
for (i = 0; i < (argc - 2); i++) {
|
||||
SAFE_STRCOPY(param[i], argv[i + 2]);
|
||||
switch(i) {
|
||||
case 0:
|
||||
src_file = param[i];
|
||||
break;
|
||||
case 1:
|
||||
packed_file = reduced_file = param[i];
|
||||
break;
|
||||
case 2:
|
||||
packed_bin_file = list_file = param[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!strncmp(argv[1], "-p", 2)) {
|
||||
if (pack_rules(src_file, packed_file, packed_bin_file) != 0)
|
||||
goto show_help;
|
||||
return 0;
|
||||
|
||||
} else if (!strncmp(argv[1], "-r", 2) && list_file) {
|
||||
if (reduce_rules(src_file, reduced_file, list_file) != 0)
|
||||
goto show_help;
|
||||
return 0;
|
||||
}
|
||||
printf("Invalid command\n");
|
||||
|
||||
show_help:
|
||||
printf("Defex rules processing utility.\nUSAGE:\n%s <CMD> <PARAMS>\n"
|
||||
"Commands:\n"
|
||||
" -p - Pack rules file to the tree. Params: <SOURCE_FILE> <PACKED_FILE> [PACKED_BIN_FILE]\n"
|
||||
" -r - Reduce rules file (remove unexistent files). Params: <SOURCE_FILE> <REDUCED_FILE> <FILE_LIST>\n"
|
||||
" -s - Show rules binary file content. Params: <PACKED_BIN_FILE>\n",
|
||||
argv[0]);
|
||||
return -1;
|
||||
}
|
Loading…
Reference in a new issue