@@ -39,6 +39,10 @@ use core::{
3939 sync:: atomic:: { AtomicU32 , Ordering } ,
4040} ;
4141
42+ fn is_aligned ( value : usize , to : usize ) -> bool {
43+ value % to == 0
44+ }
45+
4246/// Stores the layout of the scatter-gather entries. This is used during the `translate_objects`
4347/// call and is discarded when it returns.
4448struct ScatterGatherState {
@@ -69,17 +73,24 @@ struct ScatterGatherEntry {
6973}
7074
7175/// This entry specifies that a fixup should happen at `target_offset` of the
72- /// buffer. If `skip` is nonzero, then the fixup is a `binder_fd_array_object`
73- /// and is applied later. Otherwise if `skip` is zero, then the size of the
74- /// fixup is `sizeof::<u64>()` and `pointer_value` is written to the buffer.
75- struct PointerFixupEntry {
76- /// The number of bytes to skip, or zero for a `binder_buffer_object` fixup.
77- skip : usize ,
78- /// The translated pointer to write when `skip` is zero.
79- pointer_value : u64 ,
80- /// The offset at which the value should be written. The offset is relative
81- /// to the original buffer.
82- target_offset : usize ,
76+ /// buffer.
77+ enum PointerFixupEntry {
78+ /// A fixup for a `binder_buffer_object`.
79+ Fixup {
80+ /// The translated pointer to write.
81+ pointer_value : u64 ,
82+ /// The offset at which the value should be written. The offset is relative
83+ /// to the original buffer.
84+ target_offset : usize ,
85+ } ,
86+ /// A skip for a `binder_fd_array_object`.
87+ Skip {
88+ /// The number of bytes to skip.
89+ skip : usize ,
90+ /// The offset at which the skip should happen. The offset is relative
91+ /// to the original buffer.
92+ target_offset : usize ,
93+ } ,
8394}
8495
8596/// Return type of `apply_and_validate_fixup_in_parent`.
@@ -762,8 +773,7 @@ impl Thread {
762773
763774 parent_entry. fixup_min_offset = info. new_min_offset ;
764775 parent_entry. pointer_fixups . push (
765- PointerFixupEntry {
766- skip : 0 ,
776+ PointerFixupEntry :: Fixup {
767777 pointer_value : buffer_ptr_in_user_space,
768778 target_offset : info. target_offset ,
769779 } ,
@@ -789,6 +799,10 @@ impl Thread {
789799 let num_fds = usize:: try_from ( obj. num_fds ) . map_err ( |_| EINVAL ) ?;
790800 let fds_len = num_fds. checked_mul ( size_of :: < u32 > ( ) ) . ok_or ( EINVAL ) ?;
791801
802+ if !is_aligned ( parent_offset, size_of :: < u32 > ( ) ) {
803+ return Err ( EINVAL . into ( ) ) ;
804+ }
805+
792806 let info = sg_state. validate_parent_fixup ( parent_index, parent_offset, fds_len) ?;
793807 view. alloc . info_add_fd_reserve ( num_fds) ?;
794808
@@ -803,13 +817,16 @@ impl Thread {
803817 }
804818 } ;
805819
820+ if !is_aligned ( parent_entry. sender_uaddr , size_of :: < u32 > ( ) ) {
821+ return Err ( EINVAL . into ( ) ) ;
822+ }
823+
806824 parent_entry. fixup_min_offset = info. new_min_offset ;
807825 parent_entry
808826 . pointer_fixups
809827 . push (
810- PointerFixupEntry {
828+ PointerFixupEntry :: Skip {
811829 skip : fds_len,
812- pointer_value : 0 ,
813830 target_offset : info. target_offset ,
814831 } ,
815832 GFP_KERNEL ,
@@ -820,6 +837,7 @@ impl Thread {
820837 . sender_uaddr
821838 . checked_add ( parent_offset)
822839 . ok_or ( EINVAL ) ?;
840+
823841 let mut fda_bytes = KVec :: new ( ) ;
824842 UserSlice :: new ( UserPtr :: from_addr ( fda_uaddr as _ ) , fds_len)
825843 . read_all ( & mut fda_bytes, GFP_KERNEL ) ?;
@@ -871,17 +889,21 @@ impl Thread {
871889 let mut reader =
872890 UserSlice :: new ( UserPtr :: from_addr ( sg_entry. sender_uaddr ) , sg_entry. length ) . reader ( ) ;
873891 for fixup in & mut sg_entry. pointer_fixups {
874- let fixup_len = if fixup. skip == 0 {
875- size_of :: < u64 > ( )
876- } else {
877- fixup. skip
892+ let ( fixup_len, fixup_offset) = match fixup {
893+ PointerFixupEntry :: Fixup { target_offset, .. } => {
894+ ( size_of :: < u64 > ( ) , * target_offset)
895+ }
896+ PointerFixupEntry :: Skip {
897+ skip,
898+ target_offset,
899+ } => ( * skip, * target_offset) ,
878900 } ;
879901
880- let target_offset_end = fixup . target_offset . checked_add ( fixup_len) . ok_or ( EINVAL ) ?;
881- if fixup . target_offset < end_of_previous_fixup || offset_end < target_offset_end {
902+ let target_offset_end = fixup_offset . checked_add ( fixup_len) . ok_or ( EINVAL ) ?;
903+ if fixup_offset < end_of_previous_fixup || offset_end < target_offset_end {
882904 pr_warn ! (
883905 "Fixups oob {} {} {} {}" ,
884- fixup . target_offset ,
906+ fixup_offset ,
885907 end_of_previous_fixup,
886908 offset_end,
887909 target_offset_end
@@ -890,13 +912,13 @@ impl Thread {
890912 }
891913
892914 let copy_off = end_of_previous_fixup;
893- let copy_len = fixup . target_offset - end_of_previous_fixup;
915+ let copy_len = fixup_offset - end_of_previous_fixup;
894916 if let Err ( err) = alloc. copy_into ( & mut reader, copy_off, copy_len) {
895917 pr_warn ! ( "Failed copying into alloc: {:?}" , err) ;
896918 return Err ( err. into ( ) ) ;
897919 }
898- if fixup . skip == 0 {
899- let res = alloc. write :: < u64 > ( fixup . target_offset , & fixup . pointer_value ) ;
920+ if let PointerFixupEntry :: Fixup { pointer_value , .. } = fixup {
921+ let res = alloc. write :: < u64 > ( fixup_offset , pointer_value) ;
900922 if let Err ( err) = res {
901923 pr_warn ! ( "Failed copying ptr into alloc: {:?}" , err) ;
902924 return Err ( err. into ( ) ) ;
@@ -949,25 +971,30 @@ impl Thread {
949971
950972 let data_size = trd. data_size . try_into ( ) . map_err ( |_| EINVAL ) ?;
951973 let aligned_data_size = ptr_align ( data_size) . ok_or ( EINVAL ) ?;
952- let offsets_size = trd. offsets_size . try_into ( ) . map_err ( |_| EINVAL ) ?;
953- let aligned_offsets_size = ptr_align ( offsets_size) . ok_or ( EINVAL ) ?;
954- let buffers_size = tr. buffers_size . try_into ( ) . map_err ( |_| EINVAL ) ?;
955- let aligned_buffers_size = ptr_align ( buffers_size) . ok_or ( EINVAL ) ?;
974+ let offsets_size: usize = trd. offsets_size . try_into ( ) . map_err ( |_| EINVAL ) ?;
975+ let buffers_size: usize = tr. buffers_size . try_into ( ) . map_err ( |_| EINVAL ) ?;
956976 let aligned_secctx_size = match secctx. as_ref ( ) {
957977 Some ( ( _offset, ctx) ) => ptr_align ( ctx. len ( ) ) . ok_or ( EINVAL ) ?,
958978 None => 0 ,
959979 } ;
960980
981+ if !is_aligned ( offsets_size, size_of :: < u64 > ( ) ) {
982+ return Err ( EINVAL . into ( ) ) ;
983+ }
984+ if !is_aligned ( buffers_size, size_of :: < u64 > ( ) ) {
985+ return Err ( EINVAL . into ( ) ) ;
986+ }
987+
961988 // This guarantees that at least `sizeof(usize)` bytes will be allocated.
962989 let len = usize:: max (
963990 aligned_data_size
964- . checked_add ( aligned_offsets_size )
965- . and_then ( |sum| sum. checked_add ( aligned_buffers_size ) )
991+ . checked_add ( offsets_size )
992+ . and_then ( |sum| sum. checked_add ( buffers_size ) )
966993 . and_then ( |sum| sum. checked_add ( aligned_secctx_size) )
967994 . ok_or ( ENOMEM ) ?,
968- size_of :: < usize > ( ) ,
995+ size_of :: < u64 > ( ) ,
969996 ) ;
970- let secctx_off = aligned_data_size + aligned_offsets_size + aligned_buffers_size ;
997+ let secctx_off = aligned_data_size + offsets_size + buffers_size ;
971998 let mut alloc =
972999 match to_process. buffer_alloc ( debug_id, len, is_oneway, self . process . task . pid ( ) ) {
9731000 Ok ( alloc) => alloc,
@@ -999,13 +1026,13 @@ impl Thread {
9991026 }
10001027
10011028 let offsets_start = aligned_data_size;
1002- let offsets_end = aligned_data_size + aligned_offsets_size ;
1029+ let offsets_end = aligned_data_size + offsets_size ;
10031030
10041031 // This state is used for BINDER_TYPE_PTR objects.
10051032 let sg_state = sg_state. insert ( ScatterGatherState {
10061033 unused_buffer_space : UnusedBufferSpace {
10071034 offset : offsets_end,
1008- limit : len ,
1035+ limit : offsets_end + buffers_size ,
10091036 } ,
10101037 sg_entries : KVec :: new ( ) ,
10111038 ancestors : KVec :: new ( ) ,
@@ -1014,12 +1041,16 @@ impl Thread {
10141041 // Traverse the objects specified.
10151042 let mut view = AllocationView :: new ( & mut alloc, data_size) ;
10161043 for ( index, index_offset) in ( offsets_start..offsets_end)
1017- . step_by ( size_of :: < usize > ( ) )
1044+ . step_by ( size_of :: < u64 > ( ) )
10181045 . enumerate ( )
10191046 {
1020- let offset = view. alloc . read ( index_offset) ?;
1047+ let offset: usize = view
1048+ . alloc
1049+ . read :: < u64 > ( index_offset) ?
1050+ . try_into ( )
1051+ . map_err ( |_| EINVAL ) ?;
10211052
1022- if offset < end_of_previous_object {
1053+ if offset < end_of_previous_object || ! is_aligned ( offset , size_of :: < u32 > ( ) ) {
10231054 pr_warn ! ( "Got transaction with invalid offset." ) ;
10241055 return Err ( EINVAL . into ( ) ) ;
10251056 }
@@ -1051,7 +1082,7 @@ impl Thread {
10511082 }
10521083
10531084 // Update the indexes containing objects to clean up.
1054- let offset_after_object = index_offset + size_of :: < usize > ( ) ;
1085+ let offset_after_object = index_offset + size_of :: < u64 > ( ) ;
10551086 view. alloc
10561087 . set_info_offsets ( offsets_start..offset_after_object) ;
10571088 }
0 commit comments