smbd quotas: avoid stat of foreign file systems
authorUri Simchoni <uri@samba.org>
Mon, 18 Jan 2016 21:34:48 +0000 (23:34 +0200)
committerJeremy Allison <jra@samba.org>
Wed, 27 Jan 2016 02:35:47 +0000 (03:35 +0100)
When determining the block device of our file system, avoid
stat'ing paths which are definitely not the mount point of
our file system. This is done to avoid stalling smbd due to
unresponsive network file systems (e.g. NFS) which are not
related to the SMB shares.

See discussion in samba-technical for vfs_fileid:
https://lists.samba.org/archive/samba-technical/2016-January/111553.html

Signed-off-by: Uri Simchoni <uri@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
Autobuild-User(master): Jeremy Allison <jra@samba.org>
Autobuild-Date(master): Wed Jan 27 03:35:48 CET 2016 on sn-devel-144

source3/lib/sysquotas.c

index 2ef1d1bf8f5a7d942b1ed8cc9dfbc902c3b57e69..bacc4b231250adaa2aa5bfe48561d287c8f1d380 100644 (file)
 
 #endif /* NO_QUOTACTL_USED */
 
-#ifdef HAVE_MNTENT
+#if defined(HAVE_MNTENT) && defined(HAVE_REALPATH)
 static int sys_path_to_bdev(const char *path, char **mntpath, char **bdev, char **fs)
 {
        int ret = -1;
        SMB_STRUCT_STAT S;
        FILE *fp;
-       struct mntent *mnt;
+       struct mntent *mnt = NULL;
        SMB_DEV_T devno;
+       char *stat_mntpath = NULL;
+       char *p;
 
        /* find the block device file */
-
-       if (!path||!mntpath||!bdev||!fs)
-               smb_panic("sys_path_to_bdev: called with NULL pointer");
-
        (*mntpath) = NULL;
        (*bdev) = NULL;
        (*fs) = NULL;
-       
-       if ( sys_stat(path, &S, false) == -1 )
-               return (-1);
+
+       if (sys_stat(path, &S, false) != 0) {
+               return -1;
+       }
 
        devno = S.st_ex_dev ;
 
+       stat_mntpath = sys_realpath(path);
+       if (stat_mntpath == NULL) {
+               DBG_WARNING("realpath(%s) failed - %s\n", path,
+                           strerror(errno));
+               goto out;
+       }
+
+       if (sys_stat(stat_mntpath, &S, false) != 0) {
+               DBG_WARNING("cannot stat real path %s - %s\n", stat_mntpath,
+                           strerror(errno));
+               goto out;
+       }
+
+       if (S.st_ex_dev != devno) {
+               DBG_WARNING("device on real path has changed\n");
+               goto out;
+       }
+
+       while (true) {
+               p = strrchr(stat_mntpath, '/');
+               if (p == NULL) {
+                       DBG_ERR("realpath for %s does not begin with a '/'\n",
+                               path);
+                       goto out;
+               }
+
+               if (p == stat_mntpath) {
+                       ++p;
+               }
+
+               *p = 0;
+               if (sys_stat(stat_mntpath, &S, false) != 0) {
+                       DBG_WARNING("cannot stat real path component %s - %s\n",
+                                   stat_mntpath, strerror(errno));
+                       goto out;
+               }
+               if (S.st_ex_dev != devno) {
+                       *p = '/';
+                       break;
+               }
+
+               if (p <= stat_mntpath + 1) {
+                       break;
+               }
+       }
+
        fp = setmntent(MOUNTED,"r");
        if (fp == NULL) {
-               return -1;
+               goto out;
        }
   
        while ((mnt = getmntent(fp))) {
+               if (!strequal(mnt->mnt_dir, stat_mntpath)) {
+                       continue;
+               }
+
                if ( sys_stat(mnt->mnt_dir, &S, false) == -1 )
                        continue ;
 
@@ -91,6 +140,8 @@ static int sys_path_to_bdev(const char *path, char **mntpath, char **bdev, char
 
        endmntent(fp) ;
 
+out:
+       SAFE_FREE(stat_mntpath);
        return ret;
 }
 /* #endif HAVE_MNTENT */