Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

cifs: refactor create_sd_buf() and and avoid corrupting the buffer

When mounting with "idsfromsid" mount option, Azure
corrupted the owner SIDs due to excessive padding
caused by placing the owner fields at the end of the
security descriptor on create. Placing owners at the
front of the security descriptor (rather than the end)
is also safer, as the number of ACEs (that follow it)
are variable.

Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com>
Suggested-by: Rohith Surabattula <rohiths@microsoft.com>
CC: Stable <stable@vger.kernel.org> # v5.8
Signed-off-by: Steve French <stfrench@microsoft.com>

authored by

Ronnie Sahlberg and committed by
Steve French
ea64370b 59463eb8

+37 -34
+37 -32
fs/cifs/smb2pdu.c
··· 2272 2272 create_sd_buf(umode_t mode, bool set_owner, unsigned int *len) 2273 2273 { 2274 2274 struct crt_sd_ctxt *buf; 2275 - struct cifs_ace *pace; 2276 - unsigned int sdlen, acelen; 2275 + __u8 *ptr, *aclptr; 2276 + unsigned int acelen, acl_size, ace_count; 2277 2277 unsigned int owner_offset = 0; 2278 2278 unsigned int group_offset = 0; 2279 + struct smb3_acl acl; 2279 2280 2280 - *len = roundup(sizeof(struct crt_sd_ctxt) + (sizeof(struct cifs_ace) * 2), 8); 2281 + *len = roundup(sizeof(struct crt_sd_ctxt) + (sizeof(struct cifs_ace) * 4), 8); 2281 2282 2282 2283 if (set_owner) { 2283 - /* offset fields are from beginning of security descriptor not of create context */ 2284 - owner_offset = sizeof(struct smb3_acl) + (sizeof(struct cifs_ace) * 2); 2285 - 2286 2284 /* sizeof(struct owner_group_sids) is already multiple of 8 so no need to round */ 2287 2285 *len += sizeof(struct owner_group_sids); 2288 2286 } ··· 2289 2291 if (buf == NULL) 2290 2292 return buf; 2291 2293 2294 + ptr = (__u8 *)&buf[1]; 2292 2295 if (set_owner) { 2296 + /* offset fields are from beginning of security descriptor not of create context */ 2297 + owner_offset = ptr - (__u8 *)&buf->sd; 2293 2298 buf->sd.OffsetOwner = cpu_to_le32(owner_offset); 2294 - group_offset = owner_offset + sizeof(struct owner_sid); 2299 + group_offset = owner_offset + offsetof(struct owner_group_sids, group); 2295 2300 buf->sd.OffsetGroup = cpu_to_le32(group_offset); 2301 + 2302 + setup_owner_group_sids(ptr); 2303 + ptr += sizeof(struct owner_group_sids); 2296 2304 } else { 2297 2305 buf->sd.OffsetOwner = 0; 2298 2306 buf->sd.OffsetGroup = 0; 2299 2307 } 2300 2308 2301 - sdlen = sizeof(struct smb3_sd) + sizeof(struct smb3_acl) + 2302 - 2 * sizeof(struct cifs_ace); 2303 - if (set_owner) { 2304 - sdlen += sizeof(struct owner_group_sids); 2305 - setup_owner_group_sids(owner_offset + sizeof(struct create_context) + 8 /* name */ 2306 - + (char *)buf); 2307 - } 2308 - 2309 - buf->ccontext.DataOffset = cpu_to_le16(offsetof 2310 - (struct crt_sd_ctxt, sd)); 2311 - buf->ccontext.DataLength = cpu_to_le32(sdlen); 2309 + buf->ccontext.DataOffset = cpu_to_le16(offsetof(struct crt_sd_ctxt, sd)); 2312 2310 buf->ccontext.NameOffset = cpu_to_le16(offsetof(struct crt_sd_ctxt, Name)); 2313 2311 buf->ccontext.NameLength = cpu_to_le16(4); 2314 2312 /* SMB2_CREATE_SD_BUFFER_TOKEN is "SecD" */ ··· 2313 2319 buf->Name[2] = 'c'; 2314 2320 buf->Name[3] = 'D'; 2315 2321 buf->sd.Revision = 1; /* Must be one see MS-DTYP 2.4.6 */ 2322 + 2316 2323 /* 2317 2324 * ACL is "self relative" ie ACL is stored in contiguous block of memory 2318 2325 * and "DP" ie the DACL is present ··· 2321 2326 buf->sd.Control = cpu_to_le16(ACL_CONTROL_SR | ACL_CONTROL_DP); 2322 2327 2323 2328 /* offset owner, group and Sbz1 and SACL are all zero */ 2324 - buf->sd.OffsetDacl = cpu_to_le32(sizeof(struct smb3_sd)); 2325 - buf->acl.AclRevision = ACL_REVISION; /* See 2.4.4.1 of MS-DTYP */ 2329 + buf->sd.OffsetDacl = cpu_to_le32(ptr - (__u8 *)&buf->sd); 2330 + /* Ship the ACL for now. we will copy it into buf later. */ 2331 + aclptr = ptr; 2332 + ptr += sizeof(struct cifs_acl); 2326 2333 2327 2334 /* create one ACE to hold the mode embedded in reserved special SID */ 2328 - pace = (struct cifs_ace *)(sizeof(struct crt_sd_ctxt) + (char *)buf); 2329 - acelen = setup_special_mode_ACE(pace, (__u64)mode); 2335 + acelen = setup_special_mode_ACE((struct cifs_ace *)ptr, (__u64)mode); 2336 + ptr += acelen; 2337 + acl_size = acelen + sizeof(struct smb3_acl); 2338 + ace_count = 1; 2330 2339 2331 2340 if (set_owner) { 2332 2341 /* we do not need to reallocate buffer to add the two more ACEs. plenty of space */ 2333 - pace = (struct cifs_ace *)(acelen + (sizeof(struct crt_sd_ctxt) + (char *)buf)); 2334 - acelen += setup_special_user_owner_ACE(pace); 2335 - /* it does not appear necessary to add an ACE for the NFS group SID */ 2336 - buf->acl.AceCount = cpu_to_le16(3); 2337 - } else 2338 - buf->acl.AceCount = cpu_to_le16(2); 2342 + acelen = setup_special_user_owner_ACE((struct cifs_ace *)ptr); 2343 + ptr += acelen; 2344 + acl_size += acelen; 2345 + ace_count += 1; 2346 + } 2339 2347 2340 2348 /* and one more ACE to allow access for authenticated users */ 2341 - pace = (struct cifs_ace *)(acelen + (sizeof(struct crt_sd_ctxt) + 2342 - (char *)buf)); 2343 - acelen += setup_authusers_ACE(pace); 2349 + acelen = setup_authusers_ACE((struct cifs_ace *)ptr); 2350 + ptr += acelen; 2351 + acl_size += acelen; 2352 + ace_count += 1; 2344 2353 2345 - buf->acl.AclSize = cpu_to_le16(sizeof(struct cifs_acl) + acelen); 2354 + acl.AclRevision = ACL_REVISION; /* See 2.4.4.1 of MS-DTYP */ 2355 + acl.AclSize = cpu_to_le16(acl_size); 2356 + acl.AceCount = cpu_to_le16(ace_count); 2357 + memcpy(aclptr, &acl, sizeof(struct cifs_acl)); 2358 + 2359 + buf->ccontext.DataLength = cpu_to_le32(ptr - (__u8 *)&buf->sd); 2360 + *len = ptr - (__u8 *)buf; 2346 2361 2347 2362 return buf; 2348 2363 }
-2
fs/cifs/smb2pdu.h
··· 963 963 struct create_context ccontext; 964 964 __u8 Name[8]; 965 965 struct smb3_sd sd; 966 - struct smb3_acl acl; 967 - /* Followed by at least 4 ACEs */ 968 966 } __packed; 969 967 970 968