security: samsung: defex_lsm: nuke

This commit is contained in:
Rob Burton 2022-06-03 10:02:51 +03:00 committed by Gabriel2392
parent e6d3a12a1d
commit c453e653ba
56 changed files with 0 additions and 8218 deletions

View file

@ -7659,9 +7659,6 @@ CONFIG_INIT_ON_ALLOC_DEFAULT_ON=y
# end of Memory initialization # end of Memory initialization
# end of Kernel hardening options # 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 is not set
# CONFIG_PROCA_GKI_10 is not set # CONFIG_PROCA_GKI_10 is not set
# CONFIG_PROCA_S_OS is not set # CONFIG_PROCA_S_OS is not set

View file

@ -14,10 +14,6 @@
#include <asm/thread_info.h> #include <asm/thread_info.h>
#include <asm/unistd.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 compat_arm_syscall(struct pt_regs *regs, int scno);
long sys_ni_syscall(void); long sys_ni_syscall(void);
@ -26,10 +22,6 @@ static long do_ni_syscall(struct pt_regs *regs, int scno)
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
long ret; long ret;
if (is_compat_task()) { 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); ret = compat_arm_syscall(regs, scno);
if (ret != -ENOSYS) if (ret != -ENOSYS)
return ret; return ret;
@ -53,10 +45,6 @@ static void invoke_syscall(struct pt_regs *regs, unsigned int scno,
if (scno < sc_nr) { if (scno < sc_nr) {
syscall_fn_t syscall_fn; syscall_fn_t syscall_fn;
syscall_fn = syscall_table[array_index_nospec(scno, sc_nr)]; 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); ret = __invoke_syscall(regs, syscall_fn);
} else { } else {
ret = do_ni_syscall(regs, scno); ret = do_ni_syscall(regs, scno);

View file

@ -75,10 +75,6 @@
#include <trace/events/sched.h> #include <trace/events/sched.h>
#ifdef CONFIG_SECURITY_DEFEX
#include <linux/defex.h>
#endif
EXPORT_TRACEPOINT_SYMBOL_GPL(task_rename); EXPORT_TRACEPOINT_SYMBOL_GPL(task_rename);
static int bprm_creds_from_file(struct linux_binprm *bprm); 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)) if (IS_ERR(file))
goto out_unmark; 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(); sched_exec();
bprm->file = file; bprm->file = file;

View file

