2004-09-03 12:17:07

by Kristian Sørensen

[permalink] [raw]
Subject: Getting full path from dentry in LSM hooks

Hi!

I have a short question, concerning how to get the full path of a file
from a LSM hook.

- If the "file" of the dentry is located in the root filesystem: no
problem - simply traverse the dentrys, to generate the path.

- If the "file" is mounted from another partition, you do not get the
full path by traversing the dentrys.

Example:
If we have a system with a normal root (/) and a seperate boot partition
(mounted on /boot :). In the LSM hook inode_permission, you get the
arguments (struct inode *inode, int mask, struct nameidata *nd).
Finding the path, we traverse the dentrys from (nd->dentry). But if the
inode is a file in /boot we only get the filename (e.g. kernel-2.6.8.1
instead of /boot/kernel-2.6.8.1)


Can some one reveal the trick to get the full path nomater if the
filesystem is root or mounted elsewhere in the filesystem?


Best regards,
Kristian S?rensen.
The Umbrella Project -- http://umbrella.sf.net


2004-09-03 12:32:46

by Christoph Hellwig

[permalink] [raw]
Subject: Re: Getting full path from dentry in LSM hooks

On Fri, Sep 03, 2004 at 02:12:21PM +0200, Kristian S?rensen wrote:
> I have a short question, concerning how to get the full path of a file
> from a LSM hook.
>
> - If the "file" of the dentry is located in the root filesystem: no
> problem - simply traverse the dentrys, to generate the path.
>
> - If the "file" is mounted from another partition, you do not get the
> full path by traversing the dentrys.

There is no canonical full path for a given dentry.

2004-09-03 12:40:45

by Kristian Sørensen

[permalink] [raw]
Subject: Re: [Umbrella-devel] Re: Getting full path from dentry in LSM hooks

Hi Christoph!

Christoph Hellwig wrote:
> On Fri, Sep 03, 2004 at 02:12:21PM +0200, Kristian S?rensen wrote:
>
>>I have a short question, concerning how to get the full path of a file
>>from a LSM hook.
>>
>>- If the "file" of the dentry is located in the root filesystem: no
>> problem - simply traverse the dentrys, to generate the path.
>>
>>- If the "file" is mounted from another partition, you do not get the
>> full path by traversing the dentrys.
>
>
> There is no canonical full path for a given dentry.
Is there another way to get it? We also get an inodepointer from the LSM
hook. As far as I know, the file struct has an entry called vfs_mount,
which has an entry called root_mnt - could this be used? (and if so, how
do I get from the Inode to the file struct? :-/ )


KS.

2004-09-03 12:45:01

by Andrea Arcangeli

[permalink] [raw]
Subject: Re: Getting full path from dentry in LSM hooks

On Fri, Sep 03, 2004 at 02:12:21PM +0200, Kristian S?rensen wrote:
> Hi!
>
> I have a short question, concerning how to get the full path of a file
> from a LSM hook.
>
> - If the "file" of the dentry is located in the root filesystem: no
> problem - simply traverse the dentrys, to generate the path.
>
> - If the "file" is mounted from another partition, you do not get the
> full path by traversing the dentrys.
>
> Example:
> If we have a system with a normal root (/) and a seperate boot partition
> (mounted on /boot :). In the LSM hook inode_permission, you get the
> arguments (struct inode *inode, int mask, struct nameidata *nd).
> Finding the path, we traverse the dentrys from (nd->dentry). But if the
> inode is a file in /boot we only get the filename (e.g. kernel-2.6.8.1
> instead of /boot/kernel-2.6.8.1)
>
>
> Can some one reveal the trick to get the full path nomater if the
> filesystem is root or mounted elsewhere in the filesystem?

fix d_path, I need that too ;)

2004-09-03 13:07:18

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [Umbrella-devel] Re: Getting full path from dentry in LSM hooks

On Fri, Sep 03, 2004 at 02:38:12PM +0200, Kristian S?rensen wrote:
> Is there another way to get it? We also get an inodepointer from the LSM
> hook. As far as I know, the file struct has an entry called vfs_mount,
> which has an entry called root_mnt - could this be used? (and if so, how
> do I get from the Inode to the file struct? :-/ )

Witch a struct file you can use d_path which gives you a canonical path
in the _current_ _namespace_.

What do you want to do with the path anyway?

2004-09-03 13:22:47

by Kristian Sørensen

[permalink] [raw]
Subject: Re: [Umbrella-devel] Re: Getting full path from dentry in LSM hooks

