From owner-svn-src-all@FreeBSD.ORG Sun Feb 22 20:16:45 2015 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id D93B7578; Sun, 22 Feb 2015 20:16:45 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::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 C398CEAD; Sun, 22 Feb 2015 20:16:45 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id t1MKGjOH036040; Sun, 22 Feb 2015 20:16:45 GMT (envelope-from pfg@FreeBSD.org) Received: (from pfg@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id t1MKGjPX036038; Sun, 22 Feb 2015 20:16:45 GMT (envelope-from pfg@FreeBSD.org) Message-Id: <201502222016.t1MKGjPX036038@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: pfg set sender to pfg@FreeBSD.org using -f From: "Pedro F. Giffuni" Date: Sun, 22 Feb 2015 20:16:45 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r279186 - head/lib/libc/gen X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.18-1 Precedence: list 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: , X-List-Received-Date: Sun, 22 Feb 2015 20:16:46 -0000 Author: pfg Date: Sun Feb 22 20:16:44 2015 New Revision: 279186 URL: https://svnweb.freebsd.org/changeset/base/279186 Log: setmode(3): Make sure that setmode sets errno on failure. Our man page already documented this partially but now we have some consistent behavior. PR: 136669 Obtained from: NetBSD (CVS rev. 1.31, 1.33) Relnotes: yes MFC after: 3 weeks Modified: head/lib/libc/gen/setmode.3 head/lib/libc/gen/setmode.c Modified: head/lib/libc/gen/setmode.3 ============================================================================== --- head/lib/libc/gen/setmode.3 Sun Feb 22 19:42:50 2015 (r279185) +++ head/lib/libc/gen/setmode.3 Sun Feb 22 20:16:44 2015 (r279186) @@ -28,7 +28,7 @@ .\" @(#)setmode.3 8.2 (Berkeley) 4/28/95 .\" $FreeBSD$ .\" -.Dd April 28, 1995 +.Dd February 22, 2015 .Dt SETMODE 3 .Os .Sh NAME @@ -99,7 +99,20 @@ The function may fail and set errno for any of the errors specified for the library routine -.Xr malloc 3 . +.Xr malloc 3 +or +.Xr strtol 3 . +In addition, +.Fn setmode +will fail and set +.Va errno +to: +.Bl -tag -width Er +.It Bq Er EINVAL +The +.Fa mode +argument does not represent a valid mode. +.El .Sh SEE ALSO .Xr chmod 1 , .Xr stat 2 , Modified: head/lib/libc/gen/setmode.c ============================================================================== --- head/lib/libc/gen/setmode.c Sun Feb 22 19:42:50 2015 (r279185) +++ head/lib/libc/gen/setmode.c Sun Feb 22 20:16:44 2015 (r279186) @@ -41,6 +41,8 @@ __FBSDID("$FreeBSD$"); #include #include +#include +#include #include #include #include @@ -66,7 +68,7 @@ typedef struct bitcmd { #define CMD2_OBITS 0x08 #define CMD2_UBITS 0x10 -static BITCMD *addcmd(BITCMD *, int, int, int, u_int); +static BITCMD *addcmd(BITCMD *, mode_t, mode_t, mode_t, mode_t); static void compress_mode(BITCMD *); #ifdef SETMODE_DEBUG static void dumpmode(BITCMD *); @@ -151,33 +153,32 @@ common: if (set->cmd2 & CMD2_CLR) { BITCMD *newset; \ setlen += SET_LEN_INCR; \ newset = realloc(saveset, sizeof(BITCMD) * setlen); \ - if (!newset) { \ - if (saveset) \ - free(saveset); \ - saveset = NULL; \ - return (NULL); \ - } \ + if (newset == NULL) \ + goto out; \ set = newset + (set - saveset); \ saveset = newset; \ endset = newset + (setlen - 2); \ } \ - set = addcmd(set, (a), (b), (c), (d)) + set = addcmd(set, (mode_t)(a), (mode_t)(b), (mode_t)(c), (d)) #define STANDARD_BITS (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO) void * setmode(const char *p) { - int perm, who; + int serrno; char op, *ep; BITCMD *set, *saveset, *endset; sigset_t sigset, sigoset; - mode_t mask; - int equalopdone=0, permXbits, setlen; + mode_t mask, perm, permXbits, who; long perml; + int equalopdone; + int setlen; - if (!*p) + if (!*p) { + errno = EINVAL; return (NULL); + } /* * Get a copy of the mask for the permissions that are mask relative. @@ -203,10 +204,17 @@ setmode(const char *p) * or illegal bits. */ if (isdigit((unsigned char)*p)) { + errno = 0; perml = strtol(p, &ep, 8); - if (*ep || perml < 0 || perml & ~(STANDARD_BITS|S_ISTXT)) { - free(saveset); - return (NULL); + if (*ep) { + errno = EINVAL; + goto out; + } + if (errno == ERANGE && (perml == LONG_MAX || perml == LONG_MIN)) + goto out; + if (perml & ~(STANDARD_BITS|S_ISTXT)) { + errno = EINVAL; + goto out; } perm = (mode_t)perml; ADDCMD('=', (STANDARD_BITS|S_ISTXT), perm, mask); @@ -218,6 +226,7 @@ setmode(const char *p) * Build list of structures to set/clear/copy bits as described by * each clause of the symbolic mode. */ + equalopdone = 0; for (;;) { /* First, find out which bits might be modified. */ for (who = 0;; ++p) { @@ -240,8 +249,8 @@ setmode(const char *p) } getop: if ((op = *p++) != '+' && op != '-' && op != '=') { - free(saveset); - return (NULL); + errno = EINVAL; + goto out; } if (op == '=') equalopdone = 0; @@ -330,10 +339,15 @@ apply: if (!*p) dumpmode(saveset); #endif return (saveset); +out: + serrno = errno; + free(saveset); + errno = serrno; + return NULL; } static BITCMD * -addcmd(BITCMD *set, int op, int who, int oparg, u_int mask) +addcmd(BITCMD *set, mode_t op, mode_t who, mode_t oparg, mode_t mask) { switch (op) { case '=':