@ -36,10 +36,6 @@
#include "internal.h" #include "internal.h"
#include <trace/hooks/syscall_check.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, int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
struct file *filp) struct file *filp)
{ {
@ -1220,12 +1216,6 @@ static long do_sys_openat2(int dfd, const char __user *filename,
if (fd >= 0) { if (fd >= 0) {
struct file *f = do_filp_open(dfd, tmp, &op); 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)) { if (IS_ERR(f)) {
put_unused_fd(fd); put_unused_fd(fd);
fd = PTR_ERR(f); fd = PTR_ERR(f);

View file

@ -29,10 +29,6 @@
#include <linux/fscrypto_sdp_cache.h> #include <linux/fscrypto_sdp_cache.h>
#endif #endif
#ifdef CONFIG_SECURITY_DEFEX
#include <linux/defex.h>
#endif
const struct file_operations generic_ro_fops = { const struct file_operations generic_ro_fops = {
.llseek = generic_file_llseek, .llseek = generic_file_llseek,
.read_iter = generic_file_read_iter, .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); ret = rw_verify_area(WRITE, file, pos, count);
if (ret) if (ret)
return ret; return ret;
#ifdef CONFIG_SECURITY_DEFEX
if (task_defex_enforce(current, file, -__NR_write))
return -EPERM;
#endif
if (count > MAX_RW_COUNT) if (count > MAX_RW_COUNT)
count = MAX_RW_COUNT; count = MAX_RW_COUNT;
file_start_write(file); file_start_write(file);

View 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 */

View file

@ -113,11 +113,6 @@
#include <kunit/test.h> #include <kunit/test.h>
#endif #endif
#ifdef CONFIG_SECURITY_DEFEX
#include <linux/defex.h>
void __init __weak defex_load_rules(void) { }
#endif
#ifdef CONFIG_RKP #ifdef CONFIG_RKP
#include <linux/rkp.h> #include <linux/rkp.h>
#endif #endif
@ -1587,7 +1582,4 @@ static noinline void __init kernel_init_freeable(void)
*/ */
integrity_load_keys(); integrity_load_keys();
#ifdef CONFIG_SECURITY_DEFEX
defex_load_rules();
#endif
} }

View file

@ -117,10 +117,6 @@ static __init int kernel_exit_sysfs_init(void)
late_initcall(kernel_exit_sysfs_init); late_initcall(kernel_exit_sysfs_init);
#endif #endif
#ifdef CONFIG_SECURITY_DEFEX
#include <linux/defex.h>
#endif
#if defined(CONFIG_MEMORY_ZEROISATION) #if defined(CONFIG_MEMORY_ZEROISATION)
#include <trace/hooks/mz.h> #include <trace/hooks/mz.h>
#endif #endif
@ -776,10 +772,6 @@ void __noreturn do_exit(long code)
struct task_struct *tsk = current; struct task_struct *tsk = current;
int group_dead; 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. * We can get here from a kernel oops, sometimes with preemption off.
* Start by checking for critical errors. * Start by checking for critical errors.

View file

@ -113,10 +113,6 @@
#undef CREATE_TRACE_POINTS #undef CREATE_TRACE_POINTS
#include <trace/hooks/sched.h> #include <trace/hooks/sched.h>
#ifdef CONFIG_SECURITY_DEFEX
#include <linux/defex.h>
#endif
#ifdef CONFIG_KDP_CRED #ifdef CONFIG_KDP_CRED
#include <linux/kdp.h> #include <linux/kdp.h>
#endif #endif
@ -2654,10 +2650,6 @@ pid_t kernel_clone(struct kernel_clone_args *args)
pid = get_task_pid(p, PIDTYPE_PID); pid = get_task_pid(p, PIDTYPE_PID);
nr = pid_vnr(pid); nr = pid_vnr(pid);
#ifdef CONFIG_SECURITY_DEFEX
task_defex_zero_creds(p);
#endif
if (clone_flags & CLONE_PARENT_SETTID) if (clone_flags & CLONE_PARENT_SETTID)
put_user(nr, args->parent_tid); put_user(nr, args->parent_tid);

View file

@ -74,10 +74,6 @@
#include <asm/io.h> #include <asm/io.h>
#include <asm/unistd.h> #include <asm/unistd.h>
#ifdef CONFIG_SECURITY_DEFEX
#include <linux/defex.h>
#endif
#include "uid16.h" #include "uid16.h"
#include <trace/hooks/sys.h> #include <trace/hooks/sys.h>
@ -846,11 +842,6 @@ long __sys_setfsuid(uid_t uid)
if (!uid_valid(kuid)) if (!uid_valid(kuid))
return old_fsuid; return old_fsuid;
#ifdef CONFIG_SECURITY_DEFEX
if (task_defex_enforce(current, NULL, -__NR_setfsuid))
return old_fsuid;
#endif
new = prepare_creds(); new = prepare_creds();
if (!new) if (!new)
return old_fsuid; return old_fsuid;
@ -895,11 +886,6 @@ long __sys_setfsgid(gid_t gid)
if (!gid_valid(kgid)) if (!gid_valid(kgid))
return old_fsgid; return old_fsgid;
#ifdef CONFIG_SECURITY_DEFEX
if (task_defex_enforce(current, NULL, -__NR_setfsgid))
return old_fsgid;
#endif
new = prepare_creds(); new = prepare_creds();
if (!new) if (!new)
return old_fsgid; return old_fsgid;

View file

@ -30,10 +30,6 @@
#include <trace/events/module.h> #include <trace/events/module.h>
#ifdef CONFIG_SECURITY_DEFEX
#include <linux/defex.h>
#endif
#define CAP_BSET (void *)1 #define CAP_BSET (void *)1
#define CAP_PI (void *)2 #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) if (strlen(sub_info->path) == 0)
goto out; 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. * Set the completion pointer only if there is a waiter.
* This makes it possible to use umh_complete to free * This makes it possible to use umh_complete to free

View file

@ -302,7 +302,6 @@ config SDP_KEY_DUMP
source "security/Kconfig.hardening" 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/Kconfig" # ADDED BY LEGO AUTOMATICALLY: DO NOT SUBMIT
source "security/samsung/proca/gaf/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 source "security/samsung/mz/Kconfig" # ADDED BY LEGO AUTOMATICALLY: DO NOT SUBMIT

View file

@ -40,7 +40,6 @@ obj-$(CONFIG_INTEGRITY) += integrity/
# KNOX DAR # KNOX DAR
obj-$(CONFIG_SDP) += sdp/ obj-$(CONFIG_SDP) += sdp/
obj-$(CONFIG_SDP) += sdp/built-in.a 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/ # ADDED BY LEGO AUTOMATICALLY: DO NOT SUBMIT
obj-y += samsung/proca/gaf/ # 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 obj-y += samsung/mz/ # ADDED BY LEGO AUTOMATICALLY: DO NOT SUBMIT

View file

@ -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.

View file

@ -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)

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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
};

View file

@ -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];
}

View file

@ -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 */

View file

@ -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)

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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);

View file

@ -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 */
}

View file

@ -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 */
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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 */

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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
;

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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,
};

View file

@ -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);
}
}

View file

@ -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";
}

View file

@ -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);
}

View file

@ -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 */

View file

@ -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 */

View file

@ -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 */

View file

@ -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 */

View file

@ -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 */

View file

@ -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 */

View file

@ -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 */

View file

@ -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

View file

@ -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 */

View file

@ -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

View file

@ -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;
}