Skip to content

Commit e1aac0b

Browse files
committed
Add InvokePermission attribute when RequireOwnership is defined
1 parent a45d5f7 commit e1aac0b

File tree

3 files changed

+55
-39
lines changed

3 files changed

+55
-39
lines changed

com.unity.netcode.gameobjects/Editor/CodeGen/NetworkBehaviourILPP.cs

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,7 @@ private void CreateNetworkVariableTypeInitializers(AssemblyDefinition assembly,
470470
private FieldReference m_UniversalRpcParams_Receive_SenderClientId_FieldRef;
471471
private TypeReference m_UniversalRpcParams_TypeRef;
472472
private TypeReference m_ClientRpcParams_TypeRef;
473+
private TypeReference m_RpcInvokePermissions_TypeRef;
473474
private MethodReference m_NetworkVariableSerializationTypes_InitializeSerializer_UnmanagedByMemcpy_MethodRef;
474475
private MethodReference m_NetworkVariableSerializationTypes_InitializeSerializer_UnmanagedByMemcpyArray_MethodRef;
475476
#if UNITY_NETCODE_NATIVE_COLLECTION_SUPPORT
@@ -656,6 +657,7 @@ private bool ImportReferences(ModuleDefinition moduleDefinition, string[] assemb
656657
TypeDefinition serverRpcParamsTypeDef = null;
657658
TypeDefinition clientRpcParamsTypeDef = null;
658659
TypeDefinition universalRpcParamsTypeDef = null;
660+
TypeDefinition rpcInvokePermissionTypeDef = null;
659661
TypeDefinition fastBufferWriterTypeDef = null;
660662
TypeDefinition fastBufferReaderTypeDef = null;
661663
TypeDefinition networkVariableSerializationTypesTypeDef = null;
@@ -717,6 +719,12 @@ private bool ImportReferences(ModuleDefinition moduleDefinition, string[] assemb
717719
continue;
718720
}
719721

722+
if (rpcInvokePermissionTypeDef == null && netcodeTypeDef.Name == nameof(RpcInvokePermission))
723+
{
724+
rpcInvokePermissionTypeDef = netcodeTypeDef;
725+
continue;
726+
}
727+
720728
if (fastBufferWriterTypeDef == null && netcodeTypeDef.Name == nameof(FastBufferWriter))
721729
{
722730
fastBufferWriterTypeDef = netcodeTypeDef;
@@ -942,6 +950,7 @@ private bool ImportReferences(ModuleDefinition moduleDefinition, string[] assemb
942950
}
943951

944952
m_ClientRpcParams_TypeRef = moduleDefinition.ImportReference(clientRpcParamsTypeDef);
953+
m_RpcInvokePermissions_TypeRef = moduleDefinition.ImportReference(rpcInvokePermissionTypeDef);
945954
m_FastBufferWriter_TypeRef = moduleDefinition.ImportReference(fastBufferWriterTypeDef);
946955
m_FastBufferReader_TypeRef = moduleDefinition.ImportReference(fastBufferReaderTypeDef);
947956

@@ -1638,27 +1647,37 @@ private CustomAttribute CheckAndGetRpcAttribute(MethodDefinition methodDefinitio
16381647
return null;
16391648
}
16401649

1641-
bool hasRequireOwnership = false, hasInvokePermission = false;
1650+
var typeSystem = methodDefinition.Module.TypeSystem;
1651+
var hasInvokePermission = false;
16421652

1643-
foreach (var argument in rpcAttribute.Fields)
1653+
CustomAttributeNamedArgument? invokePermissionAttribute = null;
1654+
foreach(var argument in rpcAttribute.Fields)
16441655
{
16451656
switch (argument.Name)
16461657
{
16471658
case k_ServerRpcAttribute_RequireOwnership:
1648-
hasRequireOwnership = true;
1659+
var requireOwnership = argument.Argument.Type == typeSystem.Boolean && (bool)argument.Argument.Value;
1660+
var invokePermissionArg = new CustomAttributeArgument(m_RpcInvokePermissions_TypeRef, requireOwnership ? RpcInvokePermission.Owner : RpcInvokePermission.Everyone);
1661+
invokePermissionAttribute = new CustomAttributeNamedArgument( k_RpcAttribute_InvokePermission, invokePermissionArg);
16491662
break;
16501663
case k_RpcAttribute_InvokePermission:
16511664
hasInvokePermission = true;
16521665
break;
16531666
}
16541667
}
16551668

1656-
if (hasRequireOwnership && hasInvokePermission)
1669+
if (invokePermissionAttribute != null)
16571670
{
1658-
m_Diagnostics.AddError("Rpc attribute cannot declare both RequireOwnership and InvokePermission!");
1659-
return null;
1671+
if (hasInvokePermission)
1672+
{
1673+
m_Diagnostics.AddError($"{methodDefinition.Name} cannot declare both RequireOwnership and InvokePermission!");
1674+
return null;
1675+
}
1676+
1677+
rpcAttribute.Fields.Add(invokePermissionAttribute.Value);
16601678
}
16611679

1680+
16621681
// Checks for IsSerializable are moved to later as the check is now done by dynamically seeing if any valid
16631682
// serializer OR extension method exists for it.
16641683
return rpcAttribute;
@@ -2922,8 +2941,6 @@ private MethodDefinition GenerateStaticHandler(MethodDefinition methodDefinition
29222941
var processor = rpcHandler.Body.GetILProcessor();
29232942

29242943
var isServerRpc = rpcAttribute.AttributeType.FullName == CodeGenHelpers.ServerRpcAttribute_FullName;
2925-
var isClientRpc = rpcAttribute.AttributeType.FullName == CodeGenHelpers.ClientRpcAttribute_FullName;
2926-
var isGenericRpc = rpcAttribute.AttributeType.FullName == CodeGenHelpers.RpcAttribute_FullName;
29272944
var requireOwnership = true; // default value MUST be == `ServerRpcAttribute.RequireOwnership`
29282945
foreach (var attrField in rpcAttribute.Fields)
29292946
{

com.unity.netcode.gameobjects/Runtime/Core/NetworkBehaviour.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -335,7 +335,7 @@ internal FastBufferWriter __beginSendRpc(uint rpcMethodId, RpcParams rpcParams,
335335
throw new RpcException("This RPC can only be sent by the server.");
336336
}
337337

338-
if ((attributeParams.RequireOwnership || attributeParams.InvokePermission == RpcInvokePermission.Owner) && !IsOwner)
338+
if (attributeParams.InvokePermission == RpcInvokePermission.Owner && !IsOwner)
339339
{
340340
throw new RpcException("This RPC can only be sent by its owner.");
341341
}

com.unity.netcode.gameobjects/Tests/Runtime/Rpc/RpcInvocationTests.cs

Lines changed: 29 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ public RpcInvocationTests(NetworkTopologyTypes topologyType) : base(topologyType
2222

2323
private Dictionary<NetworkManager, InvokePermissionBehaviour> m_InvokeInstances = new();
2424

25+
// TODO: [CmbServiceTests] Enable once the CMB service fixes the client spoofing issue.
26+
protected override bool UseCMBService() => false;
27+
2528
protected override void OnServerAndClientsCreated()
2629
{
2730
m_Prefab = CreateNetworkObjectPrefab("RpcInvokePermissionTest");
@@ -188,42 +191,38 @@ public IEnumerator RpcInvokePermissionReceivingTests()
188191
yield return WaitForConditionOrTimeOut(AllExpectedCallsReceived);
189192
AssertOnTimeout("[InvokePermissions.Everyone] Incorrect Rpc calls received");
190193

191-
// DANGO-TODO: Fix the client spoofing issue
192-
if (!m_UseCmbService)
193-
{
194-
var firstClientInstance = m_InvokeInstances[firstClient];
195-
var secondClient = GetNonAuthorityNetworkManager(1);
196-
var thirdClient = GetNonAuthorityNetworkManager(2);
194+
var firstClientInstance = m_InvokeInstances[firstClient];
195+
var secondClient = GetNonAuthorityNetworkManager(1);
196+
var thirdClient = GetNonAuthorityNetworkManager(2);
197197

198-
firstClientInstance.ExpectedCallCounts[nameof(InvokePermissionBehaviour.TrackSenderIdRpc)] = 1;
198+
firstClientInstance.ExpectedCallCounts[nameof(InvokePermissionBehaviour.TrackSenderIdRpc)] = 1;
199199

200-
// Manually set the senderId to an incorrect value
201-
var secondClientInstance = m_InvokeInstances[secondClient];
202-
var bufferWriter = new FastBufferWriter(1024, Allocator.Temp);
203-
using (bufferWriter)
200+
// Manually set the senderId to an incorrect value
201+
var secondClientInstance = m_InvokeInstances[secondClient];
202+
var bufferWriter = new FastBufferWriter(1024, Allocator.Temp);
203+
using (bufferWriter)
204+
{
205+
var rpcMessage = new RpcMessage
204206
{
205-
var rpcMessage = new RpcMessage
207+
Metadata = new RpcMetadata
206208
{
207-
Metadata = new RpcMetadata
208-
{
209-
NetworkObjectId = secondClientInstance.NetworkObjectId,
210-
NetworkBehaviourId = secondClientInstance.NetworkBehaviourId,
211-
NetworkRpcMethodId = GetMethodIdFromMethodName(nameof(InvokePermissionBehaviour.TrackSenderIdRpc)),
212-
},
213-
// Set the sender to the third client
214-
SenderClientId = thirdClient.LocalClientId,
215-
WriteBuffer = bufferWriter
216-
};
217-
218-
// Send the message on the second client
219-
secondClientInstance.RpcTarget.Owner.Send(secondClientInstance, ref rpcMessage, NetworkDelivery.Reliable, new RpcParams());
220-
}
209+
NetworkObjectId = secondClientInstance.NetworkObjectId,
210+
NetworkBehaviourId = secondClientInstance.NetworkBehaviourId,
211+
NetworkRpcMethodId = GetMethodIdFromMethodName(nameof(InvokePermissionBehaviour.TrackSenderIdRpc)),
212+
},
213+
// Set the sender to the third client
214+
SenderClientId = thirdClient.LocalClientId,
215+
WriteBuffer = bufferWriter
216+
};
217+
218+
// Send the message on the second client
219+
secondClientInstance.RpcTarget.Owner.Send(secondClientInstance, ref rpcMessage, NetworkDelivery.Reliable, new RpcParams());
220+
}
221221

222-
yield return WaitForConditionOrTimeOut(AllExpectedCallsReceived);
223-
AssertOnTimeout("[SpoofedSenderId] Incorrect Rpc calls received");
222+
yield return WaitForConditionOrTimeOut(AllExpectedCallsReceived);
223+
AssertOnTimeout("[SpoofedSenderId] Incorrect Rpc calls received");
224224

225-
Assert.That(firstClientInstance.SenderIdReceived, Is.EqualTo(secondClient.LocalClientId), "Received spoofed sender id!");
226-
}
225+
Assert.That(firstClientInstance.SenderIdReceived, Is.EqualTo(secondClient.LocalClientId), "Received spoofed sender id!");
227226
}
228227

229228
private void SendUncheckedMessage(NetworkManager manager, InvokePermissionBehaviour invokePermissionsObject, string rpcMethodName)

0 commit comments

Comments
 (0)