RFC: BSD system call revoke?

Bernhard Kaindl (bk@suse.de)
Wed, 23 Jun 1999 23:56:52 +0200 (MEST)


Hi,

i´ve started a hopefully feasible linux implementation of a BSD system call.

I want to ask the experts for their comment and hand over the code if the
approach is feasible.

Here is the an application, a code extract from the login program:

#if 0
/*
* Please don't add code to chown /dev/vcs* to the user logging in -
* it's a potential security hole. I wouldn't like the previous user
* to hold the file descriptor open and watch my screen. We don't
* have the *BSD revoke() system call yet, and vhangup() only works
* for tty devices (which vcs* is not). --marekm
*/
chown (vcsn, pwd->pw_uid, (gr ? gr->gr_gid : pwd->pw_gid));
chown (vcsan, pwd->pw_uid, (gr ? gr->gr_gid : pwd->pw_gid));
chmod (vcsn, TTY_MODE);
chmod (vcsan, TTY_MODE);
#endif

The same may also apply to audio devices(recording from a microphone?) and
others.

I've found revoke manual pages for freebsd and openbsd and also looked at the
BSD kernel code. This is the manual page from openbsd:

------------------------------------------------------------------------------
REVOKE(2) UNIX Programmer's Manual REVOKE(2)

NAME
revoke - revoke file access

SYNOPSIS
#include <unistd.h>

int
revoke(const char *path)

DESCRIPTION
The revoke function invalidates all current open file descriptors in the
system for the file named by path. Subsequent operations on any such de­
scriptors fail, with the exceptions that a read() from a character device
file which has been revoked returns a count of zero (end of file), and a
close() call will succeed. If the file is a special file for a device
which is open, the device close function is called as if all open refer­
ences to the file had been closed.

Access to a file may be revoked only by its owner or the super user. The
revoke function is currently supported only for block and character spe­
cial device files. It is normally used to prepare a terminal device for
a new login session, preventing any access by a previous user of the ter­
minal.

RETURN VALUES
A 0 value indicated that the call succeeded. A -1 return value indicates
an error occurred and errno is set to indicated the reason.

ERRORS
Access to the named file is revoked unless one of the following:

[ENOTDIR] A component of the path prefix is not a directory.

[ENAMETOOLONG]
A component of a pathname exceeded 255 characters, or an
entire path name exceeded 1024 characters.

[ENOENT] The named file or a component of the path name does not ex­
ist.

[EACCES] Search permission is denied for a component of the path
prefix.

[ELOOP] Too many symbolic links were encountered in translating the
pathname.

[EFAULT] path points outside the process's allocated address space.

[EINVAL] The named file is neither a character special or block spe­
cial file.

[EPERM] The caller is neither the owner of the file nor the super
user.

SEE ALSO
close(2)

HISTORY
The revoke function was introduced in 4.3BSD-Reno.

BSD Experimental June 4, 1993 1
------------------------------------------------------------------------------

I´ve not approached it like this BSD manpage is describing it but it think it
fulfills the requirements. BTW: It is not bound to devices, so it can also
be used on regular files.

If the code here works if the processes which have opened the file are not
in kernel mode. And this is the part I want to have comments...

A possible, but not neat solution could be be to kill that processes, uh,
i hope you have better answers... ;-)

If we really can get a robust implementaion in the kernel we can optimize
it, e.g. it can finish when the usage counter is zero...

Here is the code, it just walks though the task list and closes any file,
regardless if the process is stopped in read() or running on another CPU...

--- linux/arch/i386/kernel/entry.S
+++ linux/arch/i386/kernel/entry.S 1999/06/23 20:07:54
@@ -562,6 +562,7 @@
.long SYMBOL_NAME(sys_ni_syscall) /* streams1 */
.long SYMBOL_NAME(sys_ni_syscall) /* streams2 */
.long SYMBOL_NAME(sys_vfork) /* 190 */
+ .long SYMBOL_NAME(sys_revoke) /* 191 */

/*
* NOTE!! This doesn't have to be exact - we just have
@@ -569,6 +570,6 @@
* entries. Don't panic if you notice that this hasn't
* been shrunk every time we add a new system call.
*/
- .rept NR_syscalls-190
+ .rept NR_syscalls-191
.long SYMBOL_NAME(sys_ni_syscall)
.endr
--- linux/fs/open.c
+++ linux/fs/open.c 1999/06/23 20:27:21
@@ -2,6 +2,8 @@
* linux/fs/open.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * BSD revoke system call added by Bernhard Kaindl <bk@suse.de>
*/

#include <linux/mm.h>
@@ -845,4 +847,73 @@
out:
unlock_kernel();
return ret;
+}
+
+/*
+ * Helper function for sys_revoke()
+ */
+static inline
+void files_revoke_dentry(struct files_struct * files, struct dentry * dentry)
+{
+ int i, j = 0;
+
+ if (!files)
+ return;
+
+ for (;;) {
+ unsigned long set = files->open_fds.fds_bits[j];
+ i = j * __NFDBITS;
+ j++;
+ if (i >= files->max_fds)
+ break;
+ while (set) {
+ if (set & 1) {
+ struct file * filp = files->fd[i];
+ if (filp && filp->f_dentry == dentry) {
+ files->fd[i] = NULL;
+ put_unused_fd(i);
+ FD_CLR(i, &files->close_on_exec);
+ filp_close(filp, files);
+ }
+ }
+ i++;
+ set >>= 1;
+ }
+ }
+}
+
+/*
+ * BSD revoke system call, closes all filedescriptors which belong
+ * to the passed pathname.
+ */
+asmlinkage int sys_revoke(const char * path)
+{
+ struct dentry * dentry;
+ struct task_struct *p;
+ int retval;
+
+ lock_kernel();
+ dentry = namei(path);
+ retval = PTR_ERR(dentry);
+
+ if (IS_ERR(dentry))
+ goto out;
+
+ retval = -EPERM;
+ if (!capable(CAP_DAC_OVERRIDE &&
+ current->fsuid != dentry->d_inode->i_uid)) {
+ goto out_dput;
+ }
+ retval = 0;
+
+ read_lock(&tasklist_lock);
+ for_each_task(p)
+ files_revoke_dentry(p->files, dentry);
+ read_unlock(&tasklist_lock);
+
+out_dput:
+ dput(dentry);
+out:
+ unlock_kernel();
+ return retval;
}
--- linux/include/asm-i386/unistd.h
+++ linux/include/asm-i386/unistd.h 1999/06/23 20:07:54
@@ -195,6 +195,7 @@
#define __NR_getpmsg 188 /* some people actually want streams */
#define __NR_putpmsg 189 /* some people actually want streams */
#define __NR_vfork 190
+#define __NR_revoke 191

/* user-visible error numbers are in the range -1 - -122: see <asm-i386/errno.h> */

Bernhard

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/