diff options
author | Tavian Barnes <tavianator@tavianator.com> | 2019-05-23 17:13:39 -0400 |
---|---|---|
committer | Tavian Barnes <tavianator@tavianator.com> | 2019-05-24 09:00:51 -0400 |
commit | f1fb3158d3f242f1884d8d8a7473ab0719e93e8c (patch) | |
tree | 4ab193109db3da98b779ed807f40adb3bb0b9fbd | |
parent | d9b3196d6c8f4fa0e7d0a4771040762edaebb1ee (diff) | |
download | bfs-f1fb3158d3f242f1884d8d8a7473ab0719e93e8c.tar.xz |
Implement -xattr predicate
-rw-r--r-- | .travis.yml | 6 | ||||
-rw-r--r-- | Makefile | 6 | ||||
-rw-r--r-- | eval.c | 13 | ||||
-rw-r--r-- | eval.h | 1 | ||||
-rw-r--r-- | fsade.c | 50 | ||||
-rw-r--r-- | fsade.h | 12 | ||||
-rw-r--r-- | parse.c | 18 | ||||
-rwxr-xr-x | tests.sh | 27 | ||||
-rw-r--r-- | tests/test_L_xattr.out | 2 | ||||
-rw-r--r-- | tests/test_xattr.out | 2 | ||||
-rw-r--r-- | util.h | 4 |
11 files changed, 136 insertions, 5 deletions
diff --git a/.travis.yml b/.travis.yml index 1acc520..8aeb402 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,8 +6,13 @@ addons: apt: packages: - gcc-multilib + - acl - libacl1-dev - libacl1:i386 + - attr + - libattr1-dev + - libattr1:i386 + - libcap2-bin - libcap-dev - libcap2:i386 @@ -19,6 +24,7 @@ matrix: # Ubuntu doesn't let you install the -dev packages for both amd64 and # i386 at once, so we make our own symlinks to fix -m32 -lacl -lcap - sudo ln -s libacl.so.1 /lib/i386-linux-gnu/libacl.so + - sudo ln -s libattr.so.1 /lib/i386-linux-gnu/libattr.so - sudo ln -s libcap.so.2 /lib/i386-linux-gnu/libcap.so - os: osx @@ -53,10 +53,10 @@ LOCAL_LDLIBS := ifeq ($(OS),Linux) LOCAL_LDFLAGS += -Wl,--as-needed -LOCAL_LDLIBS += -lacl -lcap -lrt +LOCAL_LDLIBS += -lacl -lcap -lattr -lrt -# These libraries are not build with msan, so disable them -MSAN_CFLAGS := -DBFS_HAS_SYS_ACL=0 -DBFS_HAS_SYS_CAPABILITY=0 +# These libraries are not built with msan, so disable them +MSAN_CFLAGS := -DBFS_HAS_SYS_ACL=0 -DBFS_HAS_SYS_CAPABILITY=0 -DBFS_HAS_SYS_XATTRS=0 endif ALL_CPPFLAGS = $(LOCAL_CPPFLAGS) $(CPPFLAGS) @@ -887,6 +887,19 @@ bool eval_type(const struct expr *expr, struct eval_state *state) { } /** + * -xattr test. + */ +bool eval_xattr(const struct expr *expr, struct eval_state *state) { + int ret = bfs_check_xattrs(state->ftwbuf); + if (ret >= 0) { + return ret; + } else { + eval_report_error(state); + return false; + } +} + +/** * -xtype test. */ bool eval_xtype(const struct expr *expr, struct eval_state *state) { @@ -32,6 +32,7 @@ bool eval_access(const struct expr *expr, struct eval_state *state); bool eval_acl(const struct expr *expr, struct eval_state *state); bool eval_capable(const struct expr *expr, struct eval_state *state); bool eval_perm(const struct expr *expr, struct eval_state *state); +bool eval_xattr(const struct expr *expr, struct eval_state *state); bool eval_newer(const struct expr *expr, struct eval_state *state); bool eval_time(const struct expr *expr, struct eval_state *state); @@ -30,7 +30,11 @@ # include <sys/capability.h> #endif -#if BFS_CAN_CHECK_ACL || BFS_CAN_CHECK_CAPABILITIES +#if BFS_CAN_CHECK_XATTRS +# include <sys/xattr.h> +#endif + +#if BFS_CAN_CHECK_ACL || BFS_CAN_CHECK_CAPABILITIES || BFS_CAN_CHECK_XATTRS /** * Many of the APIs used here don't have *at() variants, but we can try to @@ -103,7 +107,7 @@ static bool is_absence_error(int error) { return false; } -#endif // BFS_CAN_CHECK_ACL || BFS_CAN_CHECK_CAPABILITIES +#endif // BFS_CAN_CHECK_ACL || BFS_CAN_CHECK_CAPABILITIES || BFS_CAN_CHECK_XATTRS #if BFS_CAN_CHECK_ACL @@ -230,3 +234,45 @@ int bfs_check_capabilities(const struct BFTW *ftwbuf) { } #endif + +#if BFS_CAN_CHECK_XATTRS + +int bfs_check_xattrs(const struct BFTW *ftwbuf) { + const char *path = fake_at(ftwbuf); + ssize_t len; + +#if __APPLE__ + int options = ftwbuf->typeflag == BFTW_LNK ? XATTR_NOFOLLOW : 0; + len = listxattr(path, NULL, 0, options); +#else + if (ftwbuf->typeflag == BFTW_LNK) { + len = llistxattr(path, NULL, 0); + } else { + len = listxattr(path, NULL, 0); + } +#endif + + int error = errno; + + free_fake_at(ftwbuf, path); + + if (len > 0) { + return 1; + } else if (len == 0 || is_absence_error(error)) { + return 0; + } else if (error == E2BIG) { + return 1; + } else { + errno = error; + return -1; + } +} + +#else // !BFS_CAN_CHECK_XATTRS + +int bfs_check_xattrs(const struct BFTW *ftwbuf) { + errno = ENOTSUP; + return -1; +} + +#endif @@ -35,6 +35,8 @@ # endif #endif +#define BFS_CAN_CHECK_XATTRS BFS_HAS_SYS_XATTR + /** * Check if a file has a non-trvial Access Control List. * @@ -55,4 +57,14 @@ int bfs_check_acl(const struct BFTW *ftwbuf); */ int bfs_check_capabilities(const struct BFTW *ftwbuf); +/** + * Check if a file has any extended attributes set. + * + * @param ftwbuf + * The file to check. + * @return + * 1 if it does, 0 if it doesn't, or -1 if an error occurred. + */ +int bfs_check_xattrs(const struct BFTW *ftwbuf); + #endif // BFS_FSADE_H @@ -2338,6 +2338,23 @@ static struct expr *parse_warn(struct parser_state *state, int warn, int arg2) { } /** + * Parse -xattr. + */ +static struct expr *parse_xattr(struct parser_state *state, int arg1, int arg2) { +#if BFS_CAN_CHECK_XATTRS + struct expr *expr = parse_nullary_test(state, eval_xattr); + if (expr) { + expr->cost = STAT_COST; + expr->probability = 0.01; + } + return expr; +#else + parse_error(state, "%s is missing platform support.\n", state->argv[0]); + return NULL; +#endif +} + +/** * "Parse" -help. */ static struct expr *parse_help(struct parser_state *state, int arg1, int arg2) { @@ -2692,6 +2709,7 @@ static const struct table_entry parse_table[] = { {"-wholename", false, parse_path, false}, {"-writable", false, parse_access, W_OK}, {"-x", false, parse_mount}, + {"-xattr", false, parse_xattr}, {"-xdev", false, parse_mount}, {"-xtype", false, parse_type, true}, {"--"}, @@ -648,6 +648,9 @@ sudo_tests=( test_capable test_L_capable + test_xattr + test_L_xattr + test_mount test_xdev @@ -2351,6 +2354,30 @@ function test_L_capable() { bfs_diff -L scratch -capable } +function test_xattr() { + rm -rf scratch/* + touch scratch/{normal,xattr} + # Linux tmpfs doesn't support the user.* namespace, so we use the security.* + # namespace, which is writable by root and readable by others + sudo setfattr -n security.bfs_test scratch/xattr + ln -s xattr scratch/link + ln -s normal scratch/xattr_link + sudo setfattr -h -n security.bfs_test scratch/xattr_link + + bfs_diff scratch -xattr +} + +function test_L_xattr() { + rm -rf scratch/* + touch scratch/{normal,xattr} + sudo setfattr -n security.bfs_test scratch/xattr + ln -s xattr scratch/link + ln -s normal scratch/xattr_link + sudo setfattr -h -n security.bfs_test scratch/xattr_link + + bfs_diff -L scratch -xattr +} + BOL= EOL='\n' diff --git a/tests/test_L_xattr.out b/tests/test_L_xattr.out new file mode 100644 index 0000000..4dc4836 --- /dev/null +++ b/tests/test_L_xattr.out @@ -0,0 +1,2 @@ +scratch/link +scratch/xattr diff --git a/tests/test_xattr.out b/tests/test_xattr.out new file mode 100644 index 0000000..0285ac1 --- /dev/null +++ b/tests/test_xattr.out @@ -0,0 +1,2 @@ +scratch/xattr +scratch/xattr_link @@ -67,6 +67,10 @@ # define BFS_HAS_SYS_SYSMACROS BFS_HAS_INCLUDE(<sys/sysmacros.h>, __GLIBC__) #endif +#ifndef BFS_HAS_SYS_XATTR +# define BFS_HAS_SYS_XATTR BFS_HAS_INCLUDE(<sys/xattr.h>, __linux__) +#endif + #if !defined(FNM_CASEFOLD) && defined(FNM_IGNORECASE) # define FNM_CASEFOLD FNM_IGNORECASE #endif |