kernel, ksud, manager: New supercalls implementations
* This commit squashes new supercall impl:
3138651a38..562a3b9be7
Thanks to these people below:
Official KernelSU:
Co-authored-by: Wang Han <416810799@qq.com>
Co-authored-by: weishu <twsxtd@gmail.com>
Co-authored-by: Ylarod <me@ylarod.cn>
Co-authored-by: YuKongA <70465933+YuKongA@users.noreply.github.com>
xxKSU maintainer:
Co-authored-by: backslashxx <118538522+backslashxx@users.noreply.github.com>
MMRL maintainer:
Co-authored-by: Der_Googler <54764558+dergoogler@users.noreply.github.com>
KSUN maintainer:
Co-authored-by: Rifat Azad <33044977+rifsxd@users.noreply.github.com>
KOWSU maintainer:
Co-authored-by: KOWX712 <leecc0503@gmail.com>
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# clang-format configuration file. Intended for clang-format >= 11.
|
||||
# clang-format configuration file. Intended for clang-format >= 4.
|
||||
#
|
||||
# For more information, see:
|
||||
#
|
||||
# Documentation/dev-tools/clang-format.rst
|
||||
# Documentation/process/clang-format.rst
|
||||
# https://clang.llvm.org/docs/ClangFormat.html
|
||||
# https://clang.llvm.org/docs/ClangFormatStyleOptions.html
|
||||
#
|
||||
@@ -13,7 +13,7 @@ AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignEscapedNewlines: Left
|
||||
#AlignEscapedNewlines: Left # Unknown to clang-format-4.0
|
||||
AlignOperands: true
|
||||
AlignTrailingComments: false
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
@@ -37,24 +37,24 @@ BraceWrapping:
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
AfterExternBlock: false
|
||||
#AfterExternBlock: false # Unknown to clang-format-5.0
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: true
|
||||
SplitEmptyRecord: true
|
||||
SplitEmptyNamespace: true
|
||||
#SplitEmptyFunction: true # Unknown to clang-format-4.0
|
||||
#SplitEmptyRecord: true # Unknown to clang-format-4.0
|
||||
#SplitEmptyNamespace: true # Unknown to clang-format-4.0
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeBraces: Custom
|
||||
BreakBeforeInheritanceComma: false
|
||||
#BreakBeforeInheritanceComma: false # Unknown to clang-format-4.0
|
||||
BreakBeforeTernaryOperators: false
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
BreakConstructorInitializers: BeforeComma
|
||||
#BreakConstructorInitializers: BeforeComma # Unknown to clang-format-4.0
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakStringLiterals: false
|
||||
ColumnLimit: 80
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
CompactNamespaces: false
|
||||
#CompactNamespaces: false # Unknown to clang-format-4.0
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
ConstructorInitializerIndentWidth: 8
|
||||
ContinuationIndentWidth: 8
|
||||
@@ -62,61 +62,39 @@ Cpp11BracedListStyle: false
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
FixNamespaceComments: false
|
||||
#FixNamespaceComments: false # Unknown to clang-format-4.0
|
||||
|
||||
# Taken from:
|
||||
# git grep -h '^#define [^[:space:]]*for_each[^[:space:]]*(' include/ tools/ \
|
||||
# git grep -h '^#define [^[:space:]]*for_each[^[:space:]]*(' include/ \
|
||||
# | sed "s,^#define \([^[:space:]]*for_each[^[:space:]]*\)(.*$, - '\1'," \
|
||||
# | LC_ALL=C sort -u
|
||||
# | sort | uniq
|
||||
ForEachMacros:
|
||||
- '__ata_qc_for_each'
|
||||
- '__bio_for_each_bvec'
|
||||
- '__bio_for_each_segment'
|
||||
- '__evlist__for_each_entry'
|
||||
- '__evlist__for_each_entry_continue'
|
||||
- '__evlist__for_each_entry_from'
|
||||
- '__evlist__for_each_entry_reverse'
|
||||
- '__evlist__for_each_entry_safe'
|
||||
- '__for_each_mem_range'
|
||||
- '__for_each_mem_range_rev'
|
||||
- '__for_each_thread'
|
||||
- '__hlist_for_each_rcu'
|
||||
- '__map__for_each_symbol_by_name'
|
||||
- '__pci_bus_for_each_res0'
|
||||
- '__pci_bus_for_each_res1'
|
||||
- '__pci_dev_for_each_res0'
|
||||
- '__pci_dev_for_each_res1'
|
||||
- '__perf_evlist__for_each_entry'
|
||||
- '__perf_evlist__for_each_entry_reverse'
|
||||
- '__perf_evlist__for_each_entry_safe'
|
||||
- '__rq_for_each_bio'
|
||||
- '__shost_for_each_device'
|
||||
- '__sym_for_each'
|
||||
- '_for_each_counter'
|
||||
- 'apei_estatus_for_each_section'
|
||||
- 'ata_for_each_dev'
|
||||
- 'ata_for_each_link'
|
||||
- '__ata_qc_for_each'
|
||||
- 'ata_qc_for_each'
|
||||
- 'ata_qc_for_each_raw'
|
||||
- 'ata_qc_for_each_with_internal'
|
||||
- 'ax25_for_each'
|
||||
- 'ax25_uid_for_each'
|
||||
- '__bio_for_each_bvec'
|
||||
- 'bio_for_each_bvec'
|
||||
- 'bio_for_each_bvec_all'
|
||||
- 'bio_for_each_folio_all'
|
||||
- 'bio_for_each_integrity_vec'
|
||||
- '__bio_for_each_segment'
|
||||
- 'bio_for_each_segment'
|
||||
- 'bio_for_each_segment_all'
|
||||
- 'bio_list_for_each'
|
||||
- 'bip_for_each_vec'
|
||||
- 'bitmap_for_each_clear_region'
|
||||
- 'bitmap_for_each_set_region'
|
||||
- 'blkg_for_each_descendant_post'
|
||||
- 'blkg_for_each_descendant_pre'
|
||||
- 'blk_queue_for_each_rl'
|
||||
- 'bond_for_each_slave'
|
||||
- 'bond_for_each_slave_rcu'
|
||||
- 'bpf_for_each'
|
||||
- 'bpf_for_each_reg_in_vstate'
|
||||
- 'bpf_for_each_reg_in_vstate_mask'
|
||||
- 'bpf_for_each_spilled_reg'
|
||||
- 'bpf_object__for_each_map'
|
||||
- 'bpf_object__for_each_program'
|
||||
- 'btree_for_each_safe128'
|
||||
- 'btree_for_each_safe32'
|
||||
- 'btree_for_each_safe64'
|
||||
@@ -124,8 +102,6 @@ ForEachMacros:
|
||||
- 'card_for_each_dev'
|
||||
- 'cgroup_taskset_for_each'
|
||||
- 'cgroup_taskset_for_each_leader'
|
||||
- 'cpu_aggr_map__for_each_idx'
|
||||
- 'cpufreq_for_each_efficient_entry_idx'
|
||||
- 'cpufreq_for_each_entry'
|
||||
- 'cpufreq_for_each_entry_idx'
|
||||
- 'cpufreq_for_each_valid_entry'
|
||||
@@ -133,30 +109,8 @@ ForEachMacros:
|
||||
- 'css_for_each_child'
|
||||
- 'css_for_each_descendant_post'
|
||||
- 'css_for_each_descendant_pre'
|
||||
- 'damon_for_each_region'
|
||||
- 'damon_for_each_region_from'
|
||||
- 'damon_for_each_region_safe'
|
||||
- 'damon_for_each_scheme'
|
||||
- 'damon_for_each_scheme_safe'
|
||||
- 'damon_for_each_target'
|
||||
- 'damon_for_each_target_safe'
|
||||
- 'damos_for_each_filter'
|
||||
- 'damos_for_each_filter_safe'
|
||||
- 'damos_for_each_ops_filter'
|
||||
- 'damos_for_each_ops_filter_safe'
|
||||
- 'damos_for_each_quota_goal'
|
||||
- 'damos_for_each_quota_goal_safe'
|
||||
- 'data__for_each_file'
|
||||
- 'data__for_each_file_new'
|
||||
- 'data__for_each_file_start'
|
||||
- 'def_for_each_cpu'
|
||||
- 'device_for_each_child_node'
|
||||
- 'device_for_each_child_node_scoped'
|
||||
- 'dma_fence_array_for_each'
|
||||
- 'dma_fence_chain_for_each'
|
||||
- 'dma_fence_unwrap_for_each'
|
||||
- 'dma_resv_for_each_fence'
|
||||
- 'dma_resv_for_each_fence_unlocked'
|
||||
- 'do_for_each_ftrace_op'
|
||||
- 'drm_atomic_crtc_for_each_plane'
|
||||
- 'drm_atomic_crtc_state_for_each_plane'
|
||||
@@ -165,12 +119,9 @@ ForEachMacros:
|
||||
- 'drm_client_for_each_connector_iter'
|
||||
- 'drm_client_for_each_modeset'
|
||||
- 'drm_connector_for_each_possible_encoder'
|
||||
- 'drm_exec_for_each_locked_object'
|
||||
- 'drm_exec_for_each_locked_object_reverse'
|
||||
- 'drm_for_each_bridge_in_chain'
|
||||
- 'drm_for_each_connector_iter'
|
||||
- 'drm_for_each_crtc'
|
||||
- 'drm_for_each_crtc_reverse'
|
||||
- 'drm_for_each_encoder'
|
||||
- 'drm_for_each_encoder_mask'
|
||||
- 'drm_for_each_fb'
|
||||
@@ -178,64 +129,19 @@ ForEachMacros:
|
||||
- 'drm_for_each_plane'
|
||||
- 'drm_for_each_plane_mask'
|
||||
- 'drm_for_each_privobj'
|
||||
- 'drm_gem_for_each_gpuvm_bo'
|
||||
- 'drm_gem_for_each_gpuvm_bo_safe'
|
||||
- 'drm_gpusvm_for_each_range'
|
||||
- 'drm_gpuva_for_each_op'
|
||||
- 'drm_gpuva_for_each_op_from_reverse'
|
||||
- 'drm_gpuva_for_each_op_reverse'
|
||||
- 'drm_gpuva_for_each_op_safe'
|
||||
- 'drm_gpuvm_bo_for_each_va'
|
||||
- 'drm_gpuvm_bo_for_each_va_safe'
|
||||
- 'drm_gpuvm_for_each_va'
|
||||
- 'drm_gpuvm_for_each_va_range'
|
||||
- 'drm_gpuvm_for_each_va_range_safe'
|
||||
- 'drm_gpuvm_for_each_va_safe'
|
||||
- 'drm_mm_for_each_hole'
|
||||
- 'drm_mm_for_each_node'
|
||||
- 'drm_mm_for_each_node_in_range'
|
||||
- 'drm_mm_for_each_node_safe'
|
||||
- 'dsa_switch_for_each_available_port'
|
||||
- 'dsa_switch_for_each_cpu_port'
|
||||
- 'dsa_switch_for_each_cpu_port_continue_reverse'
|
||||
- 'dsa_switch_for_each_port'
|
||||
- 'dsa_switch_for_each_port_continue_reverse'
|
||||
- 'dsa_switch_for_each_port_safe'
|
||||
- 'dsa_switch_for_each_user_port'
|
||||
- 'dsa_switch_for_each_user_port_continue_reverse'
|
||||
- 'dsa_tree_for_each_cpu_port'
|
||||
- 'dsa_tree_for_each_user_port'
|
||||
- 'dsa_tree_for_each_user_port_continue_reverse'
|
||||
- 'dso__for_each_symbol'
|
||||
- 'elf_hash_for_each_possible'
|
||||
- 'elf_symtab__for_each_symbol'
|
||||
- 'evlist__for_each_cpu'
|
||||
- 'evlist__for_each_entry'
|
||||
- 'evlist__for_each_entry_continue'
|
||||
- 'evlist__for_each_entry_from'
|
||||
- 'evlist__for_each_entry_reverse'
|
||||
- 'evlist__for_each_entry_safe'
|
||||
- 'flow_action_for_each'
|
||||
- 'for_each_acpi_consumer_dev'
|
||||
- 'for_each_acpi_dev_match'
|
||||
- 'for_each_active_dev_scope'
|
||||
- 'for_each_active_drhd_unit'
|
||||
- 'for_each_active_iommu'
|
||||
- 'for_each_active_irq'
|
||||
- 'for_each_active_route'
|
||||
- 'for_each_aggr_pgid'
|
||||
- 'for_each_alloc_capable_rdt_resource'
|
||||
- 'for_each_and_bit'
|
||||
- 'for_each_andnot_bit'
|
||||
- 'for_each_available_child_of_node'
|
||||
- 'for_each_available_child_of_node_scoped'
|
||||
- 'for_each_bench'
|
||||
- 'for_each_bio'
|
||||
- 'for_each_board_func_rsrc'
|
||||
- 'for_each_btf_ext_rec'
|
||||
- 'for_each_btf_ext_sec'
|
||||
- 'for_each_bvec'
|
||||
- 'for_each_capable_rdt_resource'
|
||||
- 'for_each_card_auxs'
|
||||
- 'for_each_card_auxs_safe'
|
||||
- 'for_each_card_components'
|
||||
@@ -248,32 +154,22 @@ ForEachMacros:
|
||||
- 'for_each_card_widgets_safe'
|
||||
- 'for_each_cgroup_storage_type'
|
||||
- 'for_each_child_of_node'
|
||||
- 'for_each_child_of_node_scoped'
|
||||
- 'for_each_child_of_node_with_prefix'
|
||||
- 'for_each_clear_bit'
|
||||
- 'for_each_clear_bit_from'
|
||||
- 'for_each_clear_bitrange'
|
||||
- 'for_each_clear_bitrange_from'
|
||||
- 'for_each_cmd'
|
||||
- 'for_each_cmsghdr'
|
||||
- 'for_each_collection'
|
||||
- 'for_each_comp_order'
|
||||
- 'for_each_compatible_node'
|
||||
- 'for_each_component_dais'
|
||||
- 'for_each_component_dais_safe'
|
||||
- 'for_each_conduit'
|
||||
- 'for_each_comp_order'
|
||||
- 'for_each_console'
|
||||
- 'for_each_console_srcu'
|
||||
- 'for_each_cpu'
|
||||
- 'for_each_cpu_and'
|
||||
- 'for_each_cpu_andnot'
|
||||
- 'for_each_cpu_from'
|
||||
- 'for_each_cpu_or'
|
||||
- 'for_each_cpu_not'
|
||||
- 'for_each_cpu_wrap'
|
||||
- 'for_each_dapm_widgets'
|
||||
- 'for_each_dedup_cand'
|
||||
- 'for_each_dev_addr'
|
||||
- 'for_each_dev_scope'
|
||||
- 'for_each_displayid_db'
|
||||
- 'for_each_dma_cap_mask'
|
||||
- 'for_each_dpcm_be'
|
||||
- 'for_each_dpcm_be_rollback'
|
||||
@@ -286,160 +182,107 @@ ForEachMacros:
|
||||
- 'for_each_element'
|
||||
- 'for_each_element_extid'
|
||||
- 'for_each_element_id'
|
||||
- 'for_each_enabled_cpu'
|
||||
- 'for_each_endpoint_of_node'
|
||||
- 'for_each_event'
|
||||
- 'for_each_event_tps'
|
||||
- 'for_each_evictable_lru'
|
||||
- 'for_each_fib6_node_rt_rcu'
|
||||
- 'for_each_fib6_walker_rt'
|
||||
- 'for_each_file_lock'
|
||||
- 'for_each_free_mem_pfn_range_in_zone'
|
||||
- 'for_each_free_mem_pfn_range_in_zone_from'
|
||||
- 'for_each_free_mem_range'
|
||||
- 'for_each_free_mem_range_reverse'
|
||||
- 'for_each_func_rsrc'
|
||||
- 'for_each_gpiochip_node'
|
||||
- 'for_each_group_evsel'
|
||||
- 'for_each_group_evsel_head'
|
||||
- 'for_each_group_member'
|
||||
- 'for_each_group_member_head'
|
||||
- 'for_each_hstate'
|
||||
- 'for_each_hwgpio'
|
||||
- 'for_each_hwgpio_in_range'
|
||||
- 'for_each_if'
|
||||
- 'for_each_inject_fn'
|
||||
- 'for_each_insn'
|
||||
- 'for_each_insn_op_loc'
|
||||
- 'for_each_insn_prefix'
|
||||
- 'for_each_intid'
|
||||
- 'for_each_iommu'
|
||||
- 'for_each_ip_tunnel_rcu'
|
||||
- 'for_each_irq_desc'
|
||||
- 'for_each_irq_nr'
|
||||
- 'for_each_lang'
|
||||
- 'for_each_link_ch_maps'
|
||||
- 'for_each_link_codecs'
|
||||
- 'for_each_link_cpus'
|
||||
- 'for_each_link_platforms'
|
||||
- 'for_each_lru'
|
||||
- 'for_each_matching_node'
|
||||
- 'for_each_matching_node_and_match'
|
||||
- 'for_each_media_entity_data_link'
|
||||
- 'for_each_mem_pfn_range'
|
||||
- 'for_each_mem_range'
|
||||
- 'for_each_mem_range_rev'
|
||||
- 'for_each_mem_region'
|
||||
- 'for_each_member'
|
||||
- 'for_each_memory'
|
||||
- 'for_each_mem_region'
|
||||
- 'for_each_memblock_type'
|
||||
- 'for_each_memcg_cache_index'
|
||||
- 'for_each_mem_pfn_range'
|
||||
- '__for_each_mem_range'
|
||||
- 'for_each_mem_range'
|
||||
- '__for_each_mem_range_rev'
|
||||
- 'for_each_mem_range_rev'
|
||||
- 'for_each_migratetype_order'
|
||||
- 'for_each_missing_reg'
|
||||
- 'for_each_mle_subelement'
|
||||
- 'for_each_mod_mem_type'
|
||||
- 'for_each_mon_capable_rdt_resource'
|
||||
- 'for_each_mp_bvec'
|
||||
- 'for_each_msi_entry'
|
||||
- 'for_each_msi_entry_safe'
|
||||
- 'for_each_net'
|
||||
- 'for_each_net_continue_reverse'
|
||||
- 'for_each_net_rcu'
|
||||
- 'for_each_netdev'
|
||||
- 'for_each_netdev_continue'
|
||||
- 'for_each_netdev_continue_rcu'
|
||||
- 'for_each_netdev_continue_reverse'
|
||||
- 'for_each_netdev_dump'
|
||||
- 'for_each_netdev_feature'
|
||||
- 'for_each_netdev_in_bond_rcu'
|
||||
- 'for_each_netdev_rcu'
|
||||
- 'for_each_netdev_reverse'
|
||||
- 'for_each_netdev_safe'
|
||||
- 'for_each_net_rcu'
|
||||
- 'for_each_new_connector_in_state'
|
||||
- 'for_each_new_crtc_in_state'
|
||||
- 'for_each_new_mst_mgr_in_state'
|
||||
- 'for_each_new_plane_in_state'
|
||||
- 'for_each_new_plane_in_state_reverse'
|
||||
- 'for_each_new_private_obj_in_state'
|
||||
- 'for_each_new_reg'
|
||||
- 'for_each_nhlt_endpoint'
|
||||
- 'for_each_nhlt_endpoint_fmtcfg'
|
||||
- 'for_each_nhlt_fmtcfg'
|
||||
- 'for_each_node'
|
||||
- 'for_each_node_by_name'
|
||||
- 'for_each_node_by_type'
|
||||
- 'for_each_node_mask'
|
||||
- 'for_each_node_numadist'
|
||||
- 'for_each_node_state'
|
||||
- 'for_each_node_with_cpus'
|
||||
- 'for_each_node_with_property'
|
||||
- 'for_each_nonreserved_multicast_dest_pgid'
|
||||
- 'for_each_numa_hop_mask'
|
||||
- 'for_each_of_allnodes'
|
||||
- 'for_each_of_allnodes_from'
|
||||
- 'for_each_of_cpu_node'
|
||||
- 'for_each_of_graph_port'
|
||||
- 'for_each_of_graph_port_endpoint'
|
||||
- 'for_each_of_pci_range'
|
||||
- 'for_each_old_connector_in_state'
|
||||
- 'for_each_old_crtc_in_state'
|
||||
- 'for_each_old_mst_mgr_in_state'
|
||||
- 'for_each_old_plane_in_state'
|
||||
- 'for_each_old_private_obj_in_state'
|
||||
- 'for_each_oldnew_connector_in_state'
|
||||
- 'for_each_oldnew_crtc_in_state'
|
||||
- 'for_each_oldnew_mst_mgr_in_state'
|
||||
- 'for_each_oldnew_plane_in_state'
|
||||
- 'for_each_oldnew_plane_in_state_reverse'
|
||||
- 'for_each_oldnew_private_obj_in_state'
|
||||
- 'for_each_old_plane_in_state'
|
||||
- 'for_each_old_private_obj_in_state'
|
||||
- 'for_each_online_cpu'
|
||||
- 'for_each_online_cpu_wrap'
|
||||
- 'for_each_online_node'
|
||||
- 'for_each_online_pgdat'
|
||||
- 'for_each_or_bit'
|
||||
- 'for_each_page_ext'
|
||||
- 'for_each_path'
|
||||
- 'for_each_pci_bridge'
|
||||
- 'for_each_pci_dev'
|
||||
- 'for_each_pci_msi_entry'
|
||||
- 'for_each_pcm_streams'
|
||||
- 'for_each_physmem_range'
|
||||
- 'for_each_populated_zone'
|
||||
- 'for_each_possible_cpu'
|
||||
- 'for_each_possible_cpu_wrap'
|
||||
- 'for_each_present_blessed_reg'
|
||||
- 'for_each_present_cpu'
|
||||
- 'for_each_present_section_nr'
|
||||
- 'for_each_prime_number'
|
||||
- 'for_each_prime_number_from'
|
||||
- 'for_each_probe_cache_entry'
|
||||
- 'for_each_process'
|
||||
- 'for_each_process_thread'
|
||||
- 'for_each_prop_codec_conf'
|
||||
- 'for_each_prop_dai_codec'
|
||||
- 'for_each_prop_dai_cpu'
|
||||
- 'for_each_prop_dlc_codecs'
|
||||
- 'for_each_prop_dlc_cpus'
|
||||
- 'for_each_prop_dlc_platforms'
|
||||
- 'for_each_property_of_node'
|
||||
- 'for_each_rdt_resource'
|
||||
- 'for_each_reg'
|
||||
- 'for_each_reg_filtered'
|
||||
- 'for_each_reloc'
|
||||
- 'for_each_reloc_from'
|
||||
- 'for_each_registered_fb'
|
||||
- 'for_each_requested_gpio'
|
||||
- 'for_each_requested_gpio_in_range'
|
||||
- 'for_each_reserved_child_of_node'
|
||||
- 'for_each_reserved_mem_range'
|
||||
- 'for_each_reserved_mem_region'
|
||||
- 'for_each_rtd_ch_maps'
|
||||
- 'for_each_rtd_codec_dais'
|
||||
- 'for_each_rtd_codec_dais_rollback'
|
||||
- 'for_each_rtd_components'
|
||||
- 'for_each_rtd_cpu_dais'
|
||||
- 'for_each_rtd_cpu_dais_rollback'
|
||||
- 'for_each_rtd_dais'
|
||||
- 'for_each_rtd_dais_reverse'
|
||||
- 'for_each_sband_iftype_data'
|
||||
- 'for_each_script'
|
||||
- 'for_each_sec'
|
||||
- 'for_each_set_bit'
|
||||
- 'for_each_set_bit_from'
|
||||
- 'for_each_set_bit_wrap'
|
||||
- 'for_each_set_bitrange'
|
||||
- 'for_each_set_bitrange_from'
|
||||
- 'for_each_set_clump8'
|
||||
- 'for_each_sg'
|
||||
- 'for_each_sg_dma_page'
|
||||
@@ -449,37 +292,22 @@ ForEachMacros:
|
||||
- 'for_each_sgtable_page'
|
||||
- 'for_each_sgtable_sg'
|
||||
- 'for_each_sibling_event'
|
||||
- 'for_each_sta_active_link'
|
||||
- 'for_each_subelement'
|
||||
- 'for_each_subelement_extid'
|
||||
- 'for_each_subelement_id'
|
||||
- 'for_each_sublist'
|
||||
- 'for_each_subsystem'
|
||||
- 'for_each_suite'
|
||||
- 'for_each_supported_activate_fn'
|
||||
- 'for_each_supported_inject_fn'
|
||||
- 'for_each_sym'
|
||||
- '__for_each_thread'
|
||||
- 'for_each_thread'
|
||||
- 'for_each_token'
|
||||
- 'for_each_unicast_dest_pgid'
|
||||
- 'for_each_valid_link'
|
||||
- 'for_each_vif_active_link'
|
||||
- 'for_each_vma'
|
||||
- 'for_each_vma_range'
|
||||
- 'for_each_vsi'
|
||||
- 'for_each_wakeup_source'
|
||||
- 'for_each_zone'
|
||||
- 'for_each_zone_zonelist'
|
||||
- 'for_each_zone_zonelist_nodemask'
|
||||
- 'func_for_each_insn'
|
||||
- 'fwnode_for_each_available_child_node'
|
||||
- 'fwnode_for_each_child_node'
|
||||
- 'fwnode_for_each_parent_node'
|
||||
- 'fwnode_graph_for_each_endpoint'
|
||||
- 'gadget_for_each_ep'
|
||||
- 'genradix_for_each'
|
||||
- 'genradix_for_each_from'
|
||||
- 'genradix_for_each_reverse'
|
||||
- 'hash_for_each'
|
||||
- 'hash_for_each_possible'
|
||||
- 'hash_for_each_possible_rcu'
|
||||
@@ -487,13 +315,7 @@ ForEachMacros:
|
||||
- 'hash_for_each_possible_safe'
|
||||
- 'hash_for_each_rcu'
|
||||
- 'hash_for_each_safe'
|
||||
- 'hashmap__for_each_entry'
|
||||
- 'hashmap__for_each_entry_safe'
|
||||
- 'hashmap__for_each_key_entry'
|
||||
- 'hashmap__for_each_key_entry_safe'
|
||||
- 'hctx_for_each_ctx'
|
||||
- 'hists__for_each_format'
|
||||
- 'hists__for_each_sort_list'
|
||||
- 'hlist_bl_for_each_entry'
|
||||
- 'hlist_bl_for_each_entry_rcu'
|
||||
- 'hlist_bl_for_each_entry_safe'
|
||||
@@ -508,7 +330,7 @@ ForEachMacros:
|
||||
- 'hlist_for_each_entry_rcu_bh'
|
||||
- 'hlist_for_each_entry_rcu_notrace'
|
||||
- 'hlist_for_each_entry_safe'
|
||||
- 'hlist_for_each_entry_srcu'
|
||||
- '__hlist_for_each_rcu'
|
||||
- 'hlist_for_each_safe'
|
||||
- 'hlist_nulls_for_each_entry'
|
||||
- 'hlist_nulls_for_each_entry_from'
|
||||
@@ -516,19 +338,17 @@ ForEachMacros:
|
||||
- 'hlist_nulls_for_each_entry_safe'
|
||||
- 'i3c_bus_for_each_i2cdev'
|
||||
- 'i3c_bus_for_each_i3cdev'
|
||||
- 'ide_host_for_each_port'
|
||||
- 'ide_port_for_each_dev'
|
||||
- 'ide_port_for_each_present_dev'
|
||||
- 'idr_for_each_entry'
|
||||
- 'idr_for_each_entry_continue'
|
||||
- 'idr_for_each_entry_continue_ul'
|
||||
- 'idr_for_each_entry_ul'
|
||||
- 'iio_for_each_active_channel'
|
||||
- 'in_dev_for_each_ifa_rcu'
|
||||
- 'in_dev_for_each_ifa_rtnl'
|
||||
- 'in_dev_for_each_ifa_rtnl_net'
|
||||
- 'inet_bind_bucket_for_each'
|
||||
- 'interval_tree_for_each_span'
|
||||
- 'intlist__for_each_entry'
|
||||
- 'intlist__for_each_entry_safe'
|
||||
- 'kcore_copy__for_each_phdr'
|
||||
- 'inet_lhash2_for_each_icsk_rcu'
|
||||
- 'key_for_each'
|
||||
- 'key_for_each_safe'
|
||||
- 'klp_for_each_func'
|
||||
@@ -539,9 +359,7 @@ ForEachMacros:
|
||||
- 'klp_for_each_object_static'
|
||||
- 'kunit_suite_for_each_test_case'
|
||||
- 'kvm_for_each_memslot'
|
||||
- 'kvm_for_each_memslot_in_gfn_range'
|
||||
- 'kvm_for_each_vcpu'
|
||||
- 'libbpf_nla_for_each_attr'
|
||||
- 'list_for_each'
|
||||
- 'list_for_each_codec'
|
||||
- 'list_for_each_codec_safe'
|
||||
@@ -560,53 +378,29 @@ ForEachMacros:
|
||||
- 'list_for_each_entry_safe_continue'
|
||||
- 'list_for_each_entry_safe_from'
|
||||
- 'list_for_each_entry_safe_reverse'
|
||||
- 'list_for_each_entry_srcu'
|
||||
- 'list_for_each_from'
|
||||
- 'list_for_each_prev'
|
||||
- 'list_for_each_prev_safe'
|
||||
- 'list_for_each_rcu'
|
||||
- 'list_for_each_safe'
|
||||
- 'llist_for_each'
|
||||
- 'llist_for_each_entry'
|
||||
- 'llist_for_each_entry_safe'
|
||||
- 'llist_for_each_safe'
|
||||
- 'lwq_for_each_safe'
|
||||
- 'map__for_each_symbol'
|
||||
- 'map__for_each_symbol_by_name'
|
||||
- 'mas_for_each'
|
||||
- 'mas_for_each_rev'
|
||||
- 'mci_for_each_dimm'
|
||||
- 'media_device_for_each_entity'
|
||||
- 'media_device_for_each_intf'
|
||||
- 'media_device_for_each_link'
|
||||
- 'media_device_for_each_pad'
|
||||
- 'media_entity_for_each_pad'
|
||||
- 'media_pipeline_for_each_entity'
|
||||
- 'media_pipeline_for_each_pad'
|
||||
- 'mlx5_lag_for_each_peer_mdev'
|
||||
- 'mptcp_for_each_subflow'
|
||||
- 'msi_domain_for_each_desc'
|
||||
- 'msi_for_each_desc'
|
||||
- 'mt_for_each'
|
||||
- 'nanddev_io_for_each_block'
|
||||
- 'nanddev_io_for_each_page'
|
||||
- 'neigh_for_each_in_bucket'
|
||||
- 'neigh_for_each_in_bucket_rcu'
|
||||
- 'neigh_for_each_in_bucket_safe'
|
||||
- 'netdev_for_each_lower_dev'
|
||||
- 'netdev_for_each_lower_private'
|
||||
- 'netdev_for_each_lower_private_rcu'
|
||||
- 'netdev_for_each_mc_addr'
|
||||
- 'netdev_for_each_synced_mc_addr'
|
||||
- 'netdev_for_each_synced_uc_addr'
|
||||
- 'netdev_for_each_uc_addr'
|
||||
- 'netdev_for_each_upper_dev_rcu'
|
||||
- 'netdev_hw_addr_list_for_each'
|
||||
- 'nft_rule_for_each_expr'
|
||||
- 'nla_for_each_attr'
|
||||
- 'nla_for_each_attr_type'
|
||||
- 'nla_for_each_nested'
|
||||
- 'nla_for_each_nested_type'
|
||||
- 'nlmsg_for_each_attr'
|
||||
- 'nlmsg_for_each_msg'
|
||||
- 'nr_neigh_for_each'
|
||||
@@ -617,26 +411,8 @@ ForEachMacros:
|
||||
- 'of_property_for_each_string'
|
||||
- 'of_property_for_each_u32'
|
||||
- 'pci_bus_for_each_resource'
|
||||
- 'pci_dev_for_each_resource'
|
||||
- 'pcl_for_each_chunk'
|
||||
- 'pcl_for_each_segment'
|
||||
- 'pcm_for_each_format'
|
||||
- 'perf_config_items__for_each_entry'
|
||||
- 'perf_config_sections__for_each_entry'
|
||||
- 'perf_config_set__for_each_entry'
|
||||
- 'perf_cpu_map__for_each_cpu'
|
||||
- 'perf_cpu_map__for_each_cpu_skip_any'
|
||||
- 'perf_cpu_map__for_each_idx'
|
||||
- 'perf_evlist__for_each_entry'
|
||||
- 'perf_evlist__for_each_entry_reverse'
|
||||
- 'perf_evlist__for_each_entry_safe'
|
||||
- 'perf_evlist__for_each_evsel'
|
||||
- 'perf_evlist__for_each_mmap'
|
||||
- 'perf_evsel_for_each_per_thread_period_safe'
|
||||
- 'perf_hpp_list__for_each_format'
|
||||
- 'perf_hpp_list__for_each_format_safe'
|
||||
- 'perf_hpp_list__for_each_sort_list'
|
||||
- 'perf_hpp_list__for_each_sort_list_safe'
|
||||
- 'ping_portaddr_for_each_entry'
|
||||
- 'plist_for_each'
|
||||
- 'plist_for_each_continue'
|
||||
- 'plist_for_each_entry'
|
||||
@@ -650,7 +426,6 @@ ForEachMacros:
|
||||
- 'queue_for_each_hw_ctx'
|
||||
- 'radix_tree_for_each_slot'
|
||||
- 'radix_tree_for_each_tagged'
|
||||
- 'rb_for_each'
|
||||
- 'rbtree_postorder_for_each_entry_safe'
|
||||
- 'rdma_for_each_block'
|
||||
- 'rdma_for_each_port'
|
||||
@@ -668,24 +443,18 @@ ForEachMacros:
|
||||
- 'rht_for_each_from'
|
||||
- 'rht_for_each_rcu'
|
||||
- 'rht_for_each_rcu_from'
|
||||
- '__rq_for_each_bio'
|
||||
- 'rq_for_each_bvec'
|
||||
- 'rq_for_each_segment'
|
||||
- 'rq_list_for_each'
|
||||
- 'rq_list_for_each_safe'
|
||||
- 'sample_read_group__for_each'
|
||||
- 'scsi_for_each_prot_sg'
|
||||
- 'scsi_for_each_sg'
|
||||
- 'sctp_for_each_hentry'
|
||||
- 'sctp_skb_for_each'
|
||||
- 'sec_for_each_insn'
|
||||
- 'sec_for_each_insn_continue'
|
||||
- 'sec_for_each_insn_from'
|
||||
- 'sec_for_each_sym'
|
||||
- 'shdma_for_each_chan'
|
||||
- '__shost_for_each_device'
|
||||
- 'shost_for_each_device'
|
||||
- 'sk_for_each'
|
||||
- 'sk_for_each_bound'
|
||||
- 'sk_for_each_bound_safe'
|
||||
- 'sk_for_each_entry_offset_rcu'
|
||||
- 'sk_for_each_from'
|
||||
- 'sk_for_each_rcu'
|
||||
@@ -699,20 +468,8 @@ ForEachMacros:
|
||||
- 'snd_soc_dapm_widget_for_each_path_safe'
|
||||
- 'snd_soc_dapm_widget_for_each_sink_path'
|
||||
- 'snd_soc_dapm_widget_for_each_source_path'
|
||||
- 'sparsebit_for_each_set_range'
|
||||
- 'strlist__for_each_entry'
|
||||
- 'strlist__for_each_entry_safe'
|
||||
- 'sym_for_each_insn'
|
||||
- 'sym_for_each_insn_continue_reverse'
|
||||
- 'symbols__for_each_entry'
|
||||
- 'tb_property_for_each'
|
||||
- 'tcf_act_for_each_action'
|
||||
- 'tcf_exts_for_each_action'
|
||||
- 'test_suite__for_each_test_case'
|
||||
- 'tool_pmu__for_each_event'
|
||||
- 'ttm_bo_lru_for_each_reserved_guarded'
|
||||
- 'ttm_resource_manager_for_each_res'
|
||||
- 'udp_lrpa_for_each_entry_rcu'
|
||||
- 'udp_portaddr_for_each_entry'
|
||||
- 'udp_portaddr_for_each_entry_rcu'
|
||||
- 'usb_hub_for_each_child'
|
||||
@@ -722,15 +479,7 @@ ForEachMacros:
|
||||
- 'v4l2_m2m_for_each_src_buf'
|
||||
- 'v4l2_m2m_for_each_src_buf_safe'
|
||||
- 'virtio_device_for_each_vq'
|
||||
- 'vkms_config_for_each_connector'
|
||||
- 'vkms_config_for_each_crtc'
|
||||
- 'vkms_config_for_each_encoder'
|
||||
- 'vkms_config_for_each_plane'
|
||||
- 'vkms_config_connector_for_each_possible_encoder'
|
||||
- 'vkms_config_encoder_for_each_possible_crtc'
|
||||
- 'vkms_config_plane_for_each_possible_crtc'
|
||||
- 'while_for_each_ftrace_op'
|
||||
- 'workloads__for_each'
|
||||
- 'xa_for_each'
|
||||
- 'xa_for_each_marked'
|
||||
- 'xa_for_each_range'
|
||||
@@ -743,20 +492,15 @@ ForEachMacros:
|
||||
- 'xbc_node_for_each_array_value'
|
||||
- 'xbc_node_for_each_child'
|
||||
- 'xbc_node_for_each_key_value'
|
||||
- 'xbc_node_for_each_subkey'
|
||||
- 'ynl_attr_for_each'
|
||||
- 'ynl_attr_for_each_nested'
|
||||
- 'ynl_attr_for_each_payload'
|
||||
- 'zorro_for_each_dev'
|
||||
|
||||
IncludeBlocks: Preserve
|
||||
#IncludeBlocks: Preserve # Unknown to clang-format-5.0
|
||||
IncludeCategories:
|
||||
- Regex: '.*'
|
||||
Priority: 1
|
||||
IncludeIsMainRegex: '(Test)?$'
|
||||
IndentCaseLabels: false
|
||||
IndentGotoLabels: false
|
||||
IndentPPDirectives: None
|
||||
#IndentPPDirectives: None # Unknown to clang-format-5.0
|
||||
IndentWidth: 8
|
||||
IndentWrappedFunctionNames: false
|
||||
JavaScriptQuotes: Leave
|
||||
@@ -766,13 +510,13 @@ MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
ObjCBinPackProtocolList: Auto
|
||||
#ObjCBinPackProtocolList: Auto # Unknown to clang-format-5.0
|
||||
ObjCBlockIndentWidth: 8
|
||||
ObjCSpaceAfterProperty: true
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
|
||||
# Taken from git's rules
|
||||
PenaltyBreakAssignment: 10
|
||||
#PenaltyBreakAssignment: 10 # Unknown to clang-format-4.0
|
||||
PenaltyBreakBeforeFirstCallParameter: 30
|
||||
PenaltyBreakComment: 10
|
||||
PenaltyBreakFirstLessLess: 0
|
||||
@@ -783,14 +527,14 @@ PenaltyReturnTypeOnItsOwnLine: 60
|
||||
PointerAlignment: Right
|
||||
ReflowComments: false
|
||||
SortIncludes: false
|
||||
SortUsingDeclarations: false
|
||||
#SortUsingDeclarations: false # Unknown to clang-format-4.0
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeParens: ControlStatementsExceptForEachMacros
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
#SpaceBeforeCtorInitializerColon: true # Unknown to clang-format-5.0
|
||||
#SpaceBeforeInheritanceColon: true # Unknown to clang-format-5.0
|
||||
SpaceBeforeParens: ControlStatements
|
||||
#SpaceBeforeRangeBasedForLoopColon: true # Unknown to clang-format-5.0
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: false
|
||||
|
||||
@@ -15,15 +15,6 @@ config KSU_DEBUG
|
||||
help
|
||||
Enable KernelSU debug mode.
|
||||
|
||||
config KSU_THRONE_TRACKER_LEGACY
|
||||
bool "Use legacy throne tracker (packages.list scanning)"
|
||||
depends on KSU
|
||||
default n
|
||||
help
|
||||
Use legacy throne tracker that scans packages.list for app UIDs.
|
||||
This is kept for Ultra-Legacy Linux 4.4-3.X kernels which are prone to deadlocks.
|
||||
Enable this if default scanning deadlocks/crashes on you.
|
||||
|
||||
config KSU_ALLOWLIST_WORKAROUND
|
||||
bool "KernelSU Session init keyring workaround"
|
||||
depends on KSU
|
||||
@@ -32,14 +23,6 @@ config KSU_ALLOWLIST_WORKAROUND
|
||||
Enable session keyring init workaround for problematic devices.
|
||||
Useful for situations where the SU allowlist is not kept after a reboot.
|
||||
|
||||
config KSU_CMDLINE
|
||||
bool "Enable KernelSU cmdline"
|
||||
depends on KSU && KSU != m
|
||||
default n
|
||||
help
|
||||
Enable a cmdline called kernelsu.enabled
|
||||
Value 1 means enabled, value 0 means disabled.
|
||||
|
||||
config KPM
|
||||
bool "Enable SukiSU KPM"
|
||||
depends on KSU && 64BIT
|
||||
|
||||
@@ -3,7 +3,12 @@ kernelsu-objs += allowlist.o
|
||||
kernelsu-objs += dynamic_manager.o
|
||||
kernelsu-objs += apk_sign.o
|
||||
kernelsu-objs += sucompat.o
|
||||
kernelsu-objs += throne_tracker.o
|
||||
kernelsu-objs += pkg_observer.o
|
||||
kernelsu-objs += core_hook.o
|
||||
kernelsu-objs += supercalls.o
|
||||
kernelsu-objs += feature.o
|
||||
kernelsu-objs += throne_tracker.o
|
||||
kernelsu-objs += ksud.o
|
||||
kernelsu-objs += embed_ksud.o
|
||||
kernelsu-objs += kernel_compat.o
|
||||
@@ -13,13 +18,6 @@ ifeq ($(CONFIG_KSU_TRACEPOINT_HOOK), y)
|
||||
kernelsu-objs += ksu_trace.o
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_KSU_THRONE_TRACKER_LEGACY),y)
|
||||
$(info -- KernelSU/compat: using legacy throne tracker)
|
||||
kernelsu-objs += throne_tracker_legacy.o
|
||||
else
|
||||
$(info -- KernelSU/compat: using new throne tracker)
|
||||
kernelsu-objs += throne_tracker.o
|
||||
endif
|
||||
|
||||
kernelsu-objs += selinux/selinux.o
|
||||
kernelsu-objs += selinux/sepolicy.o
|
||||
@@ -117,28 +115,20 @@ endif
|
||||
ifeq ($(shell grep "ssize_t kernel_write" $(srctree)/fs/read_write.c | grep -q "const void" ; echo $$?),0)
|
||||
ccflags-y += -DKSU_OPTIONAL_KERNEL_WRITE
|
||||
endif
|
||||
ifeq ($(shell grep -q "inode_security_struct\s\+\*selinux_inode" $(srctree)/security/selinux/include/objsec.h; echo $$?),0)
|
||||
ccflags-y += -DKSU_OPTIONAL_SELINUX_INODE
|
||||
endif
|
||||
ifeq ($(shell grep -q "int\s\+path_umount" $(srctree)/fs/namespace.c; echo $$?),0)
|
||||
ccflags-y += -DKSU_HAS_PATH_UMOUNT
|
||||
endif
|
||||
# Checks Samsung UH drivers
|
||||
ifeq ($(shell grep -q "inode_security_struct\s\+\*selinux_inode" $(srctree)/security/selinux/include/objsec.h; echo $$?),0)
|
||||
ccflags-y += -DKSU_OPTIONAL_SELINUX_INODE
|
||||
endif
|
||||
|
||||
# Checks Samsung
|
||||
ifeq ($(shell grep -q "CONFIG_KDP_CRED" $(srctree)/kernel/cred.c; echo $$?),0)
|
||||
ccflags-y += -DSAMSUNG_UH_DRIVER_EXIST
|
||||
endif
|
||||
|
||||
# Samsung SELinux Porting
|
||||
ifeq ($(shell grep -q "SEC_SELINUX_PORTING_COMMON" $(srctree)/security/selinux/avc.c; echo $$?),0)
|
||||
ccflags-y += -DSAMSUNG_SELINUX_PORTING
|
||||
endif
|
||||
|
||||
# Check new vfs_getattr()
|
||||
ifeq ($(shell grep -A1 "^int vfs_getattr" $(srctree)/fs/stat.c | grep -q "query_flags" ; echo $$?),0)
|
||||
$(info -- KernelSU/compat: new vfs_getattr() found)
|
||||
ccflags-y += -DKSU_HAS_NEW_VFS_GETATTR
|
||||
endif
|
||||
|
||||
# Function proc_ops check
|
||||
ifeq ($(shell grep -q "struct proc_ops " $(srctree)/include/linux/proc_fs.h; echo $$?),0)
|
||||
ccflags-y += -DKSU_COMPAT_HAS_PROC_OPS
|
||||
@@ -183,6 +173,6 @@ $(info -- KPM is disabled)
|
||||
endif
|
||||
|
||||
ccflags-y += -Wno-implicit-function-declaration -Wno-strict-prototypes -Wno-int-conversion -Wno-gcc-compat
|
||||
ccflags-y += -Wno-declaration-after-statement -Wno-unused-function
|
||||
ccflags-y += -Wno-declaration-after-statement -Wno-unused-function -Wno-missing-prototypes
|
||||
|
||||
# Keep a new line here!! Because someone may append config
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#define __PT_IP_REG pc
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0)
|
||||
#define PRCTL_SYMBOL "__arm64_sys_prctl"
|
||||
#define REBOOT_SYMBOL "__arm64_sys_reboot"
|
||||
#define SYS_READ_SYMBOL "__arm64_sys_read"
|
||||
#define SYS_NEWFSTATAT_SYMBOL "__arm64_sys_newfstatat"
|
||||
#define SYS_FSTATAT64_SYMBOL "__arm64_sys_fstatat64"
|
||||
@@ -27,7 +27,7 @@
|
||||
#define SYS_EXECVE_SYMBOL "__arm64_sys_execve"
|
||||
#define SYS_EXECVE_COMPAT_SYMBOL "__arm64_compat_sys_execve"
|
||||
#else
|
||||
#define PRCTL_SYMBOL "sys_prctl"
|
||||
#define REBOOT_SYMBOL "sys_reboot"
|
||||
#define SYS_READ_SYMBOL "sys_read"
|
||||
#define SYS_NEWFSTATAT_SYMBOL "sys_newfstatat"
|
||||
#define SYS_FSTATAT64_SYMBOL "sys_fstatat64"
|
||||
@@ -52,7 +52,7 @@
|
||||
#define __PT_SP_REG sp
|
||||
#define __PT_IP_REG ip
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 16, 0)
|
||||
#define PRCTL_SYMBOL "__x64_sys_prctl"
|
||||
#define REBOOT_SYMBOL "__x64_sys_reboot"
|
||||
#define SYS_READ_SYMBOL "__x64_sys_read"
|
||||
#define SYS_NEWFSTATAT_SYMBOL "__x64_sys_newfstatat"
|
||||
#define SYS_FSTATAT64_SYMBOL "__x64_sys_fstatat64"
|
||||
@@ -60,7 +60,7 @@
|
||||
#define SYS_EXECVE_SYMBOL "__x64_sys_execve"
|
||||
#define SYS_EXECVE_COMPAT_SYMBOL "__x64_compat_sys_execve"
|
||||
#else
|
||||
#define PRCTL_SYMBOL "sys_prctl"
|
||||
#define PRCTL_SYMBOL "sys_reboot"
|
||||
#define SYS_READ_SYMBOL "sys_read"
|
||||
#define SYS_NEWFSTATAT_SYMBOL "sys_newfstatat"
|
||||
#define SYS_FSTATAT64_SYMBOL "sys_fstatat64"
|
||||
|
||||
1099
kernel/core_hook.c
1099
kernel/core_hook.c
File diff suppressed because it is too large
Load Diff
176
kernel/feature.c
Normal file
176
kernel/feature.c
Normal file
@@ -0,0 +1,176 @@
|
||||
#include "feature.h"
|
||||
#include "klog.h" // IWYU pragma: keep
|
||||
|
||||
#include <linux/mutex.h>
|
||||
|
||||
static const struct ksu_feature_handler *feature_handlers[KSU_FEATURE_MAX];
|
||||
|
||||
static DEFINE_MUTEX(feature_mutex);
|
||||
|
||||
int ksu_register_feature_handler(const struct ksu_feature_handler *handler)
|
||||
{
|
||||
if (!handler) {
|
||||
pr_err("feature: register handler is NULL\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (handler->feature_id >= KSU_FEATURE_MAX) {
|
||||
pr_err("feature: invalid feature_id %u\n", handler->feature_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!handler->get_handler && !handler->set_handler) {
|
||||
pr_err("feature: no handler provided for feature %u\n",
|
||||
handler->feature_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&feature_mutex);
|
||||
|
||||
if (feature_handlers[handler->feature_id]) {
|
||||
pr_warn("feature: handler for %u already registered, overwriting\n",
|
||||
handler->feature_id);
|
||||
}
|
||||
|
||||
feature_handlers[handler->feature_id] = handler;
|
||||
|
||||
pr_info("feature: registered handler for %s (id=%u)\n",
|
||||
handler->name ? handler->name : "unknown", handler->feature_id);
|
||||
|
||||
mutex_unlock(&feature_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ksu_unregister_feature_handler(u32 feature_id)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (feature_id >= KSU_FEATURE_MAX) {
|
||||
pr_err("feature: invalid feature_id %u\n", feature_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&feature_mutex);
|
||||
|
||||
if (!feature_handlers[feature_id]) {
|
||||
pr_warn("feature: no handler registered for %u\n", feature_id);
|
||||
ret = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
feature_handlers[feature_id] = NULL;
|
||||
|
||||
pr_info("feature: unregistered handler for id=%u\n", feature_id);
|
||||
|
||||
out:
|
||||
mutex_unlock(&feature_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ksu_get_feature(u32 feature_id, u64 *value, bool *supported)
|
||||
{
|
||||
int ret = 0;
|
||||
const struct ksu_feature_handler *handler;
|
||||
|
||||
if (feature_id >= KSU_FEATURE_MAX) {
|
||||
pr_err("feature: invalid feature_id %u\n", feature_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!value || !supported) {
|
||||
pr_err("feature: invalid parameters\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&feature_mutex);
|
||||
|
||||
handler = feature_handlers[feature_id];
|
||||
|
||||
if (!handler) {
|
||||
*supported = false;
|
||||
*value = 0;
|
||||
pr_debug("feature: feature %u not supported\n", feature_id);
|
||||
goto out;
|
||||
}
|
||||
|
||||
*supported = true;
|
||||
|
||||
if (!handler->get_handler) {
|
||||
pr_warn("feature: no get_handler for feature %u\n", feature_id);
|
||||
ret = -EOPNOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = handler->get_handler(value);
|
||||
if (ret) {
|
||||
pr_err("feature: get_handler for %u failed: %d\n", feature_id,
|
||||
ret);
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&feature_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ksu_set_feature(u32 feature_id, u64 value)
|
||||
{
|
||||
int ret = 0;
|
||||
const struct ksu_feature_handler *handler;
|
||||
|
||||
if (feature_id >= KSU_FEATURE_MAX) {
|
||||
pr_err("feature: invalid feature_id %u\n", feature_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&feature_mutex);
|
||||
|
||||
handler = feature_handlers[feature_id];
|
||||
|
||||
if (!handler) {
|
||||
pr_err("feature: feature %u not registered\n", feature_id);
|
||||
ret = -EOPNOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!handler->set_handler) {
|
||||
pr_warn("feature: no set_handler for feature %u\n", feature_id);
|
||||
ret = -EOPNOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = handler->set_handler(value);
|
||||
if (ret) {
|
||||
pr_err("feature: set_handler for %u failed: %d\n", feature_id,
|
||||
ret);
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&feature_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ksu_feature_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < KSU_FEATURE_MAX; i++) {
|
||||
feature_handlers[i] = NULL;
|
||||
}
|
||||
|
||||
pr_info("%s: feature management initialized\n", __func__);
|
||||
}
|
||||
|
||||
void ksu_feature_exit(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
mutex_lock(&feature_mutex);
|
||||
|
||||
for (i = 0; i < KSU_FEATURE_MAX; i++) {
|
||||
feature_handlers[i] = NULL;
|
||||
}
|
||||
|
||||
mutex_unlock(&feature_mutex);
|
||||
|
||||
pr_info("%s: feature management cleaned up\n", __func__);
|
||||
}
|
||||
35
kernel/feature.h
Normal file
35
kernel/feature.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#ifndef __KSU_H_FEATURE
|
||||
#define __KSU_H_FEATURE
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
enum ksu_feature_id {
|
||||
KSU_FEATURE_SU_COMPAT = 0,
|
||||
KSU_FEATURE_KERNEL_UMOUNT = 1,
|
||||
|
||||
KSU_FEATURE_MAX
|
||||
};
|
||||
|
||||
typedef int (*ksu_feature_get_t)(u64 *value);
|
||||
typedef int (*ksu_feature_set_t)(u64 value);
|
||||
|
||||
struct ksu_feature_handler {
|
||||
u32 feature_id;
|
||||
const char *name;
|
||||
ksu_feature_get_t get_handler;
|
||||
ksu_feature_set_t set_handler;
|
||||
};
|
||||
|
||||
int ksu_register_feature_handler(const struct ksu_feature_handler *handler);
|
||||
|
||||
int ksu_unregister_feature_handler(u32 feature_id);
|
||||
|
||||
int ksu_get_feature(u32 feature_id, u64 *value, bool *supported);
|
||||
|
||||
int ksu_set_feature(u32 feature_id, u64 value);
|
||||
|
||||
void ksu_feature_init(void);
|
||||
|
||||
void ksu_feature_exit(void);
|
||||
|
||||
#endif // __KSU_H_FEATURE
|
||||
@@ -7,16 +7,18 @@
|
||||
#include <linux/sched.h>
|
||||
#endif
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/filter.h>
|
||||
#include <linux/seccomp.h>
|
||||
#include "klog.h" // IWYU pragma: keep
|
||||
#include "kernel_compat.h" // Add check Huawei Device
|
||||
#include "kernel_compat.h"
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) || \
|
||||
defined(CONFIG_IS_HW_HISI) || defined(CONFIG_KSU_ALLOWLIST_WORKAROUND)
|
||||
#include <linux/key.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/cred.h>
|
||||
struct key *init_session_keyring = NULL;
|
||||
|
||||
struct key *init_session_keyring = NULL;
|
||||
static inline int install_session_keyring(struct key *keyring)
|
||||
{
|
||||
struct cred *new;
|
||||
@@ -239,3 +241,63 @@ long ksu_copy_from_user_nofault(void *dst, const void __user *src, size_t size)
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
|
||||
|
||||
struct action_cache {
|
||||
DECLARE_BITMAP(allow_native, SECCOMP_ARCH_NATIVE_NR);
|
||||
#ifdef SECCOMP_ARCH_COMPAT
|
||||
DECLARE_BITMAP(allow_compat, SECCOMP_ARCH_COMPAT_NR);
|
||||
#endif
|
||||
};
|
||||
|
||||
struct seccomp_filter {
|
||||
refcount_t refs;
|
||||
refcount_t users;
|
||||
bool log;
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)
|
||||
bool wait_killable_recv;
|
||||
#endif
|
||||
struct action_cache cache;
|
||||
struct seccomp_filter *prev;
|
||||
struct bpf_prog *prog;
|
||||
struct notification *notif;
|
||||
struct mutex notify_lock;
|
||||
wait_queue_head_t wqh;
|
||||
};
|
||||
|
||||
void ksu_seccomp_clear_cache(struct seccomp_filter *filter, int nr)
|
||||
{
|
||||
if (!filter) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (nr >= 0 && nr < SECCOMP_ARCH_NATIVE_NR) {
|
||||
clear_bit(nr, filter->cache.allow_native);
|
||||
}
|
||||
|
||||
#ifdef SECCOMP_ARCH_COMPAT
|
||||
if (nr >= 0 && nr < SECCOMP_ARCH_COMPAT_NR) {
|
||||
clear_bit(nr, filter->cache.allow_compat);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void ksu_seccomp_allow_cache(struct seccomp_filter *filter, int nr)
|
||||
{
|
||||
if (!filter) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (nr >= 0 && nr < SECCOMP_ARCH_NATIVE_NR) {
|
||||
set_bit(nr, filter->cache.allow_native);
|
||||
}
|
||||
|
||||
#ifdef SECCOMP_ARCH_COMPAT
|
||||
if (nr >= 0 && nr < SECCOMP_ARCH_COMPAT_NR) {
|
||||
set_bit(nr, filter->cache.allow_compat);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -3,53 +3,9 @@
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/cred.h>
|
||||
#include "ss/policydb.h"
|
||||
#include "linux/key.h"
|
||||
|
||||
#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
|
||||
#define kcompat_barrier() do { barrier(); isb(); } while (0)
|
||||
#else
|
||||
#define kcompat_barrier() barrier()
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Linux 6.8+ does not have LKM support, due to numerous changes on LSM.
|
||||
* Let's fails if MODULE were defined.
|
||||
*/
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 8, 0) && defined(MODULE)
|
||||
#error "LKM mode is not supported on Linux 6.8+, aborting build."
|
||||
#endif
|
||||
|
||||
/**
|
||||
* list_count_nodes - count the number of nodes in a list
|
||||
* @head: the head of the list
|
||||
*
|
||||
* This function iterates over the list starting from @head and counts
|
||||
* the number of nodes in the list. It does not modify the list.
|
||||
*
|
||||
* Context: Any context. The function is safe to call in any context,
|
||||
* including interrupt context, as it does not sleep or allocate
|
||||
* memory.
|
||||
*
|
||||
* Return: the number of nodes in the list (excluding the head)
|
||||
*/
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0)
|
||||
static inline __maybe_unused size_t list_count_nodes(const struct list_head *head)
|
||||
{
|
||||
const struct list_head *pos;
|
||||
size_t count = 0;
|
||||
|
||||
if (!head)
|
||||
return 0;
|
||||
|
||||
list_for_each(pos, head)
|
||||
count++;
|
||||
|
||||
return count;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Adapt to Huawei HISI kernel without affecting other kernels ,
|
||||
* Huawei Hisi Kernel EBITMAP Enable or Disable Flag ,
|
||||
@@ -82,7 +38,6 @@ extern long ksu_strncpy_from_user_retry(char *dst,
|
||||
defined(CONFIG_IS_HW_HISI) || defined(CONFIG_KSU_ALLOWLIST_WORKAROUND)
|
||||
extern struct key *init_session_keyring;
|
||||
#endif
|
||||
|
||||
extern void ksu_android_ns_fs_check(void);
|
||||
extern struct file *ksu_filp_open_compat(const char *filename, int flags,
|
||||
umode_t mode);
|
||||
@@ -108,6 +63,11 @@ static long ksu_copy_from_user_retry(void *to,
|
||||
return copy_from_user(to, from, count);
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
|
||||
extern void ksu_seccomp_clear_cache(struct seccomp_filter *filter, int nr);
|
||||
extern void ksu_seccomp_allow_cache(struct seccomp_filter *filter, int nr);
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0)
|
||||
#define ksu_access_ok(addr, size) access_ok(addr, size)
|
||||
#else
|
||||
|
||||
85
kernel/ksu.c
85
kernel/ksu.c
@@ -2,40 +2,19 @@
|
||||
#include <linux/fs.h>
|
||||
#include <linux/kobject.h>
|
||||
#include <linux/module.h>
|
||||
#include <generated/utsrelease.h>
|
||||
#include <generated/compile.h>
|
||||
#include <linux/version.h> /* LINUX_VERSION_CODE, KERNEL_VERSION macros */
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/version.h>
|
||||
|
||||
#include "allowlist.h"
|
||||
#include "arch.h"
|
||||
#include "core_hook.h"
|
||||
#include "feature.h"
|
||||
#include "klog.h" // IWYU pragma: keep
|
||||
#include "ksu.h"
|
||||
#include "throne_tracker.h"
|
||||
|
||||
#ifdef CONFIG_KSU_CMDLINE
|
||||
#include <linux/init.h>
|
||||
|
||||
// use get_ksu_state()!
|
||||
unsigned int enable_kernelsu = 1; // enabled by default
|
||||
static int __init read_kernelsu_state(char *s)
|
||||
{
|
||||
if (s)
|
||||
enable_kernelsu = simple_strtoul(s, NULL, 0);
|
||||
return 1;
|
||||
}
|
||||
__setup("kernelsu.enabled=", read_kernelsu_state);
|
||||
|
||||
bool get_ksu_state(void)
|
||||
{
|
||||
return enable_kernelsu >= 1;
|
||||
}
|
||||
#else
|
||||
bool get_ksu_state(void)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#endif /* CONFIG_KSU_CMDLINE */
|
||||
|
||||
static struct workqueue_struct *ksu_workqueue;
|
||||
|
||||
bool ksu_queue_work(struct work_struct *work)
|
||||
@@ -61,6 +40,7 @@ extern void ksu_sucompat_init(void);
|
||||
extern void ksu_sucompat_exit(void);
|
||||
extern void ksu_ksud_init(void);
|
||||
extern void ksu_ksud_exit(void);
|
||||
extern void ksu_supercalls_init(void);
|
||||
#ifdef CONFIG_KSU_TRACEPOINT_HOOK
|
||||
extern void ksu_trace_register();
|
||||
extern void ksu_trace_unregister();
|
||||
@@ -68,32 +48,23 @@ extern void ksu_trace_unregister();
|
||||
|
||||
int __init kernelsu_init(void)
|
||||
{
|
||||
pr_info("kernelsu.enabled=%d\n", (int)get_ksu_state());
|
||||
|
||||
#ifdef CONFIG_KSU_CMDLINE
|
||||
if (!get_ksu_state()) {
|
||||
pr_info_once("drivers is disabled.");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
pr_info("Initialized on: %s (%s) with driver version: %u\n",
|
||||
UTS_RELEASE, UTS_MACHINE, KSU_VERSION);
|
||||
|
||||
#ifdef CONFIG_KSU_DEBUG
|
||||
pr_alert(
|
||||
"*************************************************************");
|
||||
pr_alert(
|
||||
"** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **");
|
||||
pr_alert(
|
||||
"** **");
|
||||
pr_alert(
|
||||
"** You are running KernelSU in DEBUG mode **");
|
||||
pr_alert(
|
||||
"** **");
|
||||
pr_alert(
|
||||
"** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **");
|
||||
pr_alert(
|
||||
"*************************************************************");
|
||||
pr_alert("*************************************************************");
|
||||
pr_alert("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **");
|
||||
pr_alert("** **");
|
||||
pr_alert("** You are running KernelSU in DEBUG mode **");
|
||||
pr_alert("** **");
|
||||
pr_alert("** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **");
|
||||
pr_alert("*************************************************************");
|
||||
#endif
|
||||
|
||||
ksu_feature_init();
|
||||
|
||||
ksu_supercalls_init();
|
||||
|
||||
ksu_core_init();
|
||||
|
||||
ksu_workqueue = alloc_ordered_workqueue("kernelsu_work_queue", 0);
|
||||
@@ -106,8 +77,6 @@ int __init kernelsu_init(void)
|
||||
|
||||
#ifdef CONFIG_KSU_KPROBES_HOOK
|
||||
ksu_ksud_init();
|
||||
#else
|
||||
pr_debug("init ksu driver\n");
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_KSU_TRACEPOINT_HOOK
|
||||
@@ -124,15 +93,12 @@ int __init kernelsu_init(void)
|
||||
|
||||
void kernelsu_exit(void)
|
||||
{
|
||||
#ifdef CONFIG_KSU_CMDLINE
|
||||
if (!get_ksu_state()) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
ksu_allowlist_exit();
|
||||
|
||||
ksu_throne_tracker_exit();
|
||||
|
||||
ksu_observer_exit();
|
||||
|
||||
destroy_workqueue(ksu_workqueue);
|
||||
|
||||
#ifdef CONFIG_KSU_KPROBES_HOOK
|
||||
@@ -146,6 +112,7 @@ void kernelsu_exit(void)
|
||||
ksu_sucompat_exit();
|
||||
|
||||
ksu_core_exit();
|
||||
ksu_feature_exit();
|
||||
}
|
||||
|
||||
module_init(kernelsu_init);
|
||||
@@ -155,10 +122,10 @@ MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("weishu");
|
||||
MODULE_DESCRIPTION("Android KernelSU");
|
||||
|
||||
#define VFS_NS_NAME VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0)
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 13, 0)
|
||||
MODULE_IMPORT_NS("VFS_NS_NAME");
|
||||
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(5, 0, 0)
|
||||
MODULE_IMPORT_NS(VFS_NS_NAME);
|
||||
MODULE_IMPORT_NS("VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver");
|
||||
#else
|
||||
MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -58,13 +58,6 @@ struct dynamic_manager_user_config {
|
||||
char hash[65];
|
||||
};
|
||||
|
||||
struct manager_list_info {
|
||||
int count;
|
||||
struct {
|
||||
uid_t uid;
|
||||
int signature_index;
|
||||
} managers[2];
|
||||
};
|
||||
|
||||
struct root_profile {
|
||||
int32_t uid;
|
||||
|
||||
@@ -79,6 +79,7 @@ void on_post_fs_data(void)
|
||||
done = true;
|
||||
pr_info("%s!\n", __func__);
|
||||
ksu_load_allow_list();
|
||||
ksu_observer_init();
|
||||
// sanity check, this may influence the performance
|
||||
stop_input_hook();
|
||||
|
||||
@@ -426,7 +427,7 @@ int ksu_handle_input_handle_event(unsigned int *type, unsigned int *code,
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ksu_is_safe_mode()
|
||||
bool ksu_is_safe_mode(void)
|
||||
{
|
||||
static bool safe_mode = false;
|
||||
if (safe_mode) {
|
||||
|
||||
@@ -39,4 +39,7 @@ static inline void ksu_invalidate_manager_uid(void)
|
||||
ksu_manager_uid = KSU_INVALID_UID;
|
||||
}
|
||||
|
||||
int ksu_observer_init(void);
|
||||
void ksu_observer_exit(void);
|
||||
|
||||
#endif
|
||||
@@ -157,39 +157,16 @@ void apply_kernelsu_rules(void)
|
||||
#define CMD_TYPE_CHANGE 8
|
||||
#define CMD_GENFSCON 9
|
||||
|
||||
// keep it!
|
||||
extern bool ksu_is_compat __read_mostly;
|
||||
|
||||
// armv7l kernel compat
|
||||
#ifdef CONFIG_64BIT
|
||||
#define usize u64
|
||||
#else
|
||||
#define usize u32
|
||||
#endif
|
||||
|
||||
struct sepol_data {
|
||||
u32 cmd;
|
||||
u32 subcmd;
|
||||
usize field_sepol1;
|
||||
usize field_sepol2;
|
||||
usize field_sepol3;
|
||||
usize field_sepol4;
|
||||
usize field_sepol5;
|
||||
usize field_sepol6;
|
||||
usize field_sepol7;
|
||||
};
|
||||
|
||||
// ksud 32-bit on arm64 kernel
|
||||
struct __maybe_unused sepol_data_compat {
|
||||
u32 cmd;
|
||||
u32 subcmd;
|
||||
u32 field_sepol1;
|
||||
u32 field_sepol2;
|
||||
u32 field_sepol3;
|
||||
u32 field_sepol4;
|
||||
u32 field_sepol5;
|
||||
u32 field_sepol6;
|
||||
u32 field_sepol7;
|
||||
uint32_t cmd;
|
||||
uint32_t subcmd;
|
||||
uint64_t field_sepol1;
|
||||
uint64_t field_sepol2;
|
||||
uint64_t field_sepol3;
|
||||
uint64_t field_sepol4;
|
||||
uint64_t field_sepol5;
|
||||
uint64_t field_sepol6;
|
||||
uint64_t field_sepol7;
|
||||
};
|
||||
|
||||
static int get_object(char *buf, char __user *user_object, size_t buf_sz,
|
||||
@@ -242,39 +219,21 @@ int handle_sepolicy(unsigned long arg3, void __user *arg4)
|
||||
char __user *sepol1, *sepol2, *sepol3, *sepol4, *sepol5, *sepol6,
|
||||
*sepol7;
|
||||
|
||||
if (unlikely(ksu_is_compat)) {
|
||||
struct sepol_data_compat data_compat;
|
||||
if (copy_from_user(&data_compat, arg4,
|
||||
sizeof(struct sepol_data_compat))) {
|
||||
pr_err("sepol: copy sepol_data failed.\n");
|
||||
return -1;
|
||||
}
|
||||
pr_info("sepol: running in compat mode!\n");
|
||||
sepol1 = compat_ptr(data_compat.field_sepol1);
|
||||
sepol2 = compat_ptr(data_compat.field_sepol2);
|
||||
sepol3 = compat_ptr(data_compat.field_sepol3);
|
||||
sepol4 = compat_ptr(data_compat.field_sepol4);
|
||||
sepol5 = compat_ptr(data_compat.field_sepol5);
|
||||
sepol6 = compat_ptr(data_compat.field_sepol6);
|
||||
sepol7 = compat_ptr(data_compat.field_sepol7);
|
||||
cmd = data_compat.cmd;
|
||||
subcmd = data_compat.subcmd;
|
||||
} else {
|
||||
struct sepol_data data;
|
||||
struct sepol_data data = { 0 };
|
||||
if (copy_from_user(&data, arg4, sizeof(struct sepol_data))) {
|
||||
pr_err("sepol: copy sepol_data failed.\n");
|
||||
return -1;
|
||||
}
|
||||
sepol1 = data.field_sepol1;
|
||||
sepol2 = data.field_sepol2;
|
||||
sepol3 = data.field_sepol3;
|
||||
sepol4 = data.field_sepol4;
|
||||
sepol5 = data.field_sepol5;
|
||||
sepol6 = data.field_sepol6;
|
||||
sepol7 = data.field_sepol7;
|
||||
|
||||
sepol1 = (char __user *)data.field_sepol1;
|
||||
sepol2 = (char __user *)data.field_sepol2;
|
||||
sepol3 = (char __user *)data.field_sepol3;
|
||||
sepol4 = (char __user *)data.field_sepol4;
|
||||
sepol5 = (char __user *)data.field_sepol5;
|
||||
sepol6 = (char __user *)data.field_sepol6;
|
||||
sepol7 = (char __user *)data.field_sepol7;
|
||||
cmd = data.cmd;
|
||||
subcmd = data.subcmd;
|
||||
}
|
||||
|
||||
mutex_lock(&ksu_rules);
|
||||
|
||||
|
||||
@@ -552,8 +552,8 @@ static bool add_filename_trans(struct policydb *db, const char *s,
|
||||
}
|
||||
|
||||
if (trans == NULL) {
|
||||
trans = (struct filename_trans_datum *)kcalloc(1 ,sizeof(*trans),
|
||||
GFP_ATOMIC);
|
||||
trans = (struct filename_trans_datum *)kcalloc(sizeof(*trans),
|
||||
1, GFP_ATOMIC);
|
||||
struct filename_trans_key *new_key =
|
||||
(struct filename_trans_key *)kmalloc(sizeof(*new_key),
|
||||
GFP_ATOMIC);
|
||||
@@ -657,8 +657,9 @@ static bool add_type(struct policydb *db, const char *type_name, bool attr)
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0)
|
||||
struct ebitmap *new_type_attr_map_array = ksu_realloc(
|
||||
db->type_attr_map_array, value * sizeof(struct ebitmap),
|
||||
struct ebitmap *new_type_attr_map_array =
|
||||
ksu_realloc(db->type_attr_map_array,
|
||||
value * sizeof(struct ebitmap),
|
||||
(value - 1) * sizeof(struct ebitmap));
|
||||
|
||||
if (!new_type_attr_map_array) {
|
||||
@@ -666,8 +667,9 @@ static bool add_type(struct policydb *db, const char *type_name, bool attr)
|
||||
return false;
|
||||
}
|
||||
|
||||
struct type_datum **new_type_val_to_struct = ksu_realloc(
|
||||
db->type_val_to_struct, sizeof(*db->type_val_to_struct) * value,
|
||||
struct type_datum **new_type_val_to_struct =
|
||||
ksu_realloc(db->type_val_to_struct,
|
||||
sizeof(*db->type_val_to_struct) * value,
|
||||
sizeof(*db->type_val_to_struct) * (value - 1));
|
||||
|
||||
if (!new_type_val_to_struct) {
|
||||
@@ -675,8 +677,9 @@ static bool add_type(struct policydb *db, const char *type_name, bool attr)
|
||||
return false;
|
||||
}
|
||||
|
||||
char **new_val_to_name_types = ksu_realloc(
|
||||
db->sym_val_to_name[SYM_TYPES], sizeof(char *) * value,
|
||||
char **new_val_to_name_types =
|
||||
ksu_realloc(db->sym_val_to_name[SYM_TYPES],
|
||||
sizeof(char *) * value,
|
||||
sizeof(char *) * (value - 1));
|
||||
if (!new_val_to_name_types) {
|
||||
pr_err("add_type: alloc val_to_name failed\n");
|
||||
@@ -700,7 +703,7 @@ static bool add_type(struct policydb *db, const char *type_name, bool attr)
|
||||
}
|
||||
|
||||
return true;
|
||||
#elif defined(CONFIG_IS_HW_HISI) && defined(CONFIG_HISI_PMALLOC)
|
||||
#elif defined(CONFIG_IS_HW_HISI)
|
||||
/*
|
||||
* Huawei use type_attr_map and type_val_to_struct.
|
||||
* And use ebitmap not flex_array.
|
||||
@@ -724,9 +727,10 @@ static bool add_type(struct policydb *db, const char *type_name, bool attr)
|
||||
return false;
|
||||
}
|
||||
|
||||
char **new_val_to_name_types = krealloc(
|
||||
db->sym_val_to_name[SYM_TYPES],
|
||||
sizeof(char *) * db->symtab[SYM_TYPES].nprim, GFP_KERNEL);
|
||||
char **new_val_to_name_types =
|
||||
krealloc(db->sym_val_to_name[SYM_TYPES],
|
||||
sizeof(char *) * db->symtab[SYM_TYPES].nprim,
|
||||
GFP_KERNEL);
|
||||
if (!new_val_to_name_types) {
|
||||
pr_err("add_type: alloc val_to_name failed\n");
|
||||
return false;
|
||||
@@ -832,11 +836,8 @@ static bool add_type(struct policydb *db, const char *type_name, bool attr)
|
||||
if (old_fa) {
|
||||
flex_array_free(old_fa);
|
||||
}
|
||||
#if defined(CONFIG_IS_HW_HISI)
|
||||
ebitmap_init(flex_array_get(db->type_attr_map_array, value - 1), HISI_SELINUX_EBITMAP_RO);
|
||||
#else
|
||||
|
||||
ebitmap_init(flex_array_get(db->type_attr_map_array, value - 1));
|
||||
#endif
|
||||
ebitmap_set_bit(flex_array_get(db->type_attr_map_array, value - 1),
|
||||
value - 1, 1);
|
||||
|
||||
@@ -903,22 +904,16 @@ static void add_typeattribute_raw(struct policydb *db, struct type_datum *type,
|
||||
{
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 1, 0)
|
||||
struct ebitmap *sattr = &db->type_attr_map_array[type->value - 1];
|
||||
#elif defined(CONFIG_IS_HW_HISI) && defined(CONFIG_HISI_PMALLOC)
|
||||
#elif defined(CONFIG_IS_HW_HISI)
|
||||
/*
|
||||
* HISI_SELINUX_EBITMAP_RO is Huawei's unique features.
|
||||
*/
|
||||
struct ebitmap *sattr = &db->type_attr_map[type->value - 1],
|
||||
HISI_SELINUX_EBITMAP_RO;
|
||||
#else
|
||||
#if defined(CONFIG_IS_HW_HISI)
|
||||
struct ebitmap *sattr =
|
||||
flex_array_get(db->type_attr_map_array, type->value - 1),
|
||||
HISI_SELINUX_EBITMAP_RO;
|
||||
#else
|
||||
struct ebitmap *sattr =
|
||||
flex_array_get(db->type_attr_map_array, type->value - 1);
|
||||
#endif
|
||||
#endif
|
||||
ebitmap_set_bit(sattr, attr->value - 1, 1);
|
||||
|
||||
struct hashtab_node *node;
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "objsec.h"
|
||||
#include "allowlist.h"
|
||||
#include "arch.h"
|
||||
#include "feature.h"
|
||||
#include "klog.h" // IWYU pragma: keep
|
||||
#include "ksud.h"
|
||||
#include "kernel_compat.h"
|
||||
@@ -29,8 +30,44 @@ static const char su[] = SU_PATH;
|
||||
static const char ksud_path[] = KSUD_PATH;
|
||||
|
||||
extern void escape_to_root(void);
|
||||
void ksu_sucompat_enable(void);
|
||||
void ksu_sucompat_disable(void);
|
||||
|
||||
bool ksu_sucompat_hook_state __read_mostly = true;
|
||||
static bool ksu_su_compat_enabled __read_mostly = true;
|
||||
|
||||
static int su_compat_feature_get(u64 *value)
|
||||
{
|
||||
*value = ksu_su_compat_enabled ? 1 : 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int su_compat_feature_set(u64 value)
|
||||
{
|
||||
bool enable = value != 0;
|
||||
|
||||
if (enable == ksu_su_compat_enabled) {
|
||||
pr_info("su_compat: no need to change\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (enable) {
|
||||
ksu_sucompat_enable();
|
||||
} else {
|
||||
ksu_sucompat_disable();
|
||||
}
|
||||
|
||||
ksu_su_compat_enabled = enable;
|
||||
pr_info("su_compat: set to %d\n", enable);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct ksu_feature_handler su_compat_handler = {
|
||||
.feature_id = KSU_FEATURE_SU_COMPAT,
|
||||
.name = "su_compat",
|
||||
.get_handler = su_compat_feature_get,
|
||||
.set_handler = su_compat_feature_set,
|
||||
};
|
||||
|
||||
static inline void __user *userspace_stack_buffer(const void *d, size_t len)
|
||||
{
|
||||
@@ -55,7 +92,7 @@ static inline char __user *ksud_user_path(void)
|
||||
static inline bool __is_su_allowed(const void *ptr_to_check)
|
||||
{
|
||||
#ifndef CONFIG_KSU_KPROBES_HOOK
|
||||
if (!ksu_sucompat_hook_state)
|
||||
if (!ksu_su_compat_enabled)
|
||||
return false;
|
||||
#endif
|
||||
if (likely(!ksu_is_allow_uid(current_uid().val)))
|
||||
@@ -174,6 +211,7 @@ int __ksu_handle_devpts(struct inode *inode)
|
||||
#else
|
||||
struct inode_security_struct *sec = (struct inode_security_struct *)inode->i_security;
|
||||
#endif
|
||||
|
||||
if (ksu_devpts_sid && sec)
|
||||
sec->sid = ksu_devpts_sid;
|
||||
|
||||
@@ -214,7 +252,6 @@ static int execve_handler_pre(struct kprobe *p, struct pt_regs *regs)
|
||||
NULL);
|
||||
}
|
||||
|
||||
static struct kprobe *su_kps[6];
|
||||
static int pts_unix98_lookup_pre(struct kprobe *p, struct pt_regs *regs)
|
||||
{
|
||||
struct inode *inode;
|
||||
@@ -228,6 +265,12 @@ static int pts_unix98_lookup_pre(struct kprobe *p, struct pt_regs *regs)
|
||||
return ksu_handle_devpts(inode);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
static struct kprobe *su_kps[6];
|
||||
#else
|
||||
static struct kprobe *su_kps[4];
|
||||
#endif
|
||||
|
||||
static struct kprobe *init_kprobe(const char *name,
|
||||
kprobe_pre_handler_t handler)
|
||||
{
|
||||
@@ -259,31 +302,55 @@ static void destroy_kprobe(struct kprobe **kp_ptr)
|
||||
}
|
||||
#endif
|
||||
|
||||
// sucompat: permited process can execute 'su' to gain root access.
|
||||
void ksu_sucompat_init(void)
|
||||
void ksu_sucompat_enable(void)
|
||||
{
|
||||
#ifdef CONFIG_KSU_KPROBES_HOOK
|
||||
su_kps[0] = init_kprobe(SYS_EXECVE_SYMBOL, execve_handler_pre);
|
||||
su_kps[1] = init_kprobe(SYS_EXECVE_COMPAT_SYMBOL, execve_handler_pre);
|
||||
su_kps[2] = init_kprobe(SYS_FACCESSAT_SYMBOL, faccessat_handler_pre);
|
||||
su_kps[3] = init_kprobe(SYS_NEWFSTATAT_SYMBOL, newfstatat_handler_pre);
|
||||
su_kps[4] = init_kprobe(SYS_FSTATAT64_SYMBOL, newfstatat_handler_pre);
|
||||
su_kps[5] = init_kprobe("pts_unix98_lookup", pts_unix98_lookup_pre);
|
||||
#else
|
||||
ksu_sucompat_hook_state = true;
|
||||
pr_info("ksu_sucompat init\n");
|
||||
su_kps[1] = init_kprobe(SYS_FACCESSAT_SYMBOL, faccessat_handler_pre);
|
||||
su_kps[2] = init_kprobe(SYS_NEWFSTATAT_SYMBOL, newfstatat_handler_pre);
|
||||
su_kps[3] = init_kprobe("pts_unix98_lookup", pts_unix98_lookup_pre);
|
||||
#ifdef CONFIG_COMPAT
|
||||
su_kps[4] = init_kprobe(SYS_EXECVE_COMPAT_SYMBOL, execve_handler_pre);
|
||||
su_kps[5] = init_kprobe(SYS_FSTATAT64_SYMBOL, newfstatat_handler_pre);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void ksu_sucompat_exit(void)
|
||||
void ksu_sucompat_disable(void)
|
||||
{
|
||||
#ifdef CONFIG_KSU_KPROBES_HOOK
|
||||
int i;
|
||||
for (i = 0; i < ARRAY_SIZE(su_kps); i++) {
|
||||
destroy_kprobe(&su_kps[i]);
|
||||
}
|
||||
#else
|
||||
ksu_sucompat_hook_state = false;
|
||||
pr_info("ksu_sucompat exit\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
// sucompat: permited process can execute 'su' to gain root access.
|
||||
void ksu_sucompat_init(void)
|
||||
{
|
||||
if (ksu_register_feature_handler(&su_compat_handler)) {
|
||||
pr_err("Failed to register su_compat feature handler\n");
|
||||
}
|
||||
#ifdef CONFIG_KSU_KPROBES_HOOK
|
||||
if (ksu_su_compat_enabled) {
|
||||
ksu_sucompat_enable();
|
||||
}
|
||||
#else
|
||||
ksu_su_compat_enabled = true;
|
||||
pr_info("init sucompat\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
void ksu_sucompat_exit(void)
|
||||
{
|
||||
#ifdef CONFIG_KSU_KPROBES_HOOK
|
||||
if (ksu_su_compat_enabled) {
|
||||
ksu_sucompat_disable();
|
||||
}
|
||||
#else
|
||||
ksu_su_compat_enabled = false;
|
||||
pr_info("deinit sucompat\n");
|
||||
#endif
|
||||
ksu_unregister_feature_handler(KSU_FEATURE_SU_COMPAT);
|
||||
}
|
||||
|
||||
695
kernel/supercalls.c
Normal file
695
kernel/supercalls.c
Normal file
@@ -0,0 +1,695 @@
|
||||
#include "supercalls.h"
|
||||
|
||||
#include <linux/anon_inodes.h>
|
||||
#include <linux/capability.h>
|
||||
#include <linux/cred.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/version.h>
|
||||
|
||||
#include "allowlist.h"
|
||||
#include "feature.h"
|
||||
#include "klog.h" // IWYU pragma: keep
|
||||
#include "ksud.h"
|
||||
#include "manager.h"
|
||||
#include "sulog.h"
|
||||
#include "selinux/selinux.h"
|
||||
#include "kernel_compat.h"
|
||||
#include "throne_comm.h"
|
||||
#include "dynamic_manager.h"
|
||||
|
||||
#ifdef CONFIG_KSU_MANUAL_SU
|
||||
#include "manual_su.h"
|
||||
#endif
|
||||
|
||||
// Forward declarations from core_hook.c
|
||||
extern void escape_to_root(void);
|
||||
extern void nuke_ext4_sysfs(void);
|
||||
extern bool ksu_module_mounted;
|
||||
extern int handle_sepolicy(unsigned long arg3, void __user *arg4);
|
||||
extern void ksu_sucompat_init(void);
|
||||
extern void ksu_sucompat_exit(void);
|
||||
|
||||
bool ksu_uid_scanner_enabled = false;
|
||||
|
||||
// Permission check functions
|
||||
bool only_manager(void)
|
||||
{
|
||||
return is_manager();
|
||||
}
|
||||
|
||||
bool only_root(void)
|
||||
{
|
||||
return current_uid().val == 0;
|
||||
}
|
||||
|
||||
bool manager_or_root(void)
|
||||
{
|
||||
return current_uid().val == 0 || is_manager();
|
||||
}
|
||||
|
||||
bool always_allow(void)
|
||||
{
|
||||
return true; // No permission check
|
||||
}
|
||||
|
||||
bool allowed_for_su(void)
|
||||
{
|
||||
bool is_allowed = is_manager() || ksu_is_allow_uid(current_uid().val);
|
||||
#if __SULOG_GATE
|
||||
ksu_sulog_report_permission_check(current_uid().val, current->comm, is_allowed);
|
||||
#endif
|
||||
return is_allowed;
|
||||
}
|
||||
|
||||
static void init_uid_scanner(void)
|
||||
{
|
||||
ksu_uid_init();
|
||||
do_load_throne_state(NULL);
|
||||
|
||||
if (ksu_uid_scanner_enabled) {
|
||||
int ret = ksu_throne_comm_init();
|
||||
if (ret != 0) {
|
||||
pr_err("Failed to initialize throne communication: %d\n", ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int do_grant_root(void __user *arg)
|
||||
{
|
||||
// we already check uid above on allowed_for_su()
|
||||
|
||||
pr_info("allow root for: %d\n", current_uid().val);
|
||||
escape_to_root();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_get_info(void __user *arg)
|
||||
{
|
||||
struct ksu_get_info_cmd cmd = {.version = KERNEL_SU_VERSION, .flags = 0};
|
||||
|
||||
#ifdef MODULE
|
||||
cmd.flags |= 0x1;
|
||||
#endif
|
||||
if (is_manager()) {
|
||||
cmd.flags |= 0x2;
|
||||
}
|
||||
cmd.features = KSU_FEATURE_MAX;
|
||||
|
||||
if (copy_to_user(arg, &cmd, sizeof(cmd))) {
|
||||
pr_err("get_version: copy_to_user failed\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_report_event(void __user *arg)
|
||||
{
|
||||
struct ksu_report_event_cmd cmd;
|
||||
|
||||
if (copy_from_user(&cmd, arg, sizeof(cmd))) {
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
switch (cmd.event) {
|
||||
case EVENT_POST_FS_DATA: {
|
||||
static bool post_fs_data_lock = false;
|
||||
if (!post_fs_data_lock) {
|
||||
post_fs_data_lock = true;
|
||||
pr_info("post-fs-data triggered\n");
|
||||
on_post_fs_data();
|
||||
init_uid_scanner();
|
||||
#if __SULOG_GATE
|
||||
ksu_sulog_init();
|
||||
#endif
|
||||
ksu_dynamic_manager_init();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EVENT_BOOT_COMPLETED: {
|
||||
static bool boot_complete_lock = false;
|
||||
if (!boot_complete_lock) {
|
||||
boot_complete_lock = true;
|
||||
pr_info("boot_complete triggered\n");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case EVENT_MODULE_MOUNTED: {
|
||||
ksu_module_mounted = true;
|
||||
pr_info("module mounted!\n");
|
||||
nuke_ext4_sysfs();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_set_sepolicy(void __user *arg)
|
||||
{
|
||||
struct ksu_set_sepolicy_cmd cmd;
|
||||
|
||||
if (copy_from_user(&cmd, arg, sizeof(cmd))) {
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return handle_sepolicy(cmd.cmd, (void __user *)cmd.arg);
|
||||
}
|
||||
|
||||
static int do_check_safemode(void __user *arg)
|
||||
{
|
||||
struct ksu_check_safemode_cmd cmd;
|
||||
|
||||
cmd.in_safe_mode = ksu_is_safe_mode();
|
||||
|
||||
if (cmd.in_safe_mode) {
|
||||
pr_warn("safemode enabled!\n");
|
||||
}
|
||||
|
||||
if (copy_to_user(arg, &cmd, sizeof(cmd))) {
|
||||
pr_err("check_safemode: copy_to_user failed\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_get_allow_list(void __user *arg)
|
||||
{
|
||||
struct ksu_get_allow_list_cmd cmd;
|
||||
|
||||
if (copy_from_user(&cmd, arg, sizeof(cmd))) {
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
bool success = ksu_get_allow_list((int *)cmd.uids, (int *)&cmd.count, true);
|
||||
|
||||
if (!success) {
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (copy_to_user(arg, &cmd, sizeof(cmd))) {
|
||||
pr_err("get_allow_list: copy_to_user failed\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_get_deny_list(void __user *arg)
|
||||
{
|
||||
struct ksu_get_allow_list_cmd cmd;
|
||||
|
||||
if (copy_from_user(&cmd, arg, sizeof(cmd))) {
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
bool success = ksu_get_allow_list((int *)cmd.uids, (int *)&cmd.count, false);
|
||||
|
||||
if (!success) {
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (copy_to_user(arg, &cmd, sizeof(cmd))) {
|
||||
pr_err("get_deny_list: copy_to_user failed\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_uid_granted_root(void __user *arg)
|
||||
{
|
||||
struct ksu_uid_granted_root_cmd cmd;
|
||||
|
||||
if (copy_from_user(&cmd, arg, sizeof(cmd))) {
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
cmd.granted = ksu_is_allow_uid(cmd.uid);
|
||||
|
||||
if (copy_to_user(arg, &cmd, sizeof(cmd))) {
|
||||
pr_err("uid_granted_root: copy_to_user failed\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_uid_should_umount(void __user *arg)
|
||||
{
|
||||
struct ksu_uid_should_umount_cmd cmd;
|
||||
|
||||
if (copy_from_user(&cmd, arg, sizeof(cmd))) {
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
cmd.should_umount = ksu_uid_should_umount(cmd.uid);
|
||||
|
||||
if (copy_to_user(arg, &cmd, sizeof(cmd))) {
|
||||
pr_err("uid_should_umount: copy_to_user failed\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_get_manager_uid(void __user *arg)
|
||||
{
|
||||
struct ksu_get_manager_uid_cmd cmd;
|
||||
|
||||
cmd.uid = ksu_get_manager_uid();
|
||||
|
||||
if (copy_to_user(arg, &cmd, sizeof(cmd))) {
|
||||
pr_err("get_manager_uid: copy_to_user failed\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_get_app_profile(void __user *arg)
|
||||
{
|
||||
struct ksu_get_app_profile_cmd cmd;
|
||||
|
||||
if (copy_from_user(&cmd, arg, sizeof(cmd))) {
|
||||
pr_err("get_app_profile: copy_from_user failed\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (!ksu_get_app_profile(&cmd.profile)) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (copy_to_user(arg, &cmd, sizeof(cmd))) {
|
||||
pr_err("get_app_profile: copy_to_user failed\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_set_app_profile(void __user *arg)
|
||||
{
|
||||
struct ksu_set_app_profile_cmd cmd;
|
||||
|
||||
if (copy_from_user(&cmd, arg, sizeof(cmd))) {
|
||||
pr_err("set_app_profile: copy_from_user failed\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (!ksu_set_app_profile(&cmd.profile, true)) {
|
||||
#if __SULOG_GATE
|
||||
ksu_sulog_report_manager_operation("SET_APP_PROFILE",
|
||||
current_uid().val, cmd.profile.current_uid);
|
||||
#endif
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_get_feature(void __user *arg)
|
||||
{
|
||||
struct ksu_get_feature_cmd cmd;
|
||||
bool supported;
|
||||
int ret;
|
||||
|
||||
if (copy_from_user(&cmd, arg, sizeof(cmd))) {
|
||||
pr_err("get_feature: copy_from_user failed\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
ret = ksu_get_feature(cmd.feature_id, &cmd.value, &supported);
|
||||
cmd.supported = supported ? 1 : 0;
|
||||
|
||||
if (ret && supported) {
|
||||
pr_err("get_feature: failed for feature %u: %d\n", cmd.feature_id, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (copy_to_user(arg, &cmd, sizeof(cmd))) {
|
||||
pr_err("get_feature: copy_to_user failed\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_set_feature(void __user *arg)
|
||||
{
|
||||
struct ksu_set_feature_cmd cmd;
|
||||
int ret;
|
||||
|
||||
if (copy_from_user(&cmd, arg, sizeof(cmd))) {
|
||||
pr_err("set_feature: copy_from_user failed\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
ret = ksu_set_feature(cmd.feature_id, cmd.value);
|
||||
if (ret) {
|
||||
pr_err("set_feature: failed for feature %u: %d\n", cmd.feature_id, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 100. GET_FULL_VERSION - Get full version string
|
||||
static int do_get_full_version(void __user *arg)
|
||||
{
|
||||
struct ksu_get_full_version_cmd cmd = {0};
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)
|
||||
strscpy(cmd.version_full, KSU_VERSION_FULL, sizeof(cmd.version_full));
|
||||
#else
|
||||
strlcpy(cmd.version_full, KSU_VERSION_FULL, sizeof(cmd.version_full));
|
||||
#endif
|
||||
|
||||
if (copy_to_user(arg, &cmd, sizeof(cmd))) {
|
||||
pr_err("get_full_version: copy_to_user failed\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 101. HOOK_TYPE - Get hook type
|
||||
static int do_get_hook_type(void __user *arg)
|
||||
{
|
||||
struct ksu_hook_type_cmd cmd = {0};
|
||||
const char *type = "Kprobes";
|
||||
|
||||
#if defined(CONFIG_KSU_TRACEPOINT_HOOK)
|
||||
type = "Tracepoint";
|
||||
#elif defined(CONFIG_KSU_MANUAL_HOOK)
|
||||
type = "Manual";
|
||||
#endif
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 13, 0)
|
||||
strscpy(cmd.hook_type, type, sizeof(cmd.hook_type));
|
||||
#else
|
||||
strlcpy(cmd.hook_type, type, sizeof(cmd.hook_type));
|
||||
#endif
|
||||
|
||||
if (copy_to_user(arg, &cmd, sizeof(cmd))) {
|
||||
pr_err("get_hook_type: copy_to_user failed\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 102. ENABLE_KPM - Check if KPM is enabled
|
||||
static int do_enable_kpm(void __user *arg)
|
||||
{
|
||||
struct ksu_enable_kpm_cmd cmd;
|
||||
|
||||
cmd.enabled = IS_ENABLED(CONFIG_KPM);
|
||||
|
||||
if (copy_to_user(arg, &cmd, sizeof(cmd))) {
|
||||
pr_err("enable_kpm: copy_to_user failed\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_dynamic_manager(void __user *arg)
|
||||
{
|
||||
struct ksu_dynamic_manager_cmd cmd;
|
||||
|
||||
if (copy_from_user(&cmd, arg, sizeof(cmd))) {
|
||||
pr_err("dynamic_manager: copy_from_user failed\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
int ret = ksu_handle_dynamic_manager(&cmd.config);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (cmd.config.operation == DYNAMIC_MANAGER_OP_GET &&
|
||||
copy_to_user(arg, &cmd, sizeof(cmd))) {
|
||||
pr_err("dynamic_manager: copy_to_user failed\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_get_managers(void __user *arg)
|
||||
{
|
||||
struct ksu_get_managers_cmd cmd;
|
||||
|
||||
int ret = ksu_get_active_managers(&cmd.manager_info);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (copy_to_user(arg, &cmd, sizeof(cmd))) {
|
||||
pr_err("get_managers: copy_from_user failed\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_enable_uid_scanner(void __user *arg)
|
||||
{
|
||||
struct ksu_enable_uid_scanner_cmd cmd;
|
||||
|
||||
if (copy_from_user(&cmd, arg, sizeof(cmd))) {
|
||||
pr_err("enable_uid_scanner: copy_from_user failed\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
switch (cmd.operation) {
|
||||
case UID_SCANNER_OP_GET_STATUS: {
|
||||
bool status = ksu_uid_scanner_enabled;
|
||||
if (copy_to_user((void __user *)cmd.status_ptr, &status, sizeof(status))) {
|
||||
pr_err("enable_uid_scanner: copy status failed\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case UID_SCANNER_OP_TOGGLE: {
|
||||
bool enabled = cmd.enabled;
|
||||
|
||||
if (enabled == ksu_uid_scanner_enabled) {
|
||||
pr_info("enable_uid_scanner: no need to change, already %s\n",
|
||||
enabled ? "enabled" : "disabled");
|
||||
break;
|
||||
}
|
||||
|
||||
if (enabled) {
|
||||
// Enable UID scanner
|
||||
int ret = ksu_throne_comm_init();
|
||||
if (ret != 0) {
|
||||
pr_err("enable_uid_scanner: failed to initialize: %d\n", ret);
|
||||
return -EFAULT;
|
||||
}
|
||||
pr_info("enable_uid_scanner: enabled\n");
|
||||
} else {
|
||||
// Disable UID scanner
|
||||
ksu_throne_comm_exit();
|
||||
pr_info("enable_uid_scanner: disabled\n");
|
||||
}
|
||||
|
||||
ksu_uid_scanner_enabled = enabled;
|
||||
ksu_throne_comm_save_state();
|
||||
break;
|
||||
}
|
||||
case UID_SCANNER_OP_CLEAR_ENV: {
|
||||
// Clear environment (force exit)
|
||||
ksu_throne_comm_exit();
|
||||
ksu_uid_scanner_enabled = false;
|
||||
ksu_throne_comm_save_state();
|
||||
pr_info("enable_uid_scanner: environment cleared\n");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
pr_err("enable_uid_scanner: invalid operation\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_KSU_MANUAL_SU
|
||||
static bool system_uid_check(void)
|
||||
{
|
||||
return current_uid().val <= 2000;
|
||||
}
|
||||
|
||||
static int do_manual_su(void __user *arg)
|
||||
{
|
||||
struct ksu_manual_su_cmd cmd;
|
||||
struct manual_su_request request;
|
||||
int res;
|
||||
|
||||
if (copy_from_user(&cmd, arg, sizeof(cmd))) {
|
||||
pr_err("manual_su: copy_from_user failed\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
pr_info("manual_su request, option=%d, uid=%d, pid=%d\n",
|
||||
cmd.option, cmd.target_uid, cmd.target_pid);
|
||||
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.target_uid = cmd.target_uid;
|
||||
request.target_pid = cmd.target_pid;
|
||||
|
||||
if (cmd.option == MANUAL_SU_OP_GENERATE_TOKEN ||
|
||||
cmd.option == MANUAL_SU_OP_ESCALATE) {
|
||||
memcpy(request.token_buffer, cmd.token_buffer, sizeof(request.token_buffer));
|
||||
}
|
||||
|
||||
res = ksu_handle_manual_su_request(cmd.option, &request);
|
||||
|
||||
if (cmd.option == MANUAL_SU_OP_GENERATE_TOKEN && res == 0) {
|
||||
memcpy(cmd.token_buffer, request.token_buffer, sizeof(cmd.token_buffer));
|
||||
if (copy_to_user(arg, &cmd, sizeof(cmd))) {
|
||||
pr_err("manual_su: copy_to_user failed\n");
|
||||
return -EFAULT;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
// IOCTL handlers mapping table
|
||||
static const struct ksu_ioctl_cmd_map ksu_ioctl_handlers[] = {
|
||||
{ .cmd = KSU_IOCTL_GRANT_ROOT, .name = "GRANT_ROOT", .handler = do_grant_root, .perm_check = allowed_for_su },
|
||||
{ .cmd = KSU_IOCTL_GET_INFO, .name = "GET_INFO", .handler = do_get_info, .perm_check = always_allow },
|
||||
{ .cmd = KSU_IOCTL_REPORT_EVENT, .name = "REPORT_EVENT", .handler = do_report_event, .perm_check = only_root },
|
||||
{ .cmd = KSU_IOCTL_SET_SEPOLICY, .name = "SET_SEPOLICY", .handler = do_set_sepolicy, .perm_check = only_root },
|
||||
{ .cmd = KSU_IOCTL_CHECK_SAFEMODE, .name = "CHECK_SAFEMODE", .handler = do_check_safemode, .perm_check = always_allow },
|
||||
{ .cmd = KSU_IOCTL_GET_ALLOW_LIST, .name = "GET_ALLOW_LIST", .handler = do_get_allow_list, .perm_check = manager_or_root },
|
||||
{ .cmd = KSU_IOCTL_GET_DENY_LIST, .name = "GET_DENY_LIST", .handler = do_get_deny_list, .perm_check = manager_or_root },
|
||||
{ .cmd = KSU_IOCTL_UID_GRANTED_ROOT, .name = "UID_GRANTED_ROOT", .handler = do_uid_granted_root, .perm_check = manager_or_root },
|
||||
{ .cmd = KSU_IOCTL_UID_SHOULD_UMOUNT, .name = "UID_SHOULD_UMOUNT", .handler = do_uid_should_umount, .perm_check = manager_or_root },
|
||||
{ .cmd = KSU_IOCTL_GET_MANAGER_UID, .name = "GET_MANAGER_UID", .handler = do_get_manager_uid, .perm_check = manager_or_root },
|
||||
{ .cmd = KSU_IOCTL_GET_APP_PROFILE, .name = "GET_APP_PROFILE", .handler = do_get_app_profile, .perm_check = only_manager },
|
||||
{ .cmd = KSU_IOCTL_SET_APP_PROFILE, .name = "SET_APP_PROFILE", .handler = do_set_app_profile, .perm_check = only_manager },
|
||||
{ .cmd = KSU_IOCTL_GET_FEATURE, .name = "GET_FEATURE", .handler = do_get_feature, .perm_check = manager_or_root },
|
||||
{ .cmd = KSU_IOCTL_SET_FEATURE, .name = "SET_FEATURE", .handler = do_set_feature, .perm_check = manager_or_root },
|
||||
{ .cmd = KSU_IOCTL_GET_FULL_VERSION,.name = "GET_FULL_VERSION", .handler = do_get_full_version, .perm_check = always_allow},
|
||||
{ .cmd = KSU_IOCTL_HOOK_TYPE,.name = "GET_HOOK_TYPE", .handler = do_get_hook_type, .perm_check = manager_or_root},
|
||||
{ .cmd = KSU_IOCTL_ENABLE_KPM, .name = "GET_ENABLE_KPM", .handler = do_enable_kpm, .perm_check = manager_or_root},
|
||||
{ .cmd = KSU_IOCTL_DYNAMIC_MANAGER, .name = "SET_DYNAMIC_MANAGER", .handler = do_dynamic_manager, .perm_check = manager_or_root},
|
||||
{ .cmd = KSU_IOCTL_GET_MANAGERS, .name = "GET_MANAGERS", .handler = do_get_managers, .perm_check = manager_or_root},
|
||||
{ .cmd = KSU_IOCTL_ENABLE_UID_SCANNER, .name = "SET_ENABLE_UID_SCANNER", .handler = do_enable_uid_scanner, .perm_check = manager_or_root},
|
||||
#ifdef CONFIG_KSU_MANUAL_SU
|
||||
{ .cmd = KSU_IOCTL_MANUAL_SU, .name = "MANUAL_SU", .handler = do_manual_su, .perm_check = system_uid_check},
|
||||
#endif
|
||||
#ifdef CONFIG_KPM
|
||||
{ .cmd = KSU_IOCTL_KPM, .name = "KPM_OPERATION", .handler = do_kpm, .perm_check = manager_or_root},
|
||||
#endif
|
||||
{ .cmd = 0, .name = NULL, .handler = NULL, .perm_check = NULL} // Sentine
|
||||
};
|
||||
|
||||
void ksu_supercalls_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
pr_info("KernelSU IOCTL Commands:\n");
|
||||
for (i = 0; ksu_ioctl_handlers[i].handler; i++) {
|
||||
pr_info(" %-18s = 0x%08x\n", ksu_ioctl_handlers[i].name, ksu_ioctl_handlers[i].cmd);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void ksu_ioctl_audit(unsigned int cmd, const char *cmd_name, uid_t uid, int ret)
|
||||
{
|
||||
#if __SULOG_GATE
|
||||
const char *result = (ret == 0) ? "SUCCESS" :
|
||||
(ret == -EPERM) ? "DENIED" : "FAILED";
|
||||
ksu_sulog_report_syscall(uid, NULL, cmd_name, result);
|
||||
#endif
|
||||
}
|
||||
|
||||
// IOCTL dispatcher
|
||||
static long anon_ksu_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
void __user *argp = (void __user *)arg;
|
||||
int i;
|
||||
|
||||
#ifdef CONFIG_KSU_DEBUG
|
||||
pr_info("ksu ioctl: cmd=0x%x from uid=%d\n", cmd, current_uid().val);
|
||||
#endif
|
||||
|
||||
for (i = 0; ksu_ioctl_handlers[i].handler; i++) {
|
||||
if (cmd == ksu_ioctl_handlers[i].cmd) {
|
||||
// Check permission first
|
||||
if (ksu_ioctl_handlers[i].perm_check &&
|
||||
!ksu_ioctl_handlers[i].perm_check()) {
|
||||
pr_warn("ksu ioctl: permission denied for cmd=0x%x uid=%d\n",
|
||||
cmd, current_uid().val);
|
||||
ksu_ioctl_audit(cmd, ksu_ioctl_handlers[i].name,
|
||||
current_uid().val, -EPERM);
|
||||
return -EPERM;
|
||||
}
|
||||
// Execute handler
|
||||
int ret = ksu_ioctl_handlers[i].handler(argp);
|
||||
ksu_ioctl_audit(cmd, ksu_ioctl_handlers[i].name,
|
||||
current_uid().val, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
pr_warn("ksu ioctl: unsupported command 0x%x\n", cmd);
|
||||
return -ENOTTY;
|
||||
}
|
||||
|
||||
// File release handler
|
||||
static int anon_ksu_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
pr_info("ksu fd released\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// File operations structure
|
||||
static const struct file_operations anon_ksu_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.unlocked_ioctl = anon_ksu_ioctl,
|
||||
.compat_ioctl = anon_ksu_ioctl,
|
||||
.release = anon_ksu_release,
|
||||
};
|
||||
|
||||
// Install KSU fd to current process
|
||||
int ksu_install_fd(void)
|
||||
{
|
||||
struct file *filp;
|
||||
int fd;
|
||||
|
||||
// Get unused fd
|
||||
fd = get_unused_fd_flags(O_CLOEXEC);
|
||||
if (fd < 0) {
|
||||
pr_err("ksu_install_fd: failed to get unused fd\n");
|
||||
return fd;
|
||||
}
|
||||
|
||||
// Create anonymous inode file
|
||||
filp = anon_inode_getfile("[ksu_driver]", &anon_ksu_fops, NULL, O_RDWR | O_CLOEXEC);
|
||||
if (IS_ERR(filp)) {
|
||||
pr_err("ksu_install_fd: failed to create anon inode file\n");
|
||||
put_unused_fd(fd);
|
||||
return PTR_ERR(filp);
|
||||
}
|
||||
|
||||
// Install fd
|
||||
fd_install(fd, filp);
|
||||
|
||||
#if __SULOG_GATE
|
||||
ksu_sulog_report_permission_check(current_uid().val, current->comm, fd >= 0);
|
||||
#endif
|
||||
|
||||
pr_info("ksu fd installed: %d for pid %d\n", fd, current->pid);
|
||||
|
||||
return fd;
|
||||
}
|
||||
157
kernel/supercalls.h
Normal file
157
kernel/supercalls.h
Normal file
@@ -0,0 +1,157 @@
|
||||
#ifndef __KSU_H_SUPERCALLS
|
||||
#define __KSU_H_SUPERCALLS
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include "ksu.h"
|
||||
|
||||
#ifdef CONFIG_KPM
|
||||
#include "kpm/kpm.h"
|
||||
#endif
|
||||
|
||||
// Magic numbers for reboot hook to install fd
|
||||
#define KSU_INSTALL_MAGIC1 0xDEADBEEF
|
||||
#define KSU_INSTALL_MAGIC2 0xCAFEBABE
|
||||
|
||||
// Command structures for ioctl
|
||||
|
||||
struct ksu_become_daemon_cmd {
|
||||
__u8 token[65]; // Input: daemon token (null-terminated)
|
||||
};
|
||||
|
||||
struct ksu_get_info_cmd {
|
||||
__u32 version; // Output: KERNEL_SU_VERSION
|
||||
__u32 flags; // Output: flags (bit 0: MODULE mode)
|
||||
__u32 features; // Output: max feature ID supported
|
||||
};
|
||||
|
||||
struct ksu_report_event_cmd {
|
||||
__u32 event; // Input: EVENT_POST_FS_DATA, EVENT_BOOT_COMPLETED, etc.
|
||||
};
|
||||
|
||||
struct ksu_set_sepolicy_cmd {
|
||||
__u64 cmd; // Input: sepolicy command
|
||||
__aligned_u64 arg; // Input: sepolicy argument pointer
|
||||
};
|
||||
|
||||
struct ksu_check_safemode_cmd {
|
||||
__u8 in_safe_mode; // Output: true if in safe mode, false otherwise
|
||||
};
|
||||
|
||||
struct ksu_get_allow_list_cmd {
|
||||
__u32 uids[128]; // Output: array of allowed/denied UIDs
|
||||
__u32 count; // Output: number of UIDs in array
|
||||
__u8 allow; // Input: true for allow list, false for deny list
|
||||
};
|
||||
|
||||
struct ksu_uid_granted_root_cmd {
|
||||
__u32 uid; // Input: target UID to check
|
||||
__u8 granted; // Output: true if granted, false otherwise
|
||||
};
|
||||
|
||||
struct ksu_uid_should_umount_cmd {
|
||||
__u32 uid; // Input: target UID to check
|
||||
__u8 should_umount; // Output: true if should umount, false otherwise
|
||||
};
|
||||
|
||||
struct ksu_get_manager_uid_cmd {
|
||||
__u32 uid; // Output: manager UID
|
||||
};
|
||||
|
||||
struct ksu_get_app_profile_cmd {
|
||||
struct app_profile profile; // Input/Output: app profile structure
|
||||
};
|
||||
|
||||
struct ksu_set_app_profile_cmd {
|
||||
struct app_profile profile; // Input: app profile structure
|
||||
};
|
||||
|
||||
struct ksu_get_feature_cmd {
|
||||
__u32 feature_id; // Input: feature ID (enum ksu_feature_id)
|
||||
__u64 value; // Output: feature value/state
|
||||
__u8 supported; // Output: true if feature is supported, false otherwise
|
||||
};
|
||||
|
||||
struct ksu_set_feature_cmd {
|
||||
__u32 feature_id; // Input: feature ID (enum ksu_feature_id)
|
||||
__u64 value; // Input: feature value/state to set
|
||||
};
|
||||
|
||||
// Other command structures
|
||||
struct ksu_get_full_version_cmd {
|
||||
char version_full[KSU_FULL_VERSION_STRING]; // Output: full version string
|
||||
};
|
||||
|
||||
struct ksu_hook_type_cmd {
|
||||
char hook_type[32]; // Output: hook type string
|
||||
};
|
||||
|
||||
struct ksu_enable_kpm_cmd {
|
||||
__u8 enabled; // Output: true if KPM is enabled
|
||||
};
|
||||
|
||||
struct ksu_dynamic_manager_cmd {
|
||||
struct dynamic_manager_user_config config; // Input/Output: dynamic manager config
|
||||
};
|
||||
|
||||
struct ksu_get_managers_cmd {
|
||||
struct manager_list_info manager_info; // Output: manager list information
|
||||
};
|
||||
|
||||
struct ksu_enable_uid_scanner_cmd {
|
||||
__u32 operation; // Input: operation type (UID_SCANNER_OP_GET_STATUS, UID_SCANNER_OP_TOGGLE, UID_SCANNER_OP_CLEAR_ENV)
|
||||
__u32 enabled; // Input: enable or disable (for UID_SCANNER_OP_TOGGLE)
|
||||
void __user *status_ptr; // Input: pointer to store status (for UID_SCANNER_OP_GET_STATUS)
|
||||
};
|
||||
|
||||
#ifdef CONFIG_KSU_MANUAL_SU
|
||||
struct ksu_manual_su_cmd {
|
||||
__u32 option; // Input: operation type (MANUAL_SU_OP_GENERATE_TOKEN, MANUAL_SU_OP_ESCALATE, MANUAL_SU_OP_ADD_PENDING)
|
||||
__u32 target_uid; // Input: target UID
|
||||
__u32 target_pid; // Input: target PID
|
||||
char token_buffer[33]; // Input/Output: token buffer
|
||||
};
|
||||
#endif
|
||||
|
||||
// IOCTL command definitions
|
||||
#define KSU_IOCTL_GRANT_ROOT _IOC(_IOC_NONE, 'K', 1, 0)
|
||||
#define KSU_IOCTL_GET_INFO _IOC(_IOC_READ, 'K', 2, 0)
|
||||
#define KSU_IOCTL_REPORT_EVENT _IOC(_IOC_WRITE, 'K', 3, 0)
|
||||
#define KSU_IOCTL_SET_SEPOLICY _IOC(_IOC_READ|_IOC_WRITE, 'K', 4, 0)
|
||||
#define KSU_IOCTL_CHECK_SAFEMODE _IOC(_IOC_READ, 'K', 5, 0)
|
||||
#define KSU_IOCTL_GET_ALLOW_LIST _IOC(_IOC_READ|_IOC_WRITE, 'K', 6, 0)
|
||||
#define KSU_IOCTL_GET_DENY_LIST _IOC(_IOC_READ|_IOC_WRITE, 'K', 7, 0)
|
||||
#define KSU_IOCTL_UID_GRANTED_ROOT _IOC(_IOC_READ|_IOC_WRITE, 'K', 8, 0)
|
||||
#define KSU_IOCTL_UID_SHOULD_UMOUNT _IOC(_IOC_READ|_IOC_WRITE, 'K', 9, 0)
|
||||
#define KSU_IOCTL_GET_MANAGER_UID _IOC(_IOC_READ, 'K', 10, 0)
|
||||
#define KSU_IOCTL_GET_APP_PROFILE _IOC(_IOC_READ|_IOC_WRITE, 'K', 11, 0)
|
||||
#define KSU_IOCTL_SET_APP_PROFILE _IOC(_IOC_WRITE, 'K', 12, 0)
|
||||
#define KSU_IOCTL_GET_FEATURE _IOC(_IOC_READ|_IOC_WRITE, 'K', 13, 0)
|
||||
#define KSU_IOCTL_SET_FEATURE _IOC(_IOC_WRITE, 'K', 14, 0)
|
||||
// Other IOCTL command definitions
|
||||
#define KSU_IOCTL_GET_FULL_VERSION _IOC(_IOC_READ, 'K', 100, 0)
|
||||
#define KSU_IOCTL_HOOK_TYPE _IOC(_IOC_READ, 'K', 101, 0)
|
||||
#define KSU_IOCTL_ENABLE_KPM _IOC(_IOC_READ, 'K', 102, 0)
|
||||
#define KSU_IOCTL_DYNAMIC_MANAGER _IOC(_IOC_READ|_IOC_WRITE, 'K', 103, 0)
|
||||
#define KSU_IOCTL_GET_MANAGERS _IOC(_IOC_READ|_IOC_WRITE, 'K', 104, 0)
|
||||
#define KSU_IOCTL_ENABLE_UID_SCANNER _IOC(_IOC_READ|_IOC_WRITE, 'K', 105, 0)
|
||||
#ifdef CONFIG_KSU_MANUAL_SU
|
||||
#define KSU_IOCTL_MANUAL_SU _IOC(_IOC_READ|_IOC_WRITE, 'K', 106, 0)
|
||||
#endif
|
||||
|
||||
// IOCTL handler types
|
||||
typedef int (*ksu_ioctl_handler_t)(void __user *arg);
|
||||
typedef bool (*ksu_perm_check_t)(void);
|
||||
|
||||
// IOCTL command mapping
|
||||
struct ksu_ioctl_cmd_map {
|
||||
unsigned int cmd;
|
||||
const char *name;
|
||||
ksu_ioctl_handler_t handler;
|
||||
ksu_perm_check_t perm_check; // Permission check function
|
||||
};
|
||||
|
||||
// Install KSU fd to current process
|
||||
int ksu_install_fd(void);
|
||||
|
||||
#endif // __KSU_H_SUPERCALLS
|
||||
@@ -22,8 +22,7 @@ static uid_t locked_manager_uid = KSU_INVALID_UID;
|
||||
static uid_t locked_dynamic_manager_uid = KSU_INVALID_UID;
|
||||
|
||||
#define KSU_UID_LIST_PATH "/data/misc/user_uid/uid_list"
|
||||
#define USER_DATA_PATH "/data/user_de/0"
|
||||
#define USER_DATA_PATH_LEN 288
|
||||
#define SYSTEM_PACKAGES_LIST_PATH "/data/system/packages.list"
|
||||
|
||||
struct uid_data {
|
||||
struct list_head list;
|
||||
@@ -236,152 +235,6 @@ struct my_dir_context {
|
||||
#define FILLDIR_ACTOR_STOP -EINVAL
|
||||
#endif
|
||||
|
||||
struct uid_scan_stats {
|
||||
size_t total_found;
|
||||
size_t errors_encountered;
|
||||
};
|
||||
|
||||
struct user_data_context {
|
||||
struct dir_context ctx;
|
||||
struct list_head *uid_list;
|
||||
struct uid_scan_stats *stats;
|
||||
};
|
||||
|
||||
FILLDIR_RETURN_TYPE user_data_actor(struct dir_context *ctx, const char *name,
|
||||
int namelen, loff_t off, u64 ino,
|
||||
unsigned int d_type)
|
||||
{
|
||||
struct user_data_context *my_ctx =
|
||||
container_of(ctx, struct user_data_context, ctx);
|
||||
|
||||
if (!my_ctx || !my_ctx->uid_list) {
|
||||
return FILLDIR_ACTOR_STOP;
|
||||
}
|
||||
|
||||
if (!strncmp(name, "..", namelen) || !strncmp(name, ".", namelen))
|
||||
return FILLDIR_ACTOR_CONTINUE;
|
||||
|
||||
if (d_type != DT_DIR)
|
||||
return FILLDIR_ACTOR_CONTINUE;
|
||||
|
||||
if (namelen >= KSU_MAX_PACKAGE_NAME) {
|
||||
pr_warn("Package name too long: %.*s\n", namelen, name);
|
||||
if (my_ctx->stats)
|
||||
my_ctx->stats->errors_encountered++;
|
||||
return FILLDIR_ACTOR_CONTINUE;
|
||||
}
|
||||
|
||||
char package_path[USER_DATA_PATH_LEN];
|
||||
if (snprintf(package_path, sizeof(package_path), "%s/%.*s",
|
||||
USER_DATA_PATH, namelen, name) >= sizeof(package_path)) {
|
||||
pr_err("Path too long for package: %.*s\n", namelen, name);
|
||||
if (my_ctx->stats)
|
||||
my_ctx->stats->errors_encountered++;
|
||||
return FILLDIR_ACTOR_CONTINUE;
|
||||
}
|
||||
|
||||
struct path path;
|
||||
int err = kern_path(package_path, LOOKUP_FOLLOW, &path);
|
||||
if (err) {
|
||||
pr_debug("Package path lookup failed: %s (err: %d)\n", package_path, err);
|
||||
if (my_ctx->stats)
|
||||
my_ctx->stats->errors_encountered++;
|
||||
return FILLDIR_ACTOR_CONTINUE;
|
||||
}
|
||||
|
||||
/*
|
||||
4.11, also backported on lineage common kernel 4.9 !!
|
||||
int vfs_getattr(const struct path *path, struct kstat *stat,
|
||||
u32 request_mask, unsigned int query_flags)
|
||||
|
||||
4.10
|
||||
int vfs_getattr(struct path *path, struct kstat *stat)
|
||||
|
||||
basically no mask and flags for =< 4.10
|
||||
|
||||
*/
|
||||
struct kstat stat;
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,11,0) || defined(KSU_HAS_NEW_VFS_GETATTR)
|
||||
err = vfs_getattr(&path, &stat, STATX_UID, AT_STATX_SYNC_AS_STAT);
|
||||
#else
|
||||
err = vfs_getattr(&path, &stat);
|
||||
#endif
|
||||
path_put(&path);
|
||||
|
||||
if (err) {
|
||||
pr_info("Failed to get attributes for: %s (err: %d)\n", package_path, err);
|
||||
if (my_ctx->stats)
|
||||
my_ctx->stats->errors_encountered++;
|
||||
return FILLDIR_ACTOR_CONTINUE;
|
||||
}
|
||||
|
||||
uid_t uid = from_kuid(&init_user_ns, stat.uid);
|
||||
if (uid == (uid_t)-1) {
|
||||
pr_warn("Invalid UID for package: %.*s\n", namelen, name);
|
||||
if (my_ctx->stats)
|
||||
my_ctx->stats->errors_encountered++;
|
||||
return FILLDIR_ACTOR_CONTINUE;
|
||||
}
|
||||
|
||||
struct uid_data *data = kzalloc(sizeof(struct uid_data), GFP_ATOMIC);
|
||||
if (!data) {
|
||||
pr_err("Failed to allocate memory for package: %.*s\n", namelen, name);
|
||||
if (my_ctx->stats)
|
||||
my_ctx->stats->errors_encountered++;
|
||||
return FILLDIR_ACTOR_CONTINUE;
|
||||
}
|
||||
|
||||
data->uid = uid;
|
||||
size_t copy_len = min(namelen, KSU_MAX_PACKAGE_NAME - 1);
|
||||
strncpy(data->package, name, copy_len);
|
||||
data->package[copy_len] = '\0';
|
||||
|
||||
list_add_tail(&data->list, my_ctx->uid_list);
|
||||
|
||||
if (my_ctx->stats)
|
||||
my_ctx->stats->total_found++;
|
||||
|
||||
pr_info("UserDE UID: Found package: %s, uid: %u\n", data->package, data->uid);
|
||||
|
||||
return FILLDIR_ACTOR_CONTINUE;
|
||||
}
|
||||
|
||||
static int scan_user_data_for_uids(struct list_head *uid_list)
|
||||
{
|
||||
struct file *dir_file;
|
||||
struct uid_scan_stats stats = {0};
|
||||
int ret = 0;
|
||||
|
||||
if (!uid_list) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dir_file = ksu_filp_open_compat(USER_DATA_PATH, O_RDONLY, 0);
|
||||
if (IS_ERR(dir_file)) {
|
||||
pr_err("UserDE UID: Failed to open %s, err: (%ld)\n", USER_DATA_PATH, PTR_ERR(dir_file));
|
||||
return PTR_ERR(dir_file);
|
||||
}
|
||||
|
||||
struct user_data_context ctx = {
|
||||
.ctx.actor = user_data_actor,
|
||||
.uid_list = uid_list,
|
||||
.stats = &stats
|
||||
};
|
||||
|
||||
ret = iterate_dir(dir_file, &ctx.ctx);
|
||||
filp_close(dir_file, NULL);
|
||||
|
||||
if (stats.errors_encountered > 0) {
|
||||
pr_warn("Encountered %zu errors while scanning user data directory\n",
|
||||
stats.errors_encountered);
|
||||
}
|
||||
|
||||
pr_info("UserDE UID: Scanned %s directory with %zu errors\n",
|
||||
USER_DATA_PATH, stats.errors_encountered);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
FILLDIR_RETURN_TYPE my_actor(struct dir_context *ctx, const char *name,
|
||||
int namelen, loff_t off, u64 ino,
|
||||
unsigned int d_type)
|
||||
@@ -573,35 +426,84 @@ static bool is_uid_exist(uid_t uid, char *package, void *data)
|
||||
return exist;
|
||||
}
|
||||
|
||||
extern bool ksu_uid_scanner_enabled;
|
||||
|
||||
void track_throne(void)
|
||||
{
|
||||
struct list_head uid_list;
|
||||
struct uid_data *np, *n;
|
||||
struct file *fp;
|
||||
char chr = 0;
|
||||
loff_t pos = 0;
|
||||
loff_t line_start = 0;
|
||||
char buf[KSU_MAX_PACKAGE_NAME];
|
||||
static bool manager_exist = false;
|
||||
static bool dynamic_manager_exist = false;
|
||||
int current_manager_uid = ksu_get_manager_uid() % 100000;
|
||||
|
||||
// init uid list head
|
||||
INIT_LIST_HEAD(&uid_list);
|
||||
|
||||
if (ksu_uid_scanner_enabled) {
|
||||
pr_info("Scanning %s directory..\n", KSU_UID_LIST_PATH);
|
||||
|
||||
if (uid_from_um_list(&uid_list) == 0) {
|
||||
pr_info("Loaded UIDs from %s success\n", KSU_UID_LIST_PATH);
|
||||
} else {
|
||||
pr_warn("%s read failed, falling back to %s\n", KSU_UID_LIST_PATH, USER_DATA_PATH);
|
||||
if (scan_user_data_for_uids(&uid_list) < 0)
|
||||
goto out;
|
||||
goto uid_ready;
|
||||
}
|
||||
} else {
|
||||
pr_info("User mode scan disabled, scanning %s\n", USER_DATA_PATH);
|
||||
if (scan_user_data_for_uids(&uid_list) < 0)
|
||||
|
||||
pr_warn("%s read failed, fallback to %s\n",
|
||||
KSU_UID_LIST_PATH, SYSTEM_PACKAGES_LIST_PATH);
|
||||
}
|
||||
|
||||
{
|
||||
fp = ksu_filp_open_compat(SYSTEM_PACKAGES_LIST_PATH, O_RDONLY, 0);
|
||||
if (IS_ERR(fp)) {
|
||||
pr_err("%s: open " SYSTEM_PACKAGES_LIST_PATH " failed: %ld\n", __func__, PTR_ERR(fp));
|
||||
return;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
ssize_t count =
|
||||
ksu_kernel_read_compat(fp, &chr, sizeof(chr), &pos);
|
||||
if (count != sizeof(chr))
|
||||
break;
|
||||
if (chr != '\n')
|
||||
continue;
|
||||
|
||||
count = ksu_kernel_read_compat(fp, buf, sizeof(buf),
|
||||
&line_start);
|
||||
struct uid_data *data =
|
||||
kzalloc(sizeof(struct uid_data), GFP_ATOMIC);
|
||||
if (!data) {
|
||||
filp_close(fp, 0);
|
||||
goto out;
|
||||
}
|
||||
|
||||
// check if manager UID exists
|
||||
bool manager_exist = false;
|
||||
int current_manager_uid = ksu_get_manager_uid() % 100000;
|
||||
char *tmp = buf;
|
||||
const char *delim = " ";
|
||||
char *package = strsep(&tmp, delim);
|
||||
char *uid = strsep(&tmp, delim);
|
||||
if (!uid || !package) {
|
||||
pr_err("update_uid: package or uid is NULL!\n");
|
||||
break;
|
||||
}
|
||||
|
||||
u32 res;
|
||||
if (kstrtou32(uid, 10, &res)) {
|
||||
pr_err("update_uid: uid parse err\n");
|
||||
break;
|
||||
}
|
||||
data->uid = res;
|
||||
strncpy(data->package, package, KSU_MAX_PACKAGE_NAME);
|
||||
list_add_tail(&data->list, &uid_list);
|
||||
// reset line start
|
||||
line_start = pos;
|
||||
}
|
||||
|
||||
filp_close(fp, 0);
|
||||
}
|
||||
|
||||
uid_ready:
|
||||
// first, check if manager_uid exist!
|
||||
list_for_each_entry(np, &uid_list, list) {
|
||||
if (np->uid == current_manager_uid) {
|
||||
manager_exist = true;
|
||||
@@ -610,14 +512,15 @@ void track_throne(void)
|
||||
}
|
||||
|
||||
if (!manager_exist && locked_manager_uid != KSU_INVALID_UID) {
|
||||
pr_info("Manager APK removed, unlocking previous UID: %d\n", locked_manager_uid);
|
||||
pr_info("Manager APK removed, unlock previous UID: %d\n",
|
||||
locked_manager_uid);
|
||||
ksu_invalidate_manager_uid();
|
||||
locked_manager_uid = KSU_INVALID_UID;
|
||||
}
|
||||
|
||||
// Check if the Dynamic Manager exists (only check locked UIDs)
|
||||
bool dynamic_manager_exist = false;
|
||||
if (ksu_is_dynamic_manager_enabled() && locked_dynamic_manager_uid != KSU_INVALID_UID) {
|
||||
if (ksu_is_dynamic_manager_enabled() &&
|
||||
locked_dynamic_manager_uid != KSU_INVALID_UID) {
|
||||
list_for_each_entry(np, &uid_list, list) {
|
||||
if (np->uid == locked_dynamic_manager_uid) {
|
||||
dynamic_manager_exist = true;
|
||||
@@ -626,16 +529,16 @@ void track_throne(void)
|
||||
}
|
||||
|
||||
if (!dynamic_manager_exist) {
|
||||
pr_info("Dynamic manager APK removed, unlocking previous UID: %d\n", locked_dynamic_manager_uid);
|
||||
pr_info("Dynamic manager APK removed, unlock previous UID: %d\n",
|
||||
locked_dynamic_manager_uid);
|
||||
ksu_remove_manager(locked_dynamic_manager_uid);
|
||||
locked_dynamic_manager_uid = KSU_INVALID_UID;
|
||||
}
|
||||
}
|
||||
|
||||
bool need_search = !manager_exist;
|
||||
if (ksu_is_dynamic_manager_enabled() && !dynamic_manager_exist) {
|
||||
if (ksu_is_dynamic_manager_enabled() && !dynamic_manager_exist)
|
||||
need_search = true;
|
||||
}
|
||||
|
||||
if (need_search) {
|
||||
pr_info("Searching for manager(s)...\n");
|
||||
|
||||
@@ -1,609 +0,0 @@
|
||||
#include <linux/err.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/version.h>
|
||||
|
||||
#include "allowlist.h"
|
||||
#include "klog.h" // IWYU pragma: keep
|
||||
#include "ksu.h"
|
||||
#include "manager.h"
|
||||
#include "throne_tracker.h"
|
||||
#include "kernel_compat.h"
|
||||
#include "dynamic_manager.h"
|
||||
#include "throne_comm.h"
|
||||
|
||||
uid_t ksu_manager_uid = KSU_INVALID_UID;
|
||||
|
||||
#define SYSTEM_PACKAGES_LIST_PATH "/data/system/packages.list.tmp"
|
||||
#define KSU_UID_LIST_PATH "/data/misc/user_uid/uid_list"
|
||||
|
||||
struct uid_data {
|
||||
struct list_head list;
|
||||
u32 uid;
|
||||
char package[KSU_MAX_PACKAGE_NAME];
|
||||
};
|
||||
|
||||
// Try read whitelist first, fallback if failed
|
||||
static int read_uid_whitelist(struct list_head *uid_list)
|
||||
{
|
||||
struct file *fp;
|
||||
char *file_content = NULL;
|
||||
char *line, *next_line;
|
||||
loff_t file_size;
|
||||
loff_t pos = 0;
|
||||
int count = 0;
|
||||
ssize_t bytes_read;
|
||||
|
||||
fp = ksu_filp_open_compat(KSU_UID_LIST_PATH, O_RDONLY, 0);
|
||||
if (IS_ERR(fp)) {
|
||||
pr_info("whitelist not found, fallback needed\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
file_size = fp->f_inode->i_size;
|
||||
if (file_size <= 0) {
|
||||
pr_info("whitelist file is empty\n");
|
||||
filp_close(fp, NULL);
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
file_content = kzalloc(file_size + 1, GFP_ATOMIC);
|
||||
if (!file_content) {
|
||||
pr_err("failed to allocate memory for whitelist file (%lld bytes)\n", file_size);
|
||||
filp_close(fp, NULL);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
bytes_read = ksu_kernel_read_compat(fp, file_content, file_size, &pos);
|
||||
if (bytes_read != file_size) {
|
||||
pr_err("failed to read whitelist file: read %zd bytes, expected %lld bytes\n",
|
||||
bytes_read, file_size);
|
||||
kfree(file_content);
|
||||
filp_close(fp, NULL);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
file_content[file_size] = '\0';
|
||||
filp_close(fp, NULL);
|
||||
|
||||
pr_info("successfully read whitelist file (%lld bytes), parsing lines...\n", file_size);
|
||||
|
||||
line = file_content;
|
||||
while (line && *line) {
|
||||
next_line = strchr(line, '\n');
|
||||
if (next_line) {
|
||||
*next_line = '\0';
|
||||
next_line++;
|
||||
}
|
||||
|
||||
char *trimmed_line = line;
|
||||
while (*trimmed_line == ' ' || *trimmed_line == '\t' || *trimmed_line == '\r') {
|
||||
trimmed_line++;
|
||||
}
|
||||
|
||||
if (strlen(trimmed_line) > 0) {
|
||||
char *line_copy = trimmed_line;
|
||||
char *uid_str = strsep(&line_copy, " \t");
|
||||
char *package_name = line_copy;
|
||||
|
||||
if (package_name) {
|
||||
while (*package_name == ' ' || *package_name == '\t') {
|
||||
package_name++;
|
||||
}
|
||||
}
|
||||
|
||||
if (uid_str && package_name && strlen(package_name) > 0) {
|
||||
u32 uid;
|
||||
if (!kstrtou32(uid_str, 10, &uid)) {
|
||||
struct uid_data *data = kzalloc(sizeof(struct uid_data), GFP_ATOMIC);
|
||||
if (data) {
|
||||
data->uid = uid;
|
||||
size_t pkg_len = strlen(package_name);
|
||||
size_t copy_len = min(pkg_len, (size_t)(KSU_MAX_PACKAGE_NAME - 1));
|
||||
strncpy(data->package, package_name, copy_len);
|
||||
data->package[copy_len] = '\0';
|
||||
|
||||
list_add_tail(&data->list, uid_list);
|
||||
count++;
|
||||
|
||||
if (count % 100 == 0) {
|
||||
pr_info("parsed %d packages so far...\n", count);
|
||||
}
|
||||
} else {
|
||||
pr_err("failed to allocate memory for uid_data\n");
|
||||
}
|
||||
} else {
|
||||
pr_warn("invalid uid format in line: %s\n", trimmed_line);
|
||||
}
|
||||
} else {
|
||||
pr_warn("invalid line format: %s\n", trimmed_line);
|
||||
}
|
||||
}
|
||||
|
||||
line = next_line;
|
||||
}
|
||||
|
||||
kfree(file_content);
|
||||
pr_info("successfully loaded %d uids from whitelist\n", count);
|
||||
return count > 0 ? 0 : -ENODATA;
|
||||
}
|
||||
|
||||
static int get_pkg_from_apk_path(char *pkg, const char *path)
|
||||
{
|
||||
int len = strlen(path);
|
||||
if (len >= KSU_MAX_PACKAGE_NAME || len < 1)
|
||||
return -1;
|
||||
|
||||
const char *last_slash = NULL;
|
||||
const char *second_last_slash = NULL;
|
||||
|
||||
int i;
|
||||
for (i = len - 1; i >= 0; i--) {
|
||||
if (path[i] == '/') {
|
||||
if (!last_slash) {
|
||||
last_slash = &path[i];
|
||||
} else {
|
||||
second_last_slash = &path[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!last_slash || !second_last_slash)
|
||||
return -1;
|
||||
|
||||
const char *last_hyphen = strchr(second_last_slash, '-');
|
||||
if (!last_hyphen || last_hyphen > last_slash)
|
||||
return -1;
|
||||
|
||||
int pkg_len = last_hyphen - second_last_slash - 1;
|
||||
if (pkg_len >= KSU_MAX_PACKAGE_NAME || pkg_len <= 0)
|
||||
return -1;
|
||||
|
||||
// Copying the package name
|
||||
strncpy(pkg, second_last_slash + 1, pkg_len);
|
||||
pkg[pkg_len] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void crown_manager(const char *apk, struct list_head *uid_data,
|
||||
int signature_index)
|
||||
{
|
||||
char pkg[KSU_MAX_PACKAGE_NAME];
|
||||
if (get_pkg_from_apk_path(pkg, apk) < 0) {
|
||||
pr_err("Failed to get package name from apk path: %s\n", apk);
|
||||
return;
|
||||
}
|
||||
|
||||
pr_info("manager pkg: %s, signature_index: %d\n", pkg, signature_index);
|
||||
|
||||
#ifdef KSU_MANAGER_PACKAGE
|
||||
// pkg is `/<real package>`
|
||||
if (strncmp(pkg, KSU_MANAGER_PACKAGE, sizeof(KSU_MANAGER_PACKAGE))) {
|
||||
pr_info("manager package is inconsistent with kernel build: %s\n",
|
||||
KSU_MANAGER_PACKAGE);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
struct list_head *list = (struct list_head *)uid_data;
|
||||
struct uid_data *np;
|
||||
|
||||
list_for_each_entry(np, list, list) {
|
||||
if (strncmp(np->package, pkg, KSU_MAX_PACKAGE_NAME) == 0) {
|
||||
pr_info("Crowning manager: %s(uid=%d, signature_index=%d)\n",
|
||||
pkg, np->uid, signature_index);
|
||||
|
||||
// Dynamic Sign index (1) or multi-manager signatures (2+)
|
||||
if (signature_index == DYNAMIC_SIGN_INDEX || signature_index >= 2) {
|
||||
ksu_add_manager(np->uid, signature_index);
|
||||
|
||||
if (!ksu_is_manager_uid_valid()) {
|
||||
ksu_set_manager_uid(np->uid);
|
||||
}
|
||||
} else {
|
||||
ksu_set_manager_uid(np->uid);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define DATA_PATH_LEN 384 // 384 is enough for /data/app/<package>/base.apk
|
||||
|
||||
struct data_path {
|
||||
char dirpath[DATA_PATH_LEN];
|
||||
int depth;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
struct apk_path_hash {
|
||||
unsigned int hash;
|
||||
bool exists;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
static struct list_head apk_path_hash_list;
|
||||
|
||||
struct my_dir_context {
|
||||
struct dir_context ctx;
|
||||
struct list_head *data_path_list;
|
||||
char *parent_dir;
|
||||
void *private_data;
|
||||
int depth;
|
||||
int *stop;
|
||||
};
|
||||
// https://docs.kernel.org/filesystems/porting.html
|
||||
// filldir_t (readdir callbacks) calling conventions have changed. Instead of returning 0 or -E... it returns bool now. false means "no more" (as -E... used to) and true - "keep going" (as 0 in old calling conventions). Rationale: callers never looked at specific -E... values anyway. -> iterate_shared() instances require no changes at all, all filldir_t ones in the tree converted.
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)
|
||||
#define FILLDIR_RETURN_TYPE bool
|
||||
#define FILLDIR_ACTOR_CONTINUE true
|
||||
#define FILLDIR_ACTOR_STOP false
|
||||
#else
|
||||
#define FILLDIR_RETURN_TYPE int
|
||||
#define FILLDIR_ACTOR_CONTINUE 0
|
||||
#define FILLDIR_ACTOR_STOP -EINVAL
|
||||
#endif
|
||||
FILLDIR_RETURN_TYPE my_actor(struct dir_context *ctx, const char *name,
|
||||
int namelen, loff_t off, u64 ino,
|
||||
unsigned int d_type)
|
||||
{
|
||||
struct my_dir_context *my_ctx =
|
||||
container_of(ctx, struct my_dir_context, ctx);
|
||||
char dirpath[DATA_PATH_LEN];
|
||||
|
||||
if (!my_ctx) {
|
||||
pr_err("Invalid context\n");
|
||||
return FILLDIR_ACTOR_STOP;
|
||||
}
|
||||
if (my_ctx->stop && *my_ctx->stop) {
|
||||
pr_info("Stop searching\n");
|
||||
return FILLDIR_ACTOR_STOP;
|
||||
}
|
||||
|
||||
if (!strncmp(name, "..", namelen) || !strncmp(name, ".", namelen))
|
||||
return FILLDIR_ACTOR_CONTINUE; // Skip "." and ".."
|
||||
|
||||
if (d_type == DT_DIR && namelen >= 8 && !strncmp(name, "vmdl", 4) &&
|
||||
!strncmp(name + namelen - 4, ".tmp", 4)) {
|
||||
pr_info("Skipping directory: %.*s\n", namelen, name);
|
||||
return FILLDIR_ACTOR_CONTINUE; // Skip staging package
|
||||
}
|
||||
|
||||
if (snprintf(dirpath, DATA_PATH_LEN, "%s/%.*s", my_ctx->parent_dir,
|
||||
namelen, name) >= DATA_PATH_LEN) {
|
||||
pr_err("Path too long: %s/%.*s\n", my_ctx->parent_dir, namelen,
|
||||
name);
|
||||
return FILLDIR_ACTOR_CONTINUE;
|
||||
}
|
||||
|
||||
if (d_type == DT_DIR && my_ctx->depth > 0 &&
|
||||
(my_ctx->stop && !*my_ctx->stop)) {
|
||||
struct data_path *data =
|
||||
kmalloc(sizeof(struct data_path), GFP_ATOMIC);
|
||||
|
||||
if (!data) {
|
||||
pr_err("Failed to allocate memory for %s\n", dirpath);
|
||||
return FILLDIR_ACTOR_CONTINUE;
|
||||
}
|
||||
|
||||
strscpy(data->dirpath, dirpath, DATA_PATH_LEN);
|
||||
data->depth = my_ctx->depth - 1;
|
||||
list_add_tail(&data->list, my_ctx->data_path_list);
|
||||
} else {
|
||||
if ((namelen == 8) &&
|
||||
(strncmp(name, "base.apk", namelen) == 0)) {
|
||||
struct apk_path_hash *pos, *n;
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 8, 0)
|
||||
unsigned int hash =
|
||||
full_name_hash(dirpath, strlen(dirpath));
|
||||
#else
|
||||
unsigned int hash =
|
||||
full_name_hash(NULL, dirpath, strlen(dirpath));
|
||||
#endif
|
||||
list_for_each_entry(pos, &apk_path_hash_list, list) {
|
||||
if (hash == pos->hash) {
|
||||
pos->exists = true;
|
||||
return FILLDIR_ACTOR_CONTINUE;
|
||||
}
|
||||
}
|
||||
|
||||
int signature_index = -1;
|
||||
bool is_multi_manager = is_dynamic_manager_apk(
|
||||
dirpath, &signature_index);
|
||||
|
||||
pr_info("Found new base.apk at path: %s, is_multi_manager: %d, signature_index: %d\n",
|
||||
dirpath, is_multi_manager, signature_index);
|
||||
// Check for dynamic sign or multi-manager signatures
|
||||
if (is_multi_manager &&
|
||||
(signature_index == DYNAMIC_SIGN_INDEX || signature_index >= 2)) {
|
||||
crown_manager(dirpath, my_ctx->private_data,
|
||||
signature_index);
|
||||
|
||||
struct apk_path_hash *apk_data =
|
||||
kmalloc(sizeof(struct apk_path_hash),
|
||||
GFP_ATOMIC);
|
||||
|
||||
if (apk_data) {
|
||||
apk_data->hash = hash;
|
||||
apk_data->exists = true;
|
||||
list_add_tail(&apk_data->list,
|
||||
&apk_path_hash_list);
|
||||
}
|
||||
|
||||
} else if (is_manager_apk(dirpath)) {
|
||||
crown_manager(dirpath, my_ctx->private_data, 0);
|
||||
*my_ctx->stop = 1;
|
||||
|
||||
// Manager found, clear APK cache list
|
||||
list_for_each_entry_safe(
|
||||
pos, n, &apk_path_hash_list, list) {
|
||||
list_del(&pos->list);
|
||||
kfree(pos);
|
||||
}
|
||||
} else {
|
||||
struct apk_path_hash *apk_data =
|
||||
kmalloc(sizeof(struct apk_path_hash),
|
||||
GFP_ATOMIC);
|
||||
if (apk_data) {
|
||||
apk_data->hash = hash;
|
||||
apk_data->exists = true;
|
||||
list_add_tail(&apk_data->list,
|
||||
&apk_path_hash_list);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FILLDIR_ACTOR_CONTINUE;
|
||||
}
|
||||
|
||||
void search_manager(const char *path, int depth, struct list_head *uid_data)
|
||||
{
|
||||
int i, stop = 0;
|
||||
struct list_head data_path_list;
|
||||
INIT_LIST_HEAD(&data_path_list);
|
||||
INIT_LIST_HEAD(&apk_path_hash_list);
|
||||
unsigned long data_app_magic = 0;
|
||||
|
||||
// Initialize APK cache list
|
||||
struct apk_path_hash *pos, *n;
|
||||
list_for_each_entry(pos, &apk_path_hash_list, list) {
|
||||
pos->exists = false;
|
||||
}
|
||||
|
||||
// First depth
|
||||
struct data_path data;
|
||||
strscpy(data.dirpath, path, DATA_PATH_LEN);
|
||||
data.depth = depth;
|
||||
list_add_tail(&data.list, &data_path_list);
|
||||
|
||||
for (i = depth; i >= 0; i--) {
|
||||
struct data_path *pos, *n;
|
||||
|
||||
list_for_each_entry_safe(pos, n, &data_path_list, list) {
|
||||
struct my_dir_context ctx = {
|
||||
.ctx.actor = my_actor,
|
||||
.data_path_list = &data_path_list,
|
||||
.parent_dir = pos->dirpath,
|
||||
.private_data = uid_data,
|
||||
.depth = pos->depth,
|
||||
.stop = &stop
|
||||
};
|
||||
struct file *file;
|
||||
|
||||
if (!stop) {
|
||||
file = ksu_filp_open_compat(
|
||||
pos->dirpath, O_RDONLY | O_NOFOLLOW, 0);
|
||||
if (IS_ERR(file)) {
|
||||
pr_err("Failed to open directory: %s, err: %ld\n",
|
||||
pos->dirpath, PTR_ERR(file));
|
||||
goto skip_iterate;
|
||||
}
|
||||
|
||||
// grab magic on first folder, which is /data/app
|
||||
if (!data_app_magic) {
|
||||
if (file->f_inode->i_sb->s_magic) {
|
||||
data_app_magic =
|
||||
file->f_inode->i_sb
|
||||
->s_magic;
|
||||
pr_info("%s: dir: %s got magic! 0x%lx\n",
|
||||
__func__, pos->dirpath,
|
||||
data_app_magic);
|
||||
} else {
|
||||
filp_close(file, NULL);
|
||||
goto skip_iterate;
|
||||
}
|
||||
}
|
||||
|
||||
if (file->f_inode->i_sb->s_magic !=
|
||||
data_app_magic) {
|
||||
pr_info("%s: skip: %s magic: 0x%lx expected: 0x%lx\n",
|
||||
__func__, pos->dirpath,
|
||||
file->f_inode->i_sb->s_magic,
|
||||
data_app_magic);
|
||||
filp_close(file, NULL);
|
||||
goto skip_iterate;
|
||||
}
|
||||
|
||||
iterate_dir(file, &ctx.ctx);
|
||||
filp_close(file, NULL);
|
||||
}
|
||||
skip_iterate:
|
||||
list_del(&pos->list);
|
||||
if (pos != &data)
|
||||
kfree(pos);
|
||||
}
|
||||
}
|
||||
|
||||
// clear apk_path_hash_list unconditionally
|
||||
pr_info("search manager: cleanup!\n");
|
||||
list_for_each_entry_safe(pos, n, &apk_path_hash_list, list) {
|
||||
list_del(&pos->list);
|
||||
kfree(pos);
|
||||
}
|
||||
}
|
||||
|
||||
static bool is_uid_exist(uid_t uid, char *package, void *data)
|
||||
{
|
||||
struct list_head *list = (struct list_head *)data;
|
||||
struct uid_data *np;
|
||||
|
||||
bool exist = false;
|
||||
list_for_each_entry(np, list, list) {
|
||||
if (np->uid == uid % 100000 &&
|
||||
strncmp(np->package, package, KSU_MAX_PACKAGE_NAME) == 0) {
|
||||
exist = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return exist;
|
||||
}
|
||||
|
||||
void track_throne(void)
|
||||
{
|
||||
struct list_head uid_list;
|
||||
INIT_LIST_HEAD(&uid_list);
|
||||
|
||||
pr_info("track_throne triggered, attempting whitelist read\n");
|
||||
|
||||
// Try read whitelist first
|
||||
int ret = read_uid_whitelist(&uid_list);
|
||||
|
||||
if (ret < 0) {
|
||||
pr_info("whitelist read failed (%d), request userspace scan\n", ret);
|
||||
|
||||
// Request userspace to rescan
|
||||
ksu_request_userspace_scan();
|
||||
|
||||
// fallback to packages.list method
|
||||
struct file *fp = ksu_filp_open_compat(SYSTEM_PACKAGES_LIST_PATH, O_RDONLY, 0);
|
||||
if (IS_ERR(fp)) {
|
||||
pr_err("%s: open " SYSTEM_PACKAGES_LIST_PATH " failed: %ld\n",
|
||||
__func__, PTR_ERR(fp));
|
||||
goto out;
|
||||
}
|
||||
|
||||
char chr = 0;
|
||||
loff_t pos = 0;
|
||||
loff_t line_start = 0;
|
||||
char buf[KSU_MAX_PACKAGE_NAME];
|
||||
size_t fallback_count = 0;
|
||||
|
||||
for (;;) {
|
||||
ssize_t count =
|
||||
ksu_kernel_read_compat(fp, &chr, sizeof(chr), &pos);
|
||||
if (count != sizeof(chr))
|
||||
break;
|
||||
if (chr != '\n')
|
||||
continue;
|
||||
|
||||
count = ksu_kernel_read_compat(fp, buf, sizeof(buf),
|
||||
&line_start);
|
||||
|
||||
struct uid_data *data =
|
||||
kzalloc(sizeof(struct uid_data), GFP_ATOMIC);
|
||||
if (!data) {
|
||||
filp_close(fp, 0);
|
||||
goto out;
|
||||
}
|
||||
|
||||
char *tmp = buf;
|
||||
const char *delim = " ";
|
||||
char *package = strsep(&tmp, delim);
|
||||
char *uid = strsep(&tmp, delim);
|
||||
if (!uid || !package) {
|
||||
pr_err("update_uid: package or uid is NULL!\n");
|
||||
kfree(data);
|
||||
break;
|
||||
}
|
||||
|
||||
u32 res;
|
||||
if (kstrtou32(uid, 10, &res)) {
|
||||
pr_err("update_uid: uid parse err\n");
|
||||
kfree(data);
|
||||
break;
|
||||
}
|
||||
data->uid = res;
|
||||
strncpy(data->package, package, KSU_MAX_PACKAGE_NAME);
|
||||
list_add_tail(&data->list, &uid_list);
|
||||
fallback_count++;
|
||||
|
||||
// reset line start
|
||||
line_start = pos;
|
||||
}
|
||||
filp_close(fp, 0);
|
||||
pr_info("Loaded %zu packages from packages.list fallback\n", fallback_count);
|
||||
} else {
|
||||
pr_info("loaded uids from whitelist successfully\n");
|
||||
}
|
||||
|
||||
// now update uid list
|
||||
struct uid_data *np;
|
||||
struct uid_data *n;
|
||||
|
||||
// first, check if manager_uid exist!
|
||||
bool manager_exist = false;
|
||||
bool dynamic_manager_exist = false;
|
||||
|
||||
list_for_each_entry(np, &uid_list, list) {
|
||||
// if manager is installed in work profile, the uid in packages.list is still equals main profile
|
||||
// don't delete it in this case!
|
||||
int manager_uid = ksu_get_manager_uid() % 100000;
|
||||
if (np->uid == manager_uid) {
|
||||
manager_exist = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for dynamic managers
|
||||
if (!dynamic_manager_exist && ksu_is_dynamic_manager_enabled()) {
|
||||
list_for_each_entry(np, &uid_list, list) {
|
||||
// Check if this uid is a dynamic manager (not the traditional manager)
|
||||
if (ksu_is_any_manager(np->uid) &&
|
||||
np->uid != ksu_get_manager_uid()) {
|
||||
dynamic_manager_exist = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!manager_exist) {
|
||||
if (ksu_is_manager_uid_valid()) {
|
||||
pr_info("manager is uninstalled, invalidate it!\n");
|
||||
ksu_invalidate_manager_uid();
|
||||
goto prune;
|
||||
}
|
||||
pr_info("Searching manager...\n");
|
||||
search_manager("/data/app", 2, &uid_list);
|
||||
pr_info("Search manager finished\n");
|
||||
} else if (!dynamic_manager_exist && ksu_is_dynamic_manager_enabled()) {
|
||||
// Always perform search when called from dynamic manager rescan
|
||||
pr_info("Dynamic sign enabled, Searching manager...\n");
|
||||
search_manager("/data/app", 2, &uid_list);
|
||||
pr_info("Search Dynamic sign manager finished\n");
|
||||
}
|
||||
|
||||
prune:
|
||||
// then prune the allowlist
|
||||
ksu_prune_allowlist(is_uid_exist, &uid_list);
|
||||
out:
|
||||
// free uid_list
|
||||
list_for_each_entry_safe(np, n, &uid_list, list) {
|
||||
list_del(&np->list);
|
||||
kfree(np);
|
||||
}
|
||||
}
|
||||
|
||||
void ksu_throne_tracker_init(void)
|
||||
{
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
void ksu_throne_tracker_exit(void)
|
||||
{
|
||||
// nothing to do
|
||||
}
|
||||
Reference in New Issue
Block a user