Repository: secdev/scapy

Issue:
After fuzzing the copied packet, the original packet is also modified
### Brief description
here's my code
```
from scapy.all import *

class TEST2(Packet):
    name = "TEST2"
    fields_desc = [
        ByteField("type2", 0x1),
    ]
    
class TEST(Packet):
    name = "TEST"
    fields_desc = [
        PacketListField("packlist", TEST2(), TEST2),
    ]
    
d1 = TEST()
d2 = d1.copy()

hexdump(d1)
fuzz(d2)
hexdump(d1)
```
The running results are different in python2 and python3.
In python3, after fuzzing d2 packet, d1 is modified.
```
usr@test:~/WorkSpace$ python3 test.py 
0000  01                                               .
0000  8A                                               .
```
In python2, after fuzzing d2 packet, d1 has not been modified.
```
usr@test:~/WorkSpace$ python2 test.py 
0000  01                                               .
0000  01                                               .
```
For PacketListField, the results of the copy() method running with python2 and python3 seem to be different.
I found the definition of do_copy() in fields.py
```
def do_copy(self, x):
    # type: (I) -> I
    if hasattr(x, "copy"):
        return x.copy()  # type: ignore
    if isinstance(x, list):
        x = x[:]  # type: ignore
        for i in range(len(x)):
            if isinstance(x[i], BasePacket):
                x[i] = x[i].copy()
    return x
```
In python3, the list data type has a copy attribute, ```hasattr(list, "copy") ```returns true.
```
usr@test:~/WorkSpace$ python3
Python 3.8.10 (default, Jun  2 2021, 10:49:15)
[GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> list = []
>>> hasattr(list, "copy")
True
>>>
```
In python2, the list data type has no copy attribute, ```hasattr(list, "copy") ```returns false.
```
usr@test:~/WorkSpace$ python2
Python 2.7.12 (default, Mar  1 2021, 11:38:31) 
[GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> list = []
>>> hasattr(list, "copy")
False
>>>
```
so I guess this is the reason why copy() method runs differently in python2 and python3.

### Scapy version

2.4.5

### Python version

3.8

### Operating system

Ubuntu 20.04

### Additional environment information

_No response_

### How to reproduce

see brief description

### Actual result

After fuzzing the copied packet, the original packet is modified.

### Expected result

After fuzzing the copied packet, the original packet has not been modified.

### Related resources

_No response_


Discussion:
Good catch! Will you mind providing a fix?

Resolving patch:
diff --git a/scapy/fields.py b/scapy/fields.py
--- a/scapy/fields.py
+++ b/scapy/fields.py
@@ -257,13 +257,14 @@ def getfield(self, pkt, s):
 
     def do_copy(self, x):
         # type: (I) -> I
-        if hasattr(x, "copy"):
-            return x.copy()  # type: ignore
         if isinstance(x, list):
             x = x[:]  # type: ignore
             for i in range(len(x)):
                 if isinstance(x[i], BasePacket):
                     x[i] = x[i].copy()
+            return x  # type: ignore
+        if hasattr(x, "copy"):
+            return x.copy()  # type: ignore
         return x
 
     def __repr__(self):


Test patch:
diff --git a/test/regression.uts b/test/regression.uts
--- a/test/regression.uts
+++ b/test/regression.uts
@@ -3955,6 +3955,24 @@ assert(len(a.list) == 1)
 b = TestPacket()
 assert(len(b.list) == 0)
 
+= Test PacketListField deepcopy
+class SubPacket(Packet):
+    name = "SubPacket"
+    fields_desc = [
+        ByteField("mem", 1),
+    ]
+
+class TestPacket(Packet):
+    name = "TestPacket"
+    fields_desc = [
+        PacketListField("packlist", SubPacket(), SubPacket),
+    ]
+
+a = TestPacket()
+b = a.copy()
+fuzz(b)
+assert(a.packlist[0].mem == 1)
+
 = PacketField
 
 class InnerPacket(Packet):