1From eb27f9b7bf9c1dc902d9545eecf805831bd4e46c Mon Sep 17 00:00:00 2001
2From: Jeremy Allison <jra@samba.org>
3Date: Tue, 5 Jan 2016 11:18:12 -0800
4Subject: [PATCH 1/8] CVE-2015-7560: s3: smbd: Add refuse_symlink() function
5 that can be used to prevent operations on a symlink.
6
7BUG: https://bugzilla.samba.org/show_bug.cgi?id=11648
8
9Signed-off-by: Jeremy Allison <jra@samba.org>
10Reviewed-by: Michael Adam <obnox@samba.org>
11---
12 source3/smbd/trans2.c | 28 ++++++++++++++++++++++++++++
13 1 file changed, 28 insertions(+)
14
15--- a/source3/smbd/trans2.c
16+++ b/source3/smbd/trans2.c
17@@ -51,6 +51,34 @@ static char *store_file_unix_basic_info2
18 				files_struct *fsp,
19 				const SMB_STRUCT_STAT *psbuf);
20 
21+/****************************************************************************
22+ Check if an open file handle or pathname is a symlink.
23+****************************************************************************/
24+
25+static NTSTATUS refuse_symlink(connection_struct *conn,
26+			const files_struct *fsp,
27+			const char *name)
28+{
29+	SMB_STRUCT_STAT sbuf;
30+	const SMB_STRUCT_STAT *pst = NULL;
31+
32+	if (fsp) {
33+		pst = &fsp->fsp_name->st;
34+	} else {
35+		int ret = vfs_stat_smb_fname(conn,
36+				name,
37+				&sbuf);
38+		if (ret == -1) {
39+			return map_nt_error_from_unix(errno);
40+		}
41+		pst = &sbuf;
42+	}
43+	if (S_ISLNK(pst->st_ex_mode)) {
44+		return NT_STATUS_ACCESS_DENIED;
45+	}
46+	return NT_STATUS_OK;
47+}
48+
49 /********************************************************************
50  Roundup a value to the nearest allocation roundup size boundary.
51  Only do this for Windows clients.
52@@ -181,12 +209,22 @@ NTSTATUS get_ea_names_from_file(TALLOC_C
53 	char **names, **tmp;
54 	size_t num_names;
55 	ssize_t sizeret = -1;
56+	NTSTATUS status;
57+
58+	if (pnames) {
59+		*pnames = NULL;
60+	}
61+	*pnum_names = 0;
62 
63 	if (!lp_ea_support(SNUM(conn))) {
64-		if (pnames) {
65-			*pnames = NULL;
66-		}
67-		*pnum_names = 0;
68+		return NT_STATUS_OK;
69+	}
70+
71+	status = refuse_symlink(conn, fsp, fname);
72+	if (!NT_STATUS_IS_OK(status)) {
73+		/*
74+		 * Just return no EA's on a symlink.
75+		 */
76 		return NT_STATUS_OK;
77 	}
78 
79@@ -236,10 +274,6 @@ NTSTATUS get_ea_names_from_file(TALLOC_C
80 
81 	if (sizeret == 0) {
82 		TALLOC_FREE(names);
83-		if (pnames) {
84-			*pnames = NULL;
85-		}
86-		*pnum_names = 0;
87 		return NT_STATUS_OK;
88 	}
89 
90@@ -550,6 +584,7 @@ NTSTATUS set_ea(connection_struct *conn,
91 		const struct smb_filename *smb_fname, struct ea_list *ea_list)
92 {
93 	char *fname = NULL;
94+	NTSTATUS status;
95 
96 	if (!lp_ea_support(SNUM(conn))) {
97 		return NT_STATUS_EAS_NOT_SUPPORTED;
98@@ -559,6 +594,12 @@ NTSTATUS set_ea(connection_struct *conn,
99 		return NT_STATUS_ACCESS_DENIED;
100 	}
101 
102+	status = refuse_symlink(conn, fsp, smb_fname->base_name);
103+	if (!NT_STATUS_IS_OK(status)) {
104+		return status;
105+	}
106+
107+
108 	/* For now setting EAs on streams isn't supported. */
109 	fname = smb_fname->base_name;
110 
111@@ -4931,6 +4972,13 @@ NTSTATUS smbd_do_qfilepathinfo(connectio
112 				uint16 num_file_acls = 0;
113 				uint16 num_def_acls = 0;
114 
115+				status = refuse_symlink(conn,
116+						fsp,
117+						smb_fname->base_name);
118+				if (!NT_STATUS_IS_OK(status)) {
119+					return status;
120+				}
121+
122 				if (fsp && fsp->fh->fd != -1) {
123 					file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp);
124 				} else {
125@@ -6452,6 +6500,7 @@ static NTSTATUS smb_set_posix_acl(connec
126 	uint16 num_def_acls;
127 	bool valid_file_acls = True;
128 	bool valid_def_acls = True;
129+	NTSTATUS status;
130 
131 	if (total_data < SMB_POSIX_ACL_HEADER_SIZE) {
132 		return NT_STATUS_INVALID_PARAMETER;
133@@ -6479,6 +6528,11 @@ static NTSTATUS smb_set_posix_acl(connec
134 		return NT_STATUS_INVALID_PARAMETER;
135 	}
136 
137+	status = refuse_symlink(conn, fsp, smb_fname->base_name);
138+	if (!NT_STATUS_IS_OK(status)) {
139+		return status;
140+	}
141+
142 	DEBUG(10,("smb_set_posix_acl: file %s num_file_acls = %u, num_def_acls = %u\n",
143 		smb_fname ? smb_fname_str_dbg(smb_fname) : fsp_str_dbg(fsp),
144 		(unsigned int)num_file_acls,
145--- a/source3/smbd/nttrans.c
146+++ b/source3/smbd/nttrans.c
147@@ -877,6 +877,12 @@ NTSTATUS set_sd(files_struct *fsp, struc
148 		return NT_STATUS_OK;
149 	}
150 
151+	if (S_ISLNK(fsp->fsp_name->st.st_ex_mode)) {
152+		DEBUG(10, ("ACL set on symlink %s denied.\n",
153+			fsp_str_dbg(fsp)));
154+		return NT_STATUS_ACCESS_DENIED;
155+	}
156+
157 	if (psd->owner_sid == NULL) {
158 		security_info_sent &= ~SECINFO_OWNER;
159 	}
160@@ -1925,6 +1931,12 @@ NTSTATUS smbd_do_query_security_desc(con
161 		return NT_STATUS_ACCESS_DENIED;
162 	}
163 
164+	if (S_ISLNK(fsp->fsp_name->st.st_ex_mode)) {
165+		DEBUG(10, ("ACL get on symlink %s denied.\n",
166+			fsp_str_dbg(fsp)));
167+		return NT_STATUS_ACCESS_DENIED;
168+	}
169+
170 	if (security_info_wanted & (SECINFO_DACL|SECINFO_OWNER|
171 			SECINFO_GROUP|SECINFO_SACL)) {
172 		/* Don't return SECINFO_LABEL if anything else was
173