source: trunk/packages/xen-3.1/xen-3.1/tools/xenstore/xs_crashme.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 17 years ago

Add xen and xen-common

File size: 9.3 KB
Line 
1/* Code which randomly corrupts bits going to the daemon.
2    Copyright (C) 2005 Rusty Russell IBM Corporation
3
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software
16    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17*/
18#include <stdbool.h>
19#include <stdio.h>
20#include <sys/types.h>
21#include <stdarg.h>
22#include <string.h>
23#include <sys/time.h>
24#include "xs.h"
25#include "talloc.h"
26#include <errno.h>
27
28#define XSTEST
29#define RAND_FREQ 128           /* One char in 32 is corrupted. */
30
31/* jhash.h: Jenkins hash support.
32 *
33 * Copyright (C) 1996 Bob Jenkins (bob_jenkins@burtleburtle.net)
34 *
35 * http://burtleburtle.net/bob/hash/
36 *
37 * These are the credits from Bob's sources:
38 *
39 * lookup2.c, by Bob Jenkins, December 1996, Public Domain.
40 * hash(), hash2(), hash3, and mix() are externally useful functions.
41 * Routines to test the hash are included if SELF_TEST is defined.
42 * You can use this free for any purpose.  It has no warranty.
43 *
44 * Copyright (C) 2003 David S. Miller (davem@redhat.com)
45 *
46 * I've modified Bob's hash to be useful in the Linux kernel, and
47 * any bugs present are surely my fault.  -DaveM
48 */
49
50/* NOTE: Arguments are modified. */
51#define __jhash_mix(a, b, c) \
52{ \
53  a -= b; a -= c; a ^= (c>>13); \
54  b -= c; b -= a; b ^= (a<<8); \
55  c -= a; c -= b; c ^= (b>>13); \
56  a -= b; a -= c; a ^= (c>>12);  \
57  b -= c; b -= a; b ^= (a<<16); \
58  c -= a; c -= b; c ^= (b>>5); \
59  a -= b; a -= c; a ^= (c>>3);  \
60  b -= c; b -= a; b ^= (a<<10); \
61  c -= a; c -= b; c ^= (b>>15); \
62}
63
64/* The golden ration: an arbitrary value */
65#define JHASH_GOLDEN_RATIO      0x9e3779b9
66
67/* The most generic version, hashes an arbitrary sequence
68 * of bytes.  No alignment or length assumptions are made about
69 * the input key.
70 */
71static inline uint32_t jhash(const void *key, uint32_t length, uint32_t initval)
72{
73        uint32_t a, b, c, len;
74        const uint8_t *k = key;
75
76        len = length;
77        a = b = JHASH_GOLDEN_RATIO;
78        c = initval;
79
80        while (len >= 12) {
81                a += (k[0] +((uint32_t)k[1]<<8) +((uint32_t)k[2]<<16) +((uint32_t)k[3]<<24));
82                b += (k[4] +((uint32_t)k[5]<<8) +((uint32_t)k[6]<<16) +((uint32_t)k[7]<<24));
83                c += (k[8] +((uint32_t)k[9]<<8) +((uint32_t)k[10]<<16)+((uint32_t)k[11]<<24));
84
85                __jhash_mix(a,b,c);
86
87                k += 12;
88                len -= 12;
89        }
90
91        c += length;
92        switch (len) {
93        case 11: c += ((uint32_t)k[10]<<24);
94        case 10: c += ((uint32_t)k[9]<<16);
95        case 9 : c += ((uint32_t)k[8]<<8);
96        case 8 : b += ((uint32_t)k[7]<<24);
97        case 7 : b += ((uint32_t)k[6]<<16);
98        case 6 : b += ((uint32_t)k[5]<<8);
99        case 5 : b += k[4];
100        case 4 : a += ((uint32_t)k[3]<<24);
101        case 3 : a += ((uint32_t)k[2]<<16);
102        case 2 : a += ((uint32_t)k[1]<<8);
103        case 1 : a += k[0];
104        };
105
106        __jhash_mix(a,b,c);
107
108        return c;
109}
110
111/* A special optimized version that handles 1 or more of uint32_ts.
112 * The length parameter here is the number of uint32_ts in the key.
113 */
114static inline uint32_t jhash2(uint32_t *k, uint32_t length, uint32_t initval)
115{
116        uint32_t a, b, c, len;
117
118        a = b = JHASH_GOLDEN_RATIO;
119        c = initval;
120        len = length;
121
122        while (len >= 3) {
123                a += k[0];
124                b += k[1];
125                c += k[2];
126                __jhash_mix(a, b, c);
127                k += 3; len -= 3;
128        }
129
130        c += length * 4;
131
132        switch (len) {
133        case 2 : b += k[1];
134        case 1 : a += k[0];
135        };
136
137        __jhash_mix(a,b,c);
138
139        return c;
140}
141
142
143/* A special ultra-optimized versions that knows they are hashing exactly
144 * 3, 2 or 1 word(s).
145 *
146 * NOTE: In partilar the "c += length; __jhash_mix(a,b,c);" normally
147 *       done at the end is not done here.
148 */
149static inline uint32_t jhash_3words(uint32_t a, uint32_t b, uint32_t c, uint32_t initval)
150{
151        a += JHASH_GOLDEN_RATIO;
152        b += JHASH_GOLDEN_RATIO;
153        c += initval;
154
155        __jhash_mix(a, b, c);
156
157        return c;
158}
159
160static inline uint32_t jhash_2words(uint32_t a, uint32_t b, uint32_t initval)
161{
162        return jhash_3words(a, b, 0, initval);
163}
164
165static inline uint32_t jhash_1word(uint32_t a, uint32_t initval)
166{
167        return jhash_3words(a, 0, 0, initval);
168}
169
170static unsigned int get_randomness(int *state)
171{
172        return jhash_1word((*state)++, *state * 1103515243);
173}
174
175static int state;
176
177/* Lengthening headers is pointless: other end will just wait for more
178 * data and timeout.  We merely shorten the length. */
179static void corrupt_header(char *output, const struct xsd_sockmsg *msg,
180                           unsigned int *next_bit)
181{
182        struct xsd_sockmsg newmsg = *msg;
183
184        while (*next_bit < sizeof(*msg)) {
185                if (newmsg.len)
186                        newmsg.len = get_randomness(&state) % newmsg.len;
187                *next_bit += get_randomness(&state) % RAND_FREQ;
188        }
189        memcpy(output, &newmsg, sizeof(newmsg));
190}
191
192#define read_all_choice read_all
193static bool write_all_choice(int fd, const void *data, unsigned int len)
194{
195        char corrupt_data[len];
196        bool ret;
197        static unsigned int next_bit;
198
199        if (len == sizeof(struct xsd_sockmsg)
200            && ((unsigned long)data % __alignof__(struct xsd_sockmsg)) == 0)
201                corrupt_header(corrupt_data, data, &next_bit);
202        else {
203                memcpy(corrupt_data, data, len);
204                while (next_bit < len * CHAR_BIT) {
205                        corrupt_data[next_bit/CHAR_BIT]
206                                ^= (1 << (next_bit%CHAR_BIT));
207                        next_bit += get_randomness(&state) % RAND_FREQ;
208                }
209        }
210
211        ret = xs_write_all(fd, corrupt_data, len);
212        next_bit -= len * CHAR_BIT;
213        return ret;
214}
215
216#include "xs.c"
217
218static char *random_path(void)
219{
220        unsigned int i;
221        char *ret = NULL;
222
223        if (get_randomness(&state) % 20 == 0)
224                return talloc_strdup(NULL, "/");
225
226        for (i = 0; i < 1 || (get_randomness(&state) % 2); i++) {
227                ret = talloc_asprintf_append(ret, "/%i", 
228                                             get_randomness(&state) % 15);
229        }
230        return ret;
231}
232
233/* Do the next operation, return the results. */
234static void do_next_op(struct xs_handle *h, bool verbose)
235{
236        char *name;
237        unsigned int num;
238
239        if (verbose)
240                printf("State %i: ", state);
241
242        name = random_path();
243        switch (get_randomness(&state) % 9) {
244        case 0:
245                if (verbose)
246                        printf("DIR %s\n", name);
247                free(xs_directory(h, name, &num));
248                break;
249        case 1:
250                if (verbose)
251                        printf("READ %s\n", name);
252                free(xs_read(h, name, &num));
253                break;
254        case 2: {
255                char *contents = talloc_asprintf(NULL, "%i",
256                                                 get_randomness(&state));
257                unsigned int len = get_randomness(&state)%(strlen(contents)+1);
258                if (verbose)
259                        printf("WRITE %s %.*s\n", name, len, contents);
260                xs_write(h, name, contents, len);
261                break;
262        }
263        case 3:
264                if (verbose)
265                        printf("MKDIR %s\n", name);
266                xs_mkdir(h, name);
267                break;
268        case 4:
269                if (verbose)
270                        printf("RM %s\n", name);
271                xs_rm(h, name);
272                break;
273        case 5:
274                if (verbose)
275                        printf("GETPERMS %s\n", name);
276                free(xs_get_permissions(h, name, &num));
277                break;
278        case 6: {
279                unsigned int i, num = get_randomness(&state)%8;
280                struct xs_permissions perms[num];
281
282                if (verbose)
283                        printf("SETPERMS %s: ", name);
284                for (i = 0; i < num; i++) {
285                        perms[i].id = get_randomness(&state)%8;
286                        perms[i].perms = get_randomness(&state)%4;
287                        if (verbose)
288                                printf("%i%c ", perms[i].id,
289                                       perms[i].perms == XS_PERM_WRITE ? 'W'
290                                       : perms[i].perms == XS_PERM_READ ? 'R'
291                                       : perms[i].perms == 
292                                       (XS_PERM_READ|XS_PERM_WRITE) ? 'B'
293                                       : 'N');
294                }
295                if (verbose)
296                        printf("\n");
297                xs_set_permissions(h, name, perms, num);
298                break;
299        }
300        case 7: {
301                if (verbose)
302                        printf("START %s\n", name);
303                xs_transaction_start(h);
304                break;
305        }
306        case 8: {
307                bool abort = (get_randomness(&state) % 2);
308
309                if (verbose)
310                        printf("STOP %s\n", abort ? "ABORT" : "COMMIT");
311                xs_transaction_end(h, abort);
312                break;
313        }
314        default:
315                barf("Impossible randomness");
316        }
317}
318
319static struct xs_handle *h;
320static void alarmed(int sig __attribute__((unused)))
321{
322        /* We force close on timeout. */
323        close(h->fd);
324}
325
326static int start_daemon(void)
327{
328        int fds[2];
329        int daemon_pid;
330
331        /* Start daemon. */
332        pipe(fds);
333        if ((daemon_pid = fork())) {
334                /* Child writes PID when its ready: we wait for that. */
335                char buffer[20];
336                close(fds[1]);
337                if (read(fds[0], buffer, sizeof(buffer)) < 0)
338                        barf("Failed to summon daemon");
339                close(fds[0]);
340                return daemon_pid;
341        } else {
342                dup2(fds[1], STDOUT_FILENO);
343                close(fds[0]);
344#if 1
345                execlp("valgrind", "valgrind", "--log-file=/tmp/xs_crashme.vglog", "-q", "./xenstored_test", "--output-pid",
346                       "--no-fork", "--trace-file=/tmp/trace", NULL);
347#else
348                execlp("./xenstored_test", "xenstored_test", "--output-pid",
349                       "--no-fork", NULL);
350#endif
351                exit(1);
352        }
353}
354
355
356int main(int argc, char **argv)
357{
358        unsigned int i;
359        int pid;
360
361        if (argc != 3 && argc != 4)
362                barf("Usage: xs_crashme <iterations> <seed> [pid]");
363
364        if (argc == 3)
365                pid = start_daemon();
366        else
367                pid = atoi(argv[3]);
368
369        state = atoi(argv[2]);
370        h = xs_daemon_open();
371        if (!h)
372                barf_perror("Opening connection to daemon");
373        signal(SIGALRM, alarmed);
374        for (i = 0; i < (unsigned)atoi(argv[1]); i++) {
375                alarm(1);
376                do_next_op(h, false);
377                if (i % (atoi(argv[1]) / 72 ?: 1) == 0) {
378                        printf(".");
379                        fflush(stdout);
380                }
381                if (kill(pid, 0) != 0)
382                        barf_perror("Pinging daemon on iteration %i", i);
383                if (h->fd < 0) {
384                        xs_daemon_close(h);
385                        h = xs_daemon_open();
386                        if (!h)
387                                barf_perror("Connecting on iteration %i", i);
388                }
389        }
390        kill(pid, SIGTERM);
391        return 0;
392}
393
Note: See TracBrowser for help on using the repository browser.