Skip to content

Commit 07b3e14

Browse files
authored
Merge pull request #63 from cscorley/pr-62
2 parents f274445 + 92c1bb6 commit 07b3e14

File tree

8 files changed

+254
-27
lines changed

8 files changed

+254
-27
lines changed

.github/workflows/build.yml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
strategy:
1717
matrix:
1818
os: [ubuntu-latest, macos-latest, windows-latest]
19-
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
19+
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
2020

2121
steps:
2222
- uses: actions/checkout@v4
@@ -56,6 +56,13 @@ jobs:
5656
- name: Test
5757
run: |
5858
pytest --doctest-modules --doctest-glob='*.rst' --junitxml=junit/test-results-${{ matrix.python-version }}-${{ matrix.os }}.xml
59+
if: ${{ matrix.os != 'macos-latest' }}
60+
61+
- name: Test macos-latest
62+
run: |
63+
export PATH="/opt/homebrew/opt/gpatch/libexec/gnubin:$PATH"
64+
pytest --doctest-modules --doctest-glob='*.rst' --junitxml=junit/test-results-${{ matrix.python-version }}-${{ matrix.os }}.xml
65+
if: ${{ matrix.os == 'macos-latest' }}
5966

6067
- name: Upload pytest test results
6168
uses: actions/upload-artifact@v4

HISTORY.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22

33
Nothing yet :)
44

5+
# 1.0.7
6+
7+
- PR #62 fix: incorrect regular expression matching diffcmd (Thanks, @jingfelix)
8+
- Support up to 3.13
9+
- Drop support up to 3.8
10+
511
# 1.0.6
612

713
- PR #60 Improve huge_patch test (Thanks, @arkamar)

pyproject.toml

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,29 @@
11
[project]
22
name = "whatthepatch"
3-
version = "1.0.6"
3+
version = "1.0.7"
44
maintainers = [{ name = "Christopher S. Corley", email = "[email protected]" }]
5-
requires-python = ">=3.8"
5+
requires-python = ">=3.9"
66
readme = "README.rst"
77
description = "A patch parsing and application library."
88
keywords = ["patch", "diff", "parser"]
99
classifiers = [
10-
"Development Status :: 5 - Production/Stable",
11-
"Intended Audience :: Developers",
12-
"Intended Audience :: Science/Research",
13-
"License :: OSI Approved :: MIT License",
14-
"Operating System :: OS Independent",
15-
"Programming Language :: Python :: 3 :: Only",
16-
"Programming Language :: Python :: 3",
17-
"Programming Language :: Python :: 3.8",
18-
"Programming Language :: Python :: 3.9",
19-
"Programming Language :: Python :: 3.10",
20-
"Programming Language :: Python :: 3.11",
21-
"Programming Language :: Python :: 3.12",
22-
"Programming Language :: Python :: Implementation :: CPython",
23-
"Topic :: Software Development :: Libraries :: Python Modules",
24-
"Topic :: Software Development :: Version Control",
25-
"Topic :: Software Development",
26-
"Topic :: Text Processing",
10+
"Development Status :: 5 - Production/Stable",
11+
"Intended Audience :: Developers",
12+
"Intended Audience :: Science/Research",
13+
"License :: OSI Approved :: MIT License",
14+
"Operating System :: OS Independent",
15+
"Programming Language :: Python :: 3 :: Only",
16+
"Programming Language :: Python :: 3",
17+
"Programming Language :: Python :: 3.9",
18+
"Programming Language :: Python :: 3.10",
19+
"Programming Language :: Python :: 3.11",
20+
"Programming Language :: Python :: 3.12",
21+
"Programming Language :: Python :: 3.13",
22+
"Programming Language :: Python :: Implementation :: CPython",
23+
"Topic :: Software Development :: Libraries :: Python Modules",
24+
"Topic :: Software Development :: Version Control",
25+
"Topic :: Software Development",
26+
"Topic :: Text Processing",
2727
]
2828

2929
[project.urls]

