Bug 1370475 - BUG: changes to the open() semantics need to be reflected in the SELinux hooks
Summary: BUG: changes to the open() semantics need to be reflected in the SELinux hooks
Keywords:
Status: CLOSED WONTFIX
Alias: None
Product: Fedora
Classification: Fedora
Component: kernel
Version: 24
Hardware: x86_64
OS: Unspecified
unspecified
unspecified
Target Milestone: ---
Assignee: Paul Moore
QA Contact: Fedora Extras Quality Assurance
URL:
Whiteboard: abrt_hash:3b6af7330201b3bfd2b8efa5099...
: 1360673 (view as bug list)
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2016-08-26 12:53 UTC by sheepdestroyer
Modified: 2016-09-20 09:00 UTC (History)
19 users (show)

Fixed In Version:
Doc Type: If docs needed, set a value
Doc Text:
Clone Of:
Environment:
Last Closed: 2016-09-14 18:59:07 UTC
Type: ---
Embargoed:


Attachments (Terms of Use)
result of requested output (56.21 KB, text/plain)
2016-08-29 15:48 UTC, sheepdestroyer
no flags Details
followup (20.08 KB, text/plain)
2016-08-29 22:15 UTC, sheepdestroyer
no flags Details
test program for open /dev/fd/N of pipe (485 bytes, text/x-csrc)
2016-08-31 12:30 UTC, Stephen Smalley
no flags Details
my kernel config (107.62 KB, text/x-mpsub)
2016-08-31 14:40 UTC, sheepdestroyer
no flags Details

Description sheepdestroyer 2016-08-26 12:53:46 UTC
Description of problem:
SELinux is preventing wget from 'create' accesses on the file 63.

*****  Plugin catchall (100. confidence) suggests   **************************

If you believe that wget should be allowed create access on the 63 file by default.
Then you should report this as a bug.
You can generate a local policy module to allow this access.
Do
allow this access for now by executing:
# ausearch -c 'wget' --raw | audit2allow -M my-wget
# semodule -X 300 -i my-wget.pp

Additional Information:
Source Context                unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1
                              023
Target Context                unconfined_u:object_r:unconfined_t:s0
Target Objects                63 [ file ]
Source                        wget
Source Path                   wget
Port                          <Unknown>
Host                          (removed)
Source RPM Packages           
Target RPM Packages           
Policy RPM                    selinux-policy-3.13.1-191.12.fc24.noarch
Selinux Enabled               True
Policy Type                   targeted
Enforcing Mode                Enforcing
Host Name                     (removed)
Platform                      Linux (removed) 4.7.2+ #3 SMP Sun Aug 21 23:08:59
                              JST 2016 x86_64 x86_64
Alert Count                   2
First Seen                    2016-08-26 02:04:40 JST
Last Seen                     2016-08-26 21:46:50 JST
Local ID                      761c44f2-1b8b-4840-9e03-5621981c1c8a

Raw Audit Messages
type=AVC msg=audit(1472215610.33:930): avc:  denied  { create } for  pid=6337 comm="google-chrome-u" name="63" scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:unconfined_t:s0 tclass=file permissive=0


Hash: wget,unconfined_t,unconfined_t,file,create

Version-Release number of selected component:
selinux-policy-3.13.1-191.12.fc24.noarch

Additional info:
reporter:       libreport-2.7.2
hashmarkername: setroubleshoot
kernel:         4.7.2+
type:           libreport

Comment 1 Daniel Walsh 2016-08-26 15:08:40 UTC
This avc' indicates that the unconfined_t user is trying to create a file in /proc?

Perhaps this has something to do with user namespace?

Comment 2 Daniel Walsh 2016-08-26 15:09:44 UTC
Did you do some kind of chcon command to create an unconfined_t object?

Comment 3 Stephen Smalley 2016-08-26 15:43:40 UTC
Why does it say "wget" as the "Source" from setroubleshoot when the avc message has comm="google-chrome-u"?

Comment 4 sheepdestroyer 2016-08-26 15:54:51 UTC
I did not do any kind of "chcon command to create an unconfined_t object", at least not that I know of. I do not even know what that would be or do :p

Also, no idea about the wget thing. Did not use it directly for sure. 
I use chrome-unstable though, and have been receiving other selinux errors for about a week or two now when launching it. This one is new.

Comment 5 Stephen Smalley 2016-08-26 16:04:13 UTC
Would help to see more information about the syscall and path in question.  Could obtain by turning on syscall audit, e.g.
# echo "-w /etc/shadow -p w" >> /etc/audit/audit.rules
# service auditd restart
and then triggering the denial again.

Comment 6 sheepdestroyer 2016-08-27 08:10:59 UTC
Description of problem:
Got this error after reloding the crashed extension "Tabs Outliner" in google-chrome-unstable.

