aboutsummaryrefslogtreecommitdiffstats
path: root/main/libarchive/CVE-2015-2304.patch
blob: cb7be5f18cdbeaa8ba0096d4d48a3afbb5d7deb1 (plain)
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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
From 59357157706d47c365b2227739e17daba3607526 Mon Sep 17 00:00:00 2001
From: Alessandro Ghedini <alessandro@ghedini.me>
Date: Sun, 1 Mar 2015 12:07:45 +0100
Subject: [PATCH] Add ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS option

This fixes a directory traversal in the cpio tool.
---
 cpio/bsdcpio.1                           |  3 ++-
 cpio/cpio.c                              |  2 ++
 libarchive/archive.h                     |  2 ++
 libarchive/archive_write_disk.3          |  3 +++
 libarchive/archive_write_disk_posix.c    | 14 +++++++++++---
 libarchive/test/test_write_disk_secure.c | 23 +++++++++++++++++++++++
 6 files changed, 43 insertions(+), 4 deletions(-)

diff --git a/cpio/bsdcpio.1 b/cpio/bsdcpio.1
index f966aa0..e52546e 100644
--- a/cpio/bsdcpio.1
+++ b/cpio/bsdcpio.1
@@ -156,7 +156,8 @@ See above for description.
 .It Fl Fl insecure
 (i and p mode only)
 Disable security checks during extraction or copying.
-This allows extraction via symbolic links and path names containing
+This allows extraction via symbolic links, absolute paths,
+and path names containing
 .Sq ..
 in the name.
 .It Fl J , Fl Fl xz
diff --git a/cpio/cpio.c b/cpio/cpio.c
index 0acde11..b267e9b 100644
--- a/cpio/cpio.c
+++ b/cpio/cpio.c
@@ -171,6 +171,7 @@ main(int argc, char *argv[])
 	cpio->extract_flags |= ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER;
 	cpio->extract_flags |= ARCHIVE_EXTRACT_SECURE_SYMLINKS;
 	cpio->extract_flags |= ARCHIVE_EXTRACT_SECURE_NODOTDOT;
+	cpio->extract_flags |= ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS;
 	cpio->extract_flags |= ARCHIVE_EXTRACT_PERM;
 	cpio->extract_flags |= ARCHIVE_EXTRACT_FFLAGS;
 	cpio->extract_flags |= ARCHIVE_EXTRACT_ACL;
@@ -256,6 +257,7 @@ main(int argc, char *argv[])
 		case OPTION_INSECURE:
 			cpio->extract_flags &= ~ARCHIVE_EXTRACT_SECURE_SYMLINKS;
 			cpio->extract_flags &= ~ARCHIVE_EXTRACT_SECURE_NODOTDOT;
+			cpio->extract_flags &= ~ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS;
 			break;
 		case 'L': /* GNU cpio */
 			cpio->option_follow_links = 1;
diff --git a/libarchive/archive.h b/libarchive/archive.h
index 1f0fc38..ef635ac 100644
--- a/libarchive/archive.h
+++ b/libarchive/archive.h
@@ -649,6 +649,8 @@ __LA_DECL int archive_read_set_passphrase_callback(struct archive *,
 /* Default: Do not use HFS+ compression if it was not compressed. */
 /* This has no effect except on Mac OS v10.6 or later. */
 #define	ARCHIVE_EXTRACT_HFS_COMPRESSION_FORCED	(0x8000)
+/* Default: Do not reject entries with absolute paths */
+#define ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS (0x10000)
 
 __LA_DECL int archive_read_extract(struct archive *, struct archive_entry *,
 		     int flags);
diff --git a/libarchive/archive_write_disk.3 b/libarchive/archive_write_disk.3
index fa925cc..a2e7afa 100644
--- a/libarchive/archive_write_disk.3
+++ b/libarchive/archive_write_disk.3
@@ -177,6 +177,9 @@ The default is to not refuse such paths.
 Note that paths ending in
 .Pa ..
 always cause an error, regardless of this flag.
+.It Cm ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS
+Refuse to extract an absolute path.
+The default is to not refuse such paths.
 .It Cm ARCHIVE_EXTRACT_SPARSE
 Scan data for blocks of NUL bytes and try to recreate them with holes.
 This results in sparse files, independent of whether the archive format
diff --git a/libarchive/archive_write_disk_posix.c b/libarchive/archive_write_disk_posix.c
index ab3bdac..c1290eb 100644
--- a/libarchive/archive_write_disk_posix.c
+++ b/libarchive/archive_write_disk_posix.c
@@ -2509,8 +2509,9 @@ cleanup_pathname_win(struct archive_write_disk *a)
 /*
  * Canonicalize the pathname.  In particular, this strips duplicate
  * '/' characters, '.' elements, and trailing '/'.  It also raises an
- * error for an empty path, a trailing '..' or (if _SECURE_NODOTDOT is
- * set) any '..' in the path.
+ * error for an empty path, a trailing '..', (if _SECURE_NODOTDOT is
+ * set) any '..' in the path or (if ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS
+ * is set) if the path is absolute.
  */
 static int
 cleanup_pathname(struct archive_write_disk *a)
@@ -2529,8 +2530,15 @@ cleanup_pathname(struct archive_write_disk *a)
 	cleanup_pathname_win(a);
 #endif
 	/* Skip leading '/'. */
-	if (*src == '/')
+	if (*src == '/') {
+		if (a->flags & ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS) {
+			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+			                  "Path is absolute");
+			return (ARCHIVE_FAILED);
+		}
+
 		separator = *src++;
+	}
 
 	/* Scan the pathname one element at a time. */
 	for (;;) {
diff --git a/libarchive/test/test_write_disk_secure.c b/libarchive/test/test_write_disk_secure.c
index 31c5bfd..2c94206 100644
--- a/libarchive/test/test_write_disk_secure.c
+++ b/libarchive/test/test_write_disk_secure.c
@@ -178,6 +178,29 @@ DEFINE_TEST(test_write_disk_secure)
 	assert(S_ISDIR(st.st_mode));
 	archive_entry_free(ae);
 
+	/*
+	 * Without security checks, we should be able to
+	 * extract an absolute path.
+	 */
+	assert((ae = archive_entry_new()) != NULL);
+	archive_entry_copy_pathname(ae, "/tmp/libarchive_test-test_write_disk_secure-absolute_path.tmp");
+	archive_entry_set_mode(ae, S_IFREG | 0777);
+	assert(0 == archive_write_header(a, ae));
+	assert(0 == archive_write_finish_entry(a));
+	assertFileExists("/tmp/libarchive_test-test_write_disk_secure-absolute_path.tmp");
+	assert(0 == unlink("/tmp/libarchive_test-test_write_disk_secure-absolute_path.tmp"));
+
+	/* But with security checks enabled, this should fail. */
+	assert(archive_entry_clear(ae) != NULL);
+	archive_entry_copy_pathname(ae, "/tmp/libarchive_test-test_write_disk_secure-absolute_path.tmp");
+	archive_entry_set_mode(ae, S_IFREG | 0777);
+	archive_write_disk_set_options(a, ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS);
+	failure("Extracting an absolute path should fail here.");
+	assertEqualInt(ARCHIVE_FAILED, archive_write_header(a, ae));
+	archive_entry_free(ae);
+	assert(0 == archive_write_finish_entry(a));
+	assertFileNotExists("/tmp/libarchive_test-test_write_disk_secure-absolute_path.tmp");
+
 	assertEqualInt(ARCHIVE_OK, archive_write_free(a));
 
 	/* Test the entries on disk. */