smb3: Add new parm "nodelete"
authorSteve French <stfrench@microsoft.com>
Tue, 19 May 2020 08:06:57 +0000 (03:06 -0500)
committerSteve French <stfrench@microsoft.com>
Mon, 1 Jun 2020 05:10:18 +0000 (00:10 -0500)
In order to handle workloads where it is important to make sure that
a buggy app did not delete content on the drive, the new mount option
"nodelete" allows standard permission checks on the server to work,
but prevents on the client any attempts to unlink a file or delete
a directory on that mount point.  This can be helpful when running
a little understood app on a network mount that contains important
content that should not be deleted.

Signed-off-by: Steve French <stfrench@microsoft.com>
CC: Stable <stable@vger.kernel.org>
Reviewed-by: Pavel Shilovsky <pshilov@microsoft.com>
fs/cifs/cifsfs.c
fs/cifs/cifsglob.h
fs/cifs/connect.c
fs/cifs/inode.c

index c31f362fa098be64e5370ea61ea3f7cd17636ae2..889f9c71049b8638c29fda74dea0db825bbdab7e 100644 (file)
@@ -534,6 +534,8 @@ cifs_show_options(struct seq_file *s, struct dentry *root)
                seq_puts(s, ",signloosely");
        if (tcon->nocase)
                seq_puts(s, ",nocase");
+       if (tcon->nodelete)
+               seq_puts(s, ",nodelete");
        if (tcon->local_lease)
                seq_puts(s, ",locallease");
        if (tcon->retry)
index 39b708d9d86d069aa873d6a18fffbfba4fb0f028..4d261fd78fcba6d7f1e66772caed2be8aef5ee6a 100644 (file)
@@ -562,6 +562,7 @@ struct smb_vol {
        bool override_gid:1;
        bool dynperm:1;
        bool noperm:1;
+       bool nodelete:1;
        bool mode_ace:1;
        bool no_psx_acl:1; /* set if posix acl support should be disabled */
        bool cifs_acl:1;
@@ -1136,6 +1137,7 @@ struct cifs_tcon {
        bool retry:1;
        bool nocase:1;
        bool nohandlecache:1; /* if strange server resource prob can turn off */
+       bool nodelete:1;
        bool seal:1;      /* transport encryption for this mounted share */
        bool unix_ext:1;  /* if false disable Linux extensions to CIFS protocol
                                for this mount even if server would support */
index 329babc6b18a57c7a365acf5dcfc88bfd298f8d0..57d1cc6bf86fcf0483398fa8f59d19737a21ecf6 100644 (file)
@@ -75,7 +75,7 @@ enum {
        Opt_forceuid, Opt_noforceuid,
        Opt_forcegid, Opt_noforcegid,
        Opt_noblocksend, Opt_noautotune, Opt_nolease,
-       Opt_hard, Opt_soft, Opt_perm, Opt_noperm,
+       Opt_hard, Opt_soft, Opt_perm, Opt_noperm, Opt_nodelete,
        Opt_mapposix, Opt_nomapposix,
        Opt_mapchars, Opt_nomapchars, Opt_sfu,
        Opt_nosfu, Opt_nodfs, Opt_posixpaths,
@@ -141,6 +141,7 @@ static const match_table_t cifs_mount_option_tokens = {
        { Opt_soft, "soft" },
        { Opt_perm, "perm" },
        { Opt_noperm, "noperm" },
+       { Opt_nodelete, "nodelete" },
        { Opt_mapchars, "mapchars" }, /* SFU style */
        { Opt_nomapchars, "nomapchars" },
        { Opt_mapposix, "mapposix" }, /* SFM style */
@@ -1760,6 +1761,9 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
                case Opt_noperm:
                        vol->noperm = 1;
                        break;
+               case Opt_nodelete:
+                       vol->nodelete = 1;
+                       break;
                case Opt_mapchars:
                        vol->sfu_remap = true;
                        vol->remap = false; /* disable SFM mapping */
@@ -3362,6 +3366,8 @@ static int match_tcon(struct cifs_tcon *tcon, struct smb_vol *volume_info)
                return 0;
        if (tcon->no_lease != volume_info->no_lease)
                return 0;
+       if (tcon->nodelete != volume_info->nodelete)
+               return 0;
        return 1;
 }
 
@@ -3597,6 +3603,7 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info)
        tcon->retry = volume_info->retry;
        tcon->nocase = volume_info->nocase;
        tcon->nohandlecache = volume_info->nohandlecache;
+       tcon->nodelete = volume_info->nodelete;
        tcon->local_lease = volume_info->local_lease;
        INIT_LIST_HEAD(&tcon->pending_opens);
 
index 5d2965a2373054a4c288a9b6b688a05865bd3e4b..873b1effd4127eef4a969f657b6e149740c2cf0a 100644 (file)
@@ -1418,6 +1418,11 @@ int cifs_unlink(struct inode *dir, struct dentry *dentry)
 
        xid = get_xid();
 
+       if (tcon->nodelete) {
+               rc = -EACCES;
+               goto unlink_out;
+       }
+
        /* Unlink can be called from rename so we can not take the
         * sb->s_vfs_rename_mutex here */
        full_path = build_path_from_dentry(dentry);
@@ -1746,6 +1751,12 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
                goto rmdir_exit;
        }
 
+       if (tcon->nodelete) {
+               rc = -EACCES;
+               cifs_put_tlink(tlink);
+               goto rmdir_exit;
+       }
+
        rc = server->ops->rmdir(xid, tcon, full_path, cifs_sb);
        cifs_put_tlink(tlink);