Skip to content
This repository has been archived by the owner on May 21, 2019. It is now read-only.

Commit

Permalink
[msan] Intercept *getxattr and *listxattr.
Browse files Browse the repository at this point in the history
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@200464 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
earthdok committed Jan 30, 2014
1 parent 2ea4365 commit fce5d11
Show file tree
Hide file tree
Showing 5 changed files with 232 additions and 12 deletions.
142 changes: 142 additions & 0 deletions lib/msan/lit_tests/Linux/xattr.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
// RUN: %clangxx_msan -m64 -O0 %s -o %t && %t %p 2>&1
// RUN: %clangxx_msan -m64 -O0 -D_FILE_OFFSET_BITS=64 %s -o %t && %t %p 2>&1
// RUN: %clangxx_msan -m64 -O3 %s -o %t && %t %p 2>&1

#include <argz.h>
#include <assert.h>
#include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <sanitizer/msan_interface.h>

// Do not depend on libattr headers.
#ifndef ENOATTR
#define ENOATTR ENODATA
#endif

extern "C" {
ssize_t listxattr(const char *path, char *list, size_t size);
ssize_t llistxattr(const char *path, char *list, size_t size);
ssize_t flistxattr(int fd, char *list, size_t size);
ssize_t getxattr(const char *path, const char *name, void *value, size_t size);
ssize_t lgetxattr(const char *path, const char *name, void *value, size_t size);
ssize_t fgetxattr(int fd, const char *name, void *value, size_t size);
}

char g_path[1024];
int g_fd;

// Life before closures...
ssize_t listxattr_wrapper(char *buf, size_t size) {
return listxattr(g_path, buf, size);
}

ssize_t llistxattr_wrapper(char *buf, size_t size) {
return llistxattr(g_path, buf, size);
}

ssize_t flistxattr_wrapper(char *buf, size_t size) {
return flistxattr(g_fd, buf, size);
}

ssize_t getxattr_wrapper(const char *name, char *buf, size_t size) {
return getxattr(g_path, name, buf, size);
}

ssize_t lgetxattr_wrapper(const char *name, char *buf, size_t size) {
return lgetxattr(g_path, name, buf, size);
}

ssize_t fgetxattr_wrapper(const char *name, char *buf, size_t size) {
return fgetxattr(g_fd, name, buf, size);
}

size_t test_list(ssize_t fun(char*, size_t), char **buf) {
int buf_size = 1024;
while (true) {
*buf = (char *)malloc(buf_size);
assert(__msan_test_shadow(*buf, buf_size) != -1);
ssize_t res = fun(*buf, buf_size);
if (res >= 0) {
assert(__msan_test_shadow(*buf, buf_size) == res);
return res;
}
if (errno == ENOTSUP) {
printf("Extended attributes are disabled. *xattr test is a no-op.\n");
exit(0);
}
assert(errno == ERANGE);
free(*buf);
buf_size *= 2;
}
}

// True means success. False means result inconclusive because we don't have
// access to this attribute.
bool test_get_single_attr(ssize_t fun(const char *, char *, size_t),
const char *attr_name) {
char *buf;
int buf_size = 1024;
while (true) {
buf = (char *)malloc(buf_size);
assert(__msan_test_shadow(buf, buf_size) != -1);
ssize_t res = fun(attr_name, buf, buf_size);
if (res >= 0) {
assert(__msan_test_shadow(buf, buf_size) == res);
free(buf);
return true;
}
if (errno == ENOTSUP) {
printf("Extended attributes are disabled. *xattr test is a no-op.\n");
exit(0);
}
if (errno == ENOATTR)
return false;
assert(errno == ERANGE);
free(buf);
buf_size *= 2;
}
}

