From 9e279e15c1d1c09949b6cd1b42153aff5334cfbc Mon Sep 17 00:00:00 2001 From: erikzhang Date: Wed, 18 Sep 2019 15:13:45 +0800 Subject: [PATCH 1/6] Add limits to `System.Runtime.Notify` and `System.Runtime.Log` --- neo/SmartContract/InteropService.cs | 44 +++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/neo/SmartContract/InteropService.cs b/neo/SmartContract/InteropService.cs index 7aa7fd7284..745e339f7a 100644 --- a/neo/SmartContract/InteropService.cs +++ b/neo/SmartContract/InteropService.cs @@ -14,6 +14,8 @@ using System.Linq; using System.Numerics; using System.Text; +using Array = Neo.VM.Types.Array; +using Boolean = Neo.VM.Types.Boolean; namespace Neo.SmartContract { @@ -22,6 +24,7 @@ public static partial class InteropService public const long GasPerByte = 100000; public const int MaxStorageKeySize = 64; public const int MaxStorageValueSize = ushort.MaxValue; + public const int MaxNotificationSize = 1024; private static readonly Dictionary methods = new Dictionary(); @@ -64,6 +67,39 @@ public static partial class InteropService public static readonly uint System_Storage_Delete = Register("System.Storage.Delete", Storage_Delete, 0_01000000, TriggerType.Application); public static readonly uint System_StorageContext_AsReadOnly = Register("System.StorageContext.AsReadOnly", StorageContext_AsReadOnly, 0_00000400, TriggerType.Application); + private static bool CheckItemForNotification(StackItem state) + { + int size = 0; + Queue items = new Queue(); + while (true) + { + switch (state) + { + case Array array: + foreach (StackItem item in array) + items.Enqueue(item); + break; + case Boolean _: + case ByteArray _: + case Integer _: + size += state.GetByteLength(); + break; + case InteropInterface _: + return false; + case Map map: + foreach (var pair in map) + { + size += pair.Key.GetByteLength(); + items.Enqueue(pair.Value); + } + break; + } + if (size > MaxNotificationSize) return false; + if (items.Count == 0) return true; + state = items.Dequeue(); + } + } + private static bool CheckStorageContext(ApplicationEngine engine, StorageContext context) { ContractState contract = engine.Snapshot.Contracts.TryGet(context.ScriptHash); @@ -200,13 +236,17 @@ private static bool Runtime_CheckWitness(ApplicationEngine engine) private static bool Runtime_Notify(ApplicationEngine engine) { - engine.SendNotification(engine.CurrentScriptHash, engine.CurrentContext.EvaluationStack.Pop()); + StackItem state = engine.CurrentContext.EvaluationStack.Pop(); + if (!CheckItemForNotification(state)) return false; + engine.SendNotification(engine.CurrentScriptHash, state); return true; } private static bool Runtime_Log(ApplicationEngine engine) { - string message = Encoding.UTF8.GetString(engine.CurrentContext.EvaluationStack.Pop().GetByteArray()); + byte[] state = engine.CurrentContext.EvaluationStack.Pop().GetByteArray(); + if (state.Length > MaxNotificationSize) return false; + string message = Encoding.UTF8.GetString(state); engine.SendLog(engine.CurrentScriptHash, message); return true; } From ee9b131fb5247ad733a57d47c9f01c3108cee2ae Mon Sep 17 00:00:00 2001 From: erikzhang Date: Wed, 18 Sep 2019 15:14:20 +0800 Subject: [PATCH 2/6] Change prices --- neo/SmartContract/InteropService.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/neo/SmartContract/InteropService.cs b/neo/SmartContract/InteropService.cs index 745e339f7a..6a1b266b96 100644 --- a/neo/SmartContract/InteropService.cs +++ b/neo/SmartContract/InteropService.cs @@ -35,8 +35,8 @@ public static partial class InteropService public static readonly uint System_Runtime_Platform = Register("System.Runtime.Platform", Runtime_Platform, 0_00000250, TriggerType.All); public static readonly uint System_Runtime_GetTrigger = Register("System.Runtime.GetTrigger", Runtime_GetTrigger, 0_00000250, TriggerType.All); public static readonly uint System_Runtime_CheckWitness = Register("System.Runtime.CheckWitness", Runtime_CheckWitness, 0_00030000, TriggerType.All); - public static readonly uint System_Runtime_Notify = Register("System.Runtime.Notify", Runtime_Notify, 0_00000250, TriggerType.All); - public static readonly uint System_Runtime_Log = Register("System.Runtime.Log", Runtime_Log, 0_00300000, TriggerType.All); + public static readonly uint System_Runtime_Notify = Register("System.Runtime.Notify", Runtime_Notify, 0_01000000, TriggerType.All); + public static readonly uint System_Runtime_Log = Register("System.Runtime.Log", Runtime_Log, 0_01000000, TriggerType.All); public static readonly uint System_Runtime_GetTime = Register("System.Runtime.GetTime", Runtime_GetTime, 0_00000250, TriggerType.Application); public static readonly uint System_Runtime_Serialize = Register("System.Runtime.Serialize", Runtime_Serialize, 0_00100000, TriggerType.All); public static readonly uint System_Runtime_Deserialize = Register("System.Runtime.Deserialize", Runtime_Deserialize, 0_00500000, TriggerType.All); From 89354176b2322439d500eb3df536cc1be4450134 Mon Sep 17 00:00:00 2001 From: erikzhang Date: Wed, 18 Sep 2019 17:57:50 +0800 Subject: [PATCH 3/6] prevent ddos --- neo/SmartContract/InteropService.cs | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/neo/SmartContract/InteropService.cs b/neo/SmartContract/InteropService.cs index 6a1b266b96..ff09b3da3a 100644 --- a/neo/SmartContract/InteropService.cs +++ b/neo/SmartContract/InteropService.cs @@ -70,14 +70,23 @@ public static partial class InteropService private static bool CheckItemForNotification(StackItem state) { int size = 0; - Queue items = new Queue(); + List items_checked = new List(); + Queue items_unchecked = new Queue(); while (true) { switch (state) { - case Array array: + case Struct array: foreach (StackItem item in array) - items.Enqueue(item); + items_unchecked.Enqueue(item); + break; + case Array array: + if (items_checked.All(p => !ReferenceEquals(p, array))) + { + items_checked.Add(array); + foreach (StackItem item in array) + items_unchecked.Enqueue(item); + } break; case Boolean _: case ByteArray _: @@ -87,16 +96,20 @@ private static bool CheckItemForNotification(StackItem state) case InteropInterface _: return false; case Map map: - foreach (var pair in map) + if (items_checked.All(p => !ReferenceEquals(p, map))) { - size += pair.Key.GetByteLength(); - items.Enqueue(pair.Value); + items_checked.Add(map); + foreach (var pair in map) + { + size += pair.Key.GetByteLength(); + items_unchecked.Enqueue(pair.Value); + } } break; } if (size > MaxNotificationSize) return false; - if (items.Count == 0) return true; - state = items.Dequeue(); + if (items_unchecked.Count == 0) return true; + state = items_unchecked.Dequeue(); } } From fc0db893f6f0919cc3bc963929b791508567f1ae Mon Sep 17 00:00:00 2001 From: Shargon Date: Tue, 15 Oct 2019 06:32:28 +0200 Subject: [PATCH 4/6] Add null type --- neo/SmartContract/InteropService.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/neo/SmartContract/InteropService.cs b/neo/SmartContract/InteropService.cs index ff09b3da3a..8b831d9a18 100644 --- a/neo/SmartContract/InteropService.cs +++ b/neo/SmartContract/InteropService.cs @@ -93,6 +93,8 @@ private static bool CheckItemForNotification(StackItem state) case Integer _: size += state.GetByteLength(); break; + case Null _: + break; case InteropInterface _: return false; case Map map: From 4e6132c126049bd046e89d595a133b9b4454a305 Mon Sep 17 00:00:00 2001 From: Shargon Date: Tue, 15 Oct 2019 06:33:22 +0200 Subject: [PATCH 5/6] Update NeoVM --- neo/neo.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/neo/neo.csproj b/neo/neo.csproj index 724090c004..b60b204915 100644 --- a/neo/neo.csproj +++ b/neo/neo.csproj @@ -30,7 +30,7 @@ - + From 88c5106f99f37e210ea64516ab2740851a13a69d Mon Sep 17 00:00:00 2001 From: Shargon Date: Tue, 15 Oct 2019 06:45:44 +0200 Subject: [PATCH 6/6] Add NULL prices --- neo/SmartContract/ApplicationEngine.OpCodePrices.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/neo/SmartContract/ApplicationEngine.OpCodePrices.cs b/neo/SmartContract/ApplicationEngine.OpCodePrices.cs index 271a76f935..b6b65b37da 100644 --- a/neo/SmartContract/ApplicationEngine.OpCodePrices.cs +++ b/neo/SmartContract/ApplicationEngine.OpCodePrices.cs @@ -87,6 +87,7 @@ partial class ApplicationEngine [OpCode.PUSHDATA2] = 13000, [OpCode.PUSHDATA4] = 110000, [OpCode.PUSHM1] = 30, + [OpCode.PUSHNULL] = 30, [OpCode.PUSH1] = 30, [OpCode.PUSH2] = 30, [OpCode.PUSH3] = 30, @@ -114,6 +115,7 @@ partial class ApplicationEngine [OpCode.DUPFROMALTSTACK] = 60, [OpCode.TOALTSTACK] = 60, [OpCode.FROMALTSTACK] = 60, + [OpCode.ISNULL] = 60, [OpCode.XDROP] = 400, [OpCode.XSWAP] = 60, [OpCode.XTUCK] = 400,