samba: fix some security problems
[openwrt.git] / package / network / services / samba36 / patches / 015-patch-cve-2015-7560.patch
diff --git a/package/network/services/samba36/patches/015-patch-cve-2015-7560.patch b/package/network/services/samba36/patches/015-patch-cve-2015-7560.patch
new file mode 100644 (file)
index 0000000..6ce8e2f
--- /dev/null
@@ -0,0 +1,172 @@
+From eb27f9b7bf9c1dc902d9545eecf805831bd4e46c Mon Sep 17 00:00:00 2001
+From: Jeremy Allison <jra@samba.org>
+Date: Tue, 5 Jan 2016 11:18:12 -0800
+Subject: [PATCH 1/8] CVE-2015-7560: s3: smbd: Add refuse_symlink() function
+ that can be used to prevent operations on a symlink.
+
+BUG: https://bugzilla.samba.org/show_bug.cgi?id=11648
+
+Signed-off-by: Jeremy Allison <jra@samba.org>
+Reviewed-by: Michael Adam <obnox@samba.org>
+---
+ source3/smbd/trans2.c | 28 ++++++++++++++++++++++++++++
+ 1 file changed, 28 insertions(+)
+
+--- a/source3/smbd/trans2.c
++++ b/source3/smbd/trans2.c
+@@ -51,6 +51,34 @@ static char *store_file_unix_basic_info2
+                               files_struct *fsp,
+                               const SMB_STRUCT_STAT *psbuf);
++/****************************************************************************
++ Check if an open file handle or pathname is a symlink.
++****************************************************************************/
++
++static NTSTATUS refuse_symlink(connection_struct *conn,
++                      const files_struct *fsp,
++                      const char *name)
++{
++      SMB_STRUCT_STAT sbuf;
++      const SMB_STRUCT_STAT *pst = NULL;
++
++      if (fsp) {
++              pst = &fsp->fsp_name->st;
++      } else {
++              int ret = vfs_stat_smb_fname(conn,
++                              name,
++                              &sbuf);
++              if (ret == -1) {
++                      return map_nt_error_from_unix(errno);
++              }
++              pst = &sbuf;
++      }
++      if (S_ISLNK(pst->st_ex_mode)) {
++              return NT_STATUS_ACCESS_DENIED;
++      }
++      return NT_STATUS_OK;
++}
++
+ /********************************************************************
+  Roundup a value to the nearest allocation roundup size boundary.
+  Only do this for Windows clients.
+@@ -181,12 +209,22 @@ NTSTATUS get_ea_names_from_file(TALLOC_C
+       char **names, **tmp;
+       size_t num_names;
+       ssize_t sizeret = -1;
++      NTSTATUS status;
++
++      if (pnames) {
++              *pnames = NULL;
++      }
++      *pnum_names = 0;
+       if (!lp_ea_support(SNUM(conn))) {
+-              if (pnames) {
+-                      *pnames = NULL;
+-              }
+-              *pnum_names = 0;
++              return NT_STATUS_OK;
++      }
++
++      status = refuse_symlink(conn, fsp, fname);
++      if (!NT_STATUS_IS_OK(status)) {
++              /*
++               * Just return no EA's on a symlink.
++               */
+               return NT_STATUS_OK;
+       }
+@@ -236,10 +274,6 @@ NTSTATUS get_ea_names_from_file(TALLOC_C
+       if (sizeret == 0) {
+               TALLOC_FREE(names);
+-              if (pnames) {
+-                      *pnames = NULL;
+-              }
+-              *pnum_names = 0;
+               return NT_STATUS_OK;
+       }
+@@ -550,6 +584,7 @@ NTSTATUS set_ea(connection_struct *conn,
+               const struct smb_filename *smb_fname, struct ea_list *ea_list)
+ {
+       char *fname = NULL;
++      NTSTATUS status;
+       if (!lp_ea_support(SNUM(conn))) {
+               return NT_STATUS_EAS_NOT_SUPPORTED;
+@@ -559,6 +594,12 @@ NTSTATUS set_ea(connection_struct *conn,
+               return NT_STATUS_ACCESS_DENIED;
+       }
++      status = refuse_symlink(conn, fsp, smb_fname->base_name);
++      if (!NT_STATUS_IS_OK(status)) {
++              return status;
++      }
++
++
+       /* For now setting EAs on streams isn't supported. */
+       fname = smb_fname->base_name;
+@@ -4931,6 +4972,13 @@ NTSTATUS smbd_do_qfilepathinfo(connectio
+                               uint16 num_file_acls = 0;
+                               uint16 num_def_acls = 0;
++                              status = refuse_symlink(conn,
++                                              fsp,
++                                              smb_fname->base_name);
++                              if (!NT_STATUS_IS_OK(status)) {
++                                      return status;
++                              }
++
+                               if (fsp && fsp->fh->fd != -1) {
+                                       file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp);
+                               } else {
+@@ -6452,6 +6500,7 @@ static NTSTATUS smb_set_posix_acl(connec
+       uint16 num_def_acls;
+       bool valid_file_acls = True;
+       bool valid_def_acls = True;
++      NTSTATUS status;
+       if (total_data < SMB_POSIX_ACL_HEADER_SIZE) {
+               return NT_STATUS_INVALID_PARAMETER;
+@@ -6479,6 +6528,11 @@ static NTSTATUS smb_set_posix_acl(connec
+               return NT_STATUS_INVALID_PARAMETER;
+       }
++      status = refuse_symlink(conn, fsp, smb_fname->base_name);
++      if (!NT_STATUS_IS_OK(status)) {
++              return status;
++      }
++
+       DEBUG(10,("smb_set_posix_acl: file %s num_file_acls = %u, num_def_acls = %u\n",
+               smb_fname ? smb_fname_str_dbg(smb_fname) : fsp_str_dbg(fsp),
+               (unsigned int)num_file_acls,
+--- a/source3/smbd/nttrans.c
++++ b/source3/smbd/nttrans.c
+@@ -877,6 +877,12 @@ NTSTATUS set_sd(files_struct *fsp, struc
+               return NT_STATUS_OK;
+       }
++      if (S_ISLNK(fsp->fsp_name->st.st_ex_mode)) {
++              DEBUG(10, ("ACL set on symlink %s denied.\n",
++                      fsp_str_dbg(fsp)));
++              return NT_STATUS_ACCESS_DENIED;
++      }
++
+       if (psd->owner_sid == NULL) {
+               security_info_sent &= ~SECINFO_OWNER;
+       }
+@@ -1925,6 +1931,12 @@ NTSTATUS smbd_do_query_security_desc(con
+               return NT_STATUS_ACCESS_DENIED;
+       }
++      if (S_ISLNK(fsp->fsp_name->st.st_ex_mode)) {
++              DEBUG(10, ("ACL get on symlink %s denied.\n",
++                      fsp_str_dbg(fsp)));
++              return NT_STATUS_ACCESS_DENIED;
++      }
++
+       if (security_info_wanted & (SECINFO_DACL|SECINFO_OWNER|
+                       SECINFO_GROUP|SECINFO_SACL)) {
+               /* Don't return SECINFO_LABEL if anything else was