summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRalph Wuerthner <ralph.wuerthner@de.ibm.com>2016-01-12 16:00:24 +0100
committerJeremy Allison <jra@samba.org>2018-01-06 00:07:17 +0100
commit996249571d0e8f9285d1b714b1c36d66e7649271 (patch)
tree8f21fdf268e8e4e1f6f72de7a4e2e651d8ac0600
parent326df161736abc16fb3bd35a18a3e55a44fb3c5d (diff)
downloadsamba-996249571d0e8f9285d1b714b1c36d66e7649271.tar.gz
vfs_fileid: add "fstype/mntdir deny/allow list" option
When using the fsname or fsid algorithm a stat() and statfs() call is required for all mounted file systems to generate the file_id. If e.g. an NFS file system is unresponsive such a call might block and the smbd process will become unresponsive. Add "fileid:fstype deny", "fileid:fstype allow", "fileid:mntdir deny", and "fileid:mntdir allow" options to ignore potentially unresponsive file systems. See also https://lists.samba.org/archive/samba-technical/2016-January/111553.html for a discussion about why this is useful. Signed-off-by: Ralph Wuerthner <ralph.wuerthner@de.ibm.com> Reviewed-by: Ralph Boehme <slow@samba.org> Reviewed-by: Jeremy Allison <jra@samba.org>
-rw-r--r--docs-xml/manpages/vfs_fileid.8.xml47
-rw-r--r--source3/modules/vfs_fileid.c114
2 files changed, 161 insertions, 0 deletions
diff --git a/docs-xml/manpages/vfs_fileid.8.xml b/docs-xml/manpages/vfs_fileid.8.xml
index 5a3a70e9b95..568756ba519 100644
--- a/docs-xml/manpages/vfs_fileid.8.xml
+++ b/docs-xml/manpages/vfs_fileid.8.xml
@@ -40,6 +40,15 @@
generates the device number based on the configured algorithm
(see the "fileid:algorithm" option).
</para>
+
+ <para>When using the fsname or fsid algorithm a
+ <command>stat()</command> and <command>statfs()</command> call is
+ required for all mounted file systems to generate the file_id. If e.g.
+ an NFS file system is unresponsive such a call might block and the smbd
+ process will become unresponsive. Use the "fileid:fstype deny",
+ "fileid:fstype allow", "fileid:mntdir deny", or "fileid:mntdir allow"
+ options to ignore potentially unresponsive file systems.
+ </para>
</refsect1>
@@ -75,6 +84,44 @@
</listitem>
</varlistentry>
+ <varlistentry>
+ <term>fileid:fstype deny = LIST</term>
+ <listitem>
+ <para>List of file system types to be ignored for file_id
+ generation.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>fileid:fstype allow = LIST</term>
+ <listitem>
+ <para>List of file system types to be allowed for file_id
+ generation. If this option is set, file system types not listed
+ here are ignored.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>fileid:mntdir deny = LIST</term>
+ <listitem>
+ <para>List of file system mount points to be ignored for
+ file_id generation.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>fileid:mntdir allow = LIST</term>
+ <listitem>
+ <para>List of file system mount points to be allowed for file_id
+ generation. If this option is set, file system mount points
+ not listed here are ignored.
+ </para>
+ </listitem>
+ </varlistentry>
+
</variablelist>
</refsect1>
diff --git a/source3/modules/vfs_fileid.c b/source3/modules/vfs_fileid.c
index fedcac7e6d5..583665775b2 100644
--- a/source3/modules/vfs_fileid.c
+++ b/source3/modules/vfs_fileid.c
@@ -38,10 +38,62 @@ struct fileid_mount_entry {
struct fileid_handle_data {
uint64_t (*device_mapping_fn)(struct fileid_handle_data *data,
SMB_DEV_T dev);
+ char **fstype_deny_list;
+ char **fstype_allow_list;
+ char **mntdir_deny_list;
+ char **mntdir_allow_list;
unsigned num_mount_entries;
struct fileid_mount_entry *mount_entries;
};
+/* check if a mount entry is allowed based on fstype and mount directory */
+static bool fileid_mount_entry_allowed(struct fileid_handle_data *data,
+ struct mntent *m)
+{
+ int i;
+ char **fstype_deny = data->fstype_deny_list;
+ char **fstype_allow = data->fstype_allow_list;
+ char **mntdir_deny = data->mntdir_deny_list;
+ char **mntdir_allow = data->mntdir_allow_list;
+
+ if (fstype_deny != NULL) {
+ for (i = 0; fstype_deny[i] != NULL; i++) {
+ if (strcmp(m->mnt_type, fstype_deny[i]) == 0) {
+ return false;
+ }
+ }
+ }
+ if (fstype_allow != NULL) {
+ for (i = 0; fstype_allow[i] != NULL; i++) {
+ if (strcmp(m->mnt_type, fstype_allow[i]) == 0) {
+ break;
+ }
+ }
+ if (fstype_allow[i] == NULL) {
+ return false;
+ }
+ }
+ if (mntdir_deny != NULL) {
+ for (i=0; mntdir_deny[i] != NULL; i++) {
+ if (strcmp(m->mnt_dir, mntdir_deny[i]) == 0) {
+ return false;
+ }
+ }
+ }
+ if (mntdir_allow != NULL) {
+ for (i=0; mntdir_allow[i] != NULL; i++) {
+ if (strcmp(m->mnt_dir, mntdir_allow[i]) == 0) {
+ break;
+ }
+ }
+ if (mntdir_allow[i] == NULL) {
+ return false;
+ }
+ }
+ return true;
+}
+
+
/* load all the mount entries from the mtab */
static void fileid_load_mount_entries(struct fileid_handle_data *data)
{
@@ -58,7 +110,13 @@ static void fileid_load_mount_entries(struct fileid_handle_data *data)
struct stat st;
struct statfs sfs;
struct fileid_mount_entry *cur;
+ bool allowed;
+ allowed = fileid_mount_entry_allowed(data, m);
+ if (!allowed) {
+ DBG_DEBUG("skipping mount entry %s\n", m->mnt_dir);
+ continue;
+ }
if (stat(m->mnt_dir, &st) != 0) continue;
if (statfs(m->mnt_dir, &sfs) != 0) continue;
@@ -183,6 +241,10 @@ static int fileid_connect(struct vfs_handle_struct *handle,
{
struct fileid_handle_data *data;
const char *algorithm;
+ const char **fstype_deny_list = NULL;
+ const char **fstype_allow_list = NULL;
+ const char **mntdir_deny_list = NULL;
+ const char **mntdir_allow_list = NULL;
int saved_errno;
int ret = SMB_VFS_NEXT_CONNECT(handle, service, user);
@@ -219,6 +281,58 @@ static int fileid_connect(struct vfs_handle_struct *handle,
return -1;
}
+ fstype_deny_list = lp_parm_string_list(SNUM(handle->conn), "fileid",
+ "fstype deny", NULL);
+ if (fstype_deny_list != NULL) {
+ data->fstype_deny_list = str_list_copy(data, fstype_deny_list);
+ if (data->fstype_deny_list == NULL) {
+ saved_errno = errno;
+ DBG_ERR("str_list_copy failed\n");
+ SMB_VFS_NEXT_DISCONNECT(handle);
+ errno = saved_errno;
+ return -1;
+ }
+ }
+
+ fstype_allow_list = lp_parm_string_list(SNUM(handle->conn), "fileid",
+ "fstype allow", NULL);
+ if (fstype_allow_list != NULL) {
+ data->fstype_allow_list = str_list_copy(data, fstype_allow_list);
+ if (data->fstype_allow_list == NULL) {
+ saved_errno = errno;
+ DBG_ERR("str_list_copy failed\n");
+ SMB_VFS_NEXT_DISCONNECT(handle);
+ errno = saved_errno;
+ return -1;
+ }
+ }
+
+ mntdir_deny_list = lp_parm_string_list(SNUM(handle->conn), "fileid",
+ "mntdir deny", NULL);
+ if (mntdir_deny_list != NULL) {
+ data->mntdir_deny_list = str_list_copy(data, mntdir_deny_list);
+ if (data->mntdir_deny_list == NULL) {
+ saved_errno = errno;
+ DBG_ERR("str_list_copy failed\n");
+ SMB_VFS_NEXT_DISCONNECT(handle);
+ errno = saved_errno;
+ return -1;
+ }
+ }
+
+ mntdir_allow_list = lp_parm_string_list(SNUM(handle->conn), "fileid",
+ "mntdir allow", NULL);
+ if (mntdir_allow_list != NULL) {
+ data->mntdir_allow_list = str_list_copy(data, mntdir_allow_list);
+ if (data->mntdir_allow_list == NULL) {
+ saved_errno = errno;
+ DBG_ERR("str_list_copy failed\n");
+ SMB_VFS_NEXT_DISCONNECT(handle);
+ errno = saved_errno;
+ return -1;
+ }
+ }
+
SMB_VFS_HANDLE_SET_DATA(handle, data, NULL,
struct fileid_handle_data,
return -1);