Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 21 Feb 2012 13:27:53 +1100 (EST)
From:      Bruce Evans <brde@optusnet.com.au>
To:        Mattias Lindgren <mlindgren@gmail.com>
Cc:        freebsd-fs@FreeBSD.org
Subject:   Re: kern/149495: [zfs] chflags sappend on zfs not working right
Message-ID:  <20120221111121.I2928@besplex.bde.org>
In-Reply-To: <201202201920.q1KJKFXE058032@freefall.freebsd.org>
References:  <201202201920.q1KJKFXE058032@freefall.freebsd.org>

next in thread | previous in thread | raw e-mail | index | archive | help
On Mon, 20 Feb 2012, Mattias Lindgren wrote:

> Having similar issues in FreeBSD 9-AMD64 with ZFS v 28
>
> $ mkdir critical
> $ touch critical/critical.log
> $ sudo chmod o= critical
>
> $ sudo chflags sappnd critical
> $ sudo chflags sappnd critical/*
>
> $ echo "test" > critical/critical.log
> -bash: critical/critical.log: Operation not permitted
> $ echo "test" >> critical/critical.log
> $ grep test critical/critical.log
> test
> $ rm -rf critical/critical.log
> $ ls -l critical/
> total 0
>
> Am under the impression that I should not be able to delete files once the
> sappend flag has been set.

It is a bug in 4.4BSD and ffs that [su]append prevents deleting files.
Deletion of files should be prevented only by the [su]nounlink flag
and the [su]immutable flag, but 4.4BSD didn't have the [su]nounlink
flag, and it is insecure to allow unlinking any [su]append file, so
4.4BSD and ffs have the non-orthogonal behaviour of never allowing one
to be unlinked, and this wasn't changed when [su]nounlink was added.

This bug apparently isn't implemented in zfs.  I don't know much about
zfs, but zfs_zacces_delete() seems to only test the immutable and
nounlink flags.  Try adding the append flag there.

Nearby bugs:
- the [su]append flags have the silly abbreviations [su]appnd in chflags(1).
   ls -o output to show these flags will be wide anyway, and 1 character is
   not worth saving.  The 1-char difference is just confusing for input.
- the [su]nounlink flags have the much worse abbreviations [su]unlnk in
   chflags(1).  Even the non-abbreviated forms [su]unlink are missing their
   'no' prefix.  So unlink means nounlink, and if you want to unset this,
   you use no[su]unlink which actually means nonounlink, that is, unlink,
   that is, unlinking is not restricted by the flag.  The u prefix also
   makes uunlink hard to read.  unounlink would be better.

The following is hopefully only in ffs (except in my version):
- setting of flags is non-orthogonal.  Normal read-modify-write operations
   don't work for users, although they work for root.

   The details of this bug were changed between 4.4BSD-Lite1 and
   4.4BSD-Lite2 and reached FreeBSD in chflags(2)'s code in 1997 and
   in chflags(2)'s man page in 2006 (the latter with grammar errors).
   This makes chflags(2) very difficult to use.  Naive programs like
   chflags(1) don't understand this, and just do a simple
   read-modify-write operation.  This gives weird behaviour which
   can be worked around if you understand chflags(2) better than
   chflags(1) does.  For example:

     Suppose you have a file with some harmless system flag like
     `archive' (this is the only one).  This doesn't prevent anyone
     changing their flags.  But it prevents users changing their
     flags in the normal way.  "chflags uchg file" will fail because
     it is turned into a chflags(2) request to set the existing
     archive flag as well as the uchg flag.  As documented, the
     former is not permitted.  So to set your uchg flag while
     preserving the archive flag (which you can't change either
     way), you must ask for the archive flag to be cleared: "chflags
     noarch uchg" after first determining which system flags are
     set.  Similarly for using chflags(2), except now you must clear
     all the system flags that are set, and can do this more easily
     by setting all the system flags.  Clearing all your flags is
     easier: just ask for flags of 0 with chflags(either 1 or 2).

     However, if you are root, then you must not request any system
     flags to be cleared unless you actually want them cleared, since
     the request will actually work for root.

     However2, since ffs has null support for the archive flag, setting
     it for ffs is almost useless and rarely done, so the bug has little
     affect.  My version also allows user changes if only the sunlink
     flag is set (why should preventing unlinking prevent chmod() when
     it doesn't prevent truncating the file or filling it with garbage?).
     But I now thing that this is not a good idea and the change should
     go the other way, so that uunlink prevents changes like sunlink does.

Bruce



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20120221111121.I2928>