~ubuntu-branches/debian/sid/subversion/sid

« back to all changes in this revision

Viewing changes to subversion/tests/libsvn_fs_fs/fs-fs-fuzzy-test.c

  • Committer: Package Import Robot
  • Author(s): James McCoy
  • Date: 2015-08-07 21:32:47 UTC
  • mfrom: (0.2.15) (4.1.7 experimental)
  • Revision ID: package-import@ubuntu.com-20150807213247-ozyewtmgsr6tkewl
Tags: 1.9.0-1
* Upload to unstable
* New upstream release.
  + Security fixes
    - CVE-2015-3184: Mixed anonymous/authenticated path-based authz with
      httpd 2.4
    - CVE-2015-3187: svn_repos_trace_node_locations() reveals paths hidden
      by authz
* Add >= 2.7 requirement for python-all-dev Build-Depends, needed to run
  tests.
* Remove Build-Conflicts against ruby-test-unit.  (Closes: #791844)
* Remove patches/apache_module_dependency in favor of expressing the
  dependencies in authz_svn.load/dav_svn.load.
* Build-Depend on apache2-dev (>= 2.4.16) to ensure ap_some_authn_required()
  is available when building mod_authz_svn and Depend on apache2-bin (>=
  2.4.16) for runtime support.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* fs-fs-fuzzy-test.c --- fuzzing tests for the FSFS filesystem
 
2
 *
 
3
 * ====================================================================
 
4
 *    Licensed to the Apache Software Foundation (ASF) under one
 
5
 *    or more contributor license agreements.  See the NOTICE file
 
6
 *    distributed with this work for additional information
 
7
 *    regarding copyright ownership.  The ASF licenses this file
 
8
 *    to you under the Apache License, Version 2.0 (the
 
9
 *    "License"); you may not use this file except in compliance
 
10
 *    with the License.  You may obtain a copy of the License at
 
11
 *
 
12
 *      http://www.apache.org/licenses/LICENSE-2.0
 
13
 *
 
14
 *    Unless required by applicable law or agreed to in writing,
 
15
 *    software distributed under the License is distributed on an
 
16
 *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 
17
 *    KIND, either express or implied.  See the License for the
 
18
 *    specific language governing permissions and limitations
 
19
 *    under the License.
 
20
 * ====================================================================
 
21
 */
 
22
 
 
23
#include <stdlib.h>
 
24
#include <string.h>
 
25
#include <apr_pools.h>
 
26
 
 
27
#include "../svn_test.h"
 
28
#include "../../libsvn_fs_fs/fs.h"
 
29
#include "../../libsvn_fs_fs/fs_fs.h"
 
30
#include "../../libsvn_fs_fs/rev_file.h"
 
31
 
 
32
#include "svn_hash.h"
 
33
#include "svn_pools.h"
 
34
#include "svn_props.h"
 
35
#include "svn_fs.h"
 
36
#include "private/svn_string_private.h"
 
37
#include "private/svn_string_private.h"
 
38
 
 
39
#include "../svn_test_fs.h"
 
40
 
 
41
 
 
42
 
 
43
/*** Helper Functions ***/
 
44
 
 
45
/* We won't log or malfunction() upon errors. */
 
46
static void
 
47
dont_filter_warnings(void *baton, svn_error_t *err)
 
48
{
 
49
  return;
 
50
}
 
51
 
 
52
 
 
53
/*** Test core code ***/
 
54
 
 
55
/* Verify that a modification of any single byte in REVISION of FS at
 
56
 * REPO_NAME using MODIFIER with BATON will be detected. */
 
57
static svn_error_t *
 
58
fuzzing_1_byte_1_rev(const char *repo_name,
 
59
                     svn_fs_t *fs,
 
60
                     svn_revnum_t revision,
 
61
                     unsigned char (* modifier)(unsigned char c, void *baton),
 
62
                     void *baton,
 
63
                     apr_pool_t *pool)
 
64
{
 
65
  svn_repos_t *repos;
 
66
  apr_hash_t *fs_config;
 
67
  svn_fs_fs__revision_file_t *rev_file;
 
68
  apr_off_t filesize = 0, offset;
 
69
  apr_off_t i;
 
70
  unsigned char footer_len;
 
71
 
 
72
  apr_pool_t *iterpool = svn_pool_create(pool);
 
73
 
 
74
  /* Open the revision file for modification. */
 
75
  SVN_ERR(svn_fs_fs__open_pack_or_rev_file_writable(&rev_file, fs, revision,
 
76
                                                    pool, iterpool));
 
77
  SVN_ERR(svn_fs_fs__auto_read_footer(rev_file));
 
78
  SVN_ERR(svn_io_file_seek(rev_file->file, APR_END, &filesize, iterpool));
 
79
 
 
80
  offset = filesize - 1;
 
81
  SVN_ERR(svn_io_file_seek(rev_file->file, APR_SET, &offset, iterpool));
 
82
  SVN_ERR(svn_io_file_getc((char *)&footer_len, rev_file->file, iterpool));
 
83
 
 
84
  /* We want all the caching we can get.  More importantly, we want to
 
85
     change the cache namespace before each test iteration. */
 
86
  fs_config = apr_hash_make(pool);
 
87
  svn_hash_sets(fs_config, SVN_FS_CONFIG_FSFS_CACHE_DELTAS, "1");
 
88
  svn_hash_sets(fs_config, SVN_FS_CONFIG_FSFS_CACHE_FULLTEXTS, "1");
 
89
  svn_hash_sets(fs_config, SVN_FS_CONFIG_FSFS_CACHE_REVPROPS, "2");
 
90
  svn_hash_sets(fs_config, SVN_FS_CONFIG_FSFS_BLOCK_READ, "0");
 
91
 
 
92
  /* Manipulate all bytes one at a time. */
 
93
  for (i = 0; i < filesize; ++i)
 
94
    {
 
95
      svn_error_t *err = SVN_NO_ERROR;
 
96
 
 
97
      /* Read byte */
 
98
      unsigned char c_old, c_new;
 
99
      SVN_ERR(svn_io_file_seek(rev_file->file, APR_SET, &i, iterpool));
 
100
      SVN_ERR(svn_io_file_getc((char *)&c_old, rev_file->file, iterpool));
 
101
 
 
102
      /* What to replace it with. Skip if there is no change. */
 
103
      c_new = modifier(c_old, baton);
 
104
      if (c_new == c_old)
 
105
        continue;
 
106
 
 
107
      /* Modify / corrupt the data. */
 
108
      SVN_ERR(svn_io_file_seek(rev_file->file, APR_SET, &i, iterpool));
 
109
      SVN_ERR(svn_io_file_putc((char)c_new, rev_file->file, iterpool));
 
110
      SVN_ERR(svn_io_file_flush(rev_file->file, iterpool));
 
111
 
 
112
      /* Make sure we use a different namespace for the caches during
 
113
         this iteration. */
 
114
      svn_hash_sets(fs_config, SVN_FS_CONFIG_FSFS_CACHE_NS,
 
115
                               svn_uuid_generate(iterpool));
 
116
      SVN_ERR(svn_repos_open3(&repos, repo_name, fs_config, iterpool, iterpool));
 
117
      svn_fs_set_warning_func(svn_repos_fs(repos), dont_filter_warnings, NULL);
 
118
 
 
119
      /* This shall detect the corruption and return an error. */
 
120
      err = svn_repos_verify_fs3(repos, revision, revision, FALSE, FALSE,
 
121
                                 NULL, NULL, NULL, NULL, NULL, NULL,
 
122
                                 iterpool);
 
123
 
 
124
      /* Case-only changes in checksum digests are not an error.
 
125
       * We allow upper case chars to be used in MD5 checksums in all other
 
126
       * places, thus restricting them here would be inconsistent. */
 
127
      if (   i >= filesize - footer_len         /* Within footer */
 
128
          && c_old >= 'a' && c_old <= 'f'       /* 'a' to 'f', only appear
 
129
                                                   in checksum digests */
 
130
          && c_new == c_old - 'a' + 'A')        /* respective upper case */
 
131
        {
 
132
          if (err)
 
133
            {
 
134
              /* Let us know where we were too strict ... */
 
135
              printf("Detected case change in checksum digest at offset 0x%"
 
136
                     APR_UINT64_T_HEX_FMT " (%" APR_OFF_T_FMT ") in r%ld: "
 
137
                     "%c -> %c\n", (apr_uint64_t)i, i, revision, c_old, c_new);
 
138
 
 
139
              SVN_ERR(err);
 
140
            }
 
141
        }
 
142
      else if (!err)
 
143
        {
 
144
          /* Let us know where we miss changes ... */
 
145
          printf("Undetected mod at offset 0x%"APR_UINT64_T_HEX_FMT
 
146
                " (%"APR_OFF_T_FMT") in r%ld: 0x%02x -> 0x%02x\n",
 
147
                (apr_uint64_t)i, i, revision, c_old, c_new);
 
148
 
 
149
          SVN_TEST_ASSERT(err);
 
150
        }
 
151
 
 
152
      svn_error_clear(err);
 
153
 
 
154
      /* Undo the corruption. */
 
155
      SVN_ERR(svn_io_file_seek(rev_file->file, APR_SET, &i, iterpool));
 
156
      SVN_ERR(svn_io_file_putc((char)c_old, rev_file->file, iterpool));
 
157
 
 
158
      svn_pool_clear(iterpool);
 
159
    }
 
160
 
 
161
  svn_pool_destroy(iterpool);
 
162
 
 
163
  return SVN_NO_ERROR;
 
164
}
 
165
 
 
166
/* Create a greek repo with OPTS at REPO_NAME.  Verify that a modification
 
167
 * of any single byte using MODIFIER with BATON will be detected. */
 
168
static svn_error_t *
 
169
fuzzing_1_byte_test(const svn_test_opts_t *opts,
 
170
                    const char *repo_name,
 
171
                    unsigned char (* modifier)(unsigned char c, void *baton),
 
172
                    void *baton,
 
173
                    apr_pool_t *pool)
 
174
{
 
175
  svn_repos_t *repos;
 
176
  svn_fs_t *fs;
 
177
  svn_fs_txn_t *txn;
 
178
  svn_fs_root_t *txn_root;
 
179
  svn_revnum_t rev;
 
180
  svn_revnum_t i;
 
181
 
 
182
  apr_pool_t *iterpool = svn_pool_create(pool);
 
183
 
 
184
  /* Bail (with success) on known-untestable scenarios */
 
185
  if (strcmp(opts->fs_type, "fsfs") != 0)
 
186
    return svn_error_create(SVN_ERR_TEST_SKIPPED, NULL,
 
187
                            "this will test FSFS repositories only");
 
188
  /* Create a filesystem */
 
189
  SVN_ERR(svn_test__create_repos(&repos, repo_name, opts, pool));
 
190
  fs = svn_repos_fs(repos);
 
191
 
 
192
  /* Revision 1 (one and only revision): the Greek tree */
 
193
  SVN_ERR(svn_fs_begin_txn(&txn, fs, 0, pool));
 
194
  SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
 
195
  SVN_ERR(svn_test__create_greek_tree(txn_root, pool));
 
196
  SVN_ERR(svn_fs_commit_txn(NULL, &rev, txn, pool));
 
197
  SVN_TEST_ASSERT(SVN_IS_VALID_REVNUM(rev));
 
198
 
 
199
  for (i = 0; i <= rev; ++i)
 
200
    {
 
201
      svn_pool_clear(iterpool);
 
202
      SVN_ERR(fuzzing_1_byte_1_rev(repo_name, fs, i, modifier, baton,
 
203
                                   iterpool));
 
204
    }
 
205
 
 
206
  svn_pool_destroy(iterpool);
 
207
 
 
208
  return SVN_NO_ERROR;
 
209
}
 
210
 
 
211
/* Modifier function to be used with fuzzing_set_byte_test.
 
212
 * We return the fixed char value given as *BATON. */
 
213
static unsigned char
 
214
set_byte(unsigned char c, void *baton)
 
215
{
 
216
  return *(const unsigned char *)baton;
 
217
}
 
218
 
 
219
/* Run the fuzzing test setting any byte in the repo to all values MIN to
 
220
 * MAX-1. */
 
221
static svn_error_t *
 
222
fuzzing_set_byte_test(const svn_test_opts_t *opts,
 
223
                      int min,
 
224
                      int max,
 
225
                      apr_pool_t *pool)
 
226
{
 
227
  apr_pool_t *iterpool = svn_pool_create(pool);
 
228
  unsigned i = 0;
 
229
  for (i = min; i < max; ++i)
 
230
    {
 
231
      unsigned char c = i;
 
232
      const char *repo_name;
 
233
      svn_pool_clear(iterpool);
 
234
 
 
235
      repo_name = apr_psprintf(iterpool, "test-repo-fuzzing_set_byte_%d_%d",
 
236
                               min, max);
 
237
      SVN_ERR(fuzzing_1_byte_test(opts, repo_name, set_byte, &c, iterpool));
 
238
    }
 
239
 
 
240
  svn_pool_destroy(iterpool);
 
241
  return SVN_NO_ERROR;
 
242
}
 
243
 
 
244
 
 
245
 
 
246
/*** Tests ***/
 
247
 
 
248
/* ------------------------------------------------------------------------ */
 
249
 
 
250
static unsigned char
 
251
invert_byte(unsigned char c, void *baton)
 
252
{
 
253
  return ~c;
 
254
}
 
255
 
 
256
static svn_error_t *
 
257
fuzzing_invert_byte_test(const svn_test_opts_t *opts,
 
258
                         apr_pool_t *pool)
 
259
{
 
260
  SVN_ERR(fuzzing_1_byte_test(opts, "test-repo-fuzzing_invert_byte",
 
261
                              invert_byte, NULL, pool));
 
262
 
 
263
  return SVN_NO_ERROR;
 
264
}
 
265
 
 
266
/* ------------------------------------------------------------------------ */
 
267
 
 
268
static unsigned char
 
269
increment_byte(unsigned char c, void *baton)
 
270
{
 
271
  return c + 1;
 
272
}
 
273
 
 
274
static svn_error_t *
 
275
fuzzing_increment_byte_test(const svn_test_opts_t *opts,
 
276
                            apr_pool_t *pool)
 
277
{
 
278
  SVN_ERR(fuzzing_1_byte_test(opts, "test-repo-fuzzing_increment_byte",
 
279
                              increment_byte, NULL, pool));
 
280
 
 
281
  return SVN_NO_ERROR;
 
282
}
 
283
 
 
284
/* ------------------------------------------------------------------------ */
 
285
 
 
286
static unsigned char
 
287
decrement_byte(unsigned char c, void *baton)
 
288
{
 
289
  return c - 1;
 
290
}
 
291
 
 
292
static svn_error_t *
 
293
fuzzing_decrement_byte_test(const svn_test_opts_t *opts,
 
294
                            apr_pool_t *pool)
 
295
{
 
296
  SVN_ERR(fuzzing_1_byte_test(opts, "test-repo-fuzzing_decrement_byte",
 
297
                              decrement_byte, NULL, pool));
 
298
 
 
299
  return SVN_NO_ERROR;
 
300
}
 
301
 
 
302
/* ------------------------------------------------------------------------ */
 
303
 
 
304
static unsigned char
 
305
null_byte(unsigned char c, void *baton)
 
306
{
 
307
  return 0;
 
308
}
 
309
 
 
310
static svn_error_t *
 
311
fuzzing_null_byte_test(const svn_test_opts_t *opts,
 
312
                       apr_pool_t *pool)
 
313
{
 
314
  SVN_ERR(fuzzing_1_byte_test(opts, "test-repo-fuzzing_null_byte",
 
315
                              null_byte, NULL, pool));
 
316
 
 
317
  return SVN_NO_ERROR;
 
318
}
 
319
 
 
320
/* ------------------------------------------------------------------------ */
 
321
 
 
322
/* Generator macro: define a test function covering byte values N to M-1 */
 
323
#define FUZZING_SET_BYTE_TEST_N(N,M)\
 
324
  static svn_error_t * \
 
325
  fuzzing_set_byte_test_ ##N(const svn_test_opts_t *opts, \
 
326
                             apr_pool_t *pool) \
 
