On Mon, Jan 06, 2003 at 07:32:23PM -0800, Terry Lambert wrote: +> > Example rules: +> > +> > We want to permit those operations: +> > - opening file /etc/master.passwd for read only, +> > - opening files that match to /tmp/temp.* for write, +> > - changing mode of files /tmp/temp.* to '0666', BUT via fchmod(2). +> +> Here is an example: +> +> ln /etc/passwd /tmp/temp.hack_Pawels_passwd_file_by_abusing_a_bad_rule +> +> fd = open( "/tmp/...", O_RDWR, 0); +> +> ...Oh look, I've just abused permissions that come from MAC based +> on inheritance, with a hard link, in order to hack the password file...
Not exactly. In my project You got special, very flexible language, so You can create more compilicated rules for situation like this: if (syscall == SYS_open && pname == "our_process" && [ more tests ]) { reg[0] = realpath(arg[0]); if (reg[0] @ "/tmp/temp.*" && arg[1] == (O_RDWR | O_CREAT)) { /* This is important. */ if (getnlinks(arg[0]) == 1) { /* Permit this operation. */ return(call()); } } } if (syscall == SYS_fchmod) { /* let's take file name of descriptor */ reg[0] = fd2name(arg[0]); if (reg[0] @ "/tmp/temp.*" && arg[1] == 0666) { /* We can check number of hardlinks one more time. */ if (fd2nlinks(arg[0]) == 1) { /* Permit this operation. */ return(call()); } } } [ arg[X] are table with syscall arguments, reg[X] are registers that could store values ] So our process can only open and fchmod file that match to /tmp/temp.* when it have no hardlinks at all. I can even create rules that will prohibit creating hard links to file not owned be user who is calling link(2): if (syscall == SYS_link && ruid > 0) { if (getouid(arg[0]) != ruid) { return(EPERM); } } Other think that I could remember dev_t/ino_t pair, because registers that are use in examples aren't cleaned, so: if (syscall == SYS_open && pname == "our_process" && [ more tests ]) { reg[0] = realpath(arg[0]); if (reg[0] @ "/tmp/temp.*" && arg[1] == (O_RDWR | O_CREAT)) { /* This is important. */ if (getnlinks(arg[0]) == 1) { /* Remember ino_t/dev_t pair. */ reg[10] = getinode(arg[0]); reg[11] = getdev(arg[0]); /* Permit this operation. */ return(call()); } } } if (syscall == SYS_fchmod) { /* let's take file name of descriptor */ reg[0] = fd2name(arg[0]); if (reg[0] @ "/tmp/temp.*" && arg[1] == 0666) { /* We can check number of hardlinks one more time. */ if (fd2nlinks(arg[0]) == 1) { /* Check remembered ino_t/dev_t. */ if (fd2inode(arg[0] == reg[10] && fd2dev(arg[0] == reg[11])) { /* Permit this operation. */ return(call()); } } } } Storing ino_t/dev_t pair was added to be sure that someone don't unlink() or rename() our file and create new one with same name. +> The "simple, clean way" is to disallow hard links, and cache the +> parent directory inode on every VOP_CREATE and VOP_MKDIR operation. +> +> The "less simple, but clean way" to do it is to create a file system +> object called a "link node", for use by hard links, and to seperate +> the vmobject_t reference out of the vnode, so that each path gets a +> seperate vnode, and each vnode that's actually an object alias gets +> the same vmobject_t reference, instead of having its own. But please, understand me. I don't want to patch kernel at all. This have to be done from kld module. PS. I think this over againg and You and Julian Elischer probably have right - I need to update cached names on rename(2) and unlink(2). -- Pawel Jakub Dawidek UNIX Systems Administrator http://garage.freebsd.pl Am I Evil? Yes, I Am. To Unsubscribe: send mail to [EMAIL PROTECTED] with "unsubscribe freebsd-hackers" in the body of the message