Path : /opt/ds_agent/
File Upload :
Current File : //opt/ds_agent/ds_am.init

#!/bin/bash

proc_img_path=$0

if [[ ${proc_img_path} =~ .*"ds_am.init" ]]; then
	drvdir="/opt/ds_agent"
	rtscan_dev=/dev/dsa_rtscan
	bm_dev=/dev/dsa_bmdev
	script_name="ds_am.init"
	bin_name="ds_am"
	amdir="/var/opt/ds_agent/am"
	bmhook="bmhook"
	bmLoadedCheck="bmsensor"
	hook_priority=20000
elif [[ ${proc_img_path} =~ .*"vls_am.init" ]]; then
	drvdir="/opt/TrendMicro/vls_agent"
	rtscan_dev=/dev/vlsa_rtscan
	bm_dev=/dev/vlsa_bmsensor
	script_name="vls_am.init"
	bin_name="vls_am"
	amdir="/var/opt/TrendMicro/vls_agent/am"
	bmhook="bmsensor"
	bmLoadedCheck="bmhook"
	hook_priority=10000
fi

tmhook="tmhook"
livepatchConfigPath="/sys/kernel/livepatch/${tmhook}/enabled"
checkUsedCount=20

RET_CODE_SUCCEED=0
RET_CODE_DRIVER_NOT_FOUND=1
RET_CODE_DRIVER_LOAD_FAILED=2
RET_CODE_DRIVER_UNLOAD_FAILED=3
RET_CODE_CREATE_DEVICE_FAILED=4
RET_CODE_DESTROY_DEVICE_FAILED=5
RET_CODE_MACHINE_OWNER_KEY_NOT_FOUND=6
RET_CODE_MACHINE_OWNER_KEY_EXPIRED=7
RET_CODE_MACHINE_OWNER_KEY_UNKOWN=8

DS20V2_DER_NAME="DS20_v2.der"
DS20V2_DER_VALIDITY_NOT_BEFORE=20201124092351
DS20V2_DER_VALIDITY_NOT_AFTER=20261024092351
DS20V2_DER_X509_SIGN_KEY=39d113faa9b73d6c43a9d23b9f55af9381958b97
DS20V2_DER_PKCS7_SIGN_KEY=ea828dccce76b891
DS2022_DER_NAME="DS2022.der"
DS2022_DER_VALIDITY_NOT_BEFORE=20211126063249
DS2022_DER_VALIDITY_NOT_AFTER=20311124063249
DS2022_DER_X509_SIGN_KEY=9db8a5e911ed975b2274f35993fdf99aaf446960
DS2022_DER_PKCS7_SIGN_KEY=87f3753936c5db76

SUPPORT_KEYS="DS2022 DS20V2"

for fd in $(ls /proc/$$/fd | cut -d ' ' -f 1); do
		case "$fd" in
		0|1|2|255)
				;;
		*)
				eval "exec $fd>&-"
				;;
		esac
done

# return code 0 indicates that module is being used by somebody, 1 otherwise
moduleIsBeingUsed() {
	local module=${1}
	local usedby=$(cat /proc/modules | grep -m 1 "^${module}" | cut -d ' ' -f4)

	if [ "${usedby}" == "" ]; then
		return 1
	elif [ "${usedby}" == "-" ]; then
		return 1
	fi

	return 0
}

moduleIsGoodToUnload() {
	local module=${1}
	local usedby=$(cat /proc/modules | grep -m 1 "^${module}" | cut -d ' ' -f3)

	until [ "${usedby}" == "0" ] || [ -z "${usedby}" ]
	do
	    if [ ${checkUsedCount} -gt 0 ]; then
	        usedby=$(cat /proc/modules | grep -m 1 "^${module}" | cut -d ' ' -f3)
	        checkUsedCount=$((${checkUsedCount} - 1))
		sleep 1
	    else
	        break
	    fi
	done

	if [ "${usedby}" == "0" ]; then
		return 0
	else
	        return 1
	fi
}

