The Pedigree Project 0.1
values.c
1#define _GNU_SOURCE
2#include <stdlib.h>
3#include <string.h>
4#include <unistd.h>
5
6#include "contract.h"
7#include <sys/mman.h>
8#include <sys/xattr.h>
9
10static int cycle(int backend) {
11 int failed = 0;
12 struct xa_file file = {.fd = -1};
13 unsigned char value[257], output[274];
14 unsigned char* fault = MAP_FAILED;
15 const char* names[] = {"user.binary", "user.empty"};
16 for (size_t n = 0; n < sizeof(value); ++n)
17 value[n] = (unsigned char)n;
18 CHECK(!xa_create(&file, backend, 0));
19 fault = mmap(NULL, 2 * xa_page, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
20 CHECK(fault != MAP_FAILED && !mprotect(fault + xa_page, xa_page, PROT_NONE));
21 fault[xa_page - 1] = 0x56;
22 void* bad = fault + xa_page;
23 const int first = backend == XA_MEMFD ? XA_FD : XA_PATH;
24 for (int how = first; how <= XA_FD; ++how) {
25 CHECK(!xa_names(&file, how, NULL, 0));
26 CHECK(xa_list(&file, how, bad, 1) == 0);
27 CHECK(!xa_set(&file, how, names[0], value, sizeof(value), XATTR_CREATE));
28 for (int read_how = first; read_how <= XA_FD; ++read_how)
29 CHECK(!xa_value(&file, read_how, names[0], value, sizeof(value)));
30 CHECK(xa_get(&file, how, names[0], bad, 0) == sizeof(value));
31 memset(output, 0xa5, sizeof(output));
32 CHECK(xa_get(&file, how, names[0], output, sizeof(value)) == sizeof(value));
33 CHECK(!memcmp(output, value, sizeof(value)) && output[sizeof(value)] == 0xa5);
34 memset(output, 0xa5, sizeof(output));
35 CHECK(xa_get(&file, how, names[0], output, sizeof(value) - 1) == -1 && errno == ERANGE);
36 for (size_t n = 0; n < sizeof(output); ++n)
37 CHECK(output[n] == 0xa5);
38 CHECK(xa_get(&file, how, names[0], output, SIZE_MAX) == sizeof(value));
39 CHECK(!memcmp(output, value, sizeof(value)) && output[sizeof(value)] == 0xa5);
40 CHECK(xa_set(&file, how, names[0], "x", 1, XATTR_CREATE) == -1 && errno == EEXIST);
41 CHECK(xa_set(&file, how, names[0], "x", 1, XATTR_CREATE | XATTR_REPLACE) == -1 &&
42 errno == EEXIST);
43 CHECK(xa_set(&file, how, names[0], "x", 1, 4) == -1 && errno == EINVAL);
44 CHECK(xa_set(&file, how, names[0], bad, 1, XATTR_REPLACE) == -1 && errno == EFAULT);
45 CHECK(xa_set(&file, how, names[0], fault + xa_page - 1, 2, 0) == -1 && errno == EFAULT);
46 CHECK(!xa_value(&file, how, names[0], value, sizeof(value)));
47 CHECK(xa_get(&file, how, names[0], bad, sizeof(value)) == -1 && errno == EFAULT);
48 CHECK(!xa_value(&file, how, names[0], value, sizeof(value)));
49 CHECK(!xa_set(&file, how, names[1], bad, 0, 0));
50 CHECK(xa_get(&file, how, names[1], bad, 1) == 0);
51 CHECK(xa_set(&file, how, names[1], NULL, 0, XATTR_CREATE) == -1 && errno == EEXIST);
52 CHECK(!xa_names(&file, how, names, 2));
53 const size_t list_size = strlen(names[0]) + strlen(names[1]) + 2;
54 CHECK(xa_list(&file, how, bad, 0) == (ssize_t)list_size);
55 memset(output, 0xa5, sizeof(output));
56 CHECK(xa_list(&file, how, (char*)output, list_size - 1) == -1 && errno == ERANGE);
57 for (size_t n = 0; n < sizeof(output); ++n)
58 CHECK(output[n] == 0xa5);
59 CHECK(xa_list(&file, how, (char*)output, SIZE_MAX) == (ssize_t)list_size);
60 CHECK(output[list_size] == 0xa5);
61 CHECK(xa_list(&file, how, bad, list_size) == -1 && errno == EFAULT);
62 CHECK(!xa_names(&file, how, names, 2));
63 CHECK(!xa_set(&file, how, names[0], value, 191, XATTR_REPLACE));
64 CHECK(!xa_value(&file, how, names[0], value, 191));
65 CHECK(!xa_set(&file, how, names[0], "last", 4, 0));
66 CHECK(!xa_value(&file, how, names[0], "last", 4));
67 CHECK(!xa_remove(&file, how, names[0]));
68 CHECK(xa_remove(&file, how, names[0]) == -1 && errno == ENODATA);
69 CHECK(xa_set(&file, how, names[0], "x", 1, XATTR_REPLACE) == -1 && errno == ENODATA);
70 CHECK(xa_set(&file, how, names[0], "x", 1, XATTR_CREATE | XATTR_REPLACE) == -1 &&
71 errno == ENODATA);
72 CHECK(!xa_remove(&file, how, names[1]));
73 CHECK(!xa_names(&file, how, NULL, 0));
74 }
75out:
76 if (fault != MAP_FAILED)
77 munmap(fault, 2 * xa_page);
78 xa_close(&file);
79 if (failed)
80 fprintf(stderr, "XATTR-CONTRACT: values backend=%d\n", backend);
81 return failed;
82}
83
84static int memory_limits(int backend) {
85 int failed = 0;
86 struct xa_file file = {.fd = -1};
87 unsigned char* large = malloc(65537);
88 CHECK(large != NULL && !xa_create(&file, backend, 0));
89 for (size_t n = 0; n < 65537; ++n)
90 large[n] = (unsigned char)(n * 29 + (n >> 8));
91 CHECK(!fsetxattr(file.fd, "user.large", large, 65536, 0));
92 CHECK(!xa_value(&file, XA_FD, "user.large", large, 65536));
93 CHECK(fsetxattr(file.fd, "user.large", large, 65537, 0) == -1 && errno == E2BIG);
94 CHECK(!xa_value(&file, XA_FD, "user.large", large, 65536));
95 CHECK(!fsetxattr(file.fd, "user.second", large, 65536, 0));
96 CHECK(!fsetxattr(file.fd, "user.third", large, 65536, 0));
97 CHECK(fsetxattr(file.fd, "user.fourth", large, 65536, 0) == -1 && errno == ENOSPC);
98 CHECK(!xa_value(&file, XA_FD, "user.large", large, 65536));
99 CHECK(!fremovexattr(file.fd, "user.large"));
100 CHECK(!fsetxattr(file.fd, "user.small", large, 32768, 0));
101 CHECK(!fsetxattr(file.fd, "user.fourth", large, 65536, 0));
102 CHECK(fsetxattr(file.fd, "user.small", large, 65536, XATTR_REPLACE) == -1 && errno == ENOSPC);
103 CHECK(!xa_value(&file, XA_FD, "user.small", large, 32768));
104 xa_close(&file);
105 CHECK(!xa_create(&file, backend, 0));
106 char names[128][24];
107 const char* pointers[128];
108 for (size_t n = 0; n < 128; ++n) {
109 snprintf(names[n], sizeof(names[n]), "user.entry%03zu", n);
110 pointers[n] = names[n];
111 CHECK(!fsetxattr(file.fd, names[n], NULL, 0, XATTR_CREATE));
112 }
113 CHECK(!xa_names(&file, XA_FD, pointers, 128));
114 CHECK(fsetxattr(file.fd, "user.overflow", NULL, 0, 0) == -1 && errno == ENOSPC);
115 CHECK(!fremovexattr(file.fd, names[17]));
116 CHECK(!fsetxattr(file.fd, "user.overflow", NULL, 0, 0));
117 pointers[17] = "user.overflow";
118 CHECK(!xa_names(&file, XA_FD, pointers, 128));
119out:
120 free(large);
121 xa_close(&file);
122 return failed;
123}
124
125int xa_values(void) {
126 for (int backend = XA_MEMFD; backend <= XA_EXT2; ++backend) {
127 if (cycle(backend))
128 return 1;
129 }
130 return memory_limits(XA_MEMFD) || memory_limits(XA_RAMFS);
131}