void test_get(ssize_t fun(const char *, char *, size_t), const char *attr_list,
size_t attr_list_size) {
// Try every attribute, until we see one we can access. Attribute names are
// null-separated strings in attr_list.
size_t attr_list_len = argz_count(attr_list, attr_list_size);
char **attrs = (char **)malloc((attr_list_len + 1) * sizeof(char *));
size_t i;
for (i = 0; (i < attr_list_len) && attrs[i]; i++) {
if (test_get_single_attr(fun, attrs[i]))
return;
}
printf("*xattr test could not access any attributes.\n");
}

// TODO: set some attributes before trying to retrieve them with *getxattr.
// Currently the list is empty, so *getxattr is not tested.
int main(int argc, char *argv[]) {
assert(argc == 2);
snprintf(g_path, sizeof(g_path), "%s/%s", argv[1], "xattr_test_root/a");

g_fd = open(g_path, O_RDONLY);
assert(g_fd);

char *attr_list;
size_t attr_list_size;
attr_list_size = test_list(listxattr_wrapper, &attr_list);
free(attr_list);
attr_list_size = test_list(llistxattr_wrapper, &attr_list);
free(attr_list);
attr_list_size = test_list(flistxattr_wrapper, &attr_list);

test_get(getxattr_wrapper, attr_list, attr_list_size);
test_get(lgetxattr_wrapper, attr_list, attr_list_size);
test_get(fgetxattr_wrapper, attr_list, attr_list_size);

free(attr_list);
return 0;
}
Empty file.
75 changes: 75 additions & 0 deletions lib/sanitizer_common/sanitizer_common_interceptors.inc
Original file line number Diff line number Diff line change
Expand Up @@ -3081,6 +3081,79 @@ INTERCEPTOR(void *, __tls_get_addr, void *arg) {
#define INIT_TLS_GET_ADDR
#endif

#if SANITIZER_INTERCEPT_LISTXATTR
INTERCEPTOR(SSIZE_T, listxattr, const char *path, char *list, SIZE_T size) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, listxattr, path, list, size);
if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
SSIZE_T res = REAL(listxattr)(path, list, size);
// Here and below, size == 0 is a special case where nothing is written to the
// buffer, and res contains the desired buffer size.
if (size && res > 0 && list) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, list, res);
return res;
}
INTERCEPTOR(SSIZE_T, llistxattr, const char *path, char *list, SIZE_T size) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, llistxattr, path, list, size);
if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
SSIZE_T res = REAL(llistxattr)(path, list, size);
if (size && res > 0 && list) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, list, res);
return res;
}
INTERCEPTOR(SSIZE_T, flistxattr, int fd, char *list, SIZE_T size) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, flistxattr, fd, list, size);
SSIZE_T res = REAL(flistxattr)(fd, list, size);
if (size && res > 0 && list) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, list, res);
return res;
}
#define INIT_LISTXATTR \
COMMON_INTERCEPT_FUNCTION(listxattr); \
COMMON_INTERCEPT_FUNCTION(llistxattr); \
COMMON_INTERCEPT_FUNCTION(flistxattr);
#else
#define INIT_LISTXATTR
#endif

#if SANITIZER_INTERCEPT_GETXATTR
INTERCEPTOR(SSIZE_T, getxattr, const char *path, const char *name, char *value,
SIZE_T size) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, getxattr, path, name, value, size);
if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
if (name) COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
SSIZE_T res = REAL(getxattr)(path, name, value, size);
if (size && res > 0 && value) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, value, res);
return res;
}
INTERCEPTOR(SSIZE_T, lgetxattr, const char *path, const char *name, char *value,
SIZE_T size) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, lgetxattr, path, name, value, size);
if (path) COMMON_INTERCEPTOR_READ_RANGE(ctx, path, REAL(strlen)(path) + 1);
if (name) COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
SSIZE_T res = REAL(lgetxattr)(path, name, value, size);
if (size && res > 0 && value) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, value, res);
return res;
}
INTERCEPTOR(SSIZE_T, fgetxattr, int fd, const char *name, char *value,
SIZE_T size) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, fgetxattr, fd, name, value, size);
if (name) COMMON_INTERCEPTOR_READ_RANGE(ctx, name, REAL(strlen)(name) + 1);
SSIZE_T res = REAL(fgetxattr)(fd, name, value, size);
if (size && res > 0 && value) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, value, res);
return res;
}
#define INIT_GETXATTR \
COMMON_INTERCEPT_FUNCTION(getxattr); \
COMMON_INTERCEPT_FUNCTION(lgetxattr); \
COMMON_INTERCEPT_FUNCTION(fgetxattr);
#else
#define INIT_GETXATTR
#endif


