linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Re: [PATCH] new syscall: flink
@ 2003-04-07  2:56 Mark Grosberg
  2003-04-07  3:39 ` H. Peter Anvin
  0 siblings, 1 reply; 51+ messages in thread
From: Mark Grosberg @ 2003-04-07  2:56 UTC (permalink / raw)
  To: linux-kernel


On Sun, Apr 6 2003, H. Peter Anvin wrote:

> > Suppose I give you an O_RDONLY handle to a file which you then
> > flink and gain write access too ?
>
> This, I believe, is the real issue.  However, we already have that
> problem:

As far as I understand it, isn't the protection information stored in the
inode? The flink call is just linking an inode into a directory that the
caller has write access to. The permissions and ownership of the file
shouldn't change.

> int main(int argc, char *argv[])
> {
>   int rfd, wfd;
>   char filebuf[PATH_MAX];
>
>   rfd = open("testfile", O_RDONLY|O_CREAT, 0666);
>   /* Now rfd is a read-only file descriptor */

There is nothing stopping the caller from re-opening the to-be flinked()
file descriptor read-write using its name if the caller has permissions.
So I don't see why that case is different.

Other than that, HPA's responses make sense.

Personally, I would like to see this system call in Linux. It does make
certain thing easier. Not necessarily even in a security context, but
sometimes its generally useful to be able to make a hard link to an
already open file rather than track the name.

L8r,
Mark G.



^ permalink raw reply	[flat|nested] 51+ messages in thread
* Re: [PATCH] new syscall: flink
@ 2003-04-11 17:11 Clayton Weaver
  0 siblings, 0 replies; 51+ messages in thread
From: Clayton Weaver @ 2003-04-11 17:11 UTC (permalink / raw)
  To: linux-kernel

> [David Wagner, "should fail closed", ie with
the capability to flink()to any given open file
descriptor disabled by default]

Ok, that's reasonable. I was imagining that
guessing when you need to enable it for an
open fd that is going to be inherited by
someone else's code that may not even have
been written yet is rather a vague proposition,
while guessing when you need to disable it regardless of what the code that you pass it to
does is likely to be all too clear and made
much of in online discussions.

But some application author not noticing that a potential flink() vulnerability is there at all will perhaps be the more common failure
scenario(so I yield the point).

flink() does seem a useful tool that I've wanted in the past (for reasons similar to the linker
example) if one could get around the implicit
security risk of a naive implementation.

Regards,

Clayton Weaver
<mailto: cgweav@email.com>


-- 
_______________________________________________
Sign-up for your own FREE Personalized E-mail at Mail.com
http://www.mail.com/?sr=signup


^ permalink raw reply	[flat|nested] 51+ messages in thread
* Re: [PATCH] new syscall: flink
@ 2003-04-10 22:10 Clayton Weaver
  2003-04-11  1:02 ` David Wagner
  0 siblings, 1 reply; 51+ messages in thread
From: Clayton Weaver @ 2003-04-10 22:10 UTC (permalink / raw)
  To: linux-kernel

One other thing: why O_CANLINK (suggested flag
to open) instead of O_NOLINK?

It seems to me that for the vast majority of
open()calls, you don't care whether the open
fd can be flink()ed to, because you don't pass
the file descriptor to an untrusted process.

A bit set to eliminate that capability is
the new feature one might need for security reasons with an implemented flink() call
available to programmers.

Seems like leaving "can be linked to" as the default setting and having an explicit flag
to prevent that would be more efficient.

Regards,

Clayton Weaver
<mailto: cgweav@email.com>


-- 
_______________________________________________
Sign-up for your own FREE Personalized E-mail at Mail.com
http://www.mail.com/?sr=signup


^ permalink raw reply	[flat|nested] 51+ messages in thread
* Re: [PATCH] new syscall: flink
@ 2003-04-10  0:31 Clayton Weaver
  0 siblings, 0 replies; 51+ messages in thread
From: Clayton Weaver @ 2003-04-10  0:31 UTC (permalink / raw)
  To: wa; +Cc: linux-kernel

----- Original Message -----
From: Werner Almesberger <wa@almesberger.net>
Date: Mon, 7 Apr 2003 15:43:03 -0300
To: Clayton Weaver <cgweav@email.com>
Subject: Re: [PATCH] new syscall: flink

> Clayton Weaver wrote:
> > If the client process subsequently flink()s to the inode, it is merely
> > a zerocopy file copy.

> As far as access to the data is concerned, yes. But there's also the
> location of the file. E.g. this might enable you to fill somebody
> else's quota, or, if distinct physical devices can be be covered by
> the same file system, to access a physical device that would
> otherwise not be available to you.