moduleIsLoaded() {
	local module=${1}

	(lsmod | tr -d '[]' | grep -m 1 "^${module}" > /dev/null) && return 0
	return 1
}

moduleIsDisabled() {
	if [ "`cat /proc/driver/gsch/redirfs/enable`" == "1" ]; then
		return 1 
	fi

	if [ "`cat /proc/driver/gsch/fshook/enable`" == "1" ]; then
		return 1
	fi

	if [ "`cat /proc/driver/gsch/syshook/enable`" == "1" ]; then
		return 1
	fi
	return 0
}

driverIsNotFound() {
	local tmhookPath="${drvdir}/`uname -r`/${tmhook}.ko"
	local bmhookPath="${drvdir}/`uname -r`/${bmhook}.ko"
	if [ ! -f ${tmhookPath} ] || [ ! -f ${bmhookPath} ]; then
		logger -t ${script_name} "The ${bin_name} module is lack of KernelSupport package for kernel `uname -r`"
		return 0
	fi

	return 1
}

create_device_gsch()
{
	rtscan_dev_major=`grep gsch /proc/devices |cut -d ' ' -f 1`
	if [ ! -z $rtscan_dev_major ]; then
		if [ ! -c $rtscan_dev ]; then
			mknod -m 0600 $rtscan_dev c $rtscan_dev_major 0
			ret=$?
			if [ ${ret} -ne 0 ]; then
				logger -t ${script_name} "The ${bin_name} module is trying to create device ${rtscan_dev} but failed"
				return ${RET_CODE_CREATE_DEVICE_FAILED}
			fi

			# For DISA STIG Compliance, label device file with SELinux file type 'misc_device_t'.
			if [ -x /usr/bin/chcon ] ; then
				/usr/bin/chcon -t misc_device_t ${rtscan_dev}
			fi
		fi                        
	fi

	return ${RET_CODE_SUCCEED}
}

destroy_device()
{
	local dev_name=${1}
	rm -f $dev_name;
	ret=$?
	if [ ${ret} -ne 0 ]; then
		logger -t ${script_name} "The ${bin_name} module is trying to destroy device ${dev_name} but failed"
		return ${RET_CODE_DESTROY_DEVICE_FAILED}
	fi

	return ${RET_CODE_SUCCEED}
}

create_device_bmhook()
{
	bmhook_dev_major=`grep ${bmhook} /proc/devices |cut -d ' ' -f 1`
	if [ ! -z $bmhook_dev_major ]; then
		if [ ! -c $bm_dev ]; then
			mknod -m 0600 $bm_dev c $bmhook_dev_major 0
			ret=$?
			if [ ${ret} -ne 0 ]; then
				logger -t ${script_name} "The ${bin_name} module is trying to create device ${bm_dev} but failed"
				return ${RET_CODE_CREATE_DEVICE_FAILED}
			fi

			# For DISA STIG Compliance, label device file with SELinux file type 'misc_device_t'.
			if [ -x /usr/bin/chcon ] ; then
				/usr/bin/chcon -t misc_device_t ${bm_dev}
			fi
		fi
	fi

	return ${RET_CODE_SUCCEED}
}

set_excl_to_proc()
{
	ini_file=${1}
	proc_entry=${2}
	if [ -f $ini_file ]; then
		IFS=$'\n'
		for f in `sort -u $ini_file || cat $ini_file` ; do echo $f > $proc_entry ; done
		unset IFS
	fi
}

