From 88451c80696f1ea6b0aa3822a9a3969f6bcae41f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jean-Pierre=20Andr=C3=A9?= Date: Wed, 6 Apr 2016 10:17:27 +0200 Subject: [PATCH] Made a full check for whether a user extended attribute is allowed User extended attributes should only be set on files and directories, not on symlinks, sockets, devices, etc. For safety they are also forbidden on metadata files, but should be allowed on the root directory. For files based on reparse points, requests are made to the plugin to determine the type. --- include/ntfs-3g/dir.h | 1 + libntfs-3g/dir.c | 12 ++++++--- src/lowntfs-3g.c | 12 ++++----- src/ntfs-3g.c | 12 ++++----- src/ntfs-3g_common.c | 58 +++++++++++++++++++++++++++++++++++++++++++ src/ntfs-3g_common.h | 1 + 6 files changed, 81 insertions(+), 15 deletions(-) diff --git a/include/ntfs-3g/dir.h b/include/ntfs-3g/dir.h index a99c1ae0..e6a2c3b1 100644 --- a/include/ntfs-3g/dir.h +++ b/include/ntfs-3g/dir.h @@ -109,6 +109,7 @@ extern int ntfs_readdir(ntfs_inode *dir_ni, s64 *pos, void *dirent, ntfs_filldir_t filldir); ntfs_inode *ntfs_dir_parent_inode(ntfs_inode *ni); +u32 ntfs_interix_types(ntfs_inode *ni); int ntfs_get_ntfs_dos_name(ntfs_inode *ni, ntfs_inode *dir_ni, char *value, size_t size); diff --git a/libntfs-3g/dir.c b/libntfs-3g/dir.c index b6447ff4..e4d48ed0 100644 --- a/libntfs-3g/dir.c +++ b/libntfs-3g/dir.c @@ -875,7 +875,7 @@ typedef enum { * and most metadata files have such similar patters. */ -static u32 ntfs_interix_types(ntfs_inode *ni) +u32 ntfs_interix_types(ntfs_inode *ni) { ntfs_attr *na; u32 dt_type; @@ -884,8 +884,14 @@ static u32 ntfs_interix_types(ntfs_inode *ni) dt_type = NTFS_DT_UNKNOWN; na = ntfs_attr_open(ni, AT_DATA, NULL, 0); if (na) { - /* Unrecognized patterns (eg HID + SYST) are plain files */ - dt_type = NTFS_DT_REG; + /* + * Unrecognized patterns (eg HID + SYST for metadata) + * are plain files or directories + */ + if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) + dt_type = NTFS_DT_DIR; + else + dt_type = NTFS_DT_REG; if (na->data_size <= 1) { if (!(ni->flags & FILE_ATTR_HIDDEN)) dt_type = (na->data_size ? diff --git a/src/lowntfs-3g.c b/src/lowntfs-3g.c index 683ac0c6..80c224f8 100644 --- a/src/lowntfs-3g.c +++ b/src/lowntfs-3g.c @@ -3165,7 +3165,7 @@ static void ntfs_fuse_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size) goto out; } /* Return with no result for symlinks, fifo, etc. */ - if (ni->flags & (FILE_ATTR_SYSTEM | FILE_ATTR_REPARSE_POINT)) + if (!user_xattrs_allowed(ctx, ni)) goto exit; /* otherwise file must be readable */ #if !KERNELPERMS | (POSIXACLS & !KERNELACLS) @@ -3314,7 +3314,7 @@ static void ntfs_fuse_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name, goto out; } /* Return with no result for symlinks, fifo, etc. */ - if (ni->flags & (FILE_ATTR_SYSTEM | FILE_ATTR_REPARSE_POINT)) { + if (!user_xattrs_allowed(ctx, ni)) { res = -ENODATA; goto exit; } @@ -3511,7 +3511,7 @@ static void ntfs_fuse_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name, break; default : /* User xattr not allowed for symlinks, fifo, etc. */ - if (ni->flags & (FILE_ATTR_SYSTEM | FILE_ATTR_REPARSE_POINT)) { + if (!user_xattrs_allowed(ctx, ni)) { res = -EPERM; goto exit; } @@ -3524,7 +3524,7 @@ static void ntfs_fuse_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name, #else /* User xattr not allowed for symlinks, fifo, etc. */ if ((namespace == XATTRNS_USER) - && (ni->flags & (FILE_ATTR_SYSTEM | FILE_ATTR_REPARSE_POINT))) { + && !user_xattrs_allowed(ctx, ni)) { res = -EPERM; goto exit; } @@ -3756,7 +3756,7 @@ static void ntfs_fuse_removexattr(fuse_req_t req, fuse_ino_t ino, const char *na break; default : /* User xattr not allowed for symlinks, fifo, etc. */ - if (ni->flags & (FILE_ATTR_SYSTEM | FILE_ATTR_REPARSE_POINT)) { + if (!user_xattrs_allowed(ctx, ni)) { res = -EPERM; goto exit; } @@ -3769,7 +3769,7 @@ static void ntfs_fuse_removexattr(fuse_req_t req, fuse_ino_t ino, const char *na #else /* User xattr not allowed for symlinks, fifo, etc. */ if ((namespace == XATTRNS_USER) - && (ni->flags & (FILE_ATTR_SYSTEM | FILE_ATTR_REPARSE_POINT))) { + && !user_xattrs_allowed(ctx, ni)) { res = -EPERM; goto exit; } diff --git a/src/ntfs-3g.c b/src/ntfs-3g.c index 5b19b1dc..4b4ec363 100644 --- a/src/ntfs-3g.c +++ b/src/ntfs-3g.c @@ -2946,7 +2946,7 @@ static int ntfs_fuse_listxattr(const char *path, char *list, size_t size) if (!ni) return -errno; /* Return with no result for symlinks, fifo, etc. */ - if (ni->flags & (FILE_ATTR_SYSTEM | FILE_ATTR_REPARSE_POINT)) + if (!user_xattrs_allowed(ctx, ni)) goto exit; /* otherwise file must be readable */ #if !KERNELPERMS | (POSIXACLS & !KERNELACLS) @@ -3148,7 +3148,7 @@ static int ntfs_fuse_getxattr(const char *path, const char *name, if (!ni) return -errno; /* Return with no result for symlinks, fifo, etc. */ - if (ni->flags & (FILE_ATTR_SYSTEM | FILE_ATTR_REPARSE_POINT)) { + if (!user_xattrs_allowed(ctx, ni)) { res = -ENODATA; goto exit; } @@ -3324,7 +3324,7 @@ static int ntfs_fuse_setxattr(const char *path, const char *name, break; default : /* User xattr not allowed for symlinks, fifo, etc. */ - if (ni->flags & (FILE_ATTR_SYSTEM | FILE_ATTR_REPARSE_POINT)) { + if (!user_xattrs_allowed(ctx, ni)) { res = -EPERM; goto exit; } @@ -3337,7 +3337,7 @@ static int ntfs_fuse_setxattr(const char *path, const char *name, #else /* User xattr not allowed for symlinks, fifo, etc. */ if ((namespace == XATTRNS_USER) - && (ni->flags & (FILE_ATTR_SYSTEM | FILE_ATTR_REPARSE_POINT))) { + && !user_xattrs_allowed(ctx, ni)) { res = -EPERM; goto exit; } @@ -3561,7 +3561,7 @@ static int ntfs_fuse_removexattr(const char *path, const char *name) break; default : /* User xattr not allowed for symlinks, fifo, etc. */ - if (ni->flags & (FILE_ATTR_SYSTEM | FILE_ATTR_REPARSE_POINT)) { + if (!user_xattrs_allowed(ctx, ni)) { res = -EPERM; goto exit; } @@ -3574,7 +3574,7 @@ static int ntfs_fuse_removexattr(const char *path, const char *name) #else /* User xattr not allowed for symlinks, fifo, etc. */ if ((namespace == XATTRNS_USER) - && (ni->flags & (FILE_ATTR_SYSTEM | FILE_ATTR_REPARSE_POINT))) { + && !user_xattrs_allowed(ctx, ni)) { res = -EPERM; goto exit; } diff --git a/src/ntfs-3g_common.c b/src/ntfs-3g_common.c index 425e8102..29fa42c0 100644 --- a/src/ntfs-3g_common.c +++ b/src/ntfs-3g_common.c @@ -48,6 +48,7 @@ #include #include "inode.h" +#include "dir.h" #include "security.h" #include "xattrs.h" #include "reparse.h" @@ -862,3 +863,60 @@ void close_reparse_plugins(ntfs_fuse_context_t *ctx) } #endif /* PLUGINS_DISABLED */ + +#ifdef HAVE_SETXATTR + +/* + * Check whether a user xattr is allowed + * + * The inode must be a plain file or a directory. The only allowed + * metadata file is the root directory (useful for MacOSX and hopefully + * does not harm Windows). + */ + +BOOL user_xattrs_allowed(ntfs_fuse_context_t *ctx, ntfs_inode *ni) +{ + u32 dt_type; + BOOL res; + + /* Quick return for common cases and root */ + if (!(ni->flags & (FILE_ATTR_SYSTEM | FILE_ATTR_REPARSE_POINT)) + || (ni->mft_no == FILE_root)) + res = TRUE; + else { + /* Reparse point depends on kind, see plugin */ + if (ni->flags & FILE_ATTR_REPARSE_POINT) { +#ifndef PLUGINS_DISABLED + struct stat stbuf; + REPARSE_POINT *reparse; + const plugin_operations_t *ops; + + res = FALSE; /* default for error cases */ + ops = select_reparse_plugin(ctx, ni, &reparse); + if (ops) { + if (ops->getattr + && !ops->getattr(ni,reparse,&stbuf)) { + res = S_ISREG(stbuf.st_mode) + || S_ISDIR(stbuf.st_mode); + } + free(reparse); +#else /* PLUGINS_DISABLED */ + res = FALSE; /* mountpoints, symlinks, ... */ +#endif /* PLUGINS_DISABLED */ + } + } else { + /* Metadata */ + if (ni->mft_no < FILE_first_user) + res = FALSE; + else { + /* Interix types */ + dt_type = ntfs_interix_types(ni); + res = (dt_type == NTFS_DT_REG) + || (dt_type == NTFS_DT_DIR); + } + } + } + return (res); +} + +#endif /* HAVE_SETXATTR */ diff --git a/src/ntfs-3g_common.h b/src/ntfs-3g_common.h index 22452321..e9026576 100644 --- a/src/ntfs-3g_common.h +++ b/src/ntfs-3g_common.h @@ -208,6 +208,7 @@ const struct plugin_operations *select_reparse_plugin(ntfs_fuse_context_t *ctx, ntfs_inode *ni, REPARSE_POINT **reparse); int register_reparse_plugin(ntfs_fuse_context_t *ctx, le32 tag, const plugin_operations_t *ops, void *handle); +BOOL user_xattrs_allowed(ntfs_fuse_context_t *ctx, ntfs_inode *ni); #endif /* PLUGINS_DISABLED */