#define SANITIZER_COMMON_INTERCEPTORS_INIT \
INIT_TEXTDOMAIN; \
INIT_STRCMP; \
Expand Down Expand Up @@ -3197,4 +3270,6 @@ INTERCEPTOR(void *, __tls_get_addr, void *arg) {
INIT_ICONV; \
INIT_TIMES; \
INIT_TLS_GET_ADDR; \
INIT_LISTXATTR; \
INIT_GETXATTR;
/**/
24 changes: 12 additions & 12 deletions lib/sanitizer_common/sanitizer_common_syscalls.inc
Original file line number Diff line number Diff line change
Expand Up @@ -1004,8 +1004,8 @@ PRE_SYSCALL(getxattr)(const void *path, const void *name, void *value,

POST_SYSCALL(getxattr)(long res, const void *path, const void *name,
void *value, long size) {
if (res >= 0) {
if (value) POST_WRITE(value, size);
if (size && res > 0) {
if (value) POST_WRITE(value, res);
}
}

Expand All @@ -1019,8 +1019,8 @@ PRE_SYSCALL(lgetxattr)(const void *path, const void *name, void *value,

POST_SYSCALL(lgetxattr)(long res, const void *path, const void *name,
void *value, long size) {
if (res >= 0) {
if (value) POST_WRITE(value, size);
if (size && res > 0) {
if (value) POST_WRITE(value, res);
}
}

Expand All @@ -1031,8 +1031,8 @@ PRE_SYSCALL(fgetxattr)(long fd, const void *name, void *value, long size) {

POST_SYSCALL(fgetxattr)(long res, long fd, const void *name, void *value,
long size) {
if (res >= 0) {
if (value) POST_WRITE(value, size);
if (size && res > 0) {
if (value) POST_WRITE(value, res);
}
}

Expand All @@ -1042,8 +1042,8 @@ PRE_SYSCALL(listxattr)(const void *path, void *list, long size) {
}

POST_SYSCALL(listxattr)(long res, const void *path, void *list, long size) {
if (res >= 0) {
if (list) POST_WRITE(list, size);
if (size && res > 0) {
if (list) POST_WRITE(list, res);
}
}

Expand All @@ -1053,16 +1053,16 @@ PRE_SYSCALL(llistxattr)(const void *path, void *list, long size) {
}

POST_SYSCALL(llistxattr)(long res, const void *path, void *list, long size) {
if (res >= 0) {
if (list) POST_WRITE(list, size);
if (size && res > 0) {
if (list) POST_WRITE(list, res);
}
}

PRE_SYSCALL(flistxattr)(long fd, void *list, long size) {}

POST_SYSCALL(flistxattr)(long res, long fd, void *list, long size) {
if (res >= 0) {
if (list) POST_WRITE(list, size);
if (size && res > 0) {
if (list) POST_WRITE(list, res);
}
}

Expand Down
3 changes: 3 additions & 0 deletions lib/sanitizer_common/sanitizer_platform_interceptors.h
Original file line number Diff line number Diff line change
Expand Up @@ -179,4 +179,7 @@

#define SANITIZER_INTERCEPT_TLS_GET_ADDR SI_LINUX_NOT_ANDROID

#define SANITIZER_INTERCEPT_LISTXATTR SI_LINUX
#define SANITIZER_INTERCEPT_GETXATTR SI_LINUX

#endif // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H

0 comments on commit fce5d11

Please sign in to comment.