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:[email protected]] 
Sent: Wednesday, September 17, 2014 5:23 PM
To: Li, Li
Cc: [email protected]
Subject: Re: [apparmor] AppArmor profile name and hard link question

On Wed, Sep 17, 2014 at 12:28:34AM +0000, Li, Li wrote:
> Hello,

Hello Lee,

> 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!

> 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.

> 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
[email protected]
Modify settings or unsubscribe at: 
https://lists.ubuntu.com/mailman/listinfo/apparmor

Reply via email to