Repository: secdev/scapy

Issue:
Corner case in scapy.utils.corrupt_bits()
#### Brief description
Function `scapy.utils.corrupt_bits()` can't flip less than one bit, even on low percentages
<!-- describe the main issue in one sentence -->
<!-- if possible, describe what components / protocols could be affected by the issue (e.g. wrpcap() + IPv6, it is likely this also affects XXX) -->

#### Environment

-   Scapy version: `2.4.3`
-   Python version: `3.7.7`
-   Operating System: `Ubuntu 18.04 LTS`

<!-- if needed - further information to get a picture of your setup (e.g. a sketch of your network setup) -->

#### How to reproduce
Call `corrupt_bits("hello")` 5 times.
Call `corrupt_bits("hello", p=0.00001)` 5 times.
<!-- step-by-step explanation or a short script, may reference section 'Related resources' -->

#### Actual result
 You will see every time occurs a bit flip with default percentage of `p=0.01` and also with `p=0.00001`
<!-- dump results that outline the issue, please format your code -->

#### Expected result
It should be possible to get 0 bit flips (important in small strings):
https://github.com/secdev/scapy/blob/349259209d4f6292a9644e68a9aced300f32e623/scapy/utils.py#L910 should be altered to         `n = max(0, int(s_len * p))`

OR

https://github.com/secdev/scapy/blob/349259209d4f6292a9644e68a9aced300f32e623/scapy/utils.py#L906 should be altered to     `"""Flip a given percentage (at least one bit) or number of bits from a string"""`
<!-- describe the expected result and outline the difference to the actual one, could also be a screen shot (e.g. wireshark) -->

#### Related resources
<!-- traces / sample pcaps (stripped to the relevant frames), related standards, RFCs or other resources -->



Discussion:
Good catch.
I'd say this is "by design" and the doc should be updated. I would expect the function to at least do something on each call (?)
I expected it would calculate the percentage right. But I think it's possibly more useful if it stays like this with updated doc, because otherwise it would be a function which corrupts nothing on a lot of calls.
I searched for a function which corrupts bits with a given probability. It would be more useful for small packets (like my 6lowpan packets from #2716 ), but I think scapy has none like that. Maybe add an other parameter to implement bit error probability too?
@Chamaeleon- maybe you could in the first place submit a PR to update the doc (that we could merge before the next 2.4.4 release). Then, in open another issue (or submit a PR) for your bit error probability idea (which I think should help).
What do you think? 

Resolving patch:
diff --git a/scapy/utils.py b/scapy/utils.py
--- a/scapy/utils.py
+++ b/scapy/utils.py
@@ -891,7 +891,7 @@ def load_object(fname):
 
 @conf.commands.register
 def corrupt_bytes(s, p=0.01, n=None):
-    """Corrupt a given percentage or number of bytes from a string"""
+    """Corrupt a given percentage (at least one byte) or number of bytes from a string"""
     s = array.array("B", bytes_encode(s))
     s_len = len(s)
     if n is None:
@@ -903,7 +903,7 @@ def corrupt_bytes(s, p=0.01, n=None):
 
 @conf.commands.register
 def corrupt_bits(s, p=0.01, n=None):
-    """Flip a given percentage or number of bits from a string"""
+    """Flip a given percentage (at least one bit) or number of bits from a string"""
     s = array.array("B", bytes_encode(s))
     s_len = len(s) * 8
     if n is None:


Test patch: