Discussion:
AppArmor profile name and hard link question
Li, Li
2014-09-17 00:28:34 UTC
Permalink
Hello,

I am new to AppArmor. I am trying to port it to an embedded linux platform. One problem I found is related to file system and/or hard link issue.

The platform I have mount system files under /rom using squashfs first. Then mount another file system jffs2 as / and create hard links to all the files under /rom. So it looks to the system everything is under "/". The problem is when I create a profile with '/path/tofile' as name, it cannot be constrained even it detects there's a profile for it.
If I create a profile with '/rom/path/tofile', it can detect it only when I run the file using '/rom/path/tofile', not from the hard link '/path/tofile'.

I understand there's some issues with links for apparmor to work correctly, but is it already fixed? BTW, the kernel I have is 3.4 and I also applied the 3.4 apparmor patches.

Thanks in advance,

Lee
Seth Arnold
2014-09-18 00:23:07 UTC
Permalink
Post by Li, Li
Hello,
Hello Lee,
Post by Li, Li
I am new to AppArmor. I am trying to port it to an embedded linux
platform. One problem I found is related to file system and/or hard link
issue.
Welcome aboard!
Post by Li, Li
The platform I have mount system files under /rom using squashfs first.
Then mount another file system jffs2 as / and create hard links to all
the files under /rom. So it looks to the system everything is under "/".
The problem is when I create a profile with '/path/tofile' as name, it
cannot be constrained even it detects there's a profile for it. If I
create a profile with '/rom/path/tofile', it can detect it only when I
run the file using '/rom/path/tofile', not from the hard link
'/path/tofile'.
I'm not familiar with squashfs or jffs2 -- do they really allow hardlinks
to cross filesystem boundaries? It was my understanding that hardlinks are
constrained to live 'within' a single filesystem -- which is one reason
why symbolic links were introduced.

Can you prepare a quick reproducer shell script which can be run easily on
e.g. a desktop system for testing? I'm curious what exactly has been done.
Post by Li, Li
I understand there's some issues with links for apparmor to work
correctly, but is it already fixed? BTW, the kernel I have is 3.4 and I
also applied the 3.4 apparmor patches.
You'll have to be more specific. Here's some points that often help people
new to AppArmor understand how it works behind the scenes:

AppArmor (well, the kernel) resolves symbolic links to a 'real' filename
before mediation. Permissions aren't checked on symlinks.

A confined progam may get different allowed permissions on a file
depending upon which hard link it uses to open the file: a file with
multiple hardlinks could have different permissions for different names.

A confined program that creates hardlinks to files needs to have
corresponding permissions to do so, and cannot expand its permissions
with this mechanism.

