1 // RUN: %clangxx_msan -O0 %s -o %t && %run %t %p 2>&1
2 // RUN: %clangxx_msan -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %run %t %p 2>&1
3 // RUN: %clangxx_msan -O3 %s -o %t && %run %t %p 2>&1
4 
5 #include <argz.h>
6 #include <assert.h>
7 #include <sys/types.h>
8 #include <errno.h>
9 #include <fcntl.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 
14 #include <sanitizer/msan_interface.h>
15 
16 // Do not depend on libattr headers.
17 #ifndef ENOATTR
18 #define ENOATTR ENODATA
19 #endif
20 
21 extern "C" {
22 ssize_t listxattr(const char *path, char *list, size_t size);
23 ssize_t llistxattr(const char *path, char *list, size_t size);
24 ssize_t flistxattr(int fd, char *list, size_t size);
25 ssize_t getxattr(const char *path, const char *name, void *value, size_t size);
26 ssize_t lgetxattr(const char *path, const char *name, void *value, size_t size);
27 ssize_t fgetxattr(int fd, const char *name, void *value, size_t size);
28 }
29 
30 char g_path[1024];
31 int g_fd;
32 
33 // Life before closures...
listxattr_wrapper(char * buf,size_t size)34 ssize_t listxattr_wrapper(char *buf, size_t size) {
35   return listxattr(g_path, buf, size);
36 }
37 
llistxattr_wrapper(char * buf,size_t size)38 ssize_t llistxattr_wrapper(char *buf, size_t size) {
39   return llistxattr(g_path, buf, size);
40 }
41 
flistxattr_wrapper(char * buf,size_t size)42 ssize_t flistxattr_wrapper(char *buf, size_t size) {
43   return flistxattr(g_fd, buf, size);
44 }
45 
getxattr_wrapper(const char * name,char * buf,size_t size)46 ssize_t getxattr_wrapper(const char *name, char *buf, size_t size) {
47   return getxattr(g_path, name, buf, size);
48 }
49 
lgetxattr_wrapper(const char * name,char * buf,size_t size)50 ssize_t lgetxattr_wrapper(const char *name, char *buf, size_t size) {
51   return lgetxattr(g_path, name, buf, size);
52 }
53 
fgetxattr_wrapper(const char * name,char * buf,size_t size)54 ssize_t fgetxattr_wrapper(const char *name, char *buf, size_t size) {
55   return fgetxattr(g_fd, name, buf, size);
56 }
57 
test_list(ssize_t fun (char *,size_t),char ** buf)58 size_t test_list(ssize_t fun(char*, size_t), char **buf) {
59   int buf_size = 1024;
60   while (true) {
61     *buf = (char *)malloc(buf_size);
62     assert(__msan_test_shadow(*buf, buf_size) != -1);
63     ssize_t res = fun(*buf, buf_size);
64     if (res >= 0) {
65       assert(__msan_test_shadow(*buf, buf_size) == res);
66       return res;
67     }
68     if (errno == ENOTSUP) {
69       printf("Extended attributes are disabled. *xattr test is a no-op.\n");
70       exit(0);
71     }
72     assert(errno == ERANGE);
73     free(*buf);
74     buf_size *= 2;
75   }
76 }
77 
78 // True means success. False means result inconclusive because we don't have
79 // access to this attribute.
test_get_single_attr(ssize_t fun (const char *,char *,size_t),const char * attr_name)80 bool test_get_single_attr(ssize_t fun(const char *, char *, size_t),
81                           const char *attr_name) {
82   char *buf;
83   int buf_size = 1024;
84   while (true) {
85     buf = (char *)malloc(buf_size);
86     assert(__msan_test_shadow(buf, buf_size) != -1);
87     ssize_t res = fun(attr_name, buf, buf_size);
88     if (res >= 0) {
89       assert(__msan_test_shadow(buf, buf_size) == res);
90       free(buf);
91       return true;
92     }
93     if (errno == ENOTSUP) {
94       printf("Extended attributes are disabled. *xattr test is a no-op.\n");
95       exit(0);
96     }
97     if (errno == ENOATTR)
98       return false;
99     assert(errno == ERANGE);
100     free(buf);
101     buf_size *= 2;
102   }
103 }
104 
test_get(ssize_t fun (const char *,char *,size_t),const char * attr_list,size_t attr_list_size)105 void test_get(ssize_t fun(const char *, char *, size_t), const char *attr_list,
106               size_t attr_list_size) {
107   // Try every attribute, until we see one we can access. Attribute names are
108   // null-separated strings in attr_list.
109   size_t attr_list_len = argz_count(attr_list, attr_list_size);
110   size_t argv_size = (attr_list_len + 1) * sizeof(char *);
111   char **attrs = (char **)malloc(argv_size);
112   argz_extract(attr_list, attr_list_size, attrs);
113   // TODO(smatveev): we need proper argz_* interceptors
114   __msan_unpoison(attrs, argv_size);
115   for (size_t i = 0; (i < attr_list_len) && attrs[i]; i++) {
116     if (test_get_single_attr(fun, attrs[i]))
117       return;
118   }
119   printf("*xattr test could not access any attributes.\n");
120 }
121 
122 // TODO: set some attributes before trying to retrieve them with *getxattr.
123 // Currently the list is empty, so *getxattr is not tested.
main(int argc,char * argv[])124 int main(int argc, char *argv[]) {
125   assert(argc == 2);
126   snprintf(g_path, sizeof(g_path), "%s/%s", argv[1], "xattr_test_root/a");
127 
128   g_fd = open(g_path, O_RDONLY);
129   assert(g_fd);
130 
131   char *attr_list;
132   size_t attr_list_size;
133   attr_list_size = test_list(listxattr_wrapper, &attr_list);
134   free(attr_list);
135   attr_list_size = test_list(llistxattr_wrapper, &attr_list);
136   free(attr_list);
137   attr_list_size = test_list(flistxattr_wrapper, &attr_list);
138 
139   test_get(getxattr_wrapper, attr_list, attr_list_size);
140   test_get(lgetxattr_wrapper, attr_list, attr_list_size);
141   test_get(fgetxattr_wrapper, attr_list, attr_list_size);
142 
143   free(attr_list);
144   return 0;
145 }
146