Version-Release number of selected component:
selinux-policy-3.13.1-191.14.fc24.noarch

Additional info:
reporter:       libreport-2.7.2
hashmarkername: setroubleshoot
kernel:         4.7.2+
type:           libreport

Comment 7 sheepdestroyer 2016-08-27 08:16:20 UTC
So, it seems to be caused by an extension call "Tabs Ouliner" : https://chrome.google.com/webstore/detail/tabs-outliner/eggkanocgddhmamlbiijnphhppkpkmkl

Recently this extenion has been crashing (seemingly randomly) after a few (5~10...) hours of browsing. A bit hard to repeat at will...
After the extension crashes, chrome proposes to reload it, and that when I then hit the SELinux alert. Just got a second one.

Just followed your logging recommendations and will update if I get a third alert.
Does this step incur any additional load however? What the way to revert it once not needed anymore?

Comment 8 sheepdestroyer 2016-08-28 13:23:10 UTC
Description of problem:
This time you should get the required info in the log if I followed your directives correctly. Is that enough?

Version-Release number of selected component:
selinux-policy-3.13.1-191.14.fc24.noarch

Additional info:
reporter:       libreport-2.7.2
hashmarkername: setroubleshoot
kernel:         4.7.2+
type:           libreport

Comment 9 sheepdestroyer 2016-08-28 15:49:32 UTC
Description of problem:
one more occurence

Version-Release number of selected component:
selinux-policy-3.13.1-191.14.fc24.noarch

Additional info:
reporter:       libreport-2.7.2
hashmarkername: setroubleshoot
kernel:         4.7.2+
type:           libreport

Comment 10 Daniel Walsh 2016-08-29 10:04:14 UTC
We need the output of 
ausearch -m avc

Comment 11 sheepdestroyer 2016-08-29 15:48:02 UTC
Created attachment 1195422 [details]
result of requested output

I just ran the command you asked. Also, a bit before, I got the same error again just by starting chrome.

