diff mbox

[CIFS] retrieving CIFS ACLs when mounted with SMB2 fails, dropping session

Message ID CAH2r5msK3t2atR5TcaYJcst91HdTPVZnof9N9_byEt4VR6aVHw@mail.gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Steve French Feb. 3, 2014, 4:40 a.m. UTC
From 1c8b653d63c451a57a41a8134d3d07b9210e1d16 Mon Sep 17 00:00:00 2001
From: Steve French <smfrench@gmail.com>
Date: Sun, 2 Feb 2014 22:25:41 -0600
Subject: [PATCH] [CIFS] retrieving CIFS ACLs when mounted with SMB2 fails
 dropping session

The get/set ACL xattr support for CIFS ACLs attempts to send old
cifs dialect protocol requests even when mounted with SMB2 or later
dialects.  So e.g. mounting with cifacl and vers=2.1 will hang until
the server drops the session due to the illegal request the
client sends.

This patch makes CIFS ACL operations protocol specific to fix that.

Attempting to query/set CIFS ACLs for SMB2 will now return
EOPNOTSUPP (until we add worker routines for sending query
ACL requests via SMB2) instead of sending invalid (cifs)
requests.

A separate followon patch will be done to fix cifs_acl_to_fattr
(which takes a cifs specific u16 fid so can't be abstracted
to work with SMB2 until that is changed).

Signed-off-by: Steve French <smfrench@gmail.com>
Reviewed-by: Shirish Pargaonkar <spargaonkar@suse.com>
CC: Stable <stable@kernel.org>
---
 fs/cifs/cifsacl.c  | 28 ++++++++++++++++++++++++----
 fs/cifs/cifsglob.h |  4 ++++
 fs/cifs/smb1ops.c  |  4 ++++
 fs/cifs/xattr.c    | 15 +++++++++++----
 4 files changed, 43 insertions(+), 8 deletions(-)

             kfree(pacl);