A program with multiple hardlinks use the specific hardlink in question
when determining attachment. For example, I always have a /tmp/bash
profile loaded that allows some very small things necessary for bash to
run, but nothing else. (It's great for testing.) But a /tmp/sh hardlink to
/tmp/bash doesn't run confined because the profile is for /tmp/bash.

You can run this kind of testing like this:

cat >/etc/apparmor.d/tmp.bash <<EOF
#include <tunables/global>
/tmp/bash {
#include <abstractions/base>
/tmp/bash rm,
}
EOF
apparmor_parser --replace /etc/apparmor.d/tmp.bash
cp /bin/bash /tmp/bash
ln /tmp/bash /tmp/sh
/tmp/bash # notice this is confined, error messages etc ^D
/tmp/sh # notice this is unconfined, no error messages ^D


I hope these cover your questions, but if you can prepare a quick shell
script to demonstrate what you mean, that'll make sure we're not talking
at cross-purposes to each other.

Thanks
Li, Li
2014-09-18 01:30:01 UTC
Permalink
Hello Seth,

Thanks for the quick response!

Well, I did a little bit more digging myself and looks like the problem I have may not be hard/symb link issues. It's file system issue.

The system I have use something called overlay-filesystem. https://git.kernel.org/cgit/linux/kernel/git/mszeredi/vfs.git/tree/Documentation/filesystems/overlayfs.txt?h=overlayfs.current

The link describe what it does. As I previously thought the two objects/files are hardlink, well it actually may not be, it's the "same" file showing up in both lower and upper layer. So essentially you have two mount points to the same object. It also mean the lookup of a requested object can exist in two "directory" if it exists on both upper and lower. I don't know how significant this have on the AppArmor code, from what I look at, it walks through dentry each time a file object is accessed.

For example, by using overlayfs, we have a lower fs mounted on '/rom', and a higher fs mounted on '/', you will find a exe file under both '/rom/bin/exe' and '/bin/exe' exists. And it's not a "hard link". For all practical purpose, all the access to the file is using upper fs, so no one will even notice there're two fs.

I did a bit debugging on the kernel AppArmor code, it looks like a "path" lookup failed each time a file under '/bin/exe' is accessed. But if I run it using '/rom/bin/exe', the lookup worked. I also looked at apparmor/path.c code:

Let's say the path passed in is 'bin/exe', and walk through the code, the function always return error -13, if the path name is the upper fs path. Hope this might help figure out where the problem is.

Lee

56 static int d_namespace_path(struct path *path, char *buf, int buflen,
57 char **name, int flags)
58 {
... <====== skipped, not executed

81 /* resolve paths relative to chroot?*/
82 if (flags & PATH_CHROOT_REL) {
83 struct path root;
84 get_fs_root(current->fs, &root);
85 res = __d_path(path, &root, buf, buflen);
86 path_put(&root);
87 } else {
88 res = d_absolute_path(path, buf, buflen); <== here, the res will be '/bin/exe'
89 if (!our_mnt(path->mnt)) <== somehow the compare of mnt->mnt_ns and current->nsproxy->mnt_ns not equal
90 connected = 0;
91 }
92
<===== skipped
108
109 *name = res;
110
<===== skipped

123 /* If the path is not connected to the expected root,
124 * check if it is a sysctl and handle specially else remove any
125 * leading / that __d_path may have returned.
126 * Unless
127 * specifically directed to connect the path,
128 * OR
129 * if in a chroot and doing chroot relative paths and the path
130 * resolves to the namespace root (would be connected outside
131 * of chroot) and specifically directed to connect paths to
132 * namespace root.
133 */
134 if (!connected) {
135 if (!(flags & PATH_CONNECT_PATH) &&
136 !(((flags & CHROOT_NSCONNECT) == CHROOT_NSCONNECT) &&
137 our_mnt(path->mnt))) {
138 /* disconnected path, don't return pathname starting
139 * with '/'
140 */
141 error = -EACCES; <====, it returns error
142 if (*res == '/')
143 *name = res + 1;
144 }
145 }



-----Original Message-----
From: Seth Arnold [mailto:seth.arnold-Z7WLFzj8eWMS+***@public.gmane.org]
Sent: Wednesday, September 17, 2014 5:23 PM
To: Li, Li
Cc: apparmor-***@public.gmane.org
Subject: Re: [apparmor] AppArmor profile name and hard link question
Post by Li, Li
Hello,
Hello Lee,
Post by Li, Li
I am new to AppArmor. I am trying to port it to an embedded linux
platform. One problem I found is related to file system and/or hard
link issue.
Welcome aboard!
Post by Li, Li
The platform I have mount system files under /rom using squashfs first.
Then mount another file system jffs2 as / and create hard links to all
the files under /rom. So it looks to the system everything is under "/".
The problem is when I create a profile with '/path/tofile' as name, it
cannot be constrained even it detects there's a profile for it. If I
create a profile with '/rom/path/tofile', it can detect it only when I
run the file using '/rom/path/tofile', not from the hard link
'/path/tofile'.
I'm not familiar with squashfs or jffs2 -- do they really allow hardlinks to cross filesystem boundaries? It was my understanding that hardlinks are constrained to live 'within' a single filesystem -- which is one reason why symbolic links were introduced.

Can you prepare a quick reproducer shell script which can be run easily on e.g. a desktop system for testing? I'm curious what exactly has been done.
Post by Li, Li
I understand there's some issues with links for apparmor to work
correctly, but is it already fixed? BTW, the kernel I have is 3.4 and
I also applied the 3.4 apparmor patches.
You'll have to be more specific. Here's some points that often help people new to AppArmor understand how it works behind the scenes:

AppArmor (well, the kernel) resolves symbolic links to a 'real' filename before mediation. Permissions aren't checked on symlinks.

A confined progam may get different allowed permissions on a file depending upon which hard link it uses to open the file: a file with multiple hardlinks could have different permissions for different names.

A confined program that creates hardlinks to files needs to have corresponding permissions to do so, and cannot expand its permissions with this mechanism.

A program with multiple hardlinks use the specific hardlink in question when determining attachment. For example, I always have a /tmp/bash profile loaded that allows some very small things necessary for bash to run, but nothing else. (It's great for testing.) But a /tmp/sh hardlink to /tmp/bash doesn't run confined because the profile is for /tmp/bash.

You can run this kind of testing like this:

cat >/etc/apparmor.d/tmp.bash <<EOF
#include <tunables/global>
/tmp/bash {
#include <abstractions/base>
/tmp/bash rm,
}
EOF
apparmor_parser --replace /etc/apparmor.d/tmp.bash cp /bin/bash /tmp/bash ln /tmp/bash /tmp/sh /tmp/bash # notice this is confined, error messages etc ^D
/tmp/sh # notice this is unconfined, no error messages ^D


I hope these cover your questions, but if you can prepare a quick shell script to demonstrate what you mean, that'll make sure we're not talking at cross-purposes to each other.

Thanks
--
AppArmor mailing list
AppArmor-***@public.gmane.org
Modify settings or unsubscribe at: https://lists.ubuntu.com/mailman/listinfo/apparmor
John Johansen
2014-09-18 07:59:20 UTC
Permalink
Post by Li, Li
Hello Seth,
Thanks for the quick response!
Well, I did a little bit more digging myself and looks like the problem I have may not be hard/symb link issues. It's file system issue.
right
Post by Li, Li
The system I have use something called overlay-filesystem. https://git.kernel.org/cgit/linux/kernel/git/mszeredi/vfs.git/tree/Documentation/filesystems/overlayfs.txt?h=overlayfs.current
okay overlayfs does some interesting things
Post by Li, Li
The link describe what it does. As I previously thought the two objects/files are hardlink, well it actually may not be, it's the "same" file showing up in both lower and upper layer. So essentially you have two mount points to the same object. It also mean the lookup of a requested object can exist in two "directory" if it exists on both upper and lower. I don't know how significant this have on the AppArmor code, from what I look at, it walks through dentry each time a file object is accessed.
yes, it is a stacked virtualfs, where the overlay filesystem presents inodes
& dentries to the the system, and then loops back into the vfs with the
corresponding mnt/dentry/inode of the underlying filesystem.
Post by Li, Li
For example, by using overlayfs, we have a lower fs mounted on '/rom', and a higher fs mounted on '/', you will find a exe file under both '/rom/bin/exe' and '/bin/exe' exists. And it's not a "hard link".
correct
Post by Li, Li
For all practical purpose, all the access to the file is using upper fs, so no one will even notice there're two fs.
Not so for apparmor, because of how this is put together in the kernel
accesses to the overlay show up for each layer.

So for your example, the access to /bin/exe will show up as a lookup to
/bin/exe, followed by a lookup of /rom/bin/exe except with a twist (see below)
yes, this is because of how overlayfs setups the lower mnt
Post by Li, Li
Let's say the path passed in is 'bin/exe', and walk through the code, the function always return error -13, if the path name is the upper fs path. Hope this might help figure out where the problem is.
again the problem is in how overlayfs sets up its overlay. To avoid having
the submount showup in certain cases the way it does for aufs (another overlay
filesystem) it uses clone_private_mount() which creates a disconnected
private mount point to hide the fact that vfs is doing a loopback into the
lower mount.

The lower mount is disconnected from the namespace and apparmor notices
this when it does its lookup, and since your profiles are not using
the attach_disconnected flag it rejects the access to the lower mount
which gets propogated back up through.

Currently disconnected paths are a problem for apparmor, there is a crude
work around, but the true fix has not landed yet.

You can add the attach_disconnected flag onto the profile eg.
profile /foo flags=(attach_disconnected) {

}

This will result in the disconnect path lookup being connected to the root
so it will likely show up as /rom/bin/exe to apparmor (your regular userspace
applications will still only see the single file /bin/exe).

The other problem you have is that apparmor policy will need rules to
allow access to these files. There is an alias command that can help
with it.

alias / -> /rom/,

adding automatically will create rule aliases (essentially doubling the
rules like you need).
Eg. for the rule
/bin/exe r,

the alias generated would be
/rom/bin/exe r,


hope this helps
john
--
AppArmor mailing list
AppArmor-***@public.gmane.org
Modify settings or unsubscribe at: https://lists.ubuntu.com/mailman/listinfo/apparmor
Li, Li
2014-09-18 23:55:11 UTC
Permalink
Hi John,

Thanks for the answer!

So when AppArmor do a path lookup it only look for the current process's mount? i.e. the upper fs directory tree?

Well, I tried as you suggest to add:
profile /foo flags=(attach_disconnected) {

}

It worked partially for me, because it's a profile flag. If the process is confined by AA already, i.e in my case if the profile using lower fs path '/rom/bin/process', then all the files accessed by '/rom/bin/process' can be mapped correctly even it's just using upper fs path, like '/lib/aa'.
However, the process cannot be confined if it's running as '/bin/process', even if I had a second profile using name '/bin/process'. Looks like when AA trying to match a profile to the process, there's no where to look for a flag? Or is there a "work around" for set (attach_disconnected) globally?

Anyway, I did a hack temporarily just to verify my theory. Inside path.c:aa_path_name(path, flags, ...) call, I always append 'PATH_CONNECT_PATH' to the flags and it seems to work. I know this is probably not supposed to be the correct way. So please let me know if there's a better and easier way to do that without changing kernel code.

Thanks,

Lee


-----Original Message-----
From: John Johansen [mailto:john.johansen-Z7WLFzj8eWMS+***@public.gmane.org]
Sent: Thursday, September 18, 2014 12:59 AM
To: Li, Li; Seth Arnold
Cc: apparmor-***@public.gmane.org
Subject: Re: [apparmor] AppArmor profile name and hard link question
Post by Li, Li
Hello Seth,
Thanks for the quick response!
Well, I did a little bit more digging myself and looks like the problem I have may not be hard/symb link issues. It's file system issue.
right
Post by Li, Li
The system I have use something called overlay-filesystem.
https://git.kernel.org/cgit/linux/kernel/git/mszeredi/vfs.git/tree/Doc
umentation/filesystems/overlayfs.txt?h=overlayfs.current
okay overlayfs does some interesting things
Post by Li, Li
The link describe what it does. As I previously thought the two objects/files are hardlink, well it actually may not be, it's the "same" file showing up in both lower and upper layer. So essentially you have two mount points to the same object. It also mean the lookup of a requested object can exist in two "directory" if it exists on both upper and lower. I don't know how significant this have on the AppArmor code, from what I look at, it walks through dentry each time a file object is accessed.
yes, it is a stacked virtualfs, where the overlay filesystem presents inodes & dentries to the the system, and then loops back into the vfs with the corresponding mnt/dentry/inode of the underlying filesystem.
Post by Li, Li
For example, by using overlayfs, we have a lower fs mounted on '/rom', and a higher fs mounted on '/', you will find a exe file under both '/rom/bin/exe' and '/bin/exe' exists. And it's not a "hard link".
correct
Post by Li, Li
For all practical purpose, all the access to the file is using upper fs, so no one will even notice there're two fs.
Not so for apparmor, because of how this is put together in the kernel accesses to the overlay show up for each layer.

So for your example, the access to /bin/exe will show up as a lookup to
/bin/exe, followed by a lookup of /rom/bin/exe except with a twist (see below)
yes, this is because of how overlayfs setups the lower mnt
Post by Li, Li
Let's say the path passed in is 'bin/exe', and walk through the code, the function always return error -13, if the path name is the upper fs path. Hope this might help figure out where the problem is.
again the problem is in how overlayfs sets up its overlay. To avoid having the submount showup in certain cases the way it does for aufs (another overlay
filesystem) it uses clone_private_mount() which creates a disconnected private mount point to hide the fact that vfs is doing a loopback into the lower mount.

The lower mount is disconnected from the namespace and apparmor notices this when it does its lookup, and since your profiles are not using the attach_disconnected flag it rejects the access to the lower mount which gets propogated back up through.

Currently disconnected paths are a problem for apparmor, there is a crude work around, but the true fix has not landed yet.

You can add the attach_disconnected flag onto the profile eg.
profile /foo flags=(attach_disconnected) {

}

This will result in the disconnect path lookup being connected to the root so it will likely show up as /rom/bin/exe to apparmor (your regular userspace applications will still only see the single file /bin/exe).

The other problem you have is that apparmor policy will need rules to allow access to these files. There is an alias command that can help with it.

alias / -> /rom/,

adding automatically will create rule aliases (essentially doubling the rules like you need).
Eg. for the rule
/bin/exe r,

the alias generated would be
/rom/bin/exe r,


hope this helps
john
--
AppArmor mailing list
AppArmor-***@public.gmane.org
Modify settings or unsubscribe at: https://lists.ubuntu.com/mailman/listinfo/apparmor
John Johansen
2014-09-18 08:08:10 UTC
Permalink
Post by Li, Li
Hello,
I am new to AppArmor. I am trying to port it to an embedded linux platform. One problem I found is related to file system and/or hard link issue.
<< snip >>
Post by Li, Li
BTW, the kernel I have is 3.4 and I also applied the 3.4 apparmor patches.
Interesting, so the current upstream apparmor even with the out of tree
patches is more limited than I would like. We do have backports of the 3.12
apparmor all the way back to the 3.0 kernel.

And if you are daring the devel (not upstreamed yet) branch of apparmor code
that Ubuntu is using also has backports to the 3.4 kernel.

Release wise the apparmor 2.8.4 and 2.9 userspaces should be released
very soon. 2.8.4 is an incremental bug fix release over the current 2.8.2/3
releases and 2.9 adds support for new features like dbus mediation if you
have the correct kernel (introspection patches) and a patched dbus daemon
(the dbus patches are on the dbus list and hopefully will be taken soon).

Don't hesitate to ask questions, it can some times take a day or two to
get a response (everyone is extremely busy), people are generally willing
to help.
--
AppArmor mailing list
AppArmor-***@public.gmane.org
Modify settings or unsubscribe at: https://lists.ubuntu.com/mailman/listinfo/apparmor
Loading...