release.nix

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
{ lib, python3Packages, setuptools }:
22
with python3Packages;
3-
buildPythonPackage rec {
3+
buildPythonPackage {
44
pname = "whatthepatch";
5-
version = "1.0.6";
5+
version = "1.0.7";
66
format = "pyproject";
77
src = ./.;
88

src/whatthepatch/patch.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
# .+? was previously [^:\t\n\r\f\v]+
2020

2121
# general diff regex
22-
diffcmd_header = re.compile("^diff.* (.+) (.+)$")
22+
diffcmd_header = re.compile("^diff(?: .+)? (.+) (.+)$")
2323
unified_header_index = re.compile("^Index: (.+)$")
2424
unified_header_old_line = re.compile(r"^--- " + file_timestamp_str + "$")
2525
unified_header_new_line = re.compile(r"^\+\+\+ " + file_timestamp_str + "$")
@@ -68,7 +68,7 @@
6868
cvs_header_rcs = re.compile(r"^RCS file: (.+)(?:,\w{1}$|$)")
6969
cvs_header_timestamp = re.compile(r"(.+)\t([\d.]+)")
7070
cvs_header_timestamp_colon = re.compile(r":([\d.]+)\t(.+)")
71-
old_cvs_diffcmd_header = re.compile("^diff.* (.+):(.*) (.+):(.*)$")
71+
old_cvs_diffcmd_header = re.compile("^diff(?: .+)? (.+):(.*) (.+):(.*)$")
7272

7373

7474
def parse_patch(text):
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
? cvsdiff
2+
? model/org/eclipse/jdt/internal/debug/core/BreakMouseGrab.java
3+
Index: model/org/eclipse/jdt/internal/debug/core/JDIDebugPlugin.java
4+
===================================================================
5+
RCS file: /home/eclipse/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JDIDebugPlugin.java,v
6+
retrieving revision 1.34
7+
diff -u -p -r1.34 JDIDebugPlugin.java
8+
--- model/org/eclipse/jdt/internal/debug/core/JDIDebugPlugin.java 6 Jun 2002 20:33:46 -0000 1.34
9+
+++ model/org/eclipse/jdt/internal/debug/core/JDIDebugPlugin.java 16 Jul 2002 20:37:56 -0000
10+
@@ -61,6 +61,13 @@ public class JDIDebugPlugin extends Plug
11+
private boolean fTrace = false;
12+
13+
/**
14+
+ * On SWT/GTK applications, we need to drop
15+
+ * any mouse grabs when a breakpoint is hit
16+
+ * or the mouse is not usable.
17+
+ */
18+
+ private BreakMouseGrab breakMouseGrab;
19+
+
20+
+ /**
21+
* Returns whether the debug UI plug-in is in trace
22+
* mode.
23+
*
24+
@@ -117,6 +124,7 @@ public class JDIDebugPlugin extends Plug
25+
fBreakpointListeners = new ListenerList(5);
26+
getPluginPreferences().setDefault(JDIDebugModel.PREF_REQUEST_TIMEOUT, JDIDebugModel.DEF_REQUEST_TIMEOUT);
27+
getPluginPreferences().addPropertyChangeListener(this);
28+
+ breakMouseGrab = new BreakMouseGrab();
29+
}
30+
31+
/**
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
From 29e1dfcd5150097f32f34891c85a50d9ead19df3 Mon Sep 17 00:00:00 2001
2+
From: Lihong Kou <[email protected]>
3+
Date: Tue, 23 Jun 2020 20:28:41 +0800
4+
Subject: Bluetooth: add a mutex lock to avoid UAF in do_enale_set
5+
6+
[ Upstream commit f9c70bdc279b191da8d60777c627702c06e4a37d ]
7+
8+
In the case we set or free the global value listen_chan in
9+
different threads, we can encounter the UAF problems because
10+
the method is not protected by any lock, add one to avoid
11+
this bug.
12+
13+
BUG: KASAN: use-after-free in l2cap_chan_close+0x48/0x990
14+
net/bluetooth/l2cap_core.c:730
15+
Read of size 8 at addr ffff888096950000 by task kworker/1:102/2868
16+
17+
CPU: 1 PID: 2868 Comm: kworker/1:102 Not tainted 5.5.0-syzkaller #0
18+
Hardware name: Google Google Compute Engine/Google Compute Engine,
19+
BIOS Google 01/01/2011
20+
Workqueue: events do_enable_set
21+
Call Trace:
22+
__dump_stack lib/dump_stack.c:77 [inline]
23+
dump_stack+0x1fb/0x318 lib/dump_stack.c:118
24+
print_address_description+0x74/0x5c0 mm/kasan/report.c:374
25+
__kasan_report+0x149/0x1c0 mm/kasan/report.c:506
26+
kasan_report+0x26/0x50 mm/kasan/common.c:641
27+
__asan_report_load8_noabort+0x14/0x20 mm/kasan/generic_report.c:135
28+
l2cap_chan_close+0x48/0x990 net/bluetooth/l2cap_core.c:730
29+
do_enable_set+0x660/0x900 net/bluetooth/6lowpan.c:1074
30+
process_one_work+0x7f5/0x10f0 kernel/workqueue.c:2264
31+
worker_thread+0xbbc/0x1630 kernel/workqueue.c:2410
32+
kthread+0x332/0x350 kernel/kthread.c:255
33+
ret_from_fork+0x24/0x30 arch/x86/entry/entry_64.S:352
34+
35+
Allocated by task 2870:
36+
save_stack mm/kasan/common.c:72 [inline]
37+
set_track mm/kasan/common.c:80 [inline]
38+
__kasan_kmalloc+0x118/0x1c0 mm/kasan/common.c:515
39+
kasan_kmalloc+0x9/0x10 mm/kasan/common.c:529
40+
kmem_cache_alloc_trace+0x221/0x2f0 mm/slab.c:3551
41+
kmalloc include/linux/slab.h:555 [inline]
42+
kzalloc include/linux/slab.h:669 [inline]
43+
l2cap_chan_create+0x50/0x320 net/bluetooth/l2cap_core.c:446
44+
chan_create net/bluetooth/6lowpan.c:640 [inline]
45+
bt_6lowpan_listen net/bluetooth/6lowpan.c:959 [inline]
46+
do_enable_set+0x6a4/0x900 net/bluetooth/6lowpan.c:1078
47+
process_one_work+0x7f5/0x10f0 kernel/workqueue.c:2264
48+
worker_thread+0xbbc/0x1630 kernel/workqueue.c:2410
49+
kthread+0x332/0x350 kernel/kthread.c:255
50+
ret_from_fork+0x24/0x30 arch/x86/entry/entry_64.S:352
51+
52+
Freed by task 2870:
53+
save_stack mm/kasan/common.c:72 [inline]
54+
set_track mm/kasan/common.c:80 [inline]
55+
kasan_set_free_info mm/kasan/common.c:337 [inline]
56+
__kasan_slab_free+0x12e/0x1e0 mm/kasan/common.c:476
57+
kasan_slab_free+0xe/0x10 mm/kasan/common.c:485
58+
__cache_free mm/slab.c:3426 [inline]
59+
kfree+0x10d/0x220 mm/slab.c:3757
60+
l2cap_chan_destroy net/bluetooth/l2cap_core.c:484 [inline]
61+
kref_put include/linux/kref.h:65 [inline]
62+
l2cap_chan_put+0x170/0x190 net/bluetooth/l2cap_core.c:498
63+
do_enable_set+0x66c/0x900 net/bluetooth/6lowpan.c:1075
64+
process_one_work+0x7f5/0x10f0 kernel/workqueue.c:2264
65+
worker_thread+0xbbc/0x1630 kernel/workqueue.c:2410
66+
kthread+0x332/0x350 kernel/kthread.c:255
67+
ret_from_fork+0x24/0x30 arch/x86/entry/entry_64.S:352
68+
69+
The buggy address belongs to the object at ffff888096950000
70+
which belongs to the cache kmalloc-2k of size 2048
71+
The buggy address is located 0 bytes inside of
72+
2048-byte region [ffff888096950000, ffff888096950800)
73+
The buggy address belongs to the page:
74+
page:ffffea00025a5400 refcount:1 mapcount:0 mapping:ffff8880aa400e00 index:0x0
75+
flags: 0xfffe0000000200(slab)
76+
raw: 00fffe0000000200 ffffea00027d1548 ffffea0002397808 ffff8880aa400e00
77+
raw: 0000000000000000 ffff888096950000 0000000100000001 0000000000000000
78+
page dumped because: kasan: bad access detected
79+
80+
Memory state around the buggy address:
81+
ffff88809694ff00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
82+
ffff88809694ff80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
83+
>ffff888096950000: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
84+
^
85+
ffff888096950080: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
86+
ffff888096950100: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb
87+
==================================================================
88+
89+
Reported-by: [email protected]
90+
Signed-off-by: Lihong Kou <[email protected]>
91+
Signed-off-by: Marcel Holtmann <[email protected]>
92+
Signed-off-by: Sasha Levin <[email protected]>
93+
---
94+
net/bluetooth/6lowpan.c | 5 +++++
95+
1 file changed, 5 insertions(+)
96+
97+
diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c
98+
index 357475cceec61b..9a75f9b00b5129 100644
99+
--- a/net/bluetooth/6lowpan.c
100+
+++ b/net/bluetooth/6lowpan.c
101+
@@ -57,6 +57,7 @@ static bool enable_6lowpan;
102+
/* We are listening incoming connections via this channel
103+
*/
104+
static struct l2cap_chan *listen_chan;
105+
+static DEFINE_MUTEX(set_lock);
106+
107+
struct lowpan_peer {
108+
struct list_head list;
109+
@@ -1082,12 +1083,14 @@ static void do_enable_set(struct work_struct *work)
110+
111+
enable_6lowpan = set_enable->flag;
112+
113+
+ mutex_lock(&set_lock);
114+
if (listen_chan) {
115+
l2cap_chan_close(listen_chan, 0);
116+
l2cap_chan_put(listen_chan);
117+
}
118+
119+
listen_chan = bt_6lowpan_listen();
120+
+ mutex_unlock(&set_lock);
121+
122+
kfree(set_enable);
123+
}
124+
@@ -1139,11 +1142,13 @@ static ssize_t lowpan_control_write(struct file *fp,
125+
if (ret == -EINVAL)
126+
return ret;
127+
128+
+ mutex_lock(&set_lock);
129+
if (listen_chan) {
130+
l2cap_chan_close(listen_chan, 0);
131+
l2cap_chan_put(listen_chan);
132+
listen_chan = NULL;
133+
}
134+
+ mutex_unlock(&set_lock);
135+
136+
if (conn) {
137+
struct lowpan_peer *peer;
138+
--
139+
cgit 1.2.3-korg
140+

tests/test_patch.py

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1390,6 +1390,7 @@ def test_apache_attachment_2241(self):
13901390
self.assert_diffs_equal(results, expected)
13911391

13921392
def test_space_in_path_header(self):
1393+
# From https://bugzillaattachments.eclipsecontent.org/bugs/attachment.cgi?id=126343
13931394
with open("tests/casefiles/eclipse-attachment-126343.header") as f:
13941395
text = f.read()
13951396

@@ -1426,7 +1427,8 @@ def test_svn_mixed_line_ends(self):
14261427
self.assertEqual(results[0].header, expected_header)
14271428

14281429
def test_huge_patch(self):
1429-
text_parts = ["""diff --git a/huge.file b/huge.file
1430+
text_parts = [
1431+
"""diff --git a/huge.file b/huge.file
14301432
index 0000000..1111111 100644
14311433
--- a/huge.file
14321434
+++ a/huge.file
@@ -1438,9 +1440,10 @@ def test_huge_patch(self):
14381440
-44444444
14391441
+55555555
14401442
+66666666
1441-
"""]
1443+
"""
1444+
]
14421445
text_parts.extend("+" + hex(n) + "\n" for n in range(0, 1000000))
1443-
text = ''.join(text_parts)
1446+
text = "".join(text_parts)
14441447
start_time = time.time()
14451448
result = list(wtp.patch.parse_patch(text))
14461449
self.assertEqual(1, len(result))
@@ -1508,6 +1511,46 @@ def test_git_bin_patch_minline(self):
15081511
== "b07b94142cfce2094b5be04e9d30b653a7c63917"
15091512
)
15101513

1514+
def test_linux_29e1dfc(self):
1515+
with open(
1516+
"tests/casefiles/linux-29e1dfcd5150097f32f34891c85a50d9ead19df3.patch"
1517+
) as f:
1518+
text = f.read()
1519+
1520+
# testing we get to the diff
1521+
path = "net/bluetooth/6lowpan.c"
1522+
expected = headerobj(
1523+
index_path=None,
1524+
old_path=path,
1525+
old_version="357475cceec61b",
1526+
new_path=path,
1527+
new_version="9a75f9b00b5129",
1528+
)
1529+
1530+
results = list(wtp.patch.parse_patch(text))
1531+
self.assertEqual(len(results), 1)
1532+
self.assertEqual(results[0].header, expected)
1533+
1534+
def test_eclipse_cvsdiff(self):
1535+
# From https://bugzillaattachments.eclipsecontent.org/bugs/attachment.cgi?id=1701
1536+
with open("tests/casefiles/eclipse-attachment-1701.patch") as f:
1537+
text = f.read()
1538+
1539+
expected = headerobj(
1540+
index_path=(
1541+
"model/org/eclipse/jdt/internal/debug/core/JDIDebugPlugin.java"
1542+
),
1543+
old_path="model/org/eclipse/jdt/internal/debug/core/JDIDebugPlugin.java",
1544+
old_version="1.34",
1545+
new_path="model/org/eclipse/jdt/internal/debug/core/JDIDebugPlugin.java",
1546+
new_version="16 Jul 2002 20:37:56 -0000",
1547+
)
1548+
1549+
results = list(wtp.patch.parse_patch(text))
1550+
self.assertEqual(len(results), 1)
1551+
self.assertEqual(results[0].header, expected)
1552+
self.assertEqual(len(results[0].changes), 20)
1553+
15111554

15121555
if __name__ == "__main__":
15131556
unittest.main()

0 commit comments

Comments
 (0)