@@ -1102,12 +1102,27 @@ bool activity_get_sessions(uint32_t *session_entries, ActivitySession *sessions)
11021102DEFINE_SYSCALL (bool , sys_activity_get_sessions , uint32_t * session_entries ,
11031103 ActivitySession * sessions ) {
11041104 if (PRIVILEGE_WAS_ELEVATED ) {
1105- if (session_entries ) {
1106- syscall_assert_userspace_buffer (session_entries , sizeof (* session_entries ));
1105+ if (!session_entries ) {
1106+ // The implementation dereferences session_entries unconditionally.
1107+ return false;
1108+ }
1109+ syscall_assert_userspace_buffer (session_entries , sizeof (* session_entries ));
1110+ // Same pattern as sys_activity_get_minute_history: snapshot *session_entries
1111+ // so the inner activity_get_sessions can't race us into a larger memcpy than
1112+ // we validated, and reject sizes whose `requested * sizeof(*sessions)` would
1113+ // wrap and let a much-smaller validated buffer gate a much-larger write.
1114+ const uint32_t requested = * session_entries ;
1115+ if (requested > SIZE_MAX / sizeof (* sessions )) {
1116+ PBL_LOG_ERR ("session_entries=%" PRIu32 " would overflow size" , requested );
1117+ syscall_failed ();
11071118 }
11081119 if (sessions ) {
1109- syscall_assert_userspace_buffer (sessions , sizeof ( * sessions ) * ( * session_entries ));
1120+ syscall_assert_userspace_buffer (sessions , requested * sizeof ( * sessions ));
11101121 }
1122+ uint32_t entries_inout = requested ;
1123+ bool result = activity_get_sessions (& entries_inout , sessions );
1124+ * session_entries = entries_inout ;
1125+ return result ;
11111126 }
11121127
11131128 return activity_get_sessions (session_entries , sessions );
@@ -1176,7 +1191,24 @@ DEFINE_SYSCALL(bool, sys_activity_get_minute_history, HealthMinuteData *minute_d
11761191 if (PRIVILEGE_WAS_ELEVATED ) {
11771192 syscall_assert_userspace_buffer (utc_start , sizeof (* utc_start ));
11781193 syscall_assert_userspace_buffer (num_records , sizeof (* num_records ));
1179- syscall_assert_userspace_buffer (minute_data , * num_records * sizeof (HealthMinuteData ));
1194+ // Snapshot the requested count to a kernel-stack local so that:
1195+ // - the size computation below can't be tricked by an app racing the
1196+ // KernelBG callback to swap *num_records after we validated it (TOCTOU);
1197+ // - we can bound the multiplication against SIZE_MAX before performing it
1198+ // (otherwise `*num_records * sizeof(HealthMinuteData)` wraps in uint32_t
1199+ // and a tiny validated size would gate a much larger kernel write).
1200+ const uint32_t requested = * num_records ;
1201+ if (requested > SIZE_MAX / sizeof (HealthMinuteData )) {
1202+ PBL_LOG_ERR ("num_records=%" PRIu32 " would overflow size" , requested );
1203+ syscall_failed ();
1204+ }
1205+ syscall_assert_userspace_buffer (minute_data , requested * sizeof (HealthMinuteData ));
1206+ uint32_t records_inout = requested ;
1207+ time_t start_inout = * utc_start ;
1208+ bool result = activity_get_minute_history (minute_data , & records_inout , & start_inout );
1209+ * num_records = records_inout ;
1210+ * utc_start = start_inout ;
1211+ return result ;
11801212 }
11811213
11821214 return activity_get_minute_history (minute_data , num_records , utc_start );
0 commit comments