Comment 12 Stephen Smalley 2016-08-29 16:33:50 UTC
Sorry, apparently I gave no longer valid instructions for enabling extended audit.  Looks like there are a couple of problems:
1. /etc/audit/audit.rules is now auto-generated from contents of /etc/audit/rules.d/*, so we aren't supposed to directly append to it and anything we write there is clobbered.

2. stock rules disable syscall audit for all tasks, so we need to disable that.

If you edit /etc/audit/rules.d/audit.rules (not to be confused with /etc/audit/audit.rules), and comment out the last line:
#-a task,never

Then add a watch or filter to turn on pathname collection:
echo "-w /etc/shadow -p w" > /etc/audit/rules.d/shadow.rules

Then you can run:
service auditd restart

And it should regenerate /etc/audit/audit.rules and reload that.
Then trigger the denial, and you don't need to include everything from ausearch -m avc; you can be more selective, e.g.
ausearch -i -m avc -ts recent # recent denials, or
ausearch -i -m avc -c google-chrome-u # denials with google-chrome-u as the comm
or other variants.

Make sure you use -i (interpret) to ausearch.

You should then get a series of records, including a type=PROCTITLE, type=PATH, type=CWD, type=SYSCALL, and type=AVC for each denial.

To restore to your original state afterward, you can rm /etc/audit/rules.d/shadow.rules, uncomment the last line of /etc/audit/rules.d/audit.rules, and service auditd restart again.

Paul and/or others, is there an easier way?  Used to be simpler.

Comment 13 Paul Moore 2016-08-29 20:30:40 UTC
(In reply to Stephen Smalley from comment #12)
> Paul and/or others, is there an easier way?  Used to be simpler.

I'm probably not the best person to ask as I typically just hack it together as I go on the command line; fine for test/debug, but not something I would recommend as a "Best Practice" to be repeated.

I've CC'd sgrubb as he can provide the "recommended" way using the current audit userspace.

Comment 14 sheepdestroyer 2016-08-29 22:15:02 UTC
Created attachment 1195550 [details]
followup

After some reboots, I do not seem to get the wget denial anymore but a /usr/bin/bash one instead. These reports were sent to bug entry https://bugzilla.redhat.com/show_bug.cgi?id=1360673

Also, attached are the result of the two commands ran after following the procedure above

Comment 15 Steve Grubb 2016-08-29 23:13:05 UTC
I suppose we could create a selinux-more-details.rule and just drop it in /etc/audit/rules.d. To make it take effect, augenrules --load. As for the audit system being neutered, that was a FESCO decision. I argued against it and lost.

Comment 16 Lukas Vrabec 2016-08-30 11:25:38 UTC
*** Bug 1360673 has been marked as a duplicate of this bug. ***

Comment 17 Paul Moore 2016-08-30 12:23:37 UTC
(In reply to Steve Grubb from comment #15)
> I suppose we could create a selinux-more-details.rule and just drop it in
> /etc/audit/rules.d. To make it take effect, augenrules --load.

I think that would be a good idea.  Do you want a separate BZ for that?

Comment 18 Stephen Smalley 2016-08-30 13:26:42 UTC
So if I am reading the audit messages correctly, google-chrome-unstable is calling open("/dev/fd/63",  O_WRONLY|O_CREAT|O_TRUNC, 0666).
That seems odd given that you can't create /dev/fd -> /proc/self/fd files, but if the file already exists, O_CREAT should be ignored and it should just open for write and truncate the file.  I think the real question is why would SELinux be checking create permission at all in this situation - security_inode_create() should only be called if the file does not already exist.  That would suggest a kernel bug, specifically a LSM bug.  However, I wrote a little program that does open("/dev/fd/2", O_WRONLY|O_CREAT|O_TRUNC, 0666); and that succeeded, and I did the same with a non-existent filename, open("/dev/fd/52", O_WRONLY|O_CREAT|O_TRUNC, 0666), and that failed with ENOENT.  Neither triggered a SELinux denial.  What kernel are you using?

Also, maybe someone from the audit side could explain the audit messages, particularly why do we get two different PATH records for /dev/fd/63, with different inodes and attributes, as part of the same event?  Is one the symlink and the other the target of the symlink?

Comment 19 Steve Grubb 2016-08-30 14:53:17 UTC
It shows 3 objects because that is what it resolved. First is /dev/fd as a dir. This is a link to /proc/self/fd. Then finally the real object which is a fifo. Did your test script try to create an existing fifo?

Comment 20 Stephen Smalley 2016-08-30 19:10:33 UTC
Just tried testing this with a pipe and a named fifo, and neither one triggered a SELinux denial.  From the audit message, looks like it was a pipe (dev=00:0a).  Anyway, would like to know what kernel version the bug reporter is using.

Comment 21 Daniel Walsh 2016-08-30 20:11:18 UTC
Any chance a combination of user namespace/pid names/mount namespace causing an issue?  Might want to add these to your test program, since we know that chrome is doing stuff with namespaces.

Comment 22 sheepdestroyer 2016-08-30 20:13:59 UTC
"would like to know what kernel version the bug reporter is using" > I am on 4.7.2, self built. Do you need my config?

Comment 23 Stephen Smalley 2016-08-31 12:30:45 UTC
Created attachment 1196339 [details]
test program for open /dev/fd/N of pipe

This is a trivial program that creates a pipe and tries to open it with O_CREAT via /dev/fd/N.  This does not trigger any SELinux denial AFAICS.

Comment 24 sheepdestroyer 2016-08-31 13:22:16 UTC
This  test program got me the same alert on my system. It was reported here : https://bugzilla.redhat.com/show_bug.cgi?id=1371940

Comment 25 Stephen Smalley 2016-08-31 13:25:04 UTC
Ok, so that's a kernel bug then and we now have a simple reproducer.
So let's get the kernel config and you already said it was 4.7.2.

Comment 26 Stephen Smalley 2016-08-31 13:49:13 UTC
BTW, my test program did not trigger a denial on the stock F24 kernel, which is 4.6-based.  So that would suggest that the regression happened between 4.6 and 4.7.  Lots of changes to the vfs code in that area during that period so quite possible...

Comment 27 Stephen Smalley 2016-08-31 13:55:07 UTC
I also don't get any denial on f25 or rawhide, with a 4.8-based kernel.
So either it got fixed already in 4.8 or it is specific to your kernel config.

Comment 28 sheepdestroyer 2016-08-31 14:40:43 UTC
Created attachment 1196408 [details]
my kernel config

Again, my kernel is a vanilla one, built with provided custom config.
I do not get the error on 4.6 distro Kernels (I saw yesterday that a 4.7.2 was available on update-testing but it does not seem to be there anymore today, so could not test that one).

Comment 29 sheepdestroyer 2016-08-31 15:41:38 UTC
Just retried the same test program on a freshly built 4.8-rc4 kernel. Got the same error that doesn't happen on distro kernels, so it must definitely be my config?

Comment 30 Stephen Smalley 2016-08-31 16:00:38 UTC
Could be config or patches in Fedora kernels.
I don't see the denial on the Fedora branched or rawhide kernels both based on 4.8.0-rc4.
I do see it on a 4.8.0-rc4 mainline kernel built with localmodconfig, but pipetest itself doesn't get any error from the open() call so it isn't fatal.
Looking at fs/namei.c, I see this:
        /*
         * Checking write permission is tricky, bacuse we don't know if we are
         * going to actually need it: O_CREAT opens should work as long as the
         * file exists.  But checking existence breaks atomicity.  The trick is
         * to check access and if not granted clear O_CREAT from the flags.
         *
         * Another problem is returing the "right" error value (e.g. for an
         * O_EXCL open we want to return EEXIST not EROFS).
         */