Christoph Hellwig wrote:
> On Fri, Sep 03, 2004 at 02:38:12PM +0200, Kristian S?rensen wrote:
>
>>Is there another way to get it? We also get an inodepointer from the LSM
>>hook. As far as I know, the file struct has an entry called vfs_mount,
>>which has an entry called root_mnt - could this be used? (and if so, how
>>do I get from the Inode to the file struct? :-/ )
>
>
> Witch a struct file you can use d_path which gives you a canonical path
> in the _current_ _namespace_.
But we do not have a struct file - just an inode or a dentry :((


> What do you want to do with the path anyway?
We are working on a project called Umbrella, (umbrella.sf.net) which
implements processbased mandatory accesscontrol in the Linux kernel.
This access control is controlled by "restriction", e.g. by restricting
some process from accessing any given file or directory.

E.g. if a root owned process is restricted from accessing /var/www, and
the process is compromised by an attacker, no mater what he does, he
would not be able to access this directory.


KS

2004-09-03 14:06:23

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [Umbrella-devel] Re: Getting full path from dentry in LSM hooks

On Fri, Sep 03, 2004 at 03:20:55PM +0200, Kristian S?rensen wrote:
> But we do not have a struct file - just an inode or a dentry :((

Then you can't generate a full path.

> We are working on a project called Umbrella, (umbrella.sf.net) which
> implements processbased mandatory accesscontrol in the Linux kernel.
> This access control is controlled by "restriction", e.g. by restricting
> some process from accessing any given file or directory.
>
> E.g. if a root owned process is restricted from accessing /var/www, and
> the process is compromised by an attacker, no mater what he does, he
> would not be able to access this directory.

mount --bind /var/www /home/joe/p0rn/, and then?

2004-09-03 15:22:10

by Alan

[permalink] [raw]
Subject: Re: Getting full path from dentry in LSM hooks

On Gwe, 2004-09-03 at 13:12, Kristian Sørensen wrote:
> I have a short question, concerning how to get the full path of a file
> from a LSM hook.

The full path or a full path. It may have several. They may also have
changed under you.

> Can some one reveal the trick to get the full path nomater if the
> filesystem is root or mounted elsewhere in the filesystem?

You can get the namespace and the name within that namespace that
represents at least one of the names of the file within the vfs layer
(this is what the VFS itself uses for the struct nameidata).

There may be multiple links to a file, it may be mounted in multiple
places and someone on a seperate NFS server may have moved it while you
are thinking about it.

2004-09-03 15:43:49

by Stephen Smalley

[permalink] [raw]
Subject: Re: [Umbrella-devel] Re: Getting full path from dentry in LSM hooks

On Fri, 2004-09-03 at 09:20, Kristian Sørensen wrote:
> E.g. if a root owned process is restricted from accessing /var/www, and
> the process is compromised by an attacker, no mater what he does, he
> would not be able to access this directory.

Control access to objects, not names. Assign security attributes to the
objects, and use those attributes in your access control checks, not a
useless pathname. Otherwise, your "security" system will always be
trivially bypassable.

--
Stephen Smalley <[email protected]>
National Security Agency

2004-09-03 19:59:31

by Kristian Sørensen

[permalink] [raw]
Subject: Re: [Umbrella-devel] Re: Getting full path from dentry in LSM hooks

Christoph Hellwig wrote:
> On Fri, Sep 03, 2004 at 03:20:55PM +0200, Kristian S?rensen wrote:
>
>>But we do not have a struct file - just an inode or a dentry :((
>
>
> Then you can't generate a full path.
>
>
>>We are working on a project called Umbrella, (umbrella.sf.net) which
>>implements processbased mandatory accesscontrol in the Linux kernel.
>>This access control is controlled by "restriction", e.g. by restricting
>> some process from accessing any given file or directory.
>>
>>E.g. if a root owned process is restricted from accessing /var/www, and
>>the process is compromised by an attacker, no mater what he does, he
>>would not be able to access this directory.
>
>
> mount --bind /var/www /home/joe/p0rn/, and then?
Actually this "attack" is avoided, because restrictions are enherited,
from parent proces to its children.

Okay, this is how it works in basic:

------------------
ks@qbox:~/umbrella-devel/userspace
$ touch /tmp/a

ks@qbox:~/umbrella-devel/userspace
$ ./umbrella_restricted_sh

sh-2.05b$ touch /tmp/a
touch: setting times of `/tmp/a': Operation not permitted

sh-2.05b$ exit
Restricted child died
Thank you for testing!
Concider joining the development at http://umbrella.sourceforge.net
------------------

- the "umbrella_restricted_sh" just forks a new shell, which is
restricted from /tmp

Now let's try your suggestion:


------------------------
root@qbox:~/umbrella-devel/userspace
$ id
uid=0(root) gid=0(root)
groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)

root@qbox:~/umbrella-devel/userspace
$ mkdir new-tmp

root@qbox:~/umbrella-devel/userspace
$ mount --bind /tmp new-tmp

root@qbox:~/umbrella-devel/userspace
$ mount
/dev/discs/disc1/part2 on / type ext3 (rw)
none on /dev type devfs (rw)
none on /proc type proc (rw)
none on /sys type sysfs (rw)
none on /dev/pts type devpts (rw)
/dev/discs/disc0/part1 on /home type ext3 (rw)
/dev/discs/disc0/part2 on /media type ext3 (rw)
none on /dev/shm type tmpfs (rw)
none on /proc/bus/usb type usbfs (rw)
/tmp on /home/ks/umbrella-devel/userspace/new-tmp type none (rw,bind)

root@qbox:~/umbrella-devel/userspace
$ ./umbrella_restricted_sh

sh-2.05b# touch /tmp/a
touch: setting times of `/tmp/a': Operation not permitted

sh-2.05b# touch new-tmp/a
touch: setting times of `new-tmp/a': Operation not permitted

sh-2.05b# ls new-tmp/
ls: new-tmp/: Operation not permitted

sh-2.05b# exit
Restricted child died
Thank you for testing!
Concider joining the development at http://umbrella.sourceforge.net
------------------------

As you can see, the bind-mount fails to succeed in accessing the files
in /tmp.



Best regards, Kristian.

2004-09-03 20:16:42

by Kristian Sørensen

[permalink] [raw]
Subject: Re: [Umbrella-devel] Re: Getting full path from dentry in LSM hooks

Alan Cox wrote:
> On Gwe, 2004-09-03 at 13:12, Kristian Sørensen wrote:
>
>>I have a short question, concerning how to get the full path of a file
>>from a LSM hook.
>
>
> The full path or a full path. It may have several. They may also have
> changed under you.
>
>
>>Can some one reveal the trick to get the full path nomater if the
>>filesystem is root or mounted elsewhere in the filesystem?
>
>
> You can get the namespace and the name within that namespace that
> represents at least one of the names of the file within the vfs layer
> (this is what the VFS itself uses for the struct nameidata).
>
> There may be multiple links to a file, it may be mounted in multiple
> places and someone on a seperate NFS server may have moved it while you
> are thinking about it.
Umbrella is mostly designed for embedded systems (where selinux is
overkill) and also it is very easy to understand. Most restrictions will
be made to e.g. stop viruses from spreading, and it is quite easy, yet
very effective:

If an email client receives an malformed email (like the countless
attacks on outlook), a simple restriction could be for the process
handeling the mail would be "$HOME/.addressbook", furthermore, you could
specify that attachments executed _from_ the emailprogram would not have
access to the network. Thus the virus cannot find mail addresses to send
itself to - and it cannot even get network access. Simple and effective.

Also simple bufferoverflows in suid-root programs may be avoided. The
simple way would to set the restriction "no fork", and thus if an
attacker tries to fork a (root) shell, this would be denied. Another way
could be to heavily restrict access to the filesystem. If the program is
restricted from /var, the root shell spawned by the attack would not
have access either. (restrictions are enherited from parent to children).


Best regards, Kristian.

2004-09-03 20:43:12

by Valdis Klētnieks

[permalink] [raw]
Subject: Re: [Umbrella-devel] Re: Getting full path from dentry in LSM hooks

On Fri, 03 Sep 2004 22:05:03 +0200, =?UTF-8?B?S3Jpc3RpYW4gU8O4cmVuc2Vu?= said:

> Also simple bufferoverflows in suid-root programs may be avoided. The
> simple way would to set the restriction "no fork", and thus if an
> attacker tries to fork a (root) shell, this would be denied.

All this does is stop fork(). I'm not sure, but most shellcodes I've seen
don't bother forking, they just execve() a shell....

It doesn't stop a buffer overflow that does this:

f1 = open("/bin/bash");
f2 = open("/tmp/bash", O_CREAT);
while ((bytes = read(f1,buffer,sizeof(buffer))) > 0)
write(f2,buffer,bytes);
fchmod(f2,4775);
close(f1); close(f2);

Papering over *that* one by restricting fchmod just means the exploit needs to
append a line to /etc/passwd, or create a trojan inetd.conf or crontab entry,
or any of the other myriad ways a program can leave a backdoor (there's a
*reason* SELinux ends up with all those rules - this isn't an easy task)...

Remember - just papering over the fact that most shellcodes just execve() a
shell doesn't fix the fundemental problem, which is that the attacker is able
to run code of his choosing as root.


Attachments:
(No filename) (226.00 B)

2004-09-04 09:06:41

by Kristian Sørensen

[permalink] [raw]
Subject: Re: [Umbrella-devel] Re: Getting full path from dentry in LSM hooks

[email protected] wrote:
> On Fri, 03 Sep 2004 22:05:03 +0200, =?UTF-8?B?S3Jpc3RpYW4gU8O4cmVuc2Vu?= said:
>
>
>>Also simple bufferoverflows in suid-root programs may be avoided. The
>>simple way would to set the restriction "no fork", and thus if an
>>attacker tries to fork a (root) shell, this would be denied.
>
>
> All this does is stop fork(). I'm not sure, but most shellcodes I've seen
> don't bother forking, they just execve() a shell....
I was not precise enough - it is not just fork, but the LSM catches
every time a new process is created - so we do have some way of generic
catching creation of processes, and denying so, if prohibited.

> It doesn't stop a buffer overflow that does this:
>
> f1 = open("/bin/bash");
> f2 = open("/tmp/bash", O_CREAT);
> while ((bytes = read(f1,buffer,sizeof(buffer))) > 0)
> write(f2,buffer,bytes);
> fchmod(f2,4775);
> close(f1); close(f2);
You are right! ... as long as a new process is not created, this may do
some damage ... but:

> Papering over *that* one by restricting fchmod just means the exploit needs to
> append a line to /etc/passwd, or create a trojan inetd.conf or crontab entry,
Not mny suid programs would really need to be able to access the /etc
and everything below... E.g. cdrecord (there were a bug a year ago or
something)... it should definitely not have access to the possibl?lities
you mention!

> Remember - just papering over the fact that most shellcodes just execve() a
> shell doesn't fix the fundemental problem, which is that the attacker is able
> to run code of his choosing as root.
Good point!

Best, Kristian.

2004-09-04 10:48:12

by Emmanuel Fleury

[permalink] [raw]
Subject: Re: [Umbrella-devel] Re: Getting full path from dentry in LSM hooks

On Fri, 2004-09-03 at 22:39, [email protected] wrote:
>
> All this does is stop fork(). I'm not sure, but most shellcodes I've seen
> don't bother forking, they just execve() a shell....

I think you totally misunderstood the thing...

Umbrella is a scheme that allow the user to restrict the capabilities of
a process within his own processes. Preventing the process to fork is
ONE thing that can be restricted but they might be plenty of others.

The idea is that each process originating from this process will inherit
from this restriction (and possibly have some more) and can NEVER been
granted to restore this capability again.

Now, this has a direct application to restrict the harm that can cause a
buffer-overflow, but nobody said that it would stop them... As Kristian
say all the time: ? We can't prevent the rain, but we don't get wet. ?

> Remember - just papering over the fact that most shellcodes just execve() a
> shell doesn't fix the fundemental problem, which is that the attacker is able
> to run code of his choosing as root.

Right.

Wonderful ! You just volunteered to find a simple and yet efficient
solution to this problem ! :)

Regards
--
Emmanuel Fleury

Computer Science Department, | Office: B1-201
Aalborg University, | Phone: +45 96 35 72 23
Fredriks Bajersvej 7E, | Fax: +45 98 15 98 89
9220 Aalborg East, Denmark | Email: [email protected]

2004-09-04 11:12:12

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [Umbrella-devel] Re: Getting full path from dentry in LSM hooks

On Fri, Sep 03, 2004 at 09:54:23PM +0200, Kristian S?rensen wrote:
> >>We are working on a project called Umbrella, (umbrella.sf.net) which
> >>implements processbased mandatory accesscontrol in the Linux kernel.
> >>This access control is controlled by "restriction", e.g. by restricting
> >> some process from accessing any given file or directory.
> >>
> >>E.g. if a root owned process is restricted from accessing /var/www, and
> >>the process is compromised by an attacker, no mater what he does, he
> >>would not be able to access this directory.
> >
> >
> > mount --bind /var/www /home/joe/p0rn/, and then?
> Actually this "attack" is avoided, because restrictions are enherited,
> from parent proces to its children.

If you restrict your process on the path /var/ww/ but the same objects
are also available below a different path, what does that have to do with
child processes?

2004-09-04 18:00:27

by Alan

[permalink] [raw]
Subject: Re: [Umbrella-devel] Re: Getting full path from dentry in LSM hooks

On Gwe, 2004-09-03 at 21:05, Kristian Sørensen wrote:
> If an email client receives an malformed email (like the countless
> attacks on outlook), a simple restriction could be for the process
> handeling the mail would be "$HOME/.addressbook", furthermore, you could
> specify that attachments executed _from_ the emailprogram would not have
> access to the network. Thus the virus cannot find mail addresses to send
> itself to - and it cannot even get network access. Simple and effective.

ln /tmp/bwhahaha $HOME/.addressbook
more /tmp/bwhahaha

As the nice man from the NSA said ;) label content not paths. Use xattrs
to say "this is an addressbook" and then the path games go away.

2004-09-04 18:47:36

by Kristian Sørensen

[permalink] [raw]
Subject: Re: [Umbrella-devel] Re: Getting full path from dentry in LSM hooks

Alan Cox wrote:
> On Gwe, 2004-09-03 at 21:05, Kristian Sørensen wrote:
>
>>If an email client receives an malformed email (like the countless
>>attacks on outlook), a simple restriction could be for the process
>>handeling the mail would be "$HOME/.addressbook", furthermore, you could
>>specify that attachments executed _from_ the emailprogram would not have
>>access to the network. Thus the virus cannot find mail addresses to send
>>itself to - and it cannot even get network access. Simple and effective.
>
>
> ln /tmp/bwhahaha $HOME/.addressbook
> more /tmp/bwhahaha
>
> As the nice man from the NSA said ;) label content not paths. Use xattrs
> to say "this is an addressbook" and then the path games go away.
Just as Christop Hellwig's suggestion (in this thread) this will not
work due to the placement of the LSM hooks :-) (he suggested making an
"mount -o bind").

KS.

2004-09-04 18:52:11

by Kristian Sørensen

[permalink] [raw]
Subject: Re: [Umbrella-devel] Re: Getting full path from dentry in LSM hooks

Christoph Hellwig wrote:
> On Fri, Sep 03, 2004 at 09:54:23PM +0200, Kristian S?rensen wrote:
>
>>>>We are working on a project called Umbrella, (umbrella.sf.net) which
>>>>implements processbased mandatory accesscontrol in the Linux kernel.
>>>>This access control is controlled by "restriction", e.g. by restricting
>>>> some process from accessing any given file or directory.
>>>>
>>>>E.g. if a root owned process is restricted from accessing /var/www, and
>>>>the process is compromised by an attacker, no mater what he does, he
>>>>would not be able to access this directory.
>>>
>>>
>>>mount --bind /var/www /home/joe/p0rn/, and then?
>>
>>Actually this "attack" is avoided, because restrictions are enherited,
>>from parent proces to its children.
>
>
> If you restrict your process on the path /var/ww/ but the same objects
> are also available below a different path, what does that have to do with
> child processes?
Well nothing :-) The point was, that links and mount bindings are
handled, and if the parent is restricted from accessing a file, the
child is too.

KS.

2004-09-07 14:19:59

by Kristian Sørensen

[permalink] [raw]
Subject: Re: [Umbrella-devel] Re: Getting full path from dentry in LSM hooks

[email protected] wrote:
> On Fri, 03 Sep 2004 22:05:03 +0200, =?UTF-8?B?S3Jpc3RpYW4gU8O4cmVuc2Vu?= said:
>
>
>>Also simple bufferoverflows in suid-root programs may be avoided. The
>>simple way would to set the restriction "no fork", and thus if an
>>attacker tries to fork a (root) shell, this would be denied.
>
>
> All this does is stop fork(). I'm not sure, but most shellcodes I've seen
> don't bother forking, they just execve() a shell....
I think you totally misunderstood the thing...

Umbrella is a scheme that allow the user to restrict the capabilities of
a process within his own processes. Preventing the process to fork is
ONE thing that can be restricted but they might be plenty of others.

The idea is that each process originating from this process will inherit
from this restriction (and possibly have some more) and can NEVER been
granted to restore this capability again.

Now, this has a direct application to restrict the harm that can cause a
buffer-overflow, but nobody said that it would stop them...

> Papering over *that* one by restricting fchmod just means the exploit needs to
> append a line to /etc/passwd, or create a trojan inetd.conf or crontab entry,
> or any of the other myriad ways a program can leave a backdoor (there's a
> *reason* SELinux ends up with all those rules - this isn't an easy task)...
>
> Remember - just papering over the fact that most shellcodes just execve() a
> shell doesn't fix the fundemental problem, which is that the attacker is able
> to run code of his choosing as root.
Right. Now who wants to volunteered to find a simple and yet efficient
solution to this problem? :-)


KS.