Skip to content

Commit

Permalink
test: add benchmark with whatthepatch parse_patch
Browse files Browse the repository at this point in the history
Signed-off-by: jingfelix <jingfelix@outlook.com>
  • Loading branch information
jingfelix committed Dec 17, 2024
1 parent 0318e20 commit fb5117f
Show file tree
Hide file tree
Showing 130 changed files with 13,269 additions and 18 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,6 @@ cython_debug/
kernel/
patches/

*.patch
.pdm-python

.vscode
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,36 @@ Modern patch, written in Python.

## Usage

The following commands are supported:

### apply

Apply a patch to target files.

```shell
patche apply <patch-file>
```

Options:
- `-R, --reverse`: Assume patches were created with old and new files swapped
- `-F, --fuzz LINES`: Set the fuzz factor to LINES for inexact matching

### show

Show details of a patch file.

```shell
patche show <patch-file>
```

### settings

Display current configuration.

```shell
patche settings
```

## Config

`patche` loads the configuration from a file named `.patche.env` in `$HOME`.
Expand Down
19 changes: 15 additions & 4 deletions pdm.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ dependencies = [
"typer[all]>=0.9.0",
"pydantic>=2.5.3",
"pydantic-settings>=2.2.1",
"whatthepatch-pydantic==1.0.6a2",
"whatthepatch-pydantic==1.0.6a3",
]
requires-python = ">=3.10"
readme = "README.md"
Expand All @@ -28,4 +28,5 @@ distribution = true
[tool.pdm.dev-dependencies]
dev = [
"viztracer>=0.16.3",
"whatthepatch>=1.0.7",
]
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ shellingham==1.5.4
typer[all]==0.15.1
typing-extensions==4.12.2
viztracer==1.0.0
whatthepatch-pydantic==1.0.6a2
whatthepatch==1.0.7
whatthepatch-pydantic==1.0.6a3
19 changes: 15 additions & 4 deletions src/Patche/commands/apply.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,21 @@