load_module_bm()
{
	local tmhookPath="${drvdir}/`uname -r`/${tmhook}.ko"
	local bmhookPath="${drvdir}/`uname -r`/${bmhook}.ko"

	# Reenforce selinux context in case being changed
	if [ -x /usr/bin/chcon ]; then
		/usr/bin/chcon -t modules_object_t "${tmhookPath}"
		/usr/bin/chcon -t modules_object_t "${bmhookPath}"
	fi

	# note that right now tmhook may be being used by someone (e.g., gsch)
	# unload it only if it is ok to remove
	if moduleIsLoaded ${tmhook} ; then
		if ! moduleIsBeingUsed ${tmhook} ; then
			(lsmod | grep -m 1 ${tmhook} > /dev/null) && rmmod ${tmhook}
		fi
	fi

	if driverIsNotFound; then
		return ${RET_CODE_DRIVER_NOT_FOUND}
	fi

	if ! moduleIsLoaded ${tmhook} ; then
		insmod ${tmhookPath};
		ret=$?
		if [ $ret -ne 0 ]; then
			logger -t ${script_name} "The ${bin_name} module load driver ${tmhook} failed"
			return ${RET_CODE_DRIVER_LOAD_FAILED}
		fi
		ln -s -f ${tmhookPath} /lib/modules/`uname -r`/ > /dev/null 2>&1
	else
	        # When BHI unpatch latency very long, livepatch config exist and unpatching not complete then recover livepatching.
	        echo 1 > ${livepatchConfigPath}

		tmhookUsedCount=$(cat /proc/modules | grep -m 1 "^${tmhook}" | cut -d ' ' -f3)
		if [ "${tmhookUsedCount}" == "0" ]; then
		        rmmod ${tmhook}
			insmod ${tmhookPath};
		        ret=$?
		        if [ $ret -ne 0 ]; then
			        logger -t ${script_name} "The ${bin_name} module load driver ${tmhook} failed"
			        return ${RET_CODE_DRIVER_LOAD_FAILED}
		        fi
		        ln -s -f ${tmhookPath} /lib/modules/`uname -r`/ > /dev/null 2>&1
		fi 
	fi
	if ! moduleIsLoaded ${bmhook} ; then
		insmod ${bmhookPath};
		ret=$?
		if [ $ret -ne 0 ]; then
			logger -t ${script_name} "The ${bin_name} module load driver ${bmhook} failed"
			return ${RET_CODE_DRIVER_LOAD_FAILED}
		fi
		ln -s -f ${bmhookPath} /lib/modules/`uname -r`/ > /dev/null 2>&1
	fi
	if moduleIsLoaded ${bmhook} ; then
		echo ${hook_priority} > /proc/driver/${bmhook}/config/priority
		echo 1 > /proc/driver/${bmhook}/ftime_innsec
		echo 1 > /proc/driver/${bmhook}/tmbpf/jit_enable
		echo 1 > /proc/driver/${bmhook}/enable
		set_excl_to_proc ${amdir}/${bin_name}-exclude-process_img_path.ini	/proc/driver/${bmhook}/exclude/process.any
		set_excl_to_proc ${amdir}/procexcept.ini							/proc/driver/${bmhook}/exclude/file_event/process.any
		set_excl_to_proc ${amdir}/${bin_name}-exclude-dir.ini				/proc/driver/${bmhook}/exclude/file_event/dir.any
		set_excl_to_proc ${amdir}/${bin_name}-exclude-file.ini				/proc/driver/${bmhook}/exclude/file_event/file.any
		# Update bmhook settings
		if [ -f ${amdir}/${bmhook}.ini ]; then
			IFS=$'\n'
			for line in `cat ${amdir}/${bmhook}.ini`; do
				k=`echo "$line"|cut -d = -f 1`
				v=`echo "$line"|cut -d = -f 2`
				if [ -e "/proc/driver/${bmhook}/config/$k" ]; then
					echo "$v" > /proc/driver/${bmhook}/config/$k
				fi
			done
			unset IFS
		fi
		if [ -n `grep ^OPENSHIFT /host/etc/os-release 2> /dev/null` ]; then
			echo 0 > /proc/driver/${bmhook}/config/cgroup_access
		fi
		return ${RET_CODE_SUCCEED}
	else
		logger -t ${script_name} "The ${bin_name} module load driver ${bmhook} failed"
		return ${RET_CODE_DRIVER_LOAD_FAILED}
	fi
}

