Discussion:
[tomoyo-users-en 521] Why have "path_group ANY_PATHNAME /" rule?
do1
2012-12-25 12:19:05 UTC
Permalink
Hello,

I see in example exception_policy.conf:

path_group ANY_PATHNAME /
path_group ANY_PATHNAME /\*

But why we have / expression? \* should match 0 or more repetitions, so /\* should match / too since it is 0 repetitions of anything non-/. Can somebody explain?

In my opinion

path_group ANY_PATHNAME /
path_group ANY_PATHNAME /\*
path_group ANY_PATHNAME /\{\*\}/
path_group ANY_PATHNAME /\{\*\}/\*

should be just two rules:

path_group ANY_PATHNAME /\*
path_group ANY_PATHNAME /\{\*\}/\*


Best regards,
Tetsuo Handa
2012-12-25 12:34:12 UTC
Permalink
Post by do1
path_group ANY_PATHNAME /
path_group ANY_PATHNAME /\*
But why we have / expression? \* should match 0 or more repetitions, so /\* should match / too since it is 0 repetitions of anything non-/. Can somebody explain?
In TOMOYO and AKARI, directory (which ends with '/') and non-directory (which
does not end with '/') are distinguished. Therefore, /\* does not imply / .

This is no longer true for CaitSith, for CaitSith allows filtering file's type
as conditions as well as pathnames.
do1
2012-12-27 11:21:49 UTC
Permalink
Hello Tetsuo Handa,

I think it may be useful for CaitSith to have also more generalized actions, like readonly_access and writable_access.

For example, if I want to make some subdirectory tree globally read-only (I think that could be very common wish) now I need to add many similar acl rules to deny all actions what can modify, add, rename, link, unlink, chmod, truncate, append, mk*, chown, and chgrp files in it. That is like 12 rules with the same path and rules, which is heavy duplication. It will be much easier to understand and write single rule which includes all these actions in good way. So, for example, I would write

1 acl writable_access path="/home/repo/\(\*\)/\*"
1 deny task.exe!="/usr/local/bin/repo-accessor"
1 allow

Instead of 12 similar rules.

Best regards,
do1
2012-12-28 16:14:38 UTC
Permalink
1. I thought such scheme will require 12 rules, but actually it required 22 rules, also becasue some acls, like link, rename, etc. have two arguments (like new_path, old_path) which should be checked separately.

# grep BACK policy/current
1 acl write path=@BACKUPS
1 acl append path=@BACKUPS
1 acl create path=@BACKUPS
1 acl unlink path=@BACKUPS
1 acl mkdir path=@BACKUPS
1 acl rmdir path=@BACKUPS
1 acl mkfifo path=@BACKUPS
1 acl mksock path=@BACKUPS
1 acl truncate path=@BACKUPS
1 acl symlink path=@BACKUPS
1 acl mkblock path=@BACKUPS
1 acl mkchar path=@BACKUPS
1 acl link old_path=@BACKUPS
1 acl link new_path=@BACKUPS
1 acl rename old_path=@BACKUPS
1 acl rename new_path=@BACKUPS
1 acl chmod path=@BACKUPS
1 acl chown path=@BACKUPS
1 acl chdrp path=@BACKUPS
1 acl ioctl path=@BACKUPS
1 acl mount source=@BACKUPS
1 acl mount target=@BACKUPS

I think I covered all operations that can modify files, excluding all that read only.

2. I wonder why operations like touch file (acl create) report ENOENT instead of EPERM (which would be logical). ENOENT is confusing.

Best regards,
Post by do1
Hello Tetsuo Handa,
I think it may be useful for CaitSith to have also more generalized actions, like readonly_access and writable_access.
For example, if I want to make some subdirectory tree globally read-only (I think that could be very common wish) now I need to add many similar acl rules to deny all actions what can modify, add, rename, link, unlink, chmod, truncate, append, mk*, chown, and chgrp files in it. That is like 12 rules with the same path and rules, which is heavy duplication. It will be much easier to understand and write single rule which includes all these actions in good way. So, for example, I would write
1 acl writable_access path="/home/repo/\(\*\)/\*"
??1 deny task.exe!="/usr/local/bin/repo-accessor"
??1 allow
Instead of 12 similar rules.
Best regards,
_______________________________________________
tomoyo-users-en mailing list
tomoyo-users-en at lists.sourceforge.jp
http://lists.sourceforge.jp/mailman/listinfo/tomoyo-users-en
Tetsuo Handa
2012-12-29 08:52:46 UTC
Permalink
Thank you for trying CaitSith.
Post by do1
1. I thought such scheme will require 12 rules, but actually it required 22
rules, also becasue some acls, like link, rename, etc. have two arguments
(like new_path, old_path) which should be checked separately.
Right. That's reason why you can't write like

1 acl writable_access path="/home/repo/\(\*\)/\*"
1 deny task.exe!="/usr/local/bin/repo-accessor"
1 allow

.

If we want generic write permission, which actions should be included into
generic write permission? Some will say only write/append/truncate should be,
some others will say write/append/truncate/create should be, yet some others
will say write/append/truncate/create/link/rename should be, and ...

If we simplify the granularity up to read/write/execute (e.g. DAC), we lose the
benefit of fine grained acl.
Post by do1
# grep BACK policy/current
s/chdrp/chgrp/
Post by do1
I think I covered all operations that can modify files, excluding all that read only.
This is different from my expected usage.

In TOMOYO/AKARI/CaitSith, I'm allowing users to restrict actions up to the
user's skill/resource affords. That is, you can choose actions to restrict.

However, as one of CaitSith's advantages compared to TOMOYO/AKARI, you don't
have to treat all actions equally because you can choose conditions to check
and conditions to allow/deny independently. Please see Chapter 4 in
http://events.linuxfoundation.org/images/stories/pdf/lcna_co2012_handa.pdf for
examples. For example, you can define rules for write/append/truncate (actions
which may change the content of file) for per-a-pathname basis

1 acl write path=@BACKUPS

1 acl append path=@BACKUPS

1 acl truncate path=@BACKUPS

and can define rules for create/link/rename/unlink (actions which may
change the content of directory) for per-device basis (examples below
use /dev/sda2 where its major number is 8 and minor number is 2)

1 acl create path.parent.major=8 path.parent.minor=2

1 acl link old_path.major=8 old_path.minor=2

1 acl rename old_path.major=8 old_path.minor=2

1 acl unlink path.major=8 path.minor=2

or per-filesystemtype basis (examples below use ext2/ext3/ext4 where its
filesystem magic number is 0xEF53)

1 acl create path.parent.fsmagic=0xEF53

1 acl link old_path.fsmagic=0xEF53

1 acl rename old_path.fsmagic=0xEF53

1 acl unlink path.fsmagic=0xEF53

and can define rules for mount/unmount for system-wide

100 acl mount
1 deny task.exe!="/bin/mount"
10 allow target="/proc/" fstype="proc" flags=0x0
10 allow target="/sys/" fstype="sysfs" flags=0x0
10 allow target="/dev/pts/" fstype="devpts" flags=0x0
10 allow target="/dev/shm/" fstype="tmpfs" flags=0x0
10 allow target="/" fstype="--remount" flags=0x1
10 allow target="/" fstype="--remount" flags=0x400
10 allow target="sysfs:/kernel/security/" fstype="securityfs" flags=0x0
100 deny

1 acl unmount
1 deny task.exe!="/bin/umount"

.
Post by do1
2. I wonder why operations like touch file (acl create) report ENOENT instead
of EPERM (which would be logical). ENOENT is confusing.
This is because /bin/touch ignores failure of open(O_CREAT) but reports failure
of utime().

"strace touch /tmp/file" with a rule like

1 acl create task.exe="/bin/touch"
1 deny

shows

open("/tmp/file", O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_LARGEFILE, 0666) = -1 EPERM (Operation not permitted)
utimensat(AT_FDCWD, "/tmp/file", NULL, 0) = -1 ENOENT (No such file or directory)
write(2, "touch: ", 7) = 7
write(2, "setting times of `/tmp/file'", 28) = 28
write(2, ": No such file or directory", 27) = 27
write(2, "\n", 1) = 1

.
do1
2012-12-29 10:49:17 UTC
Permalink
Hello Tetsuo Handa,

Thanks for reply!
Post by Tetsuo Handa
?1. I thought such scheme will require 12 rules, but actually it required 22
????rules, also becasue some acls, like link, rename, etc. have two arguments
????(like new_path, old_path) which should be checked separately.
Right. That's reason why you can't write like
??1 acl writable_access path="/home/repo/\(\*\)/\*"
????1 deny task.exe!="/usr/local/bin/repo-accessor"
????1 allow
It would be possible if writable_access handler internally check proper path,
old_path, new_path (for single path= agument) where need. Of course I don't know
implementations detail and that could be complicated if disigned unfavourable
for that.
Post by Tetsuo Handa
If we want generic write permission, which actions should be included into
generic write permission? Some will say only write/append/truncate should be,
some others will say write/append/truncate/create should be, yet some others
will say write/append/truncate/create/link/rename should be, and ...
Yes people may think differently. But every person understand concept of read-only
directory or ro mount. So to simplify understanding generic writable_access operation
could implement all restrictions to implement usual read-only mount/dir.

(Btw, you can add 'operation' variable with name or current operation to exclude some
operation from generic one in its ruleset.)
Post by Tetsuo Handa
If we simplify the granularity up to read/write/execute (e.g. DAC), we lose the
benefit of fine grained acl.
I don't say you should remove existing operations. Just to add also some generic
ones to simplify maintaining and understanding for people.
Post by Tetsuo Handa
?I think I covered all operations that can modify files, excluding all that
?read only.
This is different from my expected usage.
I don't understand, what is different from expected use? I want to make some
directory globally read only except for its accessor software. I think this is useful
in general and also useful insecurity sense. For example to protect backups from
accidental/intentional modifications. It is security for backups integrity.
Post by Tetsuo Handa
However, as one of CaitSith's advantages compared to TOMOYO/AKARI, you don't
have to treat all actions equally because you can choose conditions to check
and conditions to allow/deny independently. Please see Chapter 4 in
http://events.linuxfoundation.org/images/stories/pdf/lcna_co2012_handa.pdf for
examples. For example, you can define rules for write/append/truncate (actions
which may change the content of file) for per-a-pathname basis
I understand that flexibility, and it's great. Thanks.
Post by Tetsuo Handa
?2. I wonder why operations like touch file (acl create) report ENOENT instead
????of EPERM (which would be logical). ENOENT is confusing.
This is because /bin/touch ignores failure of open(O_CREAT) but reports failure
of utime().
Ah, thanks for explanation!


* I solved my generalisation problem myself using m4 macro processor.
(I show details in case if it's useful for someone too.)

I make config.m4 with such text at beginning:
------------------
divert(`-1')
changequote([,])
# foreach macro from /usr/doc/m4-1.4.16/examples/foreach.m4
define([foreach], [pushdef([$1])_foreach($@)popdef([$1])])
define([_arg1], [$1])
define([_foreach], [ifelse([$2], [()], [],
[define([$1], _arg1$2)$3[]$0([$1], (shift$2), [$3])])])

# generic_acl(prio, deny, (write, append, ...), path=..., [rules])
define([generic_acl], [dnl
foreach(op, $3, [
$1 acl op $4
audit 1
[$5]
11111 $2])dnl
])
# deny_writable(prio, path, [common rules])
define([deny_writable], [dnl
generic_acl($1, deny, (write, append, create, unlink, mkdir,
rmdir, mkfifo, mksock, truncate, symlink, mkblock, mkchar,
chmod, chown, chgrp, ioctl), [path=$2], [$3])dnl
generic_acl($1, deny, (link, rename), [old_path=$2], [$3])dnl
generic_acl($1, deny, (link, rename), [new_path=$2], [$3])dnl
generic_acl($1, deny, (mount), [source=$2], [$3])dnl
generic_acl($1, deny, (mount), [target=$2], [$3])dnl
])
divert[]dnl
... usual rules and headers excluded...

string_group RSYNCS /home/backup/\(\*\)/\*
deny_writable(7, @RSYNCS, [1 allow path="/usr/bin/rsync"])

* This example rule will instantiate 20 acls with proper path=, old_path=, etc, checks
Every rule will have this line: 1 allow path="/usr/bin/rsync"
And every rule will finish with 11111 deny.

For example two first acls to get the idea of output:

7 acl write path=@RSYNCS
audit 1
1 allow path="/usr/bin/rsync"
11111 deny
7 acl append path=@RSYNCS
audit 1
1 allow path="/usr/bin/rsync"
11111 deny

* Another example:

generic_acl(2, deny, (write, append), task.uid=224, [
1 allow path="/home/radio/shoutcast/sc_serv.log"
1 allow path="/home/radio/transcast/nohup.out"
1 allow path="/home/radio/transcast/sc_trans.log"
1 allow path="/home/radio/nohup.out"
1 allow path="/dev/null"
1 allow path="/dev/tty"
])

Thish rule will make two blocks of acl text each ending with 1111 deny
for acl write and acl append. Acl entry check is task.uid=224
And all quoted in [ ] rules will be duplicated for each acl.

Example output:

2 acl write task.uid=224
audit 1
1 allow path="/home/radio/shoutcast/sc_serv.log"
1 allow path="/home/radio/transcast/nohup.out"
1 allow path="/home/radio/transcast/sc_trans.log"
1 allow path="/home/radio/nohup.out"
1 allow path="/dev/null"
1 allow path="/dev/tty"
11111 deny

2 acl append task.uid=224
audit 1
1 allow path="/home/radio/shoutcast/sc_serv.log"
1 allow path="/home/radio/transcast/nohup.out"
1 allow path="/home/radio/transcast/sc_trans.log"
1 allow path="/home/radio/nohup.out"
1 allow path="/dev/null"
1 allow path="/dev/tty"
11111 deny

* Third usage example:

generic_acl(6, allow, (rename, write, create, append), task.domain="/usr/sbin/httpd", [
11 deny new_path="/\(\*\)/\*.php\@"
11 deny new_path="/\(\*\)/.htaccess"
])
generic_acl(6, deny, (link, symlink), task.domain="/usr/sbin/httpd", [])


Then I can load my config with: # m4 config.m4 | /usr/sbin/caitsith-loadpolicy

Best regards,
Tetsuo Handa
2012-12-31 11:18:17 UTC
Permalink
Post by do1
Yes people may think differently. But every person understand concept of read-only
directory or ro mount. So to simplify understanding generic writable_access operation
could implement all restrictions to implement usual read-only mount/dir.
If you care about bypassed accesses, read-only directory and read-only mount
cannot be implemented unless rules are written using inode's attributes.
Post by do1
Post by Tetsuo Handa
Post by do1
I think I covered all operations that can modify files, excluding all that read only.
This is different from my expected usage.
I don't understand, what is different from expected use? I want to make some
directory globally read only except for its accessor software. I think this is useful
in general and also useful insecurity sense. For example to protect backups from
accidental/intentional modifications. It is security for backups integrity.
I think your rules which are written using pathnames are incomplete.
I assume BACKUPS refers a name group which is defined like

name_group BACKUPS /home/backup/\(\*\)/\*

. You are trying to restrict unlink operation.

1 acl unlink path=@BACKUPS

This rule is OK as long as you don't care about bypassed accesses via
manipulating pathnames.

However, you have also defined rules which try to restrict mount operation
because you seem to care about bypassed accesses via manipulating pathnames.

1 acl mount source=@BACKUPS
1 acl mount target=@BACKUPS

These rules would block bypassed accesses like

# mount --bind /home/backup/ /tmp/
# unlink /tmp/yourbackup

. But why you don't care about bypassed accesses like

# mount --bind /home/ /tmp/
# unlink /tmp/backup/yourbackup

?

What if filesystem namespace is unshared and pivot_root is used for bringing
/home/backup to somewhere else?

You have defined rules which try to restrict rename operation.

1 acl rename old_path=@BACKUPS
1 acl rename new_path=@BACKUPS

These rules would block bypassed accesses like

# mv /home/backup /home/tmp
# unlink /home/tmp/yourbackup

. But why you don't care about bypassed accesses like

# mv /home /home2
# unlink /home2/backup/yourbackup

?

So, my expected usage for your will is to use inode's attributes.

For example, if you can allocate a dedicated partition for /home/backup
(say /dev/sda2), you can use "path.major" and "path.minor" rather than "path".

1 acl unlink path.major=8 path.minor=2
1 allow ...
2 deny

For another example, if you can allocate a dedicated user id for files and
directories in /home/backup (say 500), you can use "path.uid" rather than
"path".

1 acl unlink path.uid=500
1 allow ...
2 deny

1 acl chown path.uid=500
1 allow ...
2 deny

In this way, you don't need to care about bypassed accesses via manipulating
pathnames.

Especially for namespace manipulation operations (i.e. mount and pivot_root),
I think that these rules would look like

1 acl mount
1 allow ....
2 allow ....
3 allow ....
4 deny

1 acl pivot_root
1 allow ....
2 allow ....
3 allow ....
4 deny

. Also, ioctl rules would look like

1 acl ioctl path.type=file
1 allow cmd=@IOCTL_CMDS_FOR_FILE
2 deny

if you care about (and afford restricting) ioctl operations.

Whereas execute rules would look like examples in the PDF document.
do1
2012-12-31 12:28:22 UTC
Permalink
Thanks for the reply!
Post by Tetsuo Handa
?Yes people may think differently. But every person understand concept of read-only
?directory or ro mount. So to simplify understanding generic writable_access operation
?could implement all restrictions to implement usual read-only mount/dir.
If you care about bypassed accesses, read-only directory and read-only mount
cannot be implemented unless rules are written using inode's attributes.
Now I see what you mean. Yes, my approach (for backups protection) does not protect
against intentional deletion, but still protect against accidental deletion/curruption of backup
data, which is still very good (for me).
Post by Tetsuo Handa
?I think I covered all operations that can modify files, excluding all that
?read only.
?This is different from my expected usage.
?I don't understand, what is different from expected use? I want to make some
?directory globally read only except for its accessor software. I think this is useful
?in general and also useful insecurity sense. For example to protect backups from
?accidental/intentional modifications. It is security for backups integrity.
I think your rules which are written using pathnames are incomplete.
I assume BACKUPS refers a name group which is defined like
??name_group BACKUPS /home/backup/\(\*\)/\*
No, I used strings_group. I don't even see name_group in caitsith doc.
Post by Tetsuo Handa
. You are trying to restrict unlink operation.
This rule is OK as long as you don't care about bypassed accesses via
manipulating pathnames.
However, you have also defined rules which try to restrict mount operation
because you seem to care about bypassed accesses via manipulating pathnames.
These rules would block bypassed accesses like
??# mount --bind /home/backup/ /tmp/
??# unlink /tmp/yourbackup
. But why you don't care about bypassed accesses like
??# mount --bind /home/ /tmp/
??# unlink /tmp/backup/yourbackup
?
You are right. So to protect against intentional deletion/tampering I need to
restrict remount of all upper level directories too. Hm. I don't see general tools in
caitsith for that.

Or I should mount --make-unbindable /home/backup and then forbid umount of that.

Or I should forbid bind mounts overall, (since they are rarely (if at all) used on my server).
Post by Tetsuo Handa
What if filesystem namespace is unshared and pivot_root is used for bringing
/home/backup to somewhere else?
I'm not very understood pivot_root concept, will after pivot_root path checked as full
realpath or it will stripped to containt only after the pivot_root part?
Post by Tetsuo Handa
You have defined rules which try to restrict rename operation.
These rules would block bypassed accesses like
??# mv /home/backup /home/tmp
??# unlink /home/tmp/yourbackup
. But why you don't care about bypassed accesses like
??# mv /home /home2
??# unlink /home2/backup/yourbackup
?
ic.. Would be good to restrict that too. I probably should add deny rule
for renaming /home too. One more rule is not that bad.
Post by Tetsuo Handa
So, my expected usage for your will is to use inode's attributes.
For example, if you can allocate a dedicated partition for /home/backup
I can not.
Post by Tetsuo Handa
For another example, if you can allocate a dedicated user id for files and
directories in /home/backup (say 500), you can use "path.uid" rather than
"path".
I can not too. (This is snapshot type backup so files uid/gid can not be changed.)
Post by Tetsuo Handa
In this way, you don't need to care about bypassed accesses via manipulating
pathnames.
Maybe I still can use pathname apprach if protecting carefully against corner cases.
You did nice suggestions, thanks!


Btw, maybe can caitsith be extended to support more per inode restrinctions/checks?

I remember there is path.ino variable. But it seems it can't really protect some particular inode from access, since it report only for last element in the pathname (i.e. full pathname) and parent directory.

People, to access protected data, still need to _traverse_ path, so if it's possible to have operation like 'traverse' and apply rules to it if it's anywhere in the file path that would be useful. Example suggestion:

1 acl traverse path.ino=1234567 path.major=8 path.minor=2
1 deny

Is this possible to implement?

If yes, this could be extended to:

1 acl traverse path.ino=1234567 path.major=8 path.minor=2
1 allow path="/home/backup"
1 deny

To allow access to this inode directory only if it is in it's canonical filesystem place, but not otherwise.


Or have shorthand, instead of three rules like "path.ino=1234567 path.major=8 path.minor=2" to have path.stat="8:2:1234567". Later that can be extended to have pseudo pathname check, for example path.stat="/home/backup" which mean "on the time of loading rules determine min/maj/ino of path '/home/backup' and later check with only these numbers".

Then this can be extended to check if operation have some traverse point in realpath. Like, if I have /home/backup's min/maj/ino somewhere in the checked path, then such rules apply. Like:
maj_min_ino_group READONLIES "/home/backup/data2" # maj_min_ino_group determine attributes on time of rules load
maj_min_ino_group READONLIES "/home/backup/data3"
1 acl write anypathelementhave.stat=@READONLIES
1 allow task.exe="/usr/bin/rsync"
2 deny


Sorry for too many suggestions in single mail. ;)

Best regards,
do1
2012-12-31 12:53:38 UTC
Permalink
I got more suggestion ideas (while I not forget them).

Maybe it's possible to have kill decisive action?
So not just only deny action for some process but also instantly kill it to prevent future damage.

1 acl ...
1 deny task.kill=-9

Best regards,
Tetsuo Handa
2013-01-01 05:29:53 UTC
Permalink
Post by do1
No, I used strings_group. I don't even see name_group in caitsith doc.
Oops. I didn't check the manual. s/name_group/string_group/
Post by do1
You are right. So to protect against intentional deletion/tampering I need to
restrict remount of all upper level directories too. Hm. I don't see general tools in
caitsith for that.
To understand your wish, you need to understand how pathnames in Linux are
managed. And you will find that trying to perfectly protect from intentional
deletion/tampering using pathnames fails. There was a very long history of
battle between pathname based access control (e.g. AppArmor) and inode based
access control (e.g. SELinux). Since pathname based access control had
an advantage which cannot be achieved using inode based access control, TOMOYO
and AppArmor were able to join the mainline. (The advantage is not the ease of
use; see http://sourceforge.jp/projects/tomoyo/docs/lfj2008-bof.pdf and
http://sourceforge.jp/projects/tomoyo/docs/lca2009-kumaneko.pdf for examples.)
Post by do1
I remember there is path.ino variable. But it seems it can't really protect
some particular inode from access, since it report only for last element in
the pathname (i.e. full pathname) and parent directory.
In Linux, one inode can have multiple pathnames. Therefore, inode can be
calculated from pathnames but pathnames cannot be calculated from inode.
Post by do1
1 acl traverse path.ino=1234567 path.major=8 path.minor=2
1 allow path="/home/backup"
1 deny
To allow access to this inode directory only if it is in it's canonical
filesystem place, but not otherwise.
This is impossible because of how pathnames are managed in Linux.
Three data structures involves here: "struct inode", "struct dentry" and
"struct vfsmount". A pathname is converted to a "struct vfsmount" and
"struct dentry" pair. "struct inode" can be determined via
"struct dentry"->d_inode and parent directory can be determined via
"struct dentry"->d_parent . But a "struct vfsmount" and "struct dentry" pair
which is needed for calculating a canonical pathname cannot be determined from
"struct inode". Therefore, we cannot calculate a pathname from "struct inode".

When checking whether traversing a directory inode which has path.ino=1234567
path.major=8 path.minor=2 attributes is allowed or not, we cannot calculate
a pathname because only "struct inode" is available when the hook for checking
permission is called.

On the contrary, we have hooks for checking permissions (which TOMOYO,
AppArmor, AKARI, CaitSith uses) which are called after a pathname was converted
to a "struct vfsmount" and "struct dentry" pair. We can calculate a pathname
from these hooks but we cannot determine whether we have traversed a directory
inode which has path.ino=1234567 path.major=8 path.minor=2 attributes or not.
Post by do1
People, to access protected data, still need to _traverse_ path, so if it's
possible to have operation like 'traverse' and apply rules to it if it's
1 acl traverse path.ino=1234567 path.major=8 path.minor=2
1 deny
Is this possible to implement?
I won't try to implement it. The concept of canonical pathname does not work.

Trying to restrict based on grandparent directory's inode and/or its ascendant
inodes above does not work because only last component's inode and its parent
directory's inode are guaranteed to be checked, for a process might request
pathnames relative to current directory (e.g. unlink("yourbackup") rather than
unlink("/home/backup/year/month/day/yourbackup" when its current directory is
/home/backup/year/month/day/ ).

People can access protected data using relative pathnames. This means that,
a directory with "path.ino=1234567 path.major=8 path.minor=2" may not be
traversed when accessing a file which is located as a descendant of the
directory.

Also, /home/ or /home/backup/year/month/day/ might be bind mounted to
somewhere else.

If you use pathnames in your rules, please understand and accept that
the rules are not compatible with read-only mounts/directories.
do1
2013-01-01 12:33:35 UTC
Permalink
Post by Tetsuo Handa
?You are right. So to protect against intentional deletion/tampering I need to
?restrict remount of all upper level directories too. Hm. I don't see general tools in
?caitsith for that.
To understand your wish, you need to understand how pathnames in Linux are
managed. And you will find that trying to perfectly protect from intentional
deletion/tampering using pathnames fails.
Why? I don't agree.
Post by Tetsuo Handa
There was a very long history of
battle between pathname based access control (e.g. AppArmor) and inode based
access control (e.g. SELinux). Since pathname based access control had
an advantage which cannot be achieved using inode based access control, TOMOYO
and AppArmor were able to join the mainline. (The advantage is not the ease of
use; see http://sourceforge.jp/projects/tomoyo/docs/lfj2008-bof.pdf and
http://sourceforge.jp/projects/tomoyo/docs/lca2009-kumaneko.pdf for examples.)
Great slides, thanks for them.

In lfj2008-bof.pdf you say, that to protect /etc/shadow being read if linked to /tmp/shadow
pathname based access control needs "to restrict pathname changes", but label based
don't need to care about it. So you saying yourself that it is possible to fully control
access to /etc/shadow if we also control renaming, linking, mounting.
And all these things are controllable. So why you now saying perfectly protecting
using pathname based access control fails and I should understand and accept it.
I don't understand, if you saying in pdf yourself that it is possible. It just requires
more work. Plus, you then prove that this more work is in fact what is may be
required and is a good thing. Which I agree. (For example, binding /etc/ to /tmp
- we need protection against this, this is pathname based feature, and this also
solves problem of /etc/shadow being pathname manipulated.) So why it fail or not
compatible with read-only directories? It looks compatible and your words support it.
Post by Tetsuo Handa
?I remember there is path.ino variable. But it seems it can't really protect
?some particular inode from access, since it report only for last element in
?the pathname (i.e. full pathname) and parent directory.
In Linux, one inode can have multiple pathnames. Therefore, inode can be
calculated from pathnames but pathnames cannot be calculated from inode.
I understand that.
Post by Tetsuo Handa
?1 acl traverse path.ino=1234567 path.major=8 path.minor=2
????1 allow path="/home/backup"
????1 deny
?To allow access to this inode directory only if it is in it's canonical
?filesystem place, but not otherwise.
This is impossible because of how pathnames are managed in Linux.
Three data structures involves here: "struct inode", "struct dentry" and
"struct vfsmount". A pathname is converted to a "struct vfsmount" and
"struct dentry" pair. "struct inode" can be determined via
"struct dentry"->d_inode and parent directory can be determined via
"struct dentry"->d_parent . But a "struct vfsmount" and "struct dentry" pair
which is needed for calculating a canonical pathname cannot be determined from
"struct inode". Therefore, we cannot calculate a pathname from "struct inode".
I know. But this is 'traverse' operation, so you possible have parts of pathname (becasue it is supposed to traverse elements of pathname) not just inode numbers. (How is Smack LSM enforce r or x on directory - so probably LSM have some hooks into traverse mechanisms. I don't sure if it have parts of pathname at that time, though, if not, then it is not possible of course.) In any case you maybe able to calculate directory realpath from dentry (just cd to '..' until / is meet, I think that's how realpath is already works.)
Post by Tetsuo Handa
When checking whether traversing a directory inode which has path.ino=1234567
path.major=8 path.minor=2 attributes is allowed or not, we cannot calculate
a pathname because only "struct inode" is available when the hook for checking
permission is called.
That was just example with 'allow path="/home/backup"', but there was other examples too.
Post by Tetsuo Handa
On the contrary, we have hooks for checking permissions (which TOMOYO,
AppArmor, AKARI, CaitSith uses) which are called after a pathname was converted
to a "struct vfsmount" and "struct dentry" pair. We can calculate a pathname
?from these hooks but we cannot determine whether we have traversed a directory
inode which has path.ino=1234567 path.major=8 path.minor=2 attributes or not.
But Smack is LSM and it can restrict traverse operation. So there should be some hooks.
Post by Tetsuo Handa
?People, to access protected data, still need to _traverse_ path, so if it's
?possible to have operation like 'traverse' and apply rules to it if it's
?1 acl traverse path.ino=1234567 path.major=8 path.minor=2
????1 deny
?Is this possible to implement?
I won't try to implement it.
ic.
Post by Tetsuo Handa
The concept of canonical pathname does not work.
This exampel does not say anything about canonical pathname. It try to forbid
traverse by min/maj/inode.
Post by Tetsuo Handa
Trying to restrict based on grandparent directory's inode and/or its ascendant
inodes above does not work because only last component's inode and its parent
directory's inode are guaranteed to be checked, for a process might request
pathnames relative to current directory (e.g. unlink("yourbackup") rather than
unlink("/home/backup/year/month/day/yourbackup" when its current directory is
/home/backup/year/month/day/ ).
I understand that, but this does not mean this approach does not work at all.
For example, if I forbid for some min/maj/inode (directory) access altogether, then
user will be not able to chdir to any underlying pathname and then unlink("backupfile").
So this will work. (Plus, we still be possible able to determine realpath of parent directory.)
Post by Tetsuo Handa
People can access protected data using relative pathnames. This means that,
a directory with "path.ino=1234567 path.major=8 path.minor=2" may not be
traversed when accessing a file which is located as a descendant of the
directory.
People will not be able to chdir behing that directory, so it works.
Post by Tetsuo Handa
Also, /home/ or /home/backup/year/month/day/ might be bind mounted to
somewhere else.
If you use pathnames in your rules, please understand and accept that
the rules are not compatible with read-only mounts/directories.
I think they are compatible, or at least step in that direction. We don't need to
achieve perfect security suddenly, but can go step by step and see if this helps.

Best regards,
Tetsuo Handa
2013-01-02 11:40:17 UTC
Permalink
Post by do1
Post by Tetsuo Handa
There was a very long history of
battle between pathname based access control (e.g. AppArmor) and inode based
access control (e.g. SELinux). Since pathname based access control had
an advantage which cannot be achieved using inode based access control, TOMOYO
and AppArmor were able to join the mainline. (The advantage is not the ease of
use; see http://sourceforge.jp/projects/tomoyo/docs/lfj2008-bof.pdf and
http://sourceforge.jp/projects/tomoyo/docs/lca2009-kumaneko.pdf for examples.)
Great slides, thanks for them.
In lfj2008-bof.pdf you say, that to protect /etc/shadow being read if linked to /tmp/shadow
pathname based access control needs "to restrict pathname changes", but label based
don't need to care about it. So you saying yourself that it is possible to fully control
access to /etc/shadow if we also control renaming, linking, mounting.
I didn't say I can perfectly control access to /etc/shadow . I said we need to
care about not only readability/writability/executability of a file but also
the location of the file because whether the system works as expected depends
on whether resources are available at expected location. I said name based
access control can care about the location of resources better than inode based
access control. My opinion is that inode based access control and name based
access control play a complementary role vis-a-vis, and therefore both access
controls should be used together. LSM stacking is now under discussion and we
will be able to run both access controls in parallel by the end of this year.

Name based access control can control access to a file only if the file to
protect has uniquely identifiable pathnames. A temporary file created in /tmp/
may have random names like /tmp/w4gZ6h and multiple applications may create
such temporary files. But name based access control cannot distinguish which
temporary file should be accessible from which application because name has no
meaning in this case. Only inode based access control which associates creator
application's information can correctly distinguish such temporary files.

Not all files have uniquely identifiable names. Also, the same pathname in
different namespace may refer different resources. Inode based access control
sometimes handles better than name based access control.
Post by do1
And all these things are controllable. So why you now saying perfectly protecting
using pathname based access control fails and I should understand and accept it.
Only partially controllable. Not always perfectly controllable.

As I said above, name based access control can protect resources only when
resources have limited and meaningful names. That's reason you can't perfectly
protect using pathname based access control.
Post by do1
I don't understand, if you saying in pdf yourself that it is possible. It just requires
more work. Plus, you then prove that this more work is in fact what is may be
required and is a good thing. Which I agree. (For example, binding /etc/ to /tmp
- we need protection against this, this is pathname based feature, and this also
solves problem of /etc/shadow being pathname manipulated.) So why it fail or not
compatible with read-only directories? It looks compatible and your words support it.
Read-only mount/directory in one namespace can have read/write mount/directory
in another namespace. Pathname based access control can't do it because there
is no means to distinguish namespace.
Post by do1
Post by Tetsuo Handa
This is impossible because of how pathnames are managed in Linux.
Three data structures involves here: "struct inode", "struct dentry" and
"struct vfsmount". A pathname is converted to a "struct vfsmount" and
"struct dentry" pair. "struct inode" can be determined via
"struct dentry"->d_inode and parent directory can be determined via
"struct dentry"->d_parent . But a "struct vfsmount" and "struct dentry" pair
which is needed for calculating a canonical pathname cannot be determined from
"struct inode". Therefore, we cannot calculate a pathname from "struct inode".
I know. But this is 'traverse' operation, so you possible have parts of
pathname (becasue it is supposed to traverse elements of pathname) not just
inode numbers. (How is Smack LSM enforce r or x on directory - so probably
LSM have some hooks into traverse mechanisms. I don't sure if it have parts
of pathname at that time, though, if not, then it is not possible of course.)
No partial pathname available for traverse operation. SELinux and SMACK do not
calculate pathnames for checking permissions. The hook which SELinux and SMACK
use for checking traverse permission receives only "struct inode".

int security_inode_permission(struct inode *inode, int mask);

Since "struct dentry" and "struct vfsmount" are not passed to
security_inode_permission() hook, pathname based access control (e.g. TOMOYO,
AppArmor, AKARI, CaitSith) cannot use pathname when checking permission for
traverse operation. Of course, you can join both LSM mailing list and FS-devel
mailing list and persuade the both maintainers to pass "struct dentry" and
"struct vfsmount"; good luck.
Post by do1
In any case you maybe able to calculate directory realpath from dentry (just
cd to '..' until / is meet, I think that's how realpath is already works.)
Not true. Pathname based access control's realpath is calculated from a
"struct dentry" and "struct vfsmount" pair.

If we have only "struct dentry", we can calculate partial pathname only up to
mount point which the "struct dentry" belongs to; in order words, we cannot
calculate till / is met if "struct dentry" does not belong to / partition.
Post by do1
Post by Tetsuo Handa
On the contrary, we have hooks for checking permissions (which TOMOYO,
AppArmor, AKARI, CaitSith uses) which are called after a pathname was converted
to a "struct vfsmount" and "struct dentry" pair. We can calculate a pathname
?rom these hooks but we cannot determine whether we have traversed a directory
inode which has path.ino=1234567 path.major=8 path.minor=2 attributes or not.
But Smack is LSM and it can restrict traverse operation. So there should be some hooks.
There is a hook for checking permission for traverse operation. But we cannot
calculate pathname from that hook. SMACK can work because SMACK does not use
pathnames for checking permissions, while your proposal can't be implemented
because your proposal needs to calculate pathnames from that hook.
Post by do1
Post by Tetsuo Handa
The concept of canonical pathname does not work.
This exampel does not say anything about canonical pathname. It try to forbid
traverse by min/maj/inode.
There are multiple routes to reach the directory containing "yourbackup" file.
Try below operations. (Note the $ prompt which means non-root user.)

(1) $ mkdir -m 777 -p /tmp/dir1/dir2/dir3/
(2) $ echo hello > /tmp/dir1/dir2/dir3/file
(3) $ mkdir -m 777 -p /tmp/dir0/
(4) $ su - root -c "mount --bind /tmp/dir1/dir2/dir3/ /tmp/dir0/"
(5) $ cd /tmp/dir1/dir2/dir3/
(6) $ chmod 000 /tmp/dir1/
(7) $ cat /tmp/dir1/dir2/dir3/file
cat: /tmp/dir1/dir2/dir3/file: Permission denied
(8) $ cat file
hello
(9) $ chmod 777 /tmp/dir1/
(10) $ chmod 000 /tmp/dir1/dir2/
(11) $ cat /tmp/dir1/dir2/dir3/file
cat: /tmp/dir1/dir2/dir3/file: Permission denied
(12) $ cat file
hello
(13) $ chmod 777 /tmp/dir1/dir2/
(14) $ chmod 000 /tmp/dir1/dir2/dir3/
(15) $ cat /tmp/dir1/dir2/dir3/file
cat: /tmp/dir1/dir2/dir3/file: Permission denied
(16) $ cat file
cat: file: Permission denied
(17) $ chmod 777 /tmp/dir1/dir2/dir3
(18) $ chmod 000 /tmp/dir1/dir2/
(19) $ cat /tmp/dir1/dir2/dir3/file
cat: /tmp/dir1/dir2/dir3/file: Permission denied
(20) $ cat /tmp/dir0/file
hello

Suppose your min/maj/inode traversal checking idea is implemented and
min/maj/inode is set to attributes of /tmp/dir1/dir2/ upon the time of loading
rules, you will fail to block (20) because /tmp/dir0/file can reach
/tmp/dir1/dir2/dir3/file even though /tmp/dir1/dir2/ is not within /tmp/dir0/ .
Post by do1
Post by Tetsuo Handa
Trying to restrict based on grandparent directory's inode and/or its ascendant
inodes above does not work because only last component's inode and its parent
directory's inode are guaranteed to be checked, for a process might request
pathnames relative to current directory (e.g. unlink("yourbackup") rather than
unlink("/home/backup/year/month/day/yourbackup" when its current directory is
/home/backup/year/month/day/ ).
I understand that, but this does not mean this approach does not work at all.
For example, if I forbid for some min/maj/inode (directory) access altogether, then
user will be not able to chdir to any underlying pathname and then unlink("backupfile").
So this will work. (Plus, we still be possible able to determine realpath of parent directory.)
And comparing among (8), (12), (16), you can see that only (16) failed.
In other words, only permission of /tmp/dir1/dir2/dir3/ and
/tmp/dir1/dir2/dir3/file are checked if current directory is already
/tmp/dir1/dir2/dir3/ and requested access to ./file .

Trying to reject access using attributes of /tmp/dir1/dir2/ or /tmp/dir1/ does
not work.

You might think we can still block if we forbid changing current directory to
/tmp/dir1/dir2/dir3/ and doing bind mount operation. Yes if your system can
work even if you unconditionally forbid them. But we can't do;
security_inode_permission() cannot tell whether this is for chdir operation or
for other operations. If you unconditionally deny traverse operation at
security_inode_permission(), yourbackup becomes never reachable (i.e. even from
applications which should be able to access yourbackup).
Post by do1
Post by Tetsuo Handa
People can access protected data using relative pathnames. This means that,
a directory with "path.ino=1234567 path.major=8 path.minor=2" may not be
traversed when accessing a file which is located as a descendant of the
directory.
People will not be able to chdir behing that directory, so it works.
Post by Tetsuo Handa
Also, /home/ or /home/backup/year/month/day/ might be bind mounted to
somewhere else.
If you use pathnames in your rules, please understand and accept that
the rules are not compatible with read-only mounts/directories.
I think they are compatible, or at least step in that direction. We don't need to
achieve perfect security suddenly, but can go step by step and see if this helps.
Best regards,
I hope you have now understood why your min/maj/inode idea does not work.
do1
2013-01-03 17:09:36 UTC
Permalink
Hello Tetsuo Handa,
As explained above, open source software needs agreement from not only me but
also the Linux kernel developers community.
I hope you have now understood why your min/maj/inode idea does not work.
Thank you very much for detailed explanations.
Now I understand your position and constraints better.

Best regards,
do1
2013-09-14 19:58:37 UTC
Permalink
Hello,

Compilation error on 3.2.62 kernel with latest caitsith-patch-0.1-20130707

make bzImage output:
...
CC security/caitsith/load_policy.o
CC security/caitsith/permission.o
In file included from security/caitsith/permission.c:9:
security/caitsith/internal.h: In function 'cs_current_security':
security/caitsith/internal.h:1179: error: 'struct task_struct' has no member named 'cs_domain_info'
security/caitsith/internal.h:1180: error: 'struct task_struct' has no member named 'cs_domain_info'
security/caitsith/internal.h: In function 'cs_task_domain':
security/caitsith/internal.h:1193: error: 'struct task_struct' has no member named 'cs_domain_info'
security/caitsith/internal.h: In function 'cs_current_domain':
security/caitsith/internal.h:1204: error: 'struct task_struct' has no member named 'cs_domain_info'
security/caitsith/internal.h: In function 'cs_task_flags':
security/caitsith/internal.h:1216: error: 'struct task_struct' has no member named 'cs_flags'
security/caitsith/internal.h: In function 'cs_current_flags':
security/caitsith/internal.h:1226: error: 'struct task_struct' has no member named 'cs_flags'
security/caitsith/permission.c: In function 'cs_execute':
security/caitsith/permission.c:579: error: 'struct task_struct' has no member named 'cs_flags'
security/caitsith/permission.c: In function 'cs_start_execve':
security/caitsith/permission.c:941: error: 'struct task_struct' has no member named 'cs_domain_info'
security/caitsith/permission.c:943: error: 'struct task_struct' has no member named 'cs_flags'
security/caitsith/permission.c: In function 'cs_finish_execve':
security/caitsith/permission.c:982: error: 'struct task_struct' has no member named 'cs_domain_info'
security/caitsith/permission.c:991: error: 'struct task_struct' has no member named 'cs_flags'
security/caitsith/permission.c:994: error: 'struct task_struct' has no member named 'cs_flags'
security/caitsith/permission.c:997: error: 'struct task_struct' has no member named 'cs_flags'
security/caitsith/permission.c: In function 'cs_manager':
security/caitsith/permission.c:2533: error: 'struct task_struct' has no member named 'cs_flags'
security/caitsith/permission.c:2540: error: 'struct task_struct' has no member named 'cs_flags'
security/caitsith/permission.c:2551: error: 'struct task_struct' has no member named 'cs_domain_info'
make[2]: *** [security/caitsith/permission.o] Error 1
make[1]: *** [security/caitsith] Error 2
make: *** [security] Error 2

It seems that you use cs_domain_info there, but task struct patched to define ccs_domain_info.

Best regards,
Tetsuo Handa
2013-09-14 22:24:50 UTC
Permalink
Hello.
Post by do1
It seems that you use cs_domain_info there, but task struct patched to define ccs_domain_info.
Yes. I forgot to change from

sed -i -e 's/CCSECURITY/CAITSITH/g' -e 's/ccsecurity/caitsith/g' -- patches/ccs-patch-*.diff

to

sed -i -e 's/CCSECURITY/CAITSITH/g' -e 's/ccsecurity/caitsith/g' -e 's/ccs_domain_info/cs_domain_info/g' -e 's/ccs_flags/cs_flags/g' -- patches/ccs-patch-*.diff

.

Thank you.

do1
2013-01-01 11:25:34 UTC
Permalink
Post by Tetsuo Handa
What if filesystem namespace is unshared and pivot_root is used for bringing
/home/backup to somewhere else?
What will happen? I verified by experiment that when I have

1 acl create path="/home/backup/data1/\(\*\)/\*"
1 deny

And I do `chroot /home/backup /touch /data1/x` I have access properly denied as expected by me. Realpath seems properly accounted for chroot.

2013/01/01 11:17:37# global-pid=31896 result=denied priority=1 / create path="/home/backup/data1/x" ... task.exe="/home/backup/touch" task.domain="/usr/sbin/sshd" ...

So I don't need to care about pivot_root in my case.

Regards,
Tetsuo Handa
2013-01-02 04:53:09 UTC
Permalink
Post by do1
Post by Tetsuo Handa
What if filesystem namespace is unshared and pivot_root is used for bringing
/home/backup to somewhere else?
What will happen? I verified by experiment that when I have
See http://www.kernel.org/doc/man-pages/online/pages/man2/pivot_root.2.html for
manual. Below is a demo program.

---------- demo.c start ----------
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mount.h>
#include <sched.h>
#include <errno.h>
int pivot_root(const char *new_root, const char *put_old);

int main(int argc, char *argv[])
{
/* Unshare mount namespace */
{
if (unshare(CLONE_NEWNS)) {
const int err = errno;
fprintf(stderr, "unshare() failed: %d\n", err);
return 1;
}
}
/* Mount tmpfs on /tmp */
{
if (mount("none", "/tmp", "tmpfs", 0, NULL)) {
const int err = errno;
fprintf(stderr, "mount() failed: %d\n", err);
return 1;
}
}
/* Create /tmp/dir/ */
{
if (mkdir("/tmp/dir", 0755)) {
const int err = errno;
fprintf(stderr, "mkdir() failed: %d\n", err);
return 1;
}
}
/* Create /tmp/file */
{
const int fd = open("/tmp/file", O_CREAT | O_WRONLY, 0644);
if (fd == EOF || write(fd, "hello\n", 6) != 6 || close(fd)) {
const int err = errno;
fprintf(stderr, "open()/write()/close() failed: %d\n",
err);
return 1;
}
}
/* /tmp/file was accessible as /tmp/file */
{
char c;
const int fd = open("/tmp/file", O_RDONLY, 0666);
if (fd == EOF) {
const int err = errno;
fprintf(stderr, "open(\"/tmp/file\") failed: %d\n",
err);
return 1;
}
fprintf(stderr, "Content of /tmp/file\n");
while (read(fd, &c, 1) == 1 && write(1, &c, 1));
close(fd);
}
/* Make /tmp/ the new / */
{
if (pivot_root("/tmp/", "/tmp/dir/")) {
const int err = errno;
fprintf(stderr, "pivot_root() failed: %d\n", err);
return 1;
}
}
/* /tmp/file is now accessible as /file */
{
char c;
const int fd = open("/file", O_RDONLY);
if (fd == EOF) {
const int err = errno;
fprintf(stderr, "open(\"/file\") failed: %d\n", err);
return 1;
}
fprintf(stderr, "Content of /file\n");
while (read(fd, &c, 1) == 1 && write(1, &c, 1));
close(fd);
}
return 0;
}
---------- demo.c end ----------

Usage of this demo program is:

(Step 1) Compile this demo program.

# gcc -Wall -O3 -o a.out demo.c

(Step 2) Add CaitSith's policy that audits reading files on tmpfs.

# echo 'quota audit[0] allowed=0 denied=1024 unmatched=1024' | caitsith-loadpolicy
# echo '1 acl read path.fsmagic=0x01021994' | caitsith-loadpolicy

(Step 3) Discard the CaitSith's audit log.

# cat /proc/caitsith/audit > /dev/null

(Step 4) Run this demo program.

# ./a.out

(Step 5) Check the CaitSith's audit log.

# cat /proc/caitsith/audit

An example of audit log looks like

#2013/01/02 04:41:58# global-pid=1298 result=unmatched priority=1 / read path="/tmp/file" task.pid=1298 task.ppid=1262 task.uid=0 task.gid=0 task.euid=0 task.egid=0 task.suid=0 task.sgid=0 task.fsuid=0 task.fsgid=0 task.type!=execute_handler task.exe="/root/a.out" task.domain="<kernel>" path.uid=0 path.gid=0 path.perm=0644 path.type=file path.ino=9374 path.major=0 path.minor=21 path.fsmagic=0x1021994 path.parent.uid=0 path.parent.gid=0 path.parent.perm=01777 path.parent.ino=9372 path.parent.major=0 path.parent.minor=21 path.parent.fsmagic=0x1021994
#2013/01/02 04:41:58# global-pid=1298 result=unmatched priority=1 / read path="/file" task.pid=1298 task.ppid=1262 task.uid=0 task.gid=0 task.euid=0 task.egid=0 task.suid=0 task.sgid=0 task.fsuid=0 task.fsgid=0 task.type!=execute_handler task.exe="/root/a.out" task.domain="<kernel>" path.uid=0 path.gid=0 path.perm=0644 path.type=file path.ino=9374 path.major=0 path.minor=21 path.fsmagic=0x1021994 path.parent.uid=0 path.parent.gid=0 path.parent.perm=01777 path.parent.ino=9372 path.parent.major=0 path.parent.minor=21 path.parent.fsmagic=0x1021994

where the difference is only value of "path" variable.

You will find that the location of a file has changed by pivot_root and you
will also find that the inode's attributes (e.g. path.ino ) remain unchanged.

The pathname calculation logic used by TOMOYO, AppArmor, AKARI and CaitSith is
not affected by chroot but is affected by pivot_root .
Post by do1
1 acl create path="/home/backup/data1/\(\*\)/\*"
1 deny
And I do `chroot /home/backup /touch /data1/x` I have access properly denied as expected by me. Realpath seems properly accounted for chroot.
2013/01/01 11:17:37# global-pid=31896 result=denied priority=1 / create path="/home/backup/data1/x" ... task.exe="/home/backup/touch" task.domain="/usr/sbin/sshd" ...
So I don't need to care about pivot_root in my case.
You tested chroot case but didn't test pivot_root case.
You need to care about pivot_root in your case.
do1
2013-01-02 12:02:09 UTC
Permalink
02.01.2013, 08:53, "Tetsuo Handa" <from-tomoyo-users-en at I-love.SAKURA.ne.jp>:
...
Post by Tetsuo Handa
You tested chroot case but didn't test pivot_root case.
You need to care about pivot_root in your case.
Thank you for detailed explanation. I wan't realised pivot_root true meaning and confused it with chroot.

(So, for normal server pivot_root can be disabled altogether.)


Best regards,
Loading...