327
  { \
 
328
    return svn_error_trace(fuzzing_set_byte_test(opts, N, M, pool)); \
 
329
  }
 
330
 
 
331
/* Add the test function declared above to the test_funcs array. */
 
332
#define TEST_FUZZING_SET_BYTE_TEST_N(N,M)\
 
333
  SVN_TEST_OPTS_PASS(fuzzing_set_byte_test_ ##N, \
 
334
                     "set any byte to any value between " #N " and " #M)
 
335
 
 
336
/* Declare tests that will cover all possible byte values. */
 
337
FUZZING_SET_BYTE_TEST_N(0,16)
 
338
FUZZING_SET_BYTE_TEST_N(16,32)
 
339
FUZZING_SET_BYTE_TEST_N(32,48)
 
340
FUZZING_SET_BYTE_TEST_N(48,64)
 
341
FUZZING_SET_BYTE_TEST_N(64,80)
 
342
FUZZING_SET_BYTE_TEST_N(80,96)
 
343
FUZZING_SET_BYTE_TEST_N(96,112)
 
344
FUZZING_SET_BYTE_TEST_N(112,128)
 
345
FUZZING_SET_BYTE_TEST_N(128,144)
 
346
FUZZING_SET_BYTE_TEST_N(144,160)
 
347
FUZZING_SET_BYTE_TEST_N(160,176)
 
348
FUZZING_SET_BYTE_TEST_N(176,192)
 
349
FUZZING_SET_BYTE_TEST_N(192,208)
 
350
FUZZING_SET_BYTE_TEST_N(208,224)
 
351
FUZZING_SET_BYTE_TEST_N(224,240)
 
352
FUZZING_SET_BYTE_TEST_N(240,256)
 
353
 
 
354
 
 
355
/* The test table.  */
 
356
 
 
357
/* Allow for any number of tests to run in parallel. */
 
358
static int max_threads = 0;
 
359
 
 
360
static struct svn_test_descriptor_t test_funcs[] =
 
361
  {
 
362
    SVN_TEST_NULL,
 
363
    SVN_TEST_OPTS_PASS(fuzzing_invert_byte_test,
 
364
                       "fuzzing: invert any byte"),
 
365
    SVN_TEST_OPTS_PASS(fuzzing_increment_byte_test,
 
366
                       "fuzzing: increment any byte"),
 
367
    SVN_TEST_OPTS_PASS(fuzzing_decrement_byte_test,
 
368
                       "fuzzing: decrement any byte"),
 
369
    SVN_TEST_OPTS_PASS(fuzzing_null_byte_test,
 
370
                       "fuzzing: set any byte to 0"),
 
371
 
 
372
    /* Register generated tests. */
 
373
    TEST_FUZZING_SET_BYTE_TEST_N(0,16),
 
374
    TEST_FUZZING_SET_BYTE_TEST_N(16,32),
 
375
    TEST_FUZZING_SET_BYTE_TEST_N(32,48),
 
376
    TEST_FUZZING_SET_BYTE_TEST_N(48,64),
 
377
    TEST_FUZZING_SET_BYTE_TEST_N(64,80),
 
378
    TEST_FUZZING_SET_BYTE_TEST_N(80,96),
 
379
    TEST_FUZZING_SET_BYTE_TEST_N(96,112),
 
380
    TEST_FUZZING_SET_BYTE_TEST_N(112,128),
 
381
    TEST_FUZZING_SET_BYTE_TEST_N(128,144),
 
382
    TEST_FUZZING_SET_BYTE_TEST_N(144,160),
 
383
    TEST_FUZZING_SET_BYTE_TEST_N(160,176),
 
384
    TEST_FUZZING_SET_BYTE_TEST_N(176,192),
 
385
    TEST_FUZZING_SET_BYTE_TEST_N(192,208),
 
386
    TEST_FUZZING_SET_BYTE_TEST_N(208,224),
 
387
    TEST_FUZZING_SET_BYTE_TEST_N(224,240),
 
388
    TEST_FUZZING_SET_BYTE_TEST_N(240,256),
 
389
 
 
390
    SVN_TEST_NULL
 
391
  };
 
392
 
 
393
SVN_TEST_MAIN