unload_module_bm()
{
	moduleIsLoaded ${bmhook} && rmmod ${bmhook};
	moduleIsLoaded ${bmhook} && sleep 1 && rmmod ${bmhook};
	moduleIsLoaded ${bmhook} && sleep 1 && rmmod ${bmhook};
	if [ -f /lib/modules/`uname -r`/${bmhook}.ko ]; then unlink /lib/modules/`uname -r`/${bmhook}.ko > /dev/null 2>&1; fi

	if ! moduleIsLoaded ${bmhook} && ! moduleIsLoaded ${bmLoadedCheck} ; then
            echo 0 > ${livepatchConfigPath}
	fi

	if [ "`cat ${livepatchConfigPath}`" == "0" ]; then
	    logger -t ${script_name} "Tmhook is doing the unpatching process."
            moduleIsGoodToUnload ${tmhook}
        fi

	if ! moduleIsBeingUsed ${tmhook} ; then
	    moduleIsLoaded ${tmhook} && rmmod ${tmhook};
	    moduleIsLoaded ${tmhook} && sleep 1 && rmmod ${tmhook};
	    moduleIsLoaded ${tmhook} && sleep 1 && rmmod ${tmhook};
	    if [ -f /lib/modules/`uname -r`/${tmhook}.ko ]; then unlink /lib/modules/`uname -r`/${tmhook}.ko > /dev/null 2>&1; fi
	    moduleLoad=`moduleIsLoaded ${tmhook}`
	    logger -t ${script_name} "The ${bin_name} module try unload driver ${tmhook}, loaded=${moduleLoad}"
	fi

	if moduleIsLoaded ${bmhook}; then
	        logger -t ${script_name} "The ${bin_name} module unload driver ${bmhook} failed"
		return ${RET_CODE_DRIVER_UNLOAD_FAILED}
	fi

	return ${RET_CODE_SUCCEED}
}

load_module()
{
	local moduleOneName="tmhook"
	local moduleTwoName="redirfs"
	local moduleThreeName="gsch"
	local moduleOnePath="${drvdir}/`uname -r`/${moduleOneName}.ko"
	local moduleTwoPath="${drvdir}/`uname -r`/${moduleTwoName}.ko"
	local moduleThreePath="${drvdir}/`uname -r`/${moduleThreeName}.ko"
	if moduleIsLoaded ${moduleOneName} -o moduleIsLoaded ${moduleTwoName} -o moduleIsLoaded ${moduleThreeName} ; then
		if moduleIsDisabled ; then
			(lsmod | grep -m 1 gsch > /dev/null) && rmmod gsch
			(lsmod | grep -m 1 redirfs > /dev/null) && rmmod redirfs

			# note that right now tmhook may be being used by someone (e.g., acdc)
			# unload it only if it is ok to remove
			if ! moduleIsBeingUsed ${moduleOneName} ; then
				(lsmod | grep -m 1 ${moduleOneName} > /dev/null) && rmmod ${moduleOneName}
			fi
		fi
	fi

	if ! moduleIsLoaded ${moduleOneName} ; then
		insmod ${moduleOnePath};
		ln -s -f ${moduleOnePath} /lib/modules/`uname -r`/ > /dev/null 2>&1
	fi

	if ! moduleIsLoaded ${moduleTwoName} ; then
		insmod ${moduleTwoPath};
		ln -s -f ${moduleTwoPath} /lib/modules/`uname -r`/ > /dev/null 2>&1
	fi

	if ! moduleIsLoaded ${moduleThreeName} ; then
		insmod ${moduleThreePath};
		ln -s -f ${moduleThreePath} /lib/modules/`uname -r`/ > /dev/null 2>&1
	fi

	if moduleIsLoaded ${moduleThreeName} ; then
		if [ -f ${amdir}/${bin_name}-exclude-dir.ini ]; then
			for f in `cat ${amdir}/${bin_name}-exclude-dir.ini` ; do echo $f > /proc/driver/gsch/scan/exclusion/dir; done
		fi

		if [ -f ${amdir}/${bin_name}-exclude-file.ini ]; then
			for f in `cat ${amdir}/${bin_name}-exclude-file.ini` ; do echo $f > /proc/driver/gsch/scan/exclusion/file; done
		fi
		echo 1 > /proc/driver/gsch/scan/enable
		return 0;
	else
		return 1;
	fi
}

unload_module()
{
	if [ -f /proc/driver/gsch/syshook/enable ]; then echo 0 > /proc/driver/gsch/syshook/enable; fi
	if [ -f /proc/driver/gsch/fshook/enable ]; then echo 0 > /proc/driver/gsch/fshook/enable; fi
	if [ -f /proc/driver/gsch/redirfs/enable ]; then echo 0 > /proc/driver/gsch/redirfs/enable; fi
	(lsmod | grep -m 1 gsch > /dev/null) && rmmod gsch
	(lsmod | grep -m 1 gsch > /dev/null) && sleep 1 && rmmod gsch
	(lsmod | grep -m 1 gsch > /dev/null) && sleep 1 && rmmod gsch
	(lsmod | grep -m 1 redirfs > /dev/null) && rmmod redirfs
	if [ -f /lib/modules/`uname -r`/gsch.ko ]; then unlink /lib/modules/`uname -r`/gsch.ko > /dev/null 2>&1; fi
	if [ -f /lib/modules/`uname -r`/redirfs.ko ]; then unlink /lib/modules/`uname -r`/redirfs.ko > /dev/null 2>&1; fi

	# note that right now tmhook may be being used by someone (e.g., acdc)
	# unload it only if it is ok to remove
	if ! moduleIsBeingUsed tmhook ; then
		(lsmod | grep -m 1 tmhook > /dev/null) && rmmod tmhook
		if [ -f /lib/modules/`uname -r`/tmhook.ko ]; then unlink /lib/modules/`uname -r`/tmhook.ko > /dev/null 2>&1; fi
	fi
}

check_intercepted()
{
	# before DS-11.x, we implemented a mechanism to avoid inter-op issues
	# with 3rd-party kernel module, and this check is to test if there is
	# a kernel module hooking the same system calls.
	#
	# after adapting tmhook, gsch does not directly manipulate syscall table,
	# but we still need this to make sure the older gsch can be unloaded after
	# agent upgrade.
	local moduleThreeName="gsch"
	local returnCode="0"
	if moduleIsLoaded ${moduleThreeName} ; then
		if [ -f /proc/driver/gsch/syshook/intercepted ]; then
			returnCode="$(cat /proc/driver/gsch/syshook/intercepted)"
			if [ "$returnCode" -eq "0" ]; then
				logger -t ${script_name} "The ${bin_name} module is attempting to start and another kernel module that was running using the gsch driver is now unloaded. The gsch driver will be unloaded and then loaded again."
				unload_module
				destroy_device ${rtscan_dev}
			fi
			if [ "$returnCode" -eq "1" ]; then
				logger -t ${script_name} "The ${bin_name} module is attempting to start but another kernel module is running using the gsch driver. The gsch driver may not be updated unless another kernel module is unloaded."
				create_device_gsch # Used to check the device node still exists. When it was removed, we would create a new one.
				exit 1
			fi
		fi
	fi
}