> Example: I write some kind of RAID mounted at /world, that contains
> my disk under /world/disk, and some Flash storage under /world/flash.
> I protect /world/flash against writes by other people. If a
> read-only FD could be turned into something writeable, some malicious
> creature could "wear out" my Flash by writing to it a lot of times.

> - Werner

I'm wondering about the semantics of the unlink
of the last directory entry and subsequent
flink(). When is the inode updated?
 
I presume that the open fd has owner and mode
information from open(), but would flink()update the inode with new owner information if the
last directory reference had already been
unlinked, and how would this interact with
owner information associated with the open fd
for subsequent file operations? Would fchmod() then succeed, even if the new process is not
owned by the original owner of the flink()ed
to inode? Are any changes to the inode data
delayed until after close()?

What about multiple flink()s before an inode
update has appeared in the filesystem?

It seems to me that "change of owner of the inode" via flink() is an issue, and application programmers that unlink the last directory reference and then pass the open fd to another process had better have no sentimental attachment to the existing access constraints on the file. flink(), close(), open() isn't exactly a difficult hoop to jump through, even if you've passed an
open fd for a read-only file (that you unlinked
any directory references to).

Regards,

Clayton Weaver
<mailto: cgweav@email.com>


-- 
_______________________________________________
Sign-up for your own FREE Personalized E-mail at Mail.com
http://www.mail.com/?sr=signup


^ permalink raw reply	[flat|nested] 51+ messages in thread
* Re: [PATCH] new syscall: flink
@ 2003-04-08 13:06 Chuck Ebbert
  0 siblings, 0 replies; 51+ messages in thread
From: Chuck Ebbert @ 2003-04-08 13:06 UTC (permalink / raw)
  To: Ulrich Drepper; +Cc: linux-kernel

Ulrich Drepper wrote:


>  + temp files which have to be completed first before renamed.  Here
>    flink() and frename() would introduce the name in the filesystem.
>    This is obviously useful in many many places, e.g., the linker
>    scenario.  There is no way to attack the linker while it is doing
>    its work since the output file isn't visible until it is installed
>    under the final name.


 How about an O_LINKONCLOSE flag that says not to link the file until
it's closed?

--
 Chuck
 I am not a number!

^ permalink raw reply	[flat|nested] 51+ messages in thread
* Re: [PATCH] new syscall: flink
@ 2003-04-07 23:57 Chuck Ebbert
  0 siblings, 0 replies; 51+ messages in thread
From: Chuck Ebbert @ 2003-04-07 23:57 UTC (permalink / raw)
  To: Ulrich Drepper; +Cc: linux-kernel

Ulrich Drepper wrote:


> The people who don't want to use /proc for security reasons better
> come up with fixes to make it acceptable.


 I already have one -- FreeBSD 5.  It's gained an unbelievable
amount of security features with the merge of the TrustedBSD code.

--
 Chuck

^ permalink raw reply	[flat|nested] 51+ messages in thread
* Re: [PATCH] new syscall: flink
@ 2003-04-07 16:50 Clayton Weaver
  2003-04-07 17:11 ` Arjan van de Ven
                   ` (3 more replies)
  0 siblings, 4 replies; 51+ messages in thread
From: Clayton Weaver @ 2003-04-07 16:50 UTC (permalink / raw)
  To: linux-kernel

Once a process unlinks the last directory entry referencing a particular inode that it has an
open fd for and then passes the open fd to some other process (regardless of exactly how it does that), it seems to me that it has conceded any interest in the previous security constraints associated with that inode or with the recently
unlinked last directory entry for it. If the client process subsequently flink()s to the inode, it is merely a zerocopy file copy.

Since the client owns the new directory entry, it can chmod the inode to have any permissions it wants, create or modify an ACL where ACLs are in use, modify a capabilities mask more fine-grained than traditional unix permissions if something like that is in use, etc.

The cases with potential security implications are all in the context of flink()ing to an open fd for an inode that still corresponds to at least one directory entry.
 
Regards,

Clayton Weaver
<mailto: cgweav@email.com>


-- 
_______________________________________________
Sign-up for your own FREE Personalized E-mail at Mail.com
http://www.mail.com/?sr=signup


^ permalink raw reply	[flat|nested] 51+ messages in thread
* Re: [PATCH] new syscall: flink
@ 2003-04-07  9:01 Clayton Weaver
  0 siblings, 0 replies; 51+ messages in thread
From: Clayton Weaver @ 2003-04-07  9:01 UTC (permalink / raw)
  To: linux-kernel