@@ -323,8 +327,11 @@ ssize_t cifs_getxattr(struct dentry *direntry,
const char *ea_name,
             u32 acllen;
             struct cifs_ntsd *pacl;

-            pacl = get_cifs_acl(cifs_sb, direntry->d_inode,
-                        full_path, &acllen);
+            if (pTcon->ses->server->ops->get_acl == NULL)
+                goto get_ea_exit; /* rc already EOPNOTSUPP */
+
+            pacl = pTcon->ses->server->ops->get_acl(cifs_sb,
+                    direntry->d_inode, full_path, &acllen);
             if (IS_ERR(pacl)) {
                 rc = PTR_ERR(pacl);
                 cifs_dbg(VFS, "%s: error %zd getting sec desc\n",

Comments

Steve French Feb. 3, 2014, 4:41 a.m. UTC | #1
Shirish noted the following general suggestion about the way we check
for protocol specific operations

"Another idea would be perhaps to have a get_cifs_acl/set_cifs_acl ops
for respective smb version and them returning EOPNOSUPP error
until they are coded, so an if check for any op could be saved/skipped."

(This could apply to any protocol specific operation)

On Sun, Feb 2, 2014 at 10:40 PM, Steve French <smfrench@gmail.com> wrote:
> From 1c8b653d63c451a57a41a8134d3d07b9210e1d16 Mon Sep 17 00:00:00 2001
> From: Steve French <smfrench@gmail.com>
> Date: Sun, 2 Feb 2014 22:25:41 -0600
> Subject: [PATCH] [CIFS] retrieving CIFS ACLs when mounted with SMB2 fails
>  dropping session
>
> The get/set ACL xattr support for CIFS ACLs attempts to send old
> cifs dialect protocol requests even when mounted with SMB2 or later
> dialects.  So e.g. mounting with cifacl and vers=2.1 will hang until
> the server drops the session due to the illegal request the
> client sends.
>
> This patch makes CIFS ACL operations protocol specific to fix that.
>
> Attempting to query/set CIFS ACLs for SMB2 will now return
> EOPNOTSUPP (until we add worker routines for sending query
> ACL requests via SMB2) instead of sending invalid (cifs)
> requests.
>
> A separate followon patch will be done to fix cifs_acl_to_fattr
> (which takes a cifs specific u16 fid so can't be abstracted
> to work with SMB2 until that is changed).
>
> Signed-off-by: Steve French <smfrench@gmail.com>
> Reviewed-by: Shirish Pargaonkar <spargaonkar@suse.com>
> CC: Stable <stable@kernel.org>
> ---
>  fs/cifs/cifsacl.c  | 28 ++++++++++++++++++++++++----
>  fs/cifs/cifsglob.h |  4 ++++
>  fs/cifs/smb1ops.c  |  4 ++++
>  fs/cifs/xattr.c    | 15 +++++++++++----
>  4 files changed, 43 insertions(+), 8 deletions(-)
>
> diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c
> index 8f9b4f7..7efdb7f 100644
> --- a/fs/cifs/cifsacl.c
> +++ b/fs/cifs/cifsacl.c
> @@ -1043,15 +1043,30 @@ id_mode_to_cifs_acl(struct inode *inode, const
> char *path, __u64 nmode,
>      __u32 secdesclen = 0;
>      struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
>      struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
> +    struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
> +    struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
> +    struct cifs_tcon tcon;
> +
> +    if (IS_ERR(tlink))
> +        return PTR_ERR(tlink);
> +    tcon = tlink_tcon(tlink);
>
>      cifs_dbg(NOISY, "set ACL from mode for %s\n", path);
>
>      /* Get the security descriptor */
> -    pntsd = get_cifs_acl(CIFS_SB(inode->i_sb), inode, path, &secdesclen);
> +
> +    if (tcon->ses->server->ops->get_acl == NULL) {
> +        cifs_put_tlink(tlink);
> +        return -EOPNOTSUPP;
> +    }
> +
> +    pntsd = tcon->ses->server->ops->get_acl(cifs_sb, inode, path,
> +                        &secdesclen);
>      if (IS_ERR(pntsd)) {
>          rc = PTR_ERR(pntsd);
>          cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc);
> -        goto out;
> +        cifs_put_tlink(tlink);
> +        return rc;
>      }
>
>      /*
> @@ -1064,6 +1079,7 @@ id_mode_to_cifs_acl(struct inode *inode, const
> char *path, __u64 nmode,
>      pnntsd = kmalloc(secdesclen, GFP_KERNEL);
>      if (!pnntsd) {
>          kfree(pntsd);
> +        cifs_put_tlink(tlink);
>          return -ENOMEM;
>      }
>
> @@ -1072,14 +1088,18 @@ id_mode_to_cifs_acl(struct inode *inode, const
> char *path, __u64 nmode,
>
>      cifs_dbg(NOISY, "build_sec_desc rc: %d\n", rc);
>
> +    if (tcon->ses->server->ops->set_acl == NULL)
> +        rc = -EOPNOTSUPP;
> +
>      if (!rc) {
>          /* Set the security descriptor */
> -        rc = set_cifs_acl(pnntsd, secdesclen, inode, path, aclflag);
> +        rc = tcon->ses->server->ops->set_acl(pnntsd, secdesclen, inode,
> +                             path, aclflag);
>          cifs_dbg(NOISY, "set_cifs_acl rc: %d\n", rc);
>      }
> +    cifs_put_tlink(tlink);
>
>      kfree(pnntsd);
>      kfree(pntsd);
> -out:
>      return rc;
>  }
> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
> index a245d18..a18391f 100644
> --- a/fs/cifs/cifsglob.h
> +++ b/fs/cifs/cifsglob.h
> @@ -395,6 +395,10 @@ struct smb_version_operations {
>      int (*set_EA)(const unsigned int, struct cifs_tcon *, const char *,
>              const char *, const void *, const __u16,
>              const struct nls_table *, int);
> +    int (*get_acl)(struct cifs_sb_info *, struct inode *, const char *,
> +            u32 *);
> +    int (*set_acl)(struct cifs_ntsd *, __u32, struct inode *, const char *,
> +            int);
>  };
>
>  struct smb_version_values {
> diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
> index 3e4ff79..bfd66d8 100644
> --- a/fs/cifs/smb1ops.c
> +++ b/fs/cifs/smb1ops.c
> @@ -1071,6 +1071,10 @@ struct smb_version_operations smb1_operations = {
>      .query_all_EAs = CIFSSMBQAllEAs,
>      .set_EA = CIFSSMBSetEA,
>  #endif /* CIFS_XATTR */
> +#ifdef CONFIG_CIFS_ACL
> +    .get_acl = get_cifs_acl,
> +    .set_acl = set_cifs_acl,
> +#endif /* CIFS_ACL */
>  };
>
>  struct smb_version_values smb1_values = {
> diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c
> index 95c43bb..b163dca 100644
> --- a/fs/cifs/xattr.c
> +++ b/fs/cifs/xattr.c
> @@ -176,8 +176,12 @@ int cifs_setxattr(struct dentry *direntry, const
> char *ea_name,
>              rc = -ENOMEM;
>          } else {
>              memcpy(pacl, ea_value, value_size);
> -            rc = set_cifs_acl(pacl, value_size,
> -                direntry->d_inode, full_path, CIFS_ACL_DACL);
> +            if (pTcon->ses->server->ops->set_acl)
> +                rc = pTcon->set->server->ops->set_acl(pacl,
> +                        value_size, direntry->d_inode,
> +                        full_path, CIFS_ACL_DACL);
> +            else
> +                rc = -EOPNOTSUPP;
>              if (rc == 0) /* force revalidate of the inode */
>                  CIFS_I(direntry->d_inode)->time = 0;
>              kfree(pacl);
> @@ -323,8 +327,11 @@ ssize_t cifs_getxattr(struct dentry *direntry,
> const char *ea_name,
>              u32 acllen;
>              struct cifs_ntsd *pacl;
>
> -            pacl = get_cifs_acl(cifs_sb, direntry->d_inode,
> -                        full_path, &acllen);
> +            if (pTcon->ses->server->ops->get_acl == NULL)
> +                goto get_ea_exit; /* rc already EOPNOTSUPP */
> +
> +            pacl = pTcon->ses->server->ops->get_acl(cifs_sb,
> +                    direntry->d_inode, full_path, &acllen);
>              if (IS_ERR(pacl)) {
>                  rc = PTR_ERR(pacl);
>                  cifs_dbg(VFS, "%s: error %zd getting sec desc\n",
> --
> 1.8.5.3
>
>
> --
> Thanks,
>
> Steve
Steve French Feb. 3, 2014, 5:12 a.m. UTC | #2
ignore this version of the patch - sent older version with typos. Will
resend fixed one.

On Sun, Feb 2, 2014 at 10:40 PM, Steve French <smfrench@gmail.com> wrote:
> From 1c8b653d63c451a57a41a8134d3d07b9210e1d16 Mon Sep 17 00:00:00 2001
> From: Steve French <smfrench@gmail.com>
> Date: Sun, 2 Feb 2014 22:25:41 -0600
> Subject: [PATCH] [CIFS] retrieving CIFS ACLs when mounted with SMB2 fails
>  dropping session
>
> The get/set ACL xattr support for CIFS ACLs attempts to send old
> cifs dialect protocol requests even when mounted with SMB2 or later
> dialects.  So e.g. mounting with cifacl and vers=2.1 will hang until
> the server drops the session due to the illegal request the
> client sends.
>
> This patch makes CIFS ACL operations protocol specific to fix that.
>
> Attempting to query/set CIFS ACLs for SMB2 will now return
> EOPNOTSUPP (until we add worker routines for sending query
> ACL requests via SMB2) instead of sending invalid (cifs)
> requests.
>
> A separate followon patch will be done to fix cifs_acl_to_fattr
> (which takes a cifs specific u16 fid so can't be abstracted
> to work with SMB2 until that is changed).
>
> Signed-off-by: Steve French <smfrench@gmail.com>
> Reviewed-by: Shirish Pargaonkar <spargaonkar@suse.com>
> CC: Stable <stable@kernel.org>
> ---
>  fs/cifs/cifsacl.c  | 28 ++++++++++++++++++++++++----
>  fs/cifs/cifsglob.h |  4 ++++
>  fs/cifs/smb1ops.c  |  4 ++++
>  fs/cifs/xattr.c    | 15 +++++++++++----
>  4 files changed, 43 insertions(+), 8 deletions(-)
>
> diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c
> index 8f9b4f7..7efdb7f 100644
> --- a/fs/cifs/cifsacl.c
> +++ b/fs/cifs/cifsacl.c
> @@ -1043,15 +1043,30 @@ id_mode_to_cifs_acl(struct inode *inode, const
> char *path, __u64 nmode,
>      __u32 secdesclen = 0;
>      struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
>      struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
> +    struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
> +    struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
> +    struct cifs_tcon tcon;
> +
> +    if (IS_ERR(tlink))
> +        return PTR_ERR(tlink);
> +    tcon = tlink_tcon(tlink);
>
>      cifs_dbg(NOISY, "set ACL from mode for %s\n", path);
>
>      /* Get the security descriptor */
> -    pntsd = get_cifs_acl(CIFS_SB(inode->i_sb), inode, path, &secdesclen);
> +
> +    if (tcon->ses->server->ops->get_acl == NULL) {
> +        cifs_put_tlink(tlink);
> +        return -EOPNOTSUPP;
> +    }
> +
> +    pntsd = tcon->ses->server->ops->get_acl(cifs_sb, inode, path,
> +                        &secdesclen);
>      if (IS_ERR(pntsd)) {
>          rc = PTR_ERR(pntsd);
>          cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc);
> -        goto out;
> +        cifs_put_tlink(tlink);
> +        return rc;
>      }
>
>      /*
> @@ -1064,6 +1079,7 @@ id_mode_to_cifs_acl(struct inode *inode, const
> char *path, __u64 nmode,
>      pnntsd = kmalloc(secdesclen, GFP_KERNEL);
>      if (!pnntsd) {
>          kfree(pntsd);
> +        cifs_put_tlink(tlink);
>          return -ENOMEM;
>      }
>
> @@ -1072,14 +1088,18 @@ id_mode_to_cifs_acl(struct inode *inode, const
> char *path, __u64 nmode,
>
>      cifs_dbg(NOISY, "build_sec_desc rc: %d\n", rc);
>
> +    if (tcon->ses->server->ops->set_acl == NULL)
> +        rc = -EOPNOTSUPP;
> +
>      if (!rc) {
>          /* Set the security descriptor */
> -        rc = set_cifs_acl(pnntsd, secdesclen, inode, path, aclflag);
> +        rc = tcon->ses->server->ops->set_acl(pnntsd, secdesclen, inode,
> +                             path, aclflag);
>          cifs_dbg(NOISY, "set_cifs_acl rc: %d\n", rc);
>      }
> +    cifs_put_tlink(tlink);
>
>      kfree(pnntsd);
>      kfree(pntsd);
> -out:
>      return rc;
>  }
> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
> index a245d18..a18391f 100644
> --- a/fs/cifs/cifsglob.h
> +++ b/fs/cifs/cifsglob.h
> @@ -395,6 +395,10 @@ struct smb_version_operations {
>      int (*set_EA)(const unsigned int, struct cifs_tcon *, const char *,
>              const char *, const void *, const __u16,
>              const struct nls_table *, int);
> +    int (*get_acl)(struct cifs_sb_info *, struct inode *, const char *,
> +            u32 *);
> +    int (*set_acl)(struct cifs_ntsd *, __u32, struct inode *, const char *,
> +            int);
>  };
>
>  struct smb_version_values {
> diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
> index 3e4ff79..bfd66d8 100644
> --- a/fs/cifs/smb1ops.c
> +++ b/fs/cifs/smb1ops.c
> @@ -1071,6 +1071,10 @@ struct smb_version_operations smb1_operations = {
>      .query_all_EAs = CIFSSMBQAllEAs,
>      .set_EA = CIFSSMBSetEA,
>  #endif /* CIFS_XATTR */
> +#ifdef CONFIG_CIFS_ACL
> +    .get_acl = get_cifs_acl,
> +    .set_acl = set_cifs_acl,
> +#endif /* CIFS_ACL */
>  };
>
>  struct smb_version_values smb1_values = {
> diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c
> index 95c43bb..b163dca 100644
> --- a/fs/cifs/xattr.c
> +++ b/fs/cifs/xattr.c
> @@ -176,8 +176,12 @@ int cifs_setxattr(struct dentry *direntry, const
> char *ea_name,
>              rc = -ENOMEM;
>          } else {
>              memcpy(pacl, ea_value, value_size);
> -            rc = set_cifs_acl(pacl, value_size,
> -                direntry->d_inode, full_path, CIFS_ACL_DACL);
> +            if (pTcon->ses->server->ops->set_acl)
> +                rc = pTcon->set->server->ops->set_acl(pacl,
> +                        value_size, direntry->d_inode,
> +                        full_path, CIFS_ACL_DACL);
> +            else
> +                rc = -EOPNOTSUPP;
>              if (rc == 0) /* force revalidate of the inode */
>                  CIFS_I(direntry->d_inode)->time = 0;
>              kfree(pacl);
> @@ -323,8 +327,11 @@ ssize_t cifs_getxattr(struct dentry *direntry,
> const char *ea_name,
>              u32 acllen;
>              struct cifs_ntsd *pacl;
>
> -            pacl = get_cifs_acl(cifs_sb, direntry->d_inode,
> -                        full_path, &acllen);
> +            if (pTcon->ses->server->ops->get_acl == NULL)
> +                goto get_ea_exit; /* rc already EOPNOTSUPP */
> +
> +            pacl = pTcon->ses->server->ops->get_acl(cifs_sb,
> +                    direntry->d_inode, full_path, &acllen);
>              if (IS_ERR(pacl)) {
>                  rc = PTR_ERR(pacl);
>                  cifs_dbg(VFS, "%s: error %zd getting sec desc\n",
> --
> 1.8.5.3
>
>
> --
> Thanks,
>
> Steve
diff mbox

Patch

diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c
index 8f9b4f7..7efdb7f 100644
--- a/fs/cifs/cifsacl.c
+++ b/fs/cifs/cifsacl.c
@@ -1043,15 +1043,30 @@  id_mode_to_cifs_acl(struct inode *inode, const
char *path, __u64 nmode,
     __u32 secdesclen = 0;
     struct cifs_ntsd *pntsd = NULL; /* acl obtained from server */
     struct cifs_ntsd *pnntsd = NULL; /* modified acl to be sent to server */
+    struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
+    struct tcon_link *tlink = cifs_sb_tlink(cifs_sb);
+    struct cifs_tcon tcon;
+
+    if (IS_ERR(tlink))
+        return PTR_ERR(tlink);
+    tcon = tlink_tcon(tlink);

     cifs_dbg(NOISY, "set ACL from mode for %s\n", path);

     /* Get the security descriptor */
-    pntsd = get_cifs_acl(CIFS_SB(inode->i_sb), inode, path, &secdesclen);
+
+    if (tcon->ses->server->ops->get_acl == NULL) {
+        cifs_put_tlink(tlink);
+        return -EOPNOTSUPP;
+    }
+
+    pntsd = tcon->ses->server->ops->get_acl(cifs_sb, inode, path,
+                        &secdesclen);
     if (IS_ERR(pntsd)) {
         rc = PTR_ERR(pntsd);
         cifs_dbg(VFS, "%s: error %d getting sec desc\n", __func__, rc);
-        goto out;
+        cifs_put_tlink(tlink);
+        return rc;
     }

     /*
@@ -1064,6 +1079,7 @@  id_mode_to_cifs_acl(struct inode *inode, const
char *path, __u64 nmode,
     pnntsd = kmalloc(secdesclen, GFP_KERNEL);
     if (!pnntsd) {
         kfree(pntsd);
+        cifs_put_tlink(tlink);
         return -ENOMEM;
     }

@@ -1072,14 +1088,18 @@  id_mode_to_cifs_acl(struct inode *inode, const
char *path, __u64 nmode,

     cifs_dbg(NOISY, "build_sec_desc rc: %d\n", rc);

+    if (tcon->ses->server->ops->set_acl == NULL)
+        rc = -EOPNOTSUPP;
+
     if (!rc) {
         /* Set the security descriptor */
-        rc = set_cifs_acl(pnntsd, secdesclen, inode, path, aclflag);
+        rc = tcon->ses->server->ops->set_acl(pnntsd, secdesclen, inode,
+                             path, aclflag);
         cifs_dbg(NOISY, "set_cifs_acl rc: %d\n", rc);
     }
+    cifs_put_tlink(tlink);

     kfree(pnntsd);
     kfree(pntsd);
-out:
     return rc;
 }
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index a245d18..a18391f 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -395,6 +395,10 @@  struct smb_version_operations {
     int (*set_EA)(const unsigned int, struct cifs_tcon *, const char *,
             const char *, const void *, const __u16,
             const struct nls_table *, int);
+    int (*get_acl)(struct cifs_sb_info *, struct inode *, const char *,
+            u32 *);
+    int (*set_acl)(struct cifs_ntsd *, __u32, struct inode *, const char *,
+            int);
 };

 struct smb_version_values {
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index 3e4ff79..bfd66d8 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -1071,6 +1071,10 @@  struct smb_version_operations smb1_operations = {
     .query_all_EAs = CIFSSMBQAllEAs,
     .set_EA = CIFSSMBSetEA,
 #endif /* CIFS_XATTR */
+#ifdef CONFIG_CIFS_ACL
+    .get_acl = get_cifs_acl,
+    .set_acl = set_cifs_acl,
+#endif /* CIFS_ACL */
 };

 struct smb_version_values smb1_values = {
diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c
index 95c43bb..b163dca 100644
--- a/fs/cifs/xattr.c
+++ b/fs/cifs/xattr.c
@@ -176,8 +176,12 @@  int cifs_setxattr(struct dentry *direntry, const
char *ea_name,
             rc = -ENOMEM;
         } else {
             memcpy(pacl, ea_value, value_size);
-            rc = set_cifs_acl(pacl, value_size,
-                direntry->d_inode, full_path, CIFS_ACL_DACL);
+            if (pTcon->ses->server->ops->set_acl)
+                rc = pTcon->set->server->ops->set_acl(pacl,
+                        value_size, direntry->d_inode,
+                        full_path, CIFS_ACL_DACL);
+            else
+                rc = -EOPNOTSUPP;
             if (rc == 0) /* force revalidate of the inode */
                 CIFS_I(direntry->d_inode)->time = 0;