~sergei.glushchenko/+junk/page-scan-hack

« back to all changes in this revision

Viewing changes to src/libarchive/libarchive/test/test_write_disk_secure.c

merge parallel compression branch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-
 
2
 * Copyright (c) 2003-2007 Tim Kientzle
 
3
 * All rights reserved.
 
4
 *
 
5
 * Redistribution and use in source and binary forms, with or without
 
6
 * modification, are permitted provided that the following conditions
 
7
 * are met:
 
8
 * 1. Redistributions of source code must retain the above copyright
 
9
 *    notice, this list of conditions and the following disclaimer.
 
10
 * 2. Redistributions in binary form must reproduce the above copyright
 
11
 *    notice, this list of conditions and the following disclaimer in the
 
12
 *    documentation and/or other materials provided with the distribution.
 
13
 *
 
14
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
 
15
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 
16
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 
17
 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
 
18
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 
19
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 
20
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 
21
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
22
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 
23
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
24
 */
 
25
#include "test.h"
 
26
__FBSDID("$FreeBSD: head/lib/libarchive/test/test_write_disk_secure.c 201247 2009-12-30 05:59:21Z kientzle $");
 
27
 
 
28
#define UMASK 022
 
29
 
 
30
/*
 
31
 * Exercise security checks that should prevent certain
 
32
 * writes.
 
33
 */
 
34
 
 
35
DEFINE_TEST(test_write_disk_secure)
 
36
{
 
37
#if ARCHIVE_VERSION_NUMBER < 1009000
 
38
        skipping("archive_write_disk interface");
 
39
#elif !defined(_WIN32) || defined(__CYGWIN__)
 
40
        struct archive *a;
 
41
        struct archive_entry *ae;
 
42
        struct stat st;
 
43
 
 
44
        /* Start with a known umask. */
 
45
        assertUmask(UMASK);
 
46
 
 
47
        /* Create an archive_write_disk object. */
 
48
        assert((a = archive_write_disk_new()) != NULL);
 
49
 
 
50
        /* Write a regular dir to it. */
 
51
        assert((ae = archive_entry_new()) != NULL);
 
52
        archive_entry_copy_pathname(ae, "dir");
 
53
        archive_entry_set_mode(ae, S_IFDIR | 0777);
 
54
        assert(0 == archive_write_header(a, ae));
 
55
        archive_entry_free(ae);
 
56
        assert(0 == archive_write_finish_entry(a));
 
57
 
 
58
        /* Write a symlink to the dir above. */
 
59
        assert((ae = archive_entry_new()) != NULL);
 
60
        archive_entry_copy_pathname(ae, "link_to_dir");
 
61
        archive_entry_set_mode(ae, S_IFLNK | 0777);
 
62
        archive_entry_set_symlink(ae, "dir");
 
63
        archive_write_disk_set_options(a, 0);
 
64
        assert(0 == archive_write_header(a, ae));
 
65
        assert(0 == archive_write_finish_entry(a));
 
66
 
 
67
        /*
 
68
         * Without security checks, we should be able to
 
69
         * extract a file through the link.
 
70
         */
 
71
        assert(archive_entry_clear(ae) != NULL);
 
72
        archive_entry_copy_pathname(ae, "link_to_dir/filea");
 
73
        archive_entry_set_mode(ae, S_IFREG | 0777);
 
74
        assert(0 == archive_write_header(a, ae));
 
75
        assert(0 == archive_write_finish_entry(a));
 
76
 
 
77
        /* But with security checks enabled, this should fail. */
 
78
        assert(archive_entry_clear(ae) != NULL);
 
79
        archive_entry_copy_pathname(ae, "link_to_dir/fileb");
 
80
        archive_entry_set_mode(ae, S_IFREG | 0777);
 
81
        archive_write_disk_set_options(a, ARCHIVE_EXTRACT_SECURE_SYMLINKS);
 
82
        failure("Extracting a file through a symlink should fail here.");
 
83
        assertEqualInt(ARCHIVE_FAILED, archive_write_header(a, ae));
 
84
        archive_entry_free(ae);
 
85
        assert(0 == archive_write_finish_entry(a));
 
86
 
 
87
        /* Create another link. */
 
88
        assert((ae = archive_entry_new()) != NULL);
 
89
        archive_entry_copy_pathname(ae, "link_to_dir2");
 
90
        archive_entry_set_mode(ae, S_IFLNK | 0777);
 
91
        archive_entry_set_symlink(ae, "dir");
 
92
        archive_write_disk_set_options(a, 0);
 
93
        assert(0 == archive_write_header(a, ae));
 
94
        assert(0 == archive_write_finish_entry(a));
 
95
 
 
96
        /*
 
97
         * With symlink check and unlink option, it should remove
 
98
         * the link and create the dir.
 
99
         */
 
100
        assert(archive_entry_clear(ae) != NULL);
 
101
        archive_entry_copy_pathname(ae, "link_to_dir2/filec");
 
102
        archive_entry_set_mode(ae, S_IFREG | 0777);
 
103
        archive_write_disk_set_options(a, ARCHIVE_EXTRACT_SECURE_SYMLINKS | ARCHIVE_EXTRACT_UNLINK);
 
104
        assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
 
105
        archive_entry_free(ae);
 
106
        assert(0 == archive_write_finish_entry(a));
 
107
 
 
108
        /*
 
109
         * Without security checks, extracting a dir over a link to a
 
110
         * dir should follow the link.
 
111
         */
 
112
        /* Create a symlink to a dir. */
 
113
        assert((ae = archive_entry_new()) != NULL);
 
114
        archive_entry_copy_pathname(ae, "link_to_dir3");
 
115
        archive_entry_set_mode(ae, S_IFLNK | 0777);
 
116
        archive_entry_set_symlink(ae, "dir");
 
117
        archive_write_disk_set_options(a, 0);
 
118
        assert(0 == archive_write_header(a, ae));
 
119
        assert(0 == archive_write_finish_entry(a));
 
120
        /* Extract a dir whose name matches the symlink. */
 
121
        assert(archive_entry_clear(ae) != NULL);
 
122
        archive_entry_copy_pathname(ae, "link_to_dir3");
 
123
        archive_entry_set_mode(ae, S_IFDIR | 0777);
 
124
        assert(0 == archive_write_header(a, ae));
 
125
        assert(0 == archive_write_finish_entry(a));
 
126
        /* Verify link was followed. */
 
127
        assertEqualInt(0, lstat("link_to_dir3", &st));
 
128
        assert(S_ISLNK(st.st_mode));
 
129
        archive_entry_free(ae);
 
130
 
 
131
        /*
 
132
         * As above, but a broken link, so the link should get replaced.
 
133
         */
 
134
        /* Create a symlink to a dir. */
 
135
        assert((ae = archive_entry_new()) != NULL);
 
136
        archive_entry_copy_pathname(ae, "link_to_dir4");
 
137
        archive_entry_set_mode(ae, S_IFLNK | 0777);
 
138
        archive_entry_set_symlink(ae, "nonexistent_dir");
 
139
        archive_write_disk_set_options(a, 0);
 
140
        assert(0 == archive_write_header(a, ae));
 
141
        assert(0 == archive_write_finish_entry(a));
 
142
        /* Extract a dir whose name matches the symlink. */
 
143
        assert(archive_entry_clear(ae) != NULL);
 
144
        archive_entry_copy_pathname(ae, "link_to_dir4");
 
145
        archive_entry_set_mode(ae, S_IFDIR | 0777);
 
146
        assert(0 == archive_write_header(a, ae));
 
147
        assert(0 == archive_write_finish_entry(a));
 
148
        /* Verify link was replaced. */
 
149
        assertEqualInt(0, lstat("link_to_dir4", &st));
 
150
        assert(S_ISDIR(st.st_mode));
 
151
        archive_entry_free(ae);
 
152
 
 
153
        /*
 
154
         * As above, but a link to a non-dir, so the link should get replaced.
 
155
         */
 
156
        /* Create a regular file and a symlink to it */
 
157
        assert((ae = archive_entry_new()) != NULL);
 
158
        archive_entry_copy_pathname(ae, "non_dir");
 
159
        archive_entry_set_mode(ae, S_IFREG | 0777);
 
160
        archive_write_disk_set_options(a, 0);
 
161
        assert(0 == archive_write_header(a, ae));
 
162
        assert(0 == archive_write_finish_entry(a));
 
163
        /* Create symlink to the file. */
 
164
        archive_entry_copy_pathname(ae, "link_to_dir5");
 
165
        archive_entry_set_mode(ae, S_IFLNK | 0777);
 
166
        archive_entry_set_symlink(ae, "non_dir");
 
167
        archive_write_disk_set_options(a, 0);
 
168
        assert(0 == archive_write_header(a, ae));
 
169
        assert(0 == archive_write_finish_entry(a));
 
170
        /* Extract a dir whose name matches the symlink. */
 
171
        assert(archive_entry_clear(ae) != NULL);
 
172
        archive_entry_copy_pathname(ae, "link_to_dir5");
 
173
        archive_entry_set_mode(ae, S_IFDIR | 0777);
 
174
        assert(0 == archive_write_header(a, ae));
 
175
        assert(0 == archive_write_finish_entry(a));
 
176
        /* Verify link was replaced. */
 
177
        assertEqualInt(0, lstat("link_to_dir5", &st));
 
178
        assert(S_ISDIR(st.st_mode));
 
179
        archive_entry_free(ae);
 
180
 
 
181
        assert(0 == archive_write_finish(a));
 
182
 
 
183
        /* Test the entries on disk. */
 
184
        assert(0 == lstat("dir", &st));
 
185
        failure("dir: st.st_mode=%o", st.st_mode);
 
186
        assert((st.st_mode & 0777) == 0755);
 
187
 
 
188
        assert(0 == lstat("link_to_dir", &st));
 
189
        failure("link_to_dir: st.st_mode=%o", st.st_mode);
 
190
        assert(S_ISLNK(st.st_mode));
 
191
#if HAVE_LCHMOD
 
192
        /* Systems that lack lchmod() can't set symlink perms, so skip this. */
 
193
        failure("link_to_dir: st.st_mode=%o", st.st_mode);
 
194
        assert((st.st_mode & 07777) == 0755);
 
195
#endif
 
196
 
 
197
        assert(0 == lstat("dir/filea", &st));
 
198
        failure("dir/filea: st.st_mode=%o", st.st_mode);
 
199
        assert((st.st_mode & 07777) == 0755);
 
200
 
 
201
        failure("dir/fileb: This file should not have been created");
 
202
        assert(0 != lstat("dir/fileb", &st));
 
203
 
 
204
        assert(0 == lstat("link_to_dir2", &st));
 
205
        failure("link_to_dir2 should have been re-created as a true dir");
 
206
        assert(S_ISDIR(st.st_mode));
 
207
        failure("link_to_dir2: Implicit dir creation should obey umask, but st.st_mode=%o", st.st_mode);
 
208
        assert((st.st_mode & 0777) == 0755);
 
209
 
 
210
        assert(0 == lstat("link_to_dir2/filec", &st));
 
211
        assert(S_ISREG(st.st_mode));
 
212
        failure("link_to_dir2/filec: st.st_mode=%o", st.st_mode);
 
213
        assert((st.st_mode & 07777) == 0755);
 
214
#endif
 
215
}