From owner-svn-src-head@freebsd.org Mon Nov 20 22:01:47 2017 Return-Path: Delivered-To: svn-src-head@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 217AEDF6C1D; Mon, 20 Nov 2017 22:01:47 +0000 (UTC) (envelope-from asomers@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 mx1.freebsd.org (Postfix) with ESMTPS id D7ADB6F70B; Mon, 20 Nov 2017 22:01:46 +0000 (UTC) (envelope-from asomers@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id vAKM1jl8089353; Mon, 20 Nov 2017 22:01:45 GMT (envelope-from asomers@FreeBSD.org) Received: (from asomers@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id vAKM1jf2089349; Mon, 20 Nov 2017 22:01:45 GMT (envelope-from asomers@FreeBSD.org) Message-Id: <201711202201.vAKM1jf2089349@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: asomers set sender to asomers@FreeBSD.org using -f From: Alan Somers Date: Mon, 20 Nov 2017 22:01:45 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r326034 - in head: lib/libcam/tests sys/cam X-SVN-Group: head X-SVN-Commit-Author: asomers X-SVN-Commit-Paths: in head: lib/libcam/tests sys/cam X-SVN-Commit-Revision: 326034 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.25 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 20 Nov 2017 22:01:47 -0000 Author: asomers Date: Mon Nov 20 22:01:45 2017 New Revision: 326034 URL: https://svnweb.freebsd.org/changeset/base/326034 Log: Fix multiple bugs in cam_strmatch * Wrongly matches strings that are shorter than the pattern * Fails to match negative character sets * Fails to match character sets that aren't at the end of the pattern * Fails to match character ranges Reviewed by: imp MFC after: 3 weeks Sponsored by: Spectra Logic Corp Differential Revision: https://reviews.freebsd.org/D13173 Added: head/lib/libcam/tests/cam_test.c (contents, props changed) Modified: head/lib/libcam/tests/Makefile head/lib/libcam/tests/libcam_test.c head/sys/cam/cam.c Modified: head/lib/libcam/tests/Makefile ============================================================================== --- head/lib/libcam/tests/Makefile Mon Nov 20 21:57:04 2017 (r326033) +++ head/lib/libcam/tests/Makefile Mon Nov 20 22:01:45 2017 (r326034) @@ -1,6 +1,7 @@ # $FreeBSD$ ATF_TESTS_C+= libcam_test +ATF_TESTS_C+= cam_test LIBADD+= cam Added: head/lib/libcam/tests/cam_test.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/lib/libcam/tests/cam_test.c Mon Nov 20 22:01:45 2017 (r326034) @@ -0,0 +1,111 @@ +/*- + * Copyright (c) 2017 Spectra Logic Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* Tests functions in sys/cam/cam.c */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include + +#include + +#define ATF_CHECK_NE(x, y) ATF_CHECK((x) != (y)) + +ATF_TC_WITHOUT_HEAD(cam_strmatch); +ATF_TC_BODY(cam_strmatch, tc) +{ + /* Basic fixed patterns */ + ATF_CHECK_EQ(0, cam_strmatch("foo", "foo", 3)); + ATF_CHECK_NE(0, cam_strmatch("foo", "bar", 3)); + ATF_CHECK_NE(0, cam_strmatch("foo", "foobar", 3)); + + /* The str is not necessarily null-terminated */ + ATF_CHECK_EQ(0, cam_strmatch("fooxuehfxeuf", "foo", 3)); + ATF_CHECK_NE(0, cam_strmatch("foo\0bar", "foo", 7)); + + /* Eat trailing spaces, which get added by SAT */ + ATF_CHECK_EQ(0, cam_strmatch("foo ", "foo", 16)); + + /* '*' matches everything, like shell globbing */ + ATF_CHECK_EQ(0, cam_strmatch("foobar", "foo*", 6)); + ATF_CHECK_EQ(0, cam_strmatch("foobar", "*bar", 6)); + ATF_CHECK_NE(0, cam_strmatch("foobar", "foo*x", 6)); + ATF_CHECK_EQ(0, cam_strmatch("foobarbaz", "*bar*", 9)); + /* Even NUL */ + ATF_CHECK_EQ(0, cam_strmatch("foo\0bar", "foo*", 7)); + /* Or nothing */ + ATF_CHECK_EQ(0, cam_strmatch("foo", "foo*", 3)); + /* But stuff after the * still must match */ + ATF_CHECK_NE(0, cam_strmatch("foo", "foo*x", 3)); + + /* '?' matches exactly one single character */ + ATF_CHECK_EQ(0, cam_strmatch("foobar", "foo?ar", 6)); + ATF_CHECK_NE(0, cam_strmatch("foo", "foo?", 3)); + /* Even NUL */ + ATF_CHECK_EQ(0, cam_strmatch("foo\0bar", "foo?bar", 7)); + + /* '[]' contains a set of characters */ + ATF_CHECK_EQ(0, cam_strmatch("foobar", "foo[abc]ar", 6)); + ATF_CHECK_EQ(0, cam_strmatch("foobar", "foo[b]ar", 6)); + ATF_CHECK_NE(0, cam_strmatch("foobar", "foo[ac]ar", 6)); + + /* '[]' can contain a range of characters, too */ + ATF_CHECK_EQ(0, cam_strmatch("foobar", "foo[a-c]ar", 6)); + ATF_CHECK_EQ(0, cam_strmatch("fooxar", "foo[a-cx]ar", 6)); + ATF_CHECK_NE(0, cam_strmatch("foodar", "foo[a-c]ar", 6)); + + /* Back-to-back '[]' character sets */ + ATF_CHECK_EQ(0, cam_strmatch("foobar", "fo[a-z][abc]ar", 6)); + ATF_CHECK_NE(0, cam_strmatch("foAbar", "fo[a-z][abc]ar", 6)); + ATF_CHECK_NE(0, cam_strmatch("foodar", "fo[a-z][abc]ar", 6)); + + /* A '^' negates a set of characters */ + ATF_CHECK_NE(0, cam_strmatch("foobar", "foo[^abc]ar", 6)); + ATF_CHECK_NE(0, cam_strmatch("foobar", "foo[^b]ar", 6)); + ATF_CHECK_EQ(0, cam_strmatch("foobar", "foo[^ac]ar", 6)); + ATF_CHECK_NE(0, cam_strmatch("foobar", "foo[^a-c]ar", 6)); + ATF_CHECK_NE(0, cam_strmatch("fooxar", "foo[^a-cx]ar", 6)); + ATF_CHECK_EQ(0, cam_strmatch("foodar", "foo[^a-c]ar", 6)); + + /* Outside of '[]' a ']' is just an ordinary character */ + ATF_CHECK_EQ(0, cam_strmatch("f]o", "f]o", 3)); + ATF_CHECK_NE(0, cam_strmatch("foo", "f]o", 3)); + + /* Matching a literal '[' requires specifying a range */ + ATF_CHECK_EQ(0, cam_strmatch("f[o", "f[[]o", 3)); + ATF_CHECK_NE(0, cam_strmatch("foo", "f[[]o", 3)); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, cam_strmatch); + + return (atf_no_error()); +} Modified: head/lib/libcam/tests/libcam_test.c ============================================================================== --- head/lib/libcam/tests/libcam_test.c Mon Nov 20 21:57:04 2017 (r326033) +++ head/lib/libcam/tests/libcam_test.c Mon Nov 20 22:01:45 2017 (r326034) @@ -24,6 +24,8 @@ * SUCH DAMAGE. */ +/* Tests functions in lib/libcam/camlib.c */ + #include __FBSDID("$FreeBSD$"); Modified: head/sys/cam/cam.c ============================================================================== --- head/sys/cam/cam.c Mon Nov 20 21:57:04 2017 (r326033) +++ head/sys/cam/cam.c Mon Nov 20 22:01:45 2017 (r326034) @@ -240,24 +240,29 @@ cam_strmatch(const u_int8_t *str, const u_int8_t *patt ok = 0; sc = *str++; str_len--; + pattern++; if ((negate_range = (*pattern == '^')) != 0) pattern++; - while (((pc = *pattern) != ']') && *pattern != '\0') { - pattern++; + while ((*pattern != ']') && *pattern != '\0') { if (*pattern == '-') { if (pattern[1] == '\0') /* Bad pattern */ return (1); if (sc >= pc && sc <= pattern[1]) ok = 1; - pattern += 2; - } else if (pc == sc) + pattern++; + } else if (*pattern == sc) ok = 1; + pc = *pattern; + pattern++; } if (ok == negate_range) return (1); + pattern++; } else if (*pattern == '?') { - /* NB: || *str == ' ' of the old code is a bug and was removed */ - /* if you add it back, keep this the last if before the naked else */ + /* + * NB: || *str == ' ' of the old code is a bug and was + * removed. If you add it back, keep this the last if + * before the naked else */ pattern++; str++; str_len--; @@ -269,6 +274,17 @@ cam_strmatch(const u_int8_t *str, const u_int8_t *patt str_len--; } } + + /* '*' is allowed to match nothing, so gobble it */ + while (*pattern == '*') + pattern++; + + if ( *pattern != '\0') { + /* Pattern not fully consumed. Not a match */ + return (1); + } + + /* Eat trailing spaces, which get added by SAT */ while (str_len > 0 && *str == ' ') { str++; str_len--;