Do file access capabilities (and ACLs where those
are enabled)attach to the directory entry or the inode for a file? 

I remember Linus wishing that capabilities
on files could have different multiple concurrent values in different directory entry contexts.
Seems like the kernel would need to be able
to trump these "capability views", which
would need to be associated with directory
entries, based on data stored with the inode
(so that you can drop capabilities when creating
a link but you can't elevate them).

(Someone already mentioned in this thread that traditional unix permissions are stored in the inode.)

The restricted directories with loose permissions
on the files within them looks more like an
application programmer issue than a kernel issue to me. The parent or server could always chmod the file(or copy it to a read-only file and open that) before execing or passing the open fd.

So who owns the inode? Or does "owned by
uid #N" only make sense in the context of a
directory entry? If so, does ownership of the linked-to fd propagate to the new directory
entry from the old directory entry? What if it
had been unlinked before the flink()?

Seems like the ultimate security constraints on files have to be stored in the inode or your security is potentially hosed merely by the ability to create a new directory entry for the same inode from a different uid (whether it
needs to do it in a different directory is a
separate issue). 
 
Regards,

Clayton Weaver
<mailto: cgweav@email.com>

-- 
_______________________________________________
Sign-up for your own FREE Personalized E-mail at Mail.com
http://www.mail.com/?sr=signup


^ permalink raw reply	[flat|nested] 51+ messages in thread
[parent not found: <20030407102005.4c13ed7f.manushkinvv@desnol.ru>]
* re: [PATCH] new syscall: flink
@ 2003-04-06 19:05 Dan Kegel
  2003-04-06 19:07 ` Dan Kegel
  2003-04-06 19:56 ` Oliver Neukum
  0 siblings, 2 replies; 51+ messages in thread
From: Dan Kegel @ 2003-04-06 19:05 UTC (permalink / raw)
  To: Linux Kernel Mailing List, Ulrich Drepper

Ulrich wrote:
> I got a couple of requests for a function which isn't support on Linux
> so far.  Also not supportable, i.e., cannot be emulated at userlevel.
> It has some history in other systems (QNX I think), though, and helps
> with some security issues.

How does this differ from fattach() in SuSv3
(http://www.opengroup.org/onlinepubs/007904975/functions/fattach.html)?
(i.e. does the fact that fattach() is defined only for streams
fds make a difference?)

Out of curiosity, I did some searching for prior mentions of flink.
It gets proposed every two years or so, it seems.
There may be some security issues.  Here are two posts that
might be of interest (I wouldn't know, I'm not a security guru):

http://marc.theaimsgroup.com/?l=linux-kernel&m=88944672732020&w=2
Malcolm Beattie <mbeattie () sable ! ox ! ac ! uk> wrote:
> SysV calls this fattach() where fd is a STREAMS file descriptor
> (usually a STREAMS pipe). For general file descriptors, it has
> security implications. For example, you mustn't let it be legal
> for a process to get a read-only file descriptor and then link
> it into the file system because then it could change the file's
> permissions to read-write.

http://mail-index.netbsd.org/tech-userlevel/2001/09/29/0000.html
Andrew Brown <atatat@atatdot.net> wrote:
 ># as for flink(2), no.  flink(2) would be a terribly bad idea.  consider
 ># that when opening a file, *all* the permissions on *all* the inodes in
 ># the path to the file are considered.  if you were able to get some
 ># process to hand you an open file descriptor to some file somewhere
 ># that relies on being protected by permissions in the path and you were
 ># able to flink(2) it to some arbitrary name, you could bypass the
 ># permissions set that had been established.

- Dan

-- 
Dan Kegel
http://www.kegel.com
http://counter.li.org/cgi-bin/runscript/display-person.cgi?user=78045


^ permalink raw reply	[flat|nested] 51+ messages in thread
* [PATCH] new syscall: flink
@ 2003-04-06 18:39 Ulrich Drepper
  2003-04-07 17:35 ` Linus Torvalds
  0 siblings, 1 reply; 51+ messages in thread
From: Ulrich Drepper @ 2003-04-06 18:39 UTC (permalink / raw)
  To: Linus Torvalds, Linux Kernel


[-- Attachment #1.1: Type: text/plain, Size: 2354 bytes --]

I got a couple of requests for a function which isn't support on Linux
so far.  Also not supportable, i.e., cannot be emulated at userlevel.
It has some history in other systems (QNX I think), though, and helps
with some security issues.  It really not adding much new functionality
and I hope I got it right with my "monkey see, monkey do" technique of
looking up other places doing similar things.

The syscall I mean is

  int flink (int fd, const char *newname)

Similar to link(), but the first parameter is a file decsriptor.  Using
the file descriptor helps to avoid races in some situation.  Look at
this code bit (this is constructed and just a little test case):

#include <errno.h>
#define EE(a,x) {int e = a;if (e!=x)printf("%s = %d (%m)\n", #a, errno);}
#define E(a) EE(a,0)
int
main()
{
  printf("uid = %d, euid = %d, gid = %d, egid = %d\n", getuid(),
geteuid(), getgid(), getegid());
  E(setfsuid(getuid()));
  E(setfsgid(getgid()));
  char buf[] = "aaXXXXXX";
  int fd = mkstemp (buf);
  EE(setfsuid(0),getuid());
  EE(setfsgid(0),getgid());
  E(fchown(fd,48,48));
  E(setfsuid(getuid()));
  E(setfsgid(getgid()));
  E(syscall(268,fd,"aa"));
  E(unlink(buf));
  return 0;
}

This is for a SUID/SGID root application.  A temporary file is created
carefully using the permissions of the user running the program.  If the
syscall 268 (flink) line would be

  link(buf,"aa)

instead, somebody with limited priviledges could in theory have unlinked
the temporary file and created a new one.  With flink() this isn't
possible.  And the best is: the unlink() line can be moved right below
the mkstemp() call.  This means no temporary files are around if
something goes wrong before the unlink().  (For me this is at least as
important as the security issue, it simplifies temp file handling and
reduces the number of bugs == leftover fiels).

The patch itself is very minimal.  The impact on the link() syscall is
not measurable and the extra code for sys_flink is only a few bytes.

Is this acceptable?  Shall I add more syscall definitions for platforms
!= x86 (I'd think the port maintainers want to do this themselves)?

-- 
--------------.                        ,-.            444 Castro Street
Ulrich Drepper \    ,-----------------'   \ Mountain View, CA 94041 USA
Red Hat         `--' drepper at redhat.com `---------------------------

[-- Attachment #1.2: d-kernel-flink --]
[-- Type: text/plain, Size: 3048 bytes --]

--- linux-2.5/arch/i386/kernel/entry.S-flink	2003-03-21 23:09:32.000000000 -0800
+++ linux-2.5/arch/i386/kernel/entry.S	2003-04-06 10:32:27.000000000 -0700
@@ -852,6 +852,7 @@ ENTRY(sys_call_table)
  	.long sys_clock_gettime		/* 265 */
  	.long sys_clock_getres
  	.long sys_clock_nanosleep
+	.long sys_flink
  
  
 nr_syscalls=(.-sys_call_table)/4
--- linux-2.5/fs/namei.c-flink	2003-04-03 10:04:03.000000000 -0800
+++ linux-2.5/fs/namei.c	2003-04-06 11:20:41.000000000 -0700
@@ -16,6 +16,7 @@
 
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/file.h>
 #include <linux/fs.h>
 #include <linux/namei.h>
 #include <linux/quotaops.h>
@@ -1796,10 +1797,10 @@ int vfs_link(struct dentry *old_dentry, 
  * with linux 2.0, and to avoid hard-linking to directories
  * and other special files.  --ADM
  */
-asmlinkage long sys_link(const char * oldname, const char * newname)
+static long link_common(struct vfsmount *old_mnt, struct dentry *old_dentry, const char *newname)
 {
 	struct dentry *new_dentry;
-	struct nameidata nd, old_nd;
+	struct nameidata nd;
 	int error;
 	char * to;
 
@@ -1807,32 +1808,53 @@ asmlinkage long sys_link(const char * ol
 	if (IS_ERR(to))
 		return PTR_ERR(to);
 
-	error = __user_walk(oldname, 0, &old_nd);
-	if (error)
-		goto exit;
 	error = path_lookup(to, LOOKUP_PARENT, &nd);
 	if (error)
-		goto out;
+		goto exit;
 	error = -EXDEV;
-	if (old_nd.mnt != nd.mnt)
+	if (old_mnt != nd.mnt)
 		goto out_release;
 	new_dentry = lookup_create(&nd, 0);
 	error = PTR_ERR(new_dentry);
 	if (!IS_ERR(new_dentry)) {
-		error = vfs_link(old_nd.dentry, nd.dentry->d_inode, new_dentry);
+		error = vfs_link(old_dentry, nd.dentry->d_inode, new_dentry);
 		dput(new_dentry);
 	}
 	up(&nd.dentry->d_inode->i_sem);
 out_release:
 	path_release(&nd);
-out:
-	path_release(&old_nd);
 exit:
 	putname(to);
 
 	return error;
 }
 
+asmlinkage long sys_link(const char *oldname, const char *newname)
+{
+	struct nameidata old_nd;
+	int error;
+
+	error = __user_walk(oldname, 0, &old_nd);
+	if (!error) {
+		error = link_common(old_nd.mnt, old_nd.dentry, newname);
+		path_release(&old_nd);
+	}
+	return error;
+}
+
+asmlinkage long sys_flink(unsigned int fd, const char *newname)
+{
+	struct file *file;
+	int error = -EBADF;
+
+	file = fget(fd);
+	if (file) {
+		error = link_common(file->f_vfsmnt, file->f_dentry, newname);
+		fput(file);
+	}
+	return error;
+}
+
 /*
  * The worst of all namespace operations - renaming directory. "Perverted"
  * doesn't even start to describe it. Somebody in UCB had a heck of a trip...
--- linux-2.5/include/asm-i386/unistd.h-flink	2003-02-19 21:41:59.000000000 -0800
+++ linux-2.5/include/asm-i386/unistd.h	2003-04-06 10:30:08.000000000 -0700
@@ -273,8 +273,9 @@
 #define __NR_clock_gettime	(__NR_timer_create+6)
 #define __NR_clock_getres	(__NR_timer_create+7)
 #define __NR_clock_nanosleep	(__NR_timer_create+8)
+#define __NR_flink		268
 
-#define NR_syscalls 268
+#define NR_syscalls 269
 
 /* user-visible error numbers are in the range -1 - -124: see <asm-i386/errno.h> */
 

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 51+ messages in thread

end of thread, other threads:[~2003-04-11 16:59 UTC | newest]

Thread overview: 51+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-04-07  2:56 [PATCH] new syscall: flink Mark Grosberg
2003-04-07  3:39 ` H. Peter Anvin
2003-04-07  7:29   ` Miquel van Smoorenburg
2003-04-07  8:18     ` Olivier Galibert
2003-04-07  8:35       ` Jakub Jelinek
2003-04-07  9:11         ` Olivier Galibert
2003-04-07 11:13           ` Alan Cox
2003-04-07 12:31           ` Roman Zippel
2003-04-07 12:54             ` Andreas Schwab
2003-04-07 13:19               ` Roman Zippel
2003-04-07 20:55   ` Fredrik Tolf
2003-04-07 21:43     ` Ulrich Drepper
2003-04-07 22:17       ` Fredrik Tolf
2003-04-07 22:25         ` Ulrich Drepper
2003-04-07 22:55           ` Fredrik Tolf
  -- strict thread matches above, loose matches on Subject: below --
2003-04-11 17:11 Clayton Weaver
2003-04-10 22:10 Clayton Weaver
2003-04-11  1:02 ` David Wagner
2003-04-10  0:31 Clayton Weaver
2003-04-08 13:06 Chuck Ebbert
2003-04-07 23:57 Chuck Ebbert
2003-04-07 16:50 Clayton Weaver
2003-04-07 17:11 ` Arjan van de Ven
2003-04-07 17:37 ` David Wagner
2003-04-07 18:43 ` Werner Almesberger
2003-04-08  5:06   ` Werner Almesberger
2003-04-07 20:35 ` H. Peter Anvin
2003-04-07  9:01 Clayton Weaver
     [not found] <20030407102005.4c13ed7f.manushkinvv@desnol.ru>
     [not found] ` <200304070709.h37792815083@mozart.cs.berkeley.edu>
2003-04-07  7:35   ` Vitaly
2003-04-07 14:57     ` H. Peter Anvin
2003-04-07 18:47       ` Wichert Akkerman
2003-04-07 20:05       ` Bill Rugolsky Jr.
2003-04-07 20:32         ` H. Peter Anvin
2003-04-06 19:05 Dan Kegel
2003-04-06 19:07 ` Dan Kegel
2003-04-06 19:56 ` Oliver Neukum
2003-04-06 20:08   ` Malcolm Beattie
2003-04-06 20:33     ` Oliver Neukum
2003-04-06 21:12   ` Alan Cox
2003-04-07  2:33     ` H. Peter Anvin
2003-04-07  2:29       ` David Wagner
2003-04-07  9:09         ` Malcolm Beattie
2003-04-07 11:02           ` Olivier Galibert
2003-04-07  5:25       ` H. Peter Anvin
2003-04-07  6:43         ` David Wagner
2003-04-07  6:21           ` Vitaly
2003-04-07 16:17           ` Shaya Potter
2003-04-06 18:39 Ulrich Drepper
2003-04-07 17:35 ` Linus Torvalds
2003-04-07 20:37   ` H. Peter Anvin
2003-04-08  0:23   ` Ulrich Drepper

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).