Home | History | Annotate | Download | only in Linux
      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...
     34 ssize_t listxattr_wrapper(char *buf, size_t size) {
     35   return listxattr(g_path, buf, size);
     36 }
     37 
     38 ssize_t llistxattr_wrapper(char *buf, size_t size) {
     39   return llistxattr(g_path, buf, size);
     40 }
     41 
     42 ssize_t flistxattr_wrapper(char *buf, size_t size) {
     43   return flistxattr(g_fd, buf, size);
     44 }
     45 
     46 ssize_t getxattr_wrapper(const char *name, char *buf, size_t size) {
     47   return getxattr(g_path, name, buf, size);
     48 }
     49 
     50 ssize_t lgetxattr_wrapper(const char *name, char *buf, size_t size) {
     51   return lgetxattr(g_path, name, buf, size);
     52 }
     53 
     54 ssize_t fgetxattr_wrapper(const char *name, char *buf, size_t size) {
     55   return fgetxattr(g_fd, name, buf, size);
     56 }
     57 
     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.
     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 
    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.
    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