@app.command()
def apply(
# filename: str,
patch_path: str,
reverse: Annotated[bool, typer.Option("-R", "--reverse")] = False,
fuzz: Annotated[int, typer.Option("-F", "--fuzz")] = 0,
patch_path: Annotated[str, typer.Argument(help="Path to the patch file")],
reverse: Annotated[
bool,
typer.Option(
"-R",
"--reverse",
help="Assume patches were created with old and new files swapped.",
),
],
fuzz: Annotated[
int,
typer.Option(
"-F", "--fuzz", help="Set the fuzz factor to LINES for inexact matching."
),
] = 0,
):
"""
Apply a patch to a file.
Expand Down
6 changes: 4 additions & 2 deletions src/Patche/commands/show.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import os
from typing import Annotated

import typer
from rich.console import Console
from rich.table import Table

Expand All @@ -8,9 +10,9 @@


@app.command()
def show(filename: str):
def show(filename: Annotated[str, typer.Argument(help="Path to the patch file")]):
"""
Show detail of a patch file.
Show details of a patch file.
"""
if not os.path.exists(filename):
logger.error(f"Warning: {filename} not found!")
Expand Down
6 changes: 3 additions & 3 deletions src/Patche/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
from typing import Optional

from pydantic import BaseModel
from whatthepatch.model import Change
from whatthepatch.model import Diff as WTPDiff
from whatthepatch.model import Header
from whatthepatch_pydantic.model import Change
from whatthepatch_pydantic.model import Diff as WTPDiff
from whatthepatch_pydantic.model import Header


class Line(BaseModel):
Expand Down
4 changes: 2 additions & 2 deletions src/Patche/utils/parse.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import re

from whatthepatch import parse_patch as wtp_parse_patch
from whatthepatch.model import Diff as WTPDiff
from whatthepatch_pydantic import parse_patch as wtp_parse_patch
from whatthepatch_pydantic.model import Diff as WTPDiff

from Patche.config import settings
from Patche.model import Change, Diff, Hunk, Patch
Expand Down
126 changes: 126 additions & 0 deletions tests/bench_parse.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import logging
import os
import time

from rich.console import Console
from rich.logging import RichHandler
from rich.table import Table

logging.basicConfig(
level="INFO",
format="%(message)s",
datefmt="[%X]",
handlers=[RichHandler(markup=True)],
)

logger = logging.getLogger(__name__)


def bench_parse():

# 创建表格
table = Table(title="Benchmark Results")
table.add_column("File Name", style="cyan")
table.add_column("parse_patch Time", style="green")
table.add_column("parse_patch_patche Time", style="green")
table.add_column("parse_patch_pydantic Time", style="green")
table.add_column("Time Difference patche", style="yellow")
table.add_column("Percentage", style="red")
table.add_column("Time Difference pydantic", style="yellow")
table.add_column("Percentage", style="red")

from whatthepatch import parse_patch
from whatthepatch.patch import diffobj
from whatthepatch_pydantic import parse_patch as parse_patch_pydantic
from whatthepatch_pydantic.patch import Diff as Diff_pydantic

from Patche.model import Diff
from Patche.utils.parse import parse_patch as parse_patch_patche

time_differences = []
time_differences_pydantic = []

time_diffes = []
time_diffes_patche = []
time_diffes_pydantic = []

percentage_diffs_patche = []
percentage_diffs_pydantic = []

for patch_file in os.listdir("tests/cases"):
with open(f"tests/cases/{patch_file}", "r") as f:
patch = f.read()

try:
st = time.time()
diffes: list[diffobj] = []
for diff in parse_patch(patch):
diffes.append(diff)
parse_time = time.time() - st

st = time.time()
diffes_patche: list[Diff] = []
for diff in parse_patch_patche(patch).diff:
diffes_patche.append(diff)
parse_patche_time = time.time() - st

st = time.time()
diffes_pydantic: list[Diff_pydantic] = []
for diff in parse_patch_pydantic(patch):
diffes_pydantic.append(diff)
parse_pydantic_time = time.time() - st

time_diff = parse_patche_time - parse_time
percentage = (parse_patche_time / parse_time - 1) * 100

time_diff_pydantic = parse_pydantic_time - parse_time
percentage_pydantic = (parse_pydantic_time / parse_time - 1) * 100

# 添加数据到表格
table.add_row(
patch_file,
f"{parse_time:.8f}s",
f"{parse_patche_time:.8f}s",
f"{parse_pydantic_time:.8f}s",
f"{time_diff:.8f}s",
f"{percentage:+.2f}%",
f"{time_diff_pydantic:.8f}s",
f"{percentage_pydantic:+.2f}%",
)

time_differences.append(time_diff)
time_differences_pydantic.append(time_diff_pydantic)

percentage_diffs_patche.append(percentage)
percentage_diffs_pydantic.append(percentage_pydantic)

time_diffes.append(parse_time)
time_diffes_patche.append(parse_patche_time)
time_diffes_pydantic.append(parse_pydantic_time)

assert len(diffes) == len(diffes_patche)
for d1, d2 in zip(diffes, diffes_patche):
assert len(d1.changes) == len(d2.changes)

except Exception as e:
logger.error(f"Error in {patch_file}")

# 添加统计信息到表格
table.add_row(
"Average",
f"{sum(time_diffes)/len(time_diffes):.8f}s",
f"{sum(time_diffes_patche)/len(time_diffes_patche):.8f}s",
f"{sum(time_diffes_pydantic)/len(time_diffes_pydantic):.8f}s",
f"{sum(time_differences) / len(time_differences):.8f}s",
f"{sum(percentage_diffs_patche) / len(percentage_diffs_patche):+.2f}%",
f"{sum(time_differences_pydantic)/len(time_differences_pydantic):.8f}s",
f"{sum(percentage_diffs_pydantic)/len(percentage_diffs_pydantic):+.2f}%",
)

# 显示表格
console = Console()
console.print(table)


if __name__ == "__main__":
bench_parse()
48 changes: 48 additions & 0 deletions tests/cases/CVE-2017-11176.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
From f991af3daabaecff34684fd51fac80319d1baad1 Mon Sep 17 00:00:00 2001
From: Cong Wang <xiyou.wangcong@gmail.com>
Date: Sun, 9 Jul 2017 13:19:55 -0700
Subject: mqueue: fix a use-after-free in sys_mq_notify()

The retry logic for netlink_attachskb() inside sys_mq_notify()
is nasty and vulnerable:

1) The sock refcnt is already released when retry is needed
2) The fd is controllable by user-space because we already
release the file refcnt

so we when retry but the fd has been just closed by user-space
during this small window, we end up calling netlink_detachskb()
on the error path which releases the sock again, later when
the user-space closes this socket a use-after-free could be
triggered.

Setting 'sock' to NULL here should be sufficient to fix it.

Reported-by: GeneBlue <geneblue.mail@gmail.com>
Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Manfred Spraul <manfred@colorfullife.com>
Cc: stable@kernel.org
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
---
ipc/mqueue.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index c9ff943f19abc..eb1391b52c6f8 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -1270,8 +1270,10 @@ retry:

timeo = MAX_SCHEDULE_TIMEOUT;
ret = netlink_attachskb(sock, nc, &timeo, NULL);
- if (ret == 1)
+ if (ret == 1) {
+ sock = NULL;
goto retry;
+ }
if (ret) {
sock = NULL;
nc = NULL;
--
cgit
48 changes: 48 additions & 0 deletions tests/cases/CVE-2017-16995.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
From 95a762e2c8c942780948091f8f2a4f32fce1ac6f Mon Sep 17 00:00:00 2001
From: Jann Horn <jannh@google.com>
Date: Mon, 18 Dec 2017 20:11:54 -0800
Subject: bpf: fix incorrect sign extension in check_alu_op()

Distinguish between
BPF_ALU64|BPF_MOV|BPF_K (load 32-bit immediate, sign-extended to 64-bit)
and BPF_ALU|BPF_MOV|BPF_K (load 32-bit immediate, zero-padded to 64-bit);
only perform sign extension in the first case.

Starting with v4.14, this is exploitable by unprivileged users as long as
the unprivileged_bpf_disabled sysctl isn't set.

Debian assigned CVE-2017-16995 for this issue.

v3:
- add CVE number (Ben Hutchings)

Fixes: 484611357c19 ("bpf: allow access into map value arrays")
Signed-off-by: Jann Horn <jannh@google.com>
Acked-by: Edward Cree <ecree@solarflare.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
---
kernel/bpf/verifier.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 625e358ca765e..c086010ae51ed 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -2408,7 +2408,13 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn)
* remember the value we stored into this reg
*/
regs[insn->dst_reg].type = SCALAR_VALUE;
- __mark_reg_known(regs + insn->dst_reg, insn->imm);
+ if (BPF_CLASS(insn->code) == BPF_ALU64) {
+ __mark_reg_known(regs + insn->dst_reg,
+ insn->imm);
+ } else {
+ __mark_reg_known(regs + insn->dst_reg,
+ (u32)insn->imm);
+ }
}

} else if (opcode > BPF_END) {
--
cgit
Loading

0 comments on commit fb5117f

Please sign in to comment.