1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
From 8915bd22570ee608907f1b88a68e587d17813812 Mon Sep 17 00:00:00 2001
From: Micah Snyder <micasnyd@cisco.com>
Date: Tue, 16 Jul 2024 11:22:05 -0400
Subject: [PATCH] Fix possible out of bounds read in PDF parser
The `find_length()` function in the PDF parser incorrectly assumes that
objects found are located in the main PDF file map, and fails to take
into account whether the objects were in fact found in extracted PDF
object streams. The resulting pointer is then invalid and may be an out
of bounds read.
This issue was found by OSS-Fuzz.
This fix checks if the object is from an object stream, and then
calculates the pointer based on the start of the object stream instead
of based on the start of the PDF.
I've also added extra checks to verify the calculated pointer and object
size are within the stream (or PDF file map). I'm not entirely sure this
is necessary, but better safe than sorry.
Fixes: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=69617
Upstream-Status: Backport [https://github.com/Cisco-Talos/clamav/commit/8915bd22570ee608907f1b88a68e587d17813812]
CVE: CVE-2024-20505
Signed-off-by: Hitendra Prajapati <hprajapati@mvista.com>
---
libclamav/pdf.c | 45 +++++++++++++++++++++++++++++++++++++++------
libclamav/pdfng.c | 5 +++++
2 files changed, 44 insertions(+), 6 deletions(-)
diff --git a/libclamav/pdf.c b/libclamav/pdf.c
index 01f32e07a..40eea19eb 100644
--- a/libclamav/pdf.c
+++ b/libclamav/pdf.c
@@ -1009,8 +1009,26 @@ static size_t find_length(struct pdf_struct *pdf, struct pdf_obj *obj, const cha
return 0;
}
- indirect_obj_start = pdf->map + obj->start;
- bytes_remaining = pdf->size - obj->start;
+ if (NULL == obj->objstm) {
+ indirect_obj_start = (const char *)(obj->start + pdf->map);
+
+ if (!CLI_ISCONTAINED(pdf->map, pdf->size, indirect_obj_start, obj->size)) {
+ cli_dbgmsg("find_length: indirect object found, but not contained in PDF\n");
+ return 0;
+ }
+
+ bytes_remaining = pdf->size - obj->start;
+
+ } else {
+ indirect_obj_start = (const char *)(obj->start + obj->objstm->streambuf);
+
+ if (!CLI_ISCONTAINED(obj->objstm->streambuf, obj->objstm->streambuf_len, indirect_obj_start, obj->size)) {
+ cli_dbgmsg("find_length: indirect object found, but not contained in PDF streambuf\n");
+ return 0;
+ }
+
+ bytes_remaining = obj->objstm->streambuf_len - obj->start;
+ }
/* Ok so we found the indirect object, lets read the value. */
index = pdf_nextobject(indirect_obj_start, bytes_remaining);
@@ -3093,15 +3111,30 @@ void pdf_handle_enc(struct pdf_struct *pdf)
obj = find_obj(pdf, pdf->objs[0], pdf->enc_objid);
if (!obj) {
- cli_dbgmsg("pdf_handle_enc: can't find encrypted object %d %d\n", pdf->enc_objid >> 8, pdf->enc_objid & 0xff);
- noisy_warnmsg("pdf_handle_enc: can't find encrypted object %d %d\n", pdf->enc_objid >> 8, pdf->enc_objid & 0xff);
+ cli_dbgmsg("pdf_handle_enc: can't find encryption object %d %d\n", pdf->enc_objid >> 8, pdf->enc_objid & 0xff);
+ noisy_warnmsg("pdf_handle_enc: can't find encryption object %d %d\n", pdf->enc_objid >> 8, pdf->enc_objid & 0xff);
return;
}
len = obj->size;
- q = (obj->objstm) ? (const char *)(obj->start + obj->objstm->streambuf)
- : (const char *)(obj->start + pdf->map);
+ if (NULL == obj->objstm) {
+ q = (const char *)(obj->start + pdf->map);
+
+ if (!CLI_ISCONTAINED(pdf->map, pdf->size, q, len)) {
+ cli_dbgmsg("pdf_handle_enc: encryption object found, but not contained in PDF\n");
+ noisy_warnmsg("pdf_handle_enc: encryption object found, but not contained in PDF\n");
+ return;
+ }
+ } else {
+ q = (const char *)(obj->start + obj->objstm->streambuf);
+
+ if (!CLI_ISCONTAINED(obj->objstm->streambuf, obj->objstm->streambuf_len, q, len)) {
+ cli_dbgmsg("pdf_handle_enc: encryption object found, but not contained in PDF streambuf\n");
+ noisy_warnmsg("pdf_handle_enc: encryption object found, but not contained in PDF streambuf\n");
+ return;
+ }
+ }
O = U = UE = StmF = StrF = EFF = NULL;
do {
diff --git a/libclamav/pdfng.c b/libclamav/pdfng.c
index a5daa2891..977a95e4d 100644
--- a/libclamav/pdfng.c
+++ b/libclamav/pdfng.c
@@ -450,6 +450,11 @@ char *pdf_parse_string(struct pdf_struct *pdf, struct pdf_obj *obj, const char *
if (!(newobj))
return NULL;
+ if (!CLI_ISCONTAINED(pdf->map, pdf->size, newobj->start, newobj->size)) {
+ cli_dbgmsg("pdf_parse_string: object not contained in PDF\n");
+ return NULL;
+ }
+
if (newobj == obj)
return NULL;
--
2.25.1
|