check_machine_owner_keys()
{
	# check if we have mokutil on the system
	local mokUtil=`which mokutil 2>/dev/null`
	if [ -z "${mokUtil}" ]; then
		return ${RET_CODE_SUCCEED}
	fi

	# check if the system is booted with secure boot enabled
	secureBootState=`$mokUtil --sb-state 2>/dev/null | grep enabled`
	if [ -z "${secureBootState}" ]; then
		return ${RET_CODE_SUCCEED}
	fi

	# check if we have related key enrolled
	local bmhook=${drvdir}/`uname -r`/${bmhook}.ko
	local moduleSignkey=`modinfo ${bmhook} | grep sig_key | awk '{print $2}' | sed 's/://g' | tr 'A-Z' 'a-z'`
	local importedTMKeys=`cat /proc/keys | grep ${moduleSignkey}`
	local currentTime=`date -u +"%Y%m%d%H%M%S"`
	local timeOutString=`echo ${importedTMKeys} | awk '{print $4}'`

	if [ -n "${importedTMKeys}" ]; then
		# The key is enrolled on the system

		if [ "${timeOutString}" == "perm" ]; then
			# This key is a permanent key from kernel point of view
			return ${RET_CODE_SUCCEED}
		fi

		# we have related key enrolled, check its validity
		for key in ${SUPPORT_KEYS}; do
			target_name="${key}_DER_NAME"
			target_x509_sign_key="${key}_DER_X509_SIGN_KEY"
			target_pkcs7_sign_key="${key}_DER_PKCS7_SIGN_KEY"
			target_validity_not_before="${key}_DER_VALIDITY_NOT_BEFORE"
			target_validity_not_after="${key}_DER_VALIDITY_NOT_AFTER"

			if [ "${!target_x509_sign_key}" == "${moduleSignkey}" ] || [ "${!target_pkcs7_sign_key}" == "${moduleSignkey}" ]; then
				# this key is in our support key lists
				if [ ${!target_validity_not_before} -lt $currentTime ] && [ $currentTime -le ${!target_validity_not_after} ]; then
					return ${RET_CODE_SUCCEED}
				else
					logger -t ${script_name} "The ${bin_name} module found the enrolled key ${!target_name} has expired"
					return ${RET_CODE_MACHINE_OWNER_KEY_EXPIRED}
				fi
			fi
		done

		# key is enrolled, however, we don't recognize it
		logger -t ${script_name} "The ${bin_name} module found driver is signed with unknown sign key ${moduleSignkey}, and is enrolled: \"${importedTMKeys}\""
		return ${RET_CODE_MACHINE_OWNER_KEY_UNKOWN}
	else
		# The key is not enrolled on the system

		for key in ${SUPPORT_KEYS}; do
			target_name="${key}_DER_NAME"
			target_x509_sign_key="${key}_DER_X509_SIGN_KEY"
			target_pkcs7_sign_key="${key}_DER_PKCS7_SIGN_KEY"

			if [ "${!target_x509_sign_key}" == "${moduleSignkey}" ] || [ "${!target_pkcs7_sign_key}" == "${moduleSignkey}" ]; then
				logger -t ${script_name} "The ${bin_name} module found missing key ${!target_name}, please enroll it first"
				return ${RET_CODE_MACHINE_OWNER_KEY_NOT_FOUND}
			fi
		done

		# Key is not enrolled, and we don't recognize it
		# Two possible cases:
		#  1. The key is from Trend, not yet supported by this script
		#  2. Driver is signed with an unknown key outside Trend.
		logger -t ${script_name} "The ${bin_name} module found driver is signed with unknown sign key ${moduleSignkey}, and is not enrolled"
		return ${RET_CODE_MACHINE_OWNER_KEY_UNKOWN}
	fi
}

start() {
	check_intercepted;
	load_module;
	create_device_gsch;
	return 0;
}

stop() {
	# before DS-11.x, we implemented a mechanism to avoid inter-op issues
	# with 3rd-party kernel module, and this check is to test if there is
	# a kernel module hooking the same system calls.
	#
	# after adapting tmhook, gsch does not directly manipulate syscall table,
	# but we still need this to make sure the older gsch can be unloaded after
	# agent upgrade.
	local returnCode="0"
	if [ -f /proc/driver/gsch/syshook/intercepted ]; then
		returnCode="$(cat /proc/driver/gsch/syshook/intercepted)"
		if [ "$returnCode" -eq "1" ]; then
			logger -t ${script_name} "The ${bin_name} module is attempting to stop but another kernel module is running using the gsch driver. The ds_agent process will be stopped but the gsch driver will not be unloaded."
			destroy_device ${rtscan_dev}
			exit 1
		fi
	fi

	unload_module;
	destroy_device ${rtscan_dev};
	return 0
}

