From owner-freebsd-hackers@FreeBSD.ORG Mon Oct 11 05:53:55 2010 Return-Path: Delivered-To: freebsd-hackers@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id AEAB8106564A; Mon, 11 Oct 2010 05:53:55 +0000 (UTC) (envelope-from yanegomi@gmail.com) Received: from mail-yw0-f54.google.com (mail-yw0-f54.google.com [209.85.213.54]) by mx1.freebsd.org (Postfix) with ESMTP id 4D7178FC0A; Mon, 11 Oct 2010 05:53:54 +0000 (UTC) Received: by ywh2 with SMTP id 2so645085ywh.13 for ; Sun, 10 Oct 2010 22:53:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:mime-version:received:sender:received :in-reply-to:references:date:x-google-sender-auth:message-id:subject :from:to:cc:content-type:content-transfer-encoding; bh=IUyrSUBhhuwHNTvElWfvNuavSGrNc3E9PICqFb5MM5U=; b=Tss0xK6GB/V1bUXMDZfwCCclLMRItRI+51ulbstWqSg8NZq3jdkurE1NlDoCBaf4Xn Xmu3vXYhVphHqNAyiDDTmOriZYVDiRzJ2toD+8iYMyWCZgqE6rQvN43IJpY9rALdw1wN CN4ZJRBclfnO0TrBWym+/bAhlYL48xl7ebHIE= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=mime-version:sender:in-reply-to:references:date :x-google-sender-auth:message-id:subject:from:to:cc:content-type :content-transfer-encoding; b=GDPBrDyJ2Z4YMc3z7GnBAV6hTwYbwqpGq2193rTMxAj4eK1eFMP6Jdzdws1303/Ufq AsSgiIoEJqJ+hVuMViZ5315VeFlfgFsRXbYdDrw9gsM7RZzekuFX9671HoCB3H8ZCT1F c4t9Tx/qJqhb2T3ED+TJqBYYkNC85z+/cBMZs= MIME-Version: 1.0 Received: by 10.90.31.14 with SMTP id e14mr2819693age.21.1286776432357; Sun, 10 Oct 2010 22:53:52 -0700 (PDT) Sender: yanegomi@gmail.com Received: by 10.91.78.6 with HTTP; Sun, 10 Oct 2010 22:53:51 -0700 (PDT) In-Reply-To: <20101007103601.GA17089@freebsd.org> References: <20101005235054.GA45827@freebsd.org> <20101006173522.GA92402@freebsd.org> <20101006193827.GA13528@freebsd.org> <20101007103601.GA17089@freebsd.org> Date: Sun, 10 Oct 2010 22:53:51 -0700 X-Google-Sender-Auth: W7bm_QN2yOH7nGsra0xnuGsj4nY Message-ID: From: Garrett Cooper To: Alexander Best Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: quoted-printable Cc: freebsd-hackers@freebsd.org, Sergey Kandaurov Subject: Re: issue with unsetting 'arch' flag X-BeenThere: freebsd-hackers@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Technical Discussions relating to FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 11 Oct 2010 05:53:55 -0000 On Thu, Oct 7, 2010 at 3:36 AM, Alexander Best wrote: > On Wed Oct =A06 10, Garrett Cooper wrote: >> On Wed, Oct 6, 2010 at 4:03 PM, Garrett Cooper wro= te: >> > On Wed, Oct 6, 2010 at 3:01 PM, Sergey Kandaurov w= rote: >> >> On 6 October 2010 23:38, Alexander Best wrote: >> >>> On Wed Oct =A06 10, Garrett Cooper wrote: >> >>>> On Wed, Oct 6, 2010 at 10:35 AM, Alexander Best wrote: >> >>>> > On Wed Oct =A06 10, Garrett Cooper wrote: >> >>>> >> On Tue, Oct 5, 2010 at 4:50 PM, Alexander Best wrote: >> >>>> >> > hi there, >> >>>> >> > >> >>>> >> > i think the following example shows the problem better than a = long explanation: >> >>>> >> > >> >>>> >> > `touch ftest && chflags arch ftest && chflags -vv 0 ftest`. >> >>>> >> > =A0^^non-root =A0 =A0 ^^root =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0^^= non-root >> >>>> >> > >> >>>> >> > chflags claims to have cleared the 'arch' flag (which should b= e impossible as >> >>>> >> > non-root user), but indeed has done nothing. >> >>>> >> > >> >>>> >> > i've tried the same with 'sappnd' and that works as can be exp= ected. >> >>>> >> > >> >>>> >> > The issue was confirmed to exist in HEAD (me), stable/8 (pgoll= ucc1, jpaetzel) >> >>>> >> > and stable/7 (nox). >> >>>> >> > On stable/6 it does NOT exist (jpaetzel). chflags properly fai= ls with EPERM. >> >>>> >> >> >>>> >> =A0 =A0 Fails for me when I call the syscall directly, as I woul= d expect, >> >>>> >> and passes when I'm superuser: >> >>>> >> >> >>>> >> $ ./test_chflags >> >>>> >> (uid, euid) =3D (1000, 1000) >> >>>> >> test_chflags: chflags: Operation not permitted >> >>>> >> test_chflags: lchflags: Operation not permitted >> >>>> >> $ sudo ./test_chflags >> >>>> >> (uid, euid) =3D (0, 0) >> >>>> >> >> >>>> >> =A0 =A0 According to my basic inspection in strtofflags >> >>>> >> (.../lib/libc/gen/strtofflags.c), it works as well. >> >>>> >> =A0 =A0 And last but not least, executing the commands directly = on the CLI work: >> >>>> >> >> >>>> >> $ tmpfile=3D`mktemp /tmp/chflags.XXXXXX` >> >>>> >> $ chflags arch $tmpfile >> >>>> >> chflags: /tmp/chflags.nQm1IL: Operation not permitted >> >>>> >> $ rm $tmpfile >> >>>> >> $ tmpfile=3D`mktemp /tmp/chflags.XXXXXX` >> >>>> >> $ sudo chflags arch $tmpfile >> >>>> >> $ sudo chflags noarch $tmpfile >> >>>> >> $ rm $tmpfile >> >>>> > >> >>>> > thanks for your test app and helping out with this problem. i'm n= ot sure >> >>>> > however you understood the problem. probably i didn't explain it = right: >> >>>> > >> >>>> > $ sudo rm -d /tmp/chflags.XXXXXX >> >>>> > $ tmpfile=3D`mktemp /tmp/chflags.XXXXXX` >> >>>> > $ sudo chflags arch $tmpfile >> >>>> > $ chflags noarch $tmpfile >> >>>> > >> >>>> > is what's causing the problem. the last chflags call should fail,= but it >> >>>> > doesn't. >> >>>> >> >>>> Sorry... my CLI based example was stupid. I meant: >> >>>> >> >>>> $ tmpfile=3D`mktemp /tmp/chflags.XXXXXX` >> >>>> $ chflags arch $tmpfile >> >>>> chflags: /tmp/chflags.V2NpXR: Operation not permitted >> >>>> $ chflags noarch $tmpfile >> >>>> $ rm $tmpfile >> >>>> >> >>>> Currently chflags(2) states: >> >>>> >> >>>> =A0 =A0 =A0The SF_IMMUTABLE, SF_APPEND, SF_NOUNLINK, and SF_ARCHIVE= D flags may only >> >>>> =A0 =A0 =A0be set or unset by the super-user. =A0Attempts to set th= ese flags by non- >> >>>> =A0 =A0 =A0super-users are rejected, >>> attempts by non-superusers= to clear >> >>>> flags that >> >>>> =A0 =A0 =A0are already unset are silently ignored. <<< =A0These fla= gs may be set at any >> >>>> =A0 =A0 =A0time, but normally may only be unset when the system is = in single-user >> >>>> =A0 =A0 =A0mode. =A0(See init(8) for details.) >> >>>> >> >>>> So this behavior is already well documented :). The EPERM section >> >>>> should really note SF_ARCHIVED though (whoever added the flag forgo= t >> >>>> to add that particular item to the ERRORS section). >> >>> >> >>> that's perfectly alright. clearing an unset flag shouldn't cause any= error to >> >>> be returned. however in my example arch *does* get set and still try= ing to >> >>> unset it as normal user doesn't return an error. >> >>> >> >> >> >> It's even more interesting. >> >> >> >> As far as I could parse the code: >> >> - UFS has no special handling for SF_ARCHIVED (I found only it for ms= dosfs) >> > >> > =A0 =A0_very_ interesting: >> > >> > [/sys]$ grep -r SF_ARCHIVED kern/ fs/ ufs/ | grep -v svn >> > fs/msdosfs/msdosfs_vnops.c: =A0 =A0 =A0 =A0 =A0 =A0 vap->va_flags |=3D= SF_ARCHIVED; >> > fs/msdosfs/msdosfs_vnops.c: =A0 =A0 =A0 =A0 =A0 =A0 if (vap->va_flags = & ~SF_ARCHIVED) >> > fs/msdosfs/msdosfs_vnops.c: =A0 =A0 =A0 =A0 =A0 =A0 if (vap->va_flags = & SF_ARCHIVED) >> > >> > =A0 =A0The commit that introduced this change probably wasn't doing th= e >> > right thing: http://svn.freebsd.org/viewvc/base/head/sys/fs/msdosfs/ms= dosfs_vnops.c?revision=3D5241&view=3Dmarkup >> > ; cp(1) probably should have been fixed in lieu of `fixing' msdosfs. >> > >> >> - ufs_setattr() does not handle unsetting SF_ARCHIVED, >> >> =A0so all what it does is simply return zero. >> > >> > =A0 =A0 [EOPNOTSUPP] =A0 =A0 =A0 The underlying file system does not s= upport file >> > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0flags. >> > >> > =A0 =A0So I would expect for invalid flags to return EOPNOTSUPP. >> > >> > ... >> > >> > $ ~/test_chflags_negative >> > test_chflags_negative: should not get here >> > $ sudo ~/test_chflags_negative >> > test_chflags_negative: should not get here >> > >> > *facepalm* >> > >> > =A0 =A0I think the problem in part is here (sys/stat.h): >> > >> > =A0* >> > =A0* Super-user and owner changeable flags. >> > =A0*/ >> > #define UF_SETTABLE =A0 =A0 0x0000ffff =A0 =A0 =A0/* mask of owner cha= ngeable flags */ >> > #define UF_NODUMP =A0 =A0 =A0 0x00000001 =A0 =A0 =A0/* do not dump fil= e */ >> > #define UF_IMMUTABLE =A0 =A00x00000002 =A0 =A0 =A0/* file may not be c= hanged */ >> > #define UF_APPEND =A0 =A0 =A0 0x00000004 =A0 =A0 =A0/* writes to file = may only append */ >> > #define UF_OPAQUE =A0 =A0 =A0 0x00000008 =A0 =A0 =A0/* directory is op= aque wrt. union */ >> > #define UF_NOUNLINK =A0 =A0 0x00000010 =A0 =A0 =A0/* file may not be r= emoved or renamed */ >> > /* >> > =A0* Super-user changeable flags. >> > =A0*/ >> > #define SF_SETTABLE =A0 =A0 0xffff0000 =A0 =A0 =A0/* mask of superuser= changeable flags */ >> > #define SF_ARCHIVED =A0 =A0 0x00010000 =A0 =A0 =A0/* file is archived = */ >> > #define SF_IMMUTABLE =A0 =A00x00020000 =A0 =A0 =A0/* file may not be c= hanged */ >> > #define SF_APPEND =A0 =A0 =A0 0x00040000 =A0 =A0 =A0/* writes to file = may only append */ >> > #define SF_NOUNLINK =A0 =A0 0x00100000 =A0 =A0 =A0/* file may not be r= emoved or renamed */ >> > #define SF_SNAPSHOT =A0 =A0 0x00200000 =A0 =A0 =A0/* snapshot inode */ >> > >> > =A0 =A0Note the *_SETTABLE macros, and the fact that they allow for mo= re >> > functionality than what's currently slotted with the one-hot encoded >> > flags currently available. >> > =A0 =A0SF_ARCHIVED is not present in the other BSDs or Mac OSX either = (I >> > did some hunting for a python bug related to chflags a few weeks >> > ago)... and I'm not even sure what this functionality really buys us >> > because it's not well described (but I'd be happy to get an >> > explanation/history lesson). >> > >> >> - /bin/chflags doesn't check the actual flags value from inode after >> >> calling chflags() syscall, and blindly assumes all is well, if chflag= s() >> >> returns with zero, >> > >> > =A0 =A0Yeah... but ideally tests should be written for this stuff and >> > exercised on all filesystems and exercised whenever code in this >> > particular path is changed, because that would potentially turn into a >> > noticeable performance hit [depending on how it's implemented in >> > chflags(1)]. And lo and behold it already does exist under >> > .../tools/regression/fstest/tests/chflags . I'll audit this once I get >> > back home... >> >> =A0 =A0 For starters, the tests were moved to .../tools/regression/pjdfs= test . >> =A0 =A0 This fixes the manpage and the negative flags testcase at least.= I >> ran the pjdfstest on a UFS2 partition on my test machine and tmpfs, >> and it passed chflags with flying colors. msdosfs unfortunately isn't >> supported yet, but I did some manual testing and everything seemed ok. >> I also need to check and see whether or not pjdfstest is doing the >> right job with negative testcases. >> =A0 =A0 I didn't have a ext2/3 or zfs pool to test with, so if someone >> could poke around with those filesystems it would be much appreciated >> :). >> =A0 =A0 And finally, here are all of the references in the sourcebase to >> SF_ARCHIVED: >> >> # /usr/local/bin/svnversion >> 213377M >> # grep -r SF_ARCHIVED /usr/src/ | grep -v svn >> grep: /usr/src/tools/regression/pjdfstest/pjdfstest_5aaec5b222b60945b16d= aa0e8d61313d/pjdfstest_b4353ca81458e0bfc9ec5be8ff741eb2/usr/src/tools/regre= ssion/priv/priv_vfs_chflags.c: =A0 =A0 flags >> |=3D SF_ARCHIVED; >> /usr/src/tools/regression/priv/priv_vfs_chflags.c: =A0 =A0flags |=3D SF_= ARCHIVED; >> /usr/src/tools/regression/priv/priv_vfs_chflags.c: =A0 =A0flags |=3D SF_= ARCHIVED; >> /usr/src/tools/regression/pjdfstest/tests/chflags/00.t: =A0 =A0 =A0 allf= lags=3D"UF_NODUMP,UF_IMMUTABLE,UF_APPEND,UF_NOUNLINK,UF_OPAQUE,SF_ARCHIVED,= SF_IMMUTABLE,SF_APPEND,SF_NOUNLINK" >> /usr/src/tools/regression/pjdfstest/tests/chflags/00.t: =A0 =A0 =A0 syst= emflags=3D"SF_ARCHIVED,SF_IMMUTABLE,SF_APPEND,SF_NOUNLINK" >> Binary file /usr/src/tools/regression/pjdfstest/pjdfstest matches >> /usr/src/tools/regression/pjdfstest/pjdfstest.c:#ifdef SF_ARCHIVED >> /usr/src/tools/regression/pjdfstest/pjdfstest.c: =A0 =A0 =A0{ SF_ARCHIVE= D, "SF_ARCHIVED" }, >> : Operation not supported >> grep: warning: /usr/src/sys/modules/tmpfs/@: recursive directory loop >> /usr/src/lib/libc/gen/strtofflags.c: =A0{ "noarch", =A0 =A0 =A0 =A0 =A0 = =A0 SF_ARCHIVED, =A0 =A00 }, >> /usr/src/lib/libc/gen/strtofflags.c: =A0{ "noarchived", =A0 =A0 =A0 =A0 = SF_ARCHIVED, =A0 =A00 }, >> /usr/src/lib/libc/sys/chflags.2:.It Dv SF_ARCHIVED >> /usr/src/lib/libc/sys/chflags.2:.Dv SF_ARCHIVED >> /usr/src/lib/libc/sys/chflags.2:.Dv SF_ARCHIVED , SF_IMMUTABLE , SF_APPE= ND , >> /usr/src/lib/libc/sys/chflags.2:.Dv SF_ARCHIVED , SF_IMMUTABLE , SF_APPE= ND , >> /usr/src/lib/libarchive/archive_entry.c:#ifdef SF_ARCHIVED >> /usr/src/lib/libarchive/archive_entry.c: =A0 =A0 =A0{ >> "noarch", =A0 =A0 L"noarch", =A0 =A0 =A0SF_ARCHIVED, =A0 =A00 }, >> /usr/src/lib/libarchive/archive_entry.c: =A0 =A0 =A0{ >> "noarchived", L"noarchived", =A0 =A0 =A0 =A0 =A0SF_ARCHIVED, =A0 =A00 }, >> /usr/src/sys/fs/msdosfs/msdosfs_vnops.c: =A0 =A0 =A0 =A0 =A0 =A0 =A0vap-= >va_flags |=3D SF_ARCHIVED; >> /usr/src/sys/fs/msdosfs/msdosfs_vnops.c: =A0 =A0 =A0 =A0 =A0 =A0 =A0if (= vap->va_flags & ~SF_ARCHIVED) >> /usr/src/sys/fs/msdosfs/msdosfs_vnops.c: =A0 =A0 =A0 =A0 =A0 =A0 =A0if (= vap->va_flags & SF_ARCHIVED) >> /usr/src/sys/sys/stat.h:#define =A0 =A0 =A0 SF_ARCHIVED =A0 =A0 0x000100= 00 =A0 =A0 =A0/* file is archived */ >> /usr/src/sys/sys/stat.h:#define =A0 =A0 =A0 SF_SETTABLE =A0 =A0 (SF_ARCH= IVED | >> SF_IMMUTABLE | SF_APPEND | \ >> >> =A0 =A0 So it doesn't look like anything's utilizing the functionality, >> other than msdosfs, and all that really does is tweak the following >> attribute: >> >> #define ATTR_ARCHIVE =A0 =A00x20 =A0 =A0 =A0 =A0 =A0 =A0/* file is new o= r modified */ >> >> =A0 =A0 and vice versa. I vaguely remember archive file types in FAT32 >> from the Win95 days, but my memory is a bit hazy as to what the >> attribute actually does. > > occasionally i get errors during file copies from msdosfs to ufs2. window= s > seems to use the arch flag quite extensively actually. i think formating = a new > drive automatically markes it as 'archivable' and all new files get their= flag > set. According to sbruno@: "It gets set when a file is written to. That's it. A backup program can backup files then clear the bit; later backups can use the state of the bit to determine if the file needs backing up again. And it dates from MS-DOS 2.x, and possibly even 1.x. During those times you couldn't exactly trust timestamps on files meant anything for backup purposes, as PCs didn't have a battery backed RTC as standard. http://en.wikipedia.org/wiki/Archive_bit" So it exists purely for msdosfs for that historic reason. > so when copying files from fat32 to ufs i very often get an EPERM error, > because as a non-root user that flag cannot be preserved. doesn't matter > however since the copying suceeds. good thing the chflags operation takes= place > after copying the file and not beforehand (i.e. touch, chflags, copy). Yeah... > also: what about sorting the flags (in the manual page e.g.). should they= be > sorted alphabetically or by bitfields? They're currently sorted by value (including the patch I attached earlier). > also: is SF_SNAPSHOT really changeable by the super user? chflags(2) says= it's > not. >From what I've seen, not directly. It's used widely in querying filesystems though. Thanks, -Garrett