173 lines
4.5 KiB
Diff
173 lines
4.5 KiB
Diff
|
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
|