I haven't walked through the logic, but this seems to suggest that they are performing create checks (may_o_create() -> security_inode_create()) even if the file already exists, but a denial may not be fatal to the call if the file exists.
In that case, the audit is just noise and probably should be suppressed.

Comment 31 Stephen Smalley 2016-08-31 18:13:53 UTC
pipetest triggers a denial on vanilla 4.7.0 but does not on 4.6.0.
So at least for mainline, seems to have been introduced between 4.6 and 4.7.

Comment 32 Stephen Smalley 2016-08-31 18:30:08 UTC
AFAICT, this is an upstream kernel issue.  I don't see what in the Fedora kernel patches or config would affect this, so I'm unclear on why I don't see it there.  Anyone else tried pipetest on a Fedora 4.7 or later kernel?
In your case, you can just dontaudit it in a local policy module to silence it but it should not affect chrome since an error is not returned; it just falls back to opening the file read-write.

Comment 33 Paul Moore 2016-08-31 22:40:54 UTC
FWIW, I just verified Stephen's comments about no visible problems on Rawhide (the kernel below is the Rawhide kernel with selinux#next and audit#next added).

  # uname -r
  4.8.0-0.rc4.git0.2.1.secnext.fc26.x86_64
  # gcc -o pipetest pipetest.c
  # ausearch -m AVC
  <no matches>
  # ./pipetest
  # echo $?
  0
  # ausearch -m AVC
  <no matches>

Comment 34 Paul Moore 2016-08-31 22:46:12 UTC
Quickly scanning through the current Rawhide patches and nothing is jumping out at me either.  Considering the comment #31, it might be interesting to do a git bisect between the v4.6 and v4.7 tags to find the offending commit.

sheepdestroyer, is that something you would be willing to try?

Comment 35 Stephen Smalley 2016-09-01 12:13:33 UTC
I think we only need to check changes to fs/namei.c.
commit 1643b43fbd0524e7da7259075032936c8fb68a05 is perhaps the first place to look, given that it moved the O_CREAT logic I referenced above.

Comment 36 Stephen Smalley 2016-09-01 18:56:20 UTC
Yes, I think it is that commit that introduced this behavior.
And it isn't unintentional based on the code comment I cited above.
We could amend SELinux may_create() to just return after checking access to the directory if the file exists (i.e. dentry->d_inode is non-NULL), skipping the check of create entirely in that case.

Comment 37 Paul Moore 2016-09-01 18:59:00 UTC
For reference, the commit in question:

  commit 1643b43fbd0524e7da7259075032936c8fb68a05
  Author: Al Viro <viro.org.uk>
  Date:   Wed Apr 27 19:14:10 2016 -0400

    lookup_open(): lift the "fallback to !O_CREAT" logics from atomic_open()
    
    Signed-off-by: Al Viro <viro.org.uk>

Comment 38 Paul Moore 2016-09-01 19:01:30 UTC
I'm going to reassign this to the kernel as it clearly isn't a SELinux policy issue.

Comment 39 sheepdestroyer 2016-09-02 11:09:17 UTC
I just tried kernel 4.7.2-201.fc24 from update-testing and confirm I get the same error on it. 

I'd like to git bisect, should be fun. I am a bit short on time this week and on a low powered laptop so it may not be very timely.

Never did a git bisect yet, any pointers to how best doing it?

Comment 40 Stephen Smalley 2016-09-02 12:02:48 UTC
I don't think you need to git bisect; just test the commit I cited and the one before it.

On second thought, just changing SELinux may_create() to skip the file create check is no good since we'll still check add_name and write to the directory and that too could easily trigger a false denial.  Not sure why Fedora policy allows that for /proc/pid currently (unconfined_t -> unconfined_t:dir add_name,write) since you can't create files in /proc.

Comment 41 Stephen Smalley 2016-09-02 13:11:58 UTC
So, assuming that their reasons for performing create checks first even when the file already exists are sound and we can't just revert this, I think our only real option is to dontaudit these accesses.

Comment 42 Paul Moore 2016-09-14 18:59:07 UTC
Okay, I think adding kernel code to bail early in the case of dir:{ add_name write } is not something we want to do (too ugly) so I'm going to close this out as a WONTFIX with the understanding that the proper fix is in BZ #1345836.


Note You need to log in before you can comment on or make changes to this bug.