From owner-svn-src-all@freebsd.org Tue Sep 3 14:06:36 2019 Return-Path: Delivered-To: svn-src-all@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id E9C7DDC57F; Tue, 3 Sep 2019 14:06:13 +0000 (UTC) (envelope-from yuripv@freebsd.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2610:1c1:1:6074::16:84]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "freefall.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 46N7z92bjTz4PKt; Tue, 3 Sep 2019 14:06:13 +0000 (UTC) (envelope-from yuripv@freebsd.org) Received: by freefall.freebsd.org (Postfix, from userid 1452) id 1CD531A341; Tue, 3 Sep 2019 14:06:02 +0000 (UTC) X-Original-To: yuripv@localmail.freebsd.org Delivered-To: yuripv@localmail.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [96.47.72.80]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (Client CN "mx1.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by freefall.freebsd.org (Postfix) with ESMTPS id B9D266F7; Fri, 5 Apr 2019 02:21:20 +0000 (UTC) (envelope-from owner-src-committers@freebsd.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2610:1c1:1:6074::16:84]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "freefall.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4A25470960; Fri, 5 Apr 2019 02:21:20 +0000 (UTC) (envelope-from owner-src-committers@freebsd.org) Received: by freefall.freebsd.org (Postfix, from userid 538) id 151FD6EA; Fri, 5 Apr 2019 02:21:20 +0000 (UTC) Delivered-To: src-committers@localmail.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [96.47.72.80]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) (Client CN "mx1.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by freefall.freebsd.org (Postfix) with ESMTPS id 449FC6E1 for ; Fri, 5 Apr 2019 02:21:17 +0000 (UTC) (envelope-from delphij@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 1281870920; Fri, 5 Apr 2019 02:21:17 +0000 (UTC) (envelope-from delphij@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id D0B606914; Fri, 5 Apr 2019 02:21:16 +0000 (UTC) (envelope-from delphij@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id x352LGvQ015041; Fri, 5 Apr 2019 02:21:16 GMT (envelope-from delphij@FreeBSD.org) Received: (from delphij@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id x352LGjU015040; Fri, 5 Apr 2019 02:21:16 GMT (envelope-from delphij@FreeBSD.org) Message-Id: <201904050221.x352LGjU015040@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: delphij set sender to delphij@FreeBSD.org using -f From: Xin LI To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r345900 - head/sbin/fsck_msdosfs X-SVN-Group: head X-SVN-Commit-Author: delphij X-SVN-Commit-Paths: head/sbin/fsck_msdosfs X-SVN-Commit-Revision: 345900 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Precedence: bulk X-Loop: FreeBSD.org Sender: owner-src-committers@freebsd.org X-Rspamd-Queue-Id: 4A25470960 X-Spamd-Bar: -- Authentication-Results: mx1.freebsd.org X-Spamd-Result: default: False [-2.94 / 15.00]; local_wl_from(0.00)[freebsd.org]; NEURAL_HAM_MEDIUM(-1.00)[-0.999,0]; NEURAL_HAM_SHORT(-0.94)[-0.941,0]; ASN(0.00)[asn:11403, ipnet:2610:1c1:1::/48, country:US]; NEURAL_HAM_LONG(-1.00)[-1.000,0] Status: O X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.29 List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Date: Tue, 03 Sep 2019 14:06:36 -0000 X-Original-Date: Fri, 5 Apr 2019 02:21:16 +0000 (UTC) X-List-Received-Date: Tue, 03 Sep 2019 14:06:36 -0000 Author: delphij Date: Fri Apr 5 02:21:16 2019 New Revision: 345900 URL: https://svnweb.freebsd.org/changeset/base/345900 Log: Implement checking of `.' and `..' entries of subdirectory. Reviewed by: pfg Obtained from: Android https://android.googlesource.com/platform/external/fsck_msdos/+/b6ee08aadb580341a4d80943741b80de16a88b5d%5E%21/ MFC after: 2 weeks Differential Revision: https://reviews.freebsd.org/D19824 Modified: head/sbin/fsck_msdosfs/dir.c Modified: head/sbin/fsck_msdosfs/dir.c ============================================================================== --- head/sbin/fsck_msdosfs/dir.c Fri Apr 5 01:22:30 2019 (r345899) +++ head/sbin/fsck_msdosfs/dir.c Fri Apr 5 02:21:16 2019 (r345900) @@ -444,7 +444,78 @@ checksize(struct bootblock *boot, struct fatEntry *fat return FSOK; } +static const u_char dot_name[] = { + '.', ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ' }; +static const u_char dotdot_name[] = { + '.', '.',' ',' ',' ',' ',' ',' ',' ',' ',' ' }; + /* + * Basic sanity check if the subdirectory have good '.' and '..' entries, + * and they are directory entries. Further sanity checks are performed + * when we traverse into it. + */ +static int +check_subdirectory(int f, struct bootblock *boot, struct dosDirEntry *dir) +{ + u_char *buf, *cp; + off_t off; + cl_t cl; + int retval = FSOK; + + cl = dir->head; + if (dir->parent && (cl < CLUST_FIRST || cl >= boot->NumClusters)) { + return FSERROR; + } + + if (!(boot->flags & FAT32) && !dir->parent) { + off = boot->bpbResSectors + boot->bpbFATs * + boot->FATsecs; + } else { + off = cl * boot->bpbSecPerClust + boot->ClusterOffset; + } + + /* + * We only need to check the first two entries of the directory, + * which is found in the first sector of the directory entry, + * so read in only the first sector. + */ + buf = malloc(boot->bpbBytesPerSec); + if (buf == NULL) { + perr("No space for directory buffer (%u)", + boot->bpbBytesPerSec); + return FSFATAL; + } + + off *= boot->bpbBytesPerSec; + if (lseek(f, off, SEEK_SET) != off || + read(f, buf, boot->bpbBytesPerSec) != boot->bpbBytesPerSec) { + perr("Unable to read directory"); + free(buf); + return FSFATAL; + } + + /* + * Both `.' and `..' must be present and be the first two entries + * and be ATTR_DIRECTORY of a valid subdirectory. + */ + cp = buf; + if (memcmp(cp, dot_name, sizeof(dot_name)) != 0 || + (cp[11] & ATTR_DIRECTORY) != ATTR_DIRECTORY) { + pwarn("%s: Incorrect `.' for %s.\n", __func__, dir->name); + retval |= FSERROR; + } + cp += 32; + if (memcmp(cp, dotdot_name, sizeof(dotdot_name)) != 0 || + (cp[11] & ATTR_DIRECTORY) != ATTR_DIRECTORY) { + pwarn("%s: Incorrect `..' for %s. \n", __func__, dir->name); + retval |= FSERROR; + } + + free(buf); + return retval; +} + +/* * Read a directory and * - resolve long name records * - enter file and directory records into the parent's list @@ -491,9 +562,6 @@ readDosDirSection(int f, struct bootblock *boot, struc return FSFATAL; } last /= 32; - /* - * Check `.' and `..' entries here? XXX - */ for (p = buffer, i = 0; i < last; i++, p += 32) { if (dir->fsckflags & DIREMPWARN) { *p = SLOT_EMPTY; @@ -830,6 +898,36 @@ readDosDirSection(int f, struct bootblock *boot, struc } } continue; + } else { + /* + * Only one directory entry can point + * to dir->head, it's '.'. + */ + if (dirent.head == dir->head) { + pwarn("%s entry in %s has incorrect start cluster\n", + dirent.name, fullpath(dir)); + if (ask(1, "Remove")) { + *p = SLOT_DELETED; + mod |= THISMOD|FSDIRMOD; + } else + mod |= FSERROR; + continue; + } else if ((check_subdirectory(f, boot, + &dirent) & FSERROR) == FSERROR) { + /* + * A subdirectory should have + * a dot (.) entry and a dot-dot + * (..) entry of ATTR_DIRECTORY, + * we will inspect further when + * traversing into it. + */ + if (ask(1, "Remove")) { + *p = SLOT_DELETED; + mod |= THISMOD|FSDIRMOD; + } else + mod |= FSERROR; + continue; + } } /* create directory tree node */