restart() {
	stop
	start
}

check_and_set_cgroup_path() {
		if [ ! -z "$1" ]; then
				local t1=`echo "$1" | awk '{print $1}'`
				local t2=`echo "$1" | awk '{print $2}'`
				local t3=`echo "$1" | awk '{print $3}'`
				local bm_cgroup_base="/proc/driver/${bmhook}/config/cgroup_base"

				logger -t ${script_name} "check_and_set_cgroup_path, t1:${t1}"
				logger -t ${script_name} "check_and_set_cgroup_path, t2:${t2}"
				logger -t ${script_name} "check_and_set_cgroup_path, t3:${t3}"
				if [[ "${t1}" == "$2" ]]; then
						if [ "${t2}" == "on" ]; then
								echo "${t3}" > ${bm_cgroup_base}
								logger -t ${script_name} "check_and_set_cgroup_path, set cgroup_base as ${t3}"
								return 0
						fi
				fi
		fi
		logger -t ${script_name} "check_and_set_cgroup_path, invalid format for $2"
		return 1
}

update_bm_cgroup_path() {
		local v1_path=`mount | grep cgroup | grep /memory`
		local v2_path=`mount | grep cgroup2`

		logger -t ${script_name} "update_bm_cgroup_path, v1_path: ${v1_path}"
		logger -t ${script_name} "update_bm_cgroup_path, v2_path: ${v2_path}"
		if [ ! -z "${v1_path}" ]; then
				check_and_set_cgroup_path "${v1_path}" "cgroup"
				ret=$?
				if [ ${ret} -eq 0 ]; then
						return 0
				fi
		fi
		if [ ! -z "${v2_path}" ]; then
				check_and_set_cgroup_path "${v2_path}" "cgroup2"
				ret=$?
				if [ ${ret} -eq 0 ]; then
						return 0
				fi
		fi
		logger -t ${script_name} "update_bm_cgroup_path, failed to set cgroup_base"
		return 1
}

startBM() {
	local ret=${RET_CODE_SUCCEED}

	load_module_bm;
	ret=$?
	if [ ${ret} -ne ${RET_CODE_SUCCEED} ]; then
		if [ ${ret} -eq ${RET_CODE_DRIVER_LOAD_FAILED} ]; then
			check_machine_owner_keys
			ret2=$?
			if [ ${ret2} -ne ${RET_CODE_SUCCEED} ]; then
				# Load driver failed is related to enrolled keys in secure boot environment,
				# overwrite return code (ret)
				ret=${ret2}
			fi
		fi
		return ${ret}
	fi

	create_device_bmhook;
	ret=$?
	if [ ${ret} -ne ${RET_CODE_SUCCEED} ]; then
		return ${ret}
	fi

	update_bm_cgroup_path;
	return ${RET_CODE_SUCCEED}
}

stopBM() {
	local ret=${RET_CODE_SUCCEED}

	unload_module_bm;
	ret=$?
	if [ ${ret} -ne ${RET_CODE_SUCCEED} ]; then
		return ${ret}
	fi

	destroy_device ${bm_dev};
	ret=$?
	if [ ${ret} -ne ${RET_CODE_SUCCEED} ]; then
		return ${ret}
	fi

	return ${RET_CODE_SUCCEED}
}

restartBM() {
	stopBM
	startBM
}

stopAll() {
	# used for AM.dsp to unload all kernel modules when ds_am / vls_am process is terminated
	stopBM
	stop
}

case "$1" in
	start|stop|restart|startBM|stopBM|restartBM|stopAll)
		$1
		;;
	*)
	echo $"Usage: $0 {start|stop|restart|startBM|stopBM|restartBM|stopAll}"
	exit 1
esac