From 1a21ebb75a84c4b53fbc27654099288120f3e49e Mon Sep 17 00:00:00 2001
From: Mike Higgins <mike@kayaker.net>
Date: Sun, 2 Aug 2020 09:56:03 -0700
Subject: [PATCH] Detect bad AO scripts and disable them

---
 OpenSim/Region/Framework/Scenes/ScenePresence.cs   | 13 ++++--
 .../Shared/Api/Implementation/LSL_Api.cs           | 46 ++++++++++++++++++++--
 2 files changed, 53 insertions(+), 6 deletions(-)

diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
index 1473ec4..016c37e 100644
--- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -6655,9 +6655,16 @@ namespace OpenSim.Region.Framework.Scenes
                 if ((dest.RootPart.ScriptEvents & ev) != 0)
                 {
                     CollidingMessage = CreateColliderArgs(dest.RootPart, colliders);
-
-                    if (CollidingMessage.Colliders.Count > 0)
-                        notify(dest.RootPart.LocalId, CollidingMessage);
+                        //Kayaker:DisableAO:  in OpenSim/Region/Framework/Scenes/ScenePresence.cs I detect bad AO scripts
+                       //and disable their timers, but they also hook into the collision events to use them
+                      //as fast timers. So I wrote a special value into an unused int in the SceneObjectPart
+                     //for the prim the script is in. If I find that set here, I refuse to call the collision events
+                    //for any script in that prim. I'm storing this in STATUS_ROTATE_X which is not used anywhere
+		    if (dest.RootPart.STATUS_ROTATE_X != 0x7FFE)
+		    {
+                        if (CollidingMessage.Colliders.Count > 0)
+                            notify(dest.RootPart.LocalId, CollidingMessage);
+		    }
                 }
             }
         }
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
index 4676569..7ea7c9a 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
@@ -11071,11 +11075,47 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
             UUID avID;
             if(!UUID.TryParse(id, out avID))
                 return new LSL_List();
-
             ScenePresence av = World.GetScenePresence(avID);
             if (av == null || av.IsChildAgent) // only if in the region
                 return new LSL_List();
-
+            IConfigSource config = m_ScriptEngine.ConfigSource;
+            string Badao=config.Configs["Startup"].GetString("DisableAOPolling");
+            if (!String.IsNullOrEmpty(Badao) && Badao.ToLower()=="true")
+            {
+                  //Kayaker: DisablePollingAO is false by default. If true I check for polling
+                 //I needed someplace to put the current time and the flg indicating a bad script
+                //I used two unused ints in the SceneObjectPart of the prim this script is in
+               //Ideally I should add new fields to the TaskInventoryItem class for this
+              //but this will do for testing.
+             //the STATUS_ROTATE_X value of 0x7FFE is used to prevent collision events in bad scripts
+            //if any scripts in the prim calls llGetAnimationList twice in half a second, it is a bad script
+                int  now = (int)((Util.GetTimeStampMS())/100.0);	//I only need to the nearest 10th of a second
+	        int  delta = now - m_host.STATUS_ROTATE_Y;
+	        if (delta<0)		//happens on clock or integer wrap around
+		    delta=10;		//let this one go
+//m_log.DebugFormat("[llGetAnimationList]: now={0},last={1},delta={2},script={3}",
+ //       now,m_host.STATUS_ROTATE_Y,delta,m_item.Name);
+
+                if (delta<5)		//they called me twice in 0.5 seconds? BAD SCRIPT!
+                {            //turn off their timer, this is probably an old SL style AO
+                    AsyncCommands.TimerPlugin.SetTimerEvent(m_host.LocalId, m_item.ItemID, 0.0);
+                          //if there is a message, send it to the owning avatar
+                    Badao=config.Configs["Startup"].GetString("DisableAOMessage");
+                    if (!String.IsNullOrEmpty(Badao))
+                    {
+                        World.SimChatBroadcast(Utils.StringToBytes(Badao+"\n" + " Prim Name='"+m_host.Name+"'; Script Name='" + m_item.Name+"'"),
+                                ChatTypeEnum.Owner, 0,
+                                m_host.AbsolutePosition, m_host.Name, m_host.UUID, false);
+                    }
+			//display the offending avatar, prim and script names
+		    m_log.DebugFormat("[DisableAO]: Owner='{0}'; Prim Name='{1}'; Script Name='{2}'; Delta={3}",
+                                                av.ControllingClient.Name,m_host.Name,m_item.Name,delta);
+		    m_host.STATUS_ROTATE_X = 0x7FFE;	//use this as a flag to indicate I don't like the prim this script is in
+                    return new LSL_List();
+                }
+                m_host.STATUS_ROTATE_Y = now;        //record the current time for next call
+//                m_host.STATUS_ROTATE_X = 0;		//indicate that I like this script again? Causes multiple messages.
+            }
             UUID[] anims;
             anims = av.Animator.GetAnimationArray();
             LSL_List l = new LSL_List();
-- 
2.7.4

