2017-08-04 14:49:42

by Olga Kornievskaia

[permalink] [raw]
Subject: [RFC v2 0/3] VFS/NFS support to destroy FS credentials

Allow a user to call into the file system and ask to destroy FS
credentials. For instance, when the user logs out after using
a kerberized NFS share, he destroys Kerberos credentials but NFS
credentials remain valid until the gss context expires. Allow
the user (or things like pam) to trigger destruction of such
credentials.

A userland application would do:

fd = open("/mnt", O_DIRECTORY|O_RDONLY);
syscall(_NR_destroy_creds, fd);

v2: fixing a hasty IS_DIR check, definition of __NR_destroy_creds
and order of the patches

Olga Kornievskaia (3):
VFS adding destroy_creds call
SUNRPC mark user credentials destroyed
NFS define vfs destroy_creds functions

arch/x86/entry/syscalls/syscall_32.tbl | 1 +
arch/x86/entry/syscalls/syscall_64.tbl | 1 +
fs/nfs/dir.c | 8 ++++++++
fs/read_write.c | 22 ++++++++++++++++++++++
include/linux/fs.h | 2 ++
include/linux/sunrpc/auth.h | 5 +++++
include/linux/syscalls.h | 2 +-
include/uapi/asm-generic/unistd.h | 4 +++-
kernel/sys_ni.c | 1 +
net/sunrpc/auth.c | 9 +++++++++
net/sunrpc/auth_generic.c | 15 +++++++++++++++
net/sunrpc/auth_gss/auth_gss.c | 3 +++
12 files changed, 71 insertions(+), 2 deletions(-)

--
1.8.3.1



2017-08-04 14:49:43

by Olga Kornievskaia

[permalink] [raw]
Subject: [RFC v2 1/3] VFS adding destroy_creds call

Filesystems (like NFS) would benefit from an ability to destroy
credentials for the current uid.

Systemcall takes in a file descriptor that's a mount point of the
file system. If a non-directory file descriptor supplied it will
failed with EINVAL. It will return 1 upto success. If the file
system doesn't define a destroy_creds callout, it will return 0.

Signed-off-by: Olga Kornievskaia <[email protected]>
---
arch/x86/entry/syscalls/syscall_32.tbl | 1 +
arch/x86/entry/syscalls/syscall_64.tbl | 1 +
fs/read_write.c | 22 ++++++++++++++++++++++
include/linux/fs.h | 2 ++
include/linux/syscalls.h | 2 +-
include/uapi/asm-generic/unistd.h | 4 +++-
kernel/sys_ni.c | 1 +
7 files changed, 31 insertions(+), 2 deletions(-)

diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl
index 448ac21..298e72b 100644
--- a/arch/x86/entry/syscalls/syscall_32.tbl
+++ b/arch/x86/entry/syscalls/syscall_32.tbl
@@ -391,3 +391,4 @@
382 i386 pkey_free sys_pkey_free
383 i386 statx sys_statx
384 i386 arch_prctl sys_arch_prctl compat_sys_arch_prctl
+385 i386 destroy_creds sys_destroy_creds
diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl
index 5aef183..c8a7e38 100644
--- a/arch/x86/entry/syscalls/syscall_64.tbl
+++ b/arch/x86/entry/syscalls/syscall_64.tbl
@@ -339,6 +339,7 @@
330 common pkey_alloc sys_pkey_alloc
331 common pkey_free sys_pkey_free
332 common statx sys_statx
+333 common destroy_creds sys_destroy_creds

#
# x32-specific system call numbers start at 512 to avoid cache impact
diff --git a/fs/read_write.c b/fs/read_write.c
index 406d1c6..2e05287 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -2085,3 +2085,25 @@ int vfs_dedupe_file_range(struct file *file, struct file_dedupe_range *same)
return ret;
}
EXPORT_SYMBOL(vfs_dedupe_file_range);
+
+long vfs_destroy_creds(struct file *fd)
+{
+ struct inode *inode = file_inode(fd);
+
+ if (!S_ISDIR(inode->i_mode))
+ return -EINVAL;
+ if (fd->f_op->destroy_creds)
+ return fd->f_op->destroy_creds(fd);
+ return 0;
+}
+EXPORT_SYMBOL(vfs_destroy_creds);
+
+SYSCALL_DEFINE1(destroy_creds, int, fd_in)
+{
+ struct fd f_in;
+
+ f_in = fdget(fd_in);
+ if (!f_in.file)
+ return 0;
+ return vfs_destroy_creds(f_in.file);
+}
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 803e5a9..28f93e9 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1690,6 +1690,7 @@ struct file_operations {
u64);
ssize_t (*dedupe_file_range)(struct file *, u64, u64, struct file *,
u64);
+ int (*destroy_creds)(struct file *);
};

struct inode_operations {
@@ -1770,6 +1771,7 @@ extern int vfs_dedupe_file_range_compare(struct inode *src, loff_t srcoff,
loff_t len, bool *is_same);
extern int vfs_dedupe_file_range(struct file *file,
struct file_dedupe_range *same);
+extern long vfs_destroy_creds(struct file *fd);

struct super_operations {
struct inode *(*alloc_inode)(struct super_block *sb);
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 980c3c9..586d0ae 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -905,5 +905,5 @@ asmlinkage long sys_pkey_mprotect(unsigned long start, size_t len,
asmlinkage long sys_pkey_free(int pkey);
asmlinkage long sys_statx(int dfd, const char __user *path, unsigned flags,
unsigned mask, struct statx __user *buffer);
-
+asmlinkage long sys_destroy_creds(int fd_in);
#endif
diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h
index 061185a..0ad6a0d 100644
--- a/include/uapi/asm-generic/unistd.h
+++ b/include/uapi/asm-generic/unistd.h
@@ -731,9 +731,11 @@
__SYSCALL(__NR_pkey_free, sys_pkey_free)
#define __NR_statx 291
__SYSCALL(__NR_statx, sys_statx)
+#define __NR_destroy_creds 292
+__SYSCALL(__NR_destroy_creds, sys_destroy_creds)

#undef __NR_syscalls
-#define __NR_syscalls 292
+#define __NR_syscalls 293

/*
* All syscalls below here should go away really,
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index 8acef85..cb9ee0b 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -178,6 +178,7 @@ asmlinkage long sys_ni_syscall(void)
cond_syscall(sys_capget);
cond_syscall(sys_capset);
cond_syscall(sys_copy_file_range);
+cond_syscall(sys_destroy_creds);

/* arch-specific weak syscall entries */
cond_syscall(sys_pciconfig_read);
--
1.8.3.1


2017-08-04 14:49:44

by Olga Kornievskaia

[permalink] [raw]
Subject: [RFC v2 2/3] SUNRPC mark user credentials destroyed

Provide an API -- rpcauth_key_set_destroy() -- to mark specific
gss user's creds destroyed. Afterwards, these credentials come up
as expired and require new credentials to be established. If
previously the user did a kdestroy, then user has no access to
the nfs mount.

Signed-off-by: Olga Kornievskaia <[email protected]>
---
include/linux/sunrpc/auth.h | 5 +++++
net/sunrpc/auth.c | 9 +++++++++
net/sunrpc/auth_generic.c | 15 +++++++++++++++
net/sunrpc/auth_gss/auth_gss.c | 3 +++
4 files changed, 32 insertions(+)

diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h
index 8fd3504..2ab0bc9 100644
--- a/include/linux/sunrpc/auth.h
+++ b/include/linux/sunrpc/auth.h
@@ -76,6 +76,7 @@ struct rpc_cred {
#define RPCAUTH_CRED_UPTODATE 1
#define RPCAUTH_CRED_HASHED 2
#define RPCAUTH_CRED_NEGATIVE 3
+#define RPCAUTH_CRED_DESTROYED 4

/* rpc_auth au_flags */
#define RPCAUTH_AUTH_NO_CRKEY_TIMEOUT 0x0001 /* underlying cred has no key timeout */
@@ -136,6 +137,8 @@ struct rpc_authops {
struct rpcsec_gss_info *);
int (*key_timeout)(struct rpc_auth *,
struct rpc_cred *);
+ int (*key_destroy)(struct rpc_auth *,
+ struct rpc_cred *);
};

struct rpc_credops {
@@ -198,6 +201,8 @@ int rpcauth_get_gssinfo(rpc_authflavor_t,
void rpcauth_clear_credcache(struct rpc_cred_cache *);
int rpcauth_key_timeout_notify(struct rpc_auth *,
struct rpc_cred *);
+int rpcauth_key_set_destroy(struct rpc_auth *,
+ struct rpc_cred *);
bool rpcauth_cred_key_to_expire(struct rpc_auth *, struct rpc_cred *);
char * rpcauth_stringify_acceptor(struct rpc_cred *);

diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c
index d2623b9..408452c 100644
--- a/net/sunrpc/auth.c
+++ b/net/sunrpc/auth.c
@@ -357,6 +357,15 @@ struct rpc_auth *
}
EXPORT_SYMBOL_GPL(rpcauth_key_timeout_notify);

+int
+rpcauth_key_set_destroy(struct rpc_auth *auth, struct rpc_cred *cred)
+{
+ if (!cred->cr_auth->au_ops->key_destroy)
+ return 0;
+ return cred->cr_auth->au_ops->key_destroy(auth, cred);
+}
+EXPORT_SYMBOL_GPL(rpcauth_key_set_destroy);
+
bool
rpcauth_cred_key_to_expire(struct rpc_auth *auth, struct rpc_cred *cred)
{
diff --git a/net/sunrpc/auth_generic.c b/net/sunrpc/auth_generic.c
index f1df983..f434a03 100644
--- a/net/sunrpc/auth_generic.c
+++ b/net/sunrpc/auth_generic.c
@@ -223,6 +223,20 @@ void rpc_destroy_generic_auth(void)
* on the acred ac_flags and return 0.
*/
static int
+generic_key_destroy(struct rpc_auth *auth, struct rpc_cred *cred)
+{
+ struct auth_cred *acred = &container_of(cred, struct generic_cred,
+ gc_base)->acred;
+ struct rpc_cred *tcred;
+
+ tcred = auth->au_ops->lookup_cred(auth, acred, 0);
+ if (IS_ERR(tcred))
+ return -EACCES;
+ set_bit(RPCAUTH_CRED_DESTROYED, &tcred->cr_flags);
+ return 1;
+}
+
+static int
generic_key_timeout(struct rpc_auth *auth, struct rpc_cred *cred)
{
struct auth_cred *acred = &container_of(cred, struct generic_cred,
@@ -270,6 +284,7 @@ void rpc_destroy_generic_auth(void)
.lookup_cred = generic_lookup_cred,
.crcreate = generic_create_cred,
.key_timeout = generic_key_timeout,
+ .key_destroy = generic_key_destroy,
};

static struct rpc_auth generic_auth = {
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c
index 4f16953..75f062c 100644
--- a/net/sunrpc/auth_gss/auth_gss.c
+++ b/net/sunrpc/auth_gss/auth_gss.c
@@ -1473,6 +1473,9 @@ static void gss_pipe_free(struct gss_pipe *p)
if (ret == 0)
return ret;

+ if (test_bit(RPCAUTH_CRED_DESTROYED, &rc->cr_flags))
+ return 0;
+
/* Notify acred users of GSS context expiration timeout */
if (test_bit(RPC_CRED_NOTIFY_TIMEOUT, &acred->ac_flags) &&
(gss_key_timeout(rc) != 0)) {
--
1.8.3.1


2017-08-04 14:49:45

by Olga Kornievskaia

[permalink] [raw]
Subject: [RFC v2 3/3] NFS define vfs destroy_creds functions

Define the destroy_creds function for the NFS directory.

Signed-off-by: Olga Kornievskaia <[email protected]>
---
fs/nfs/dir.c | 8 ++++++++
1 file changed, 8 insertions(+)

diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 2ac00bf..2146aa5 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -54,6 +54,13 @@
static loff_t nfs_llseek_dir(struct file *, loff_t, int);
static void nfs_readdir_clear_array(struct page*);

+static int nfs_destroy_creds(struct file *file)
+{
+ struct rpc_auth *auth = NFS_SERVER(file_inode(file))->client->cl_auth;
+
+ return rpcauth_key_set_destroy(auth, rpc_lookup_cred());
+}
+
const struct file_operations nfs_dir_operations = {
.llseek = nfs_llseek_dir,
.read = generic_read_dir,
@@ -61,6 +68,7 @@
.open = nfs_opendir,
.release = nfs_closedir,
.fsync = nfs_fsync_dir,
+ .destroy_creds = nfs_destroy_creds,
};

const struct address_space_operations nfs_dir_aops = {
--
1.8.3.1


2017-08-07 10:27:40

by Jeff Layton

[permalink] [raw]
Subject: Re: [RFC v2 0/3] VFS/NFS support to destroy FS credentials

On Fri, 2017-08-04 at 10:49 -0400, Olga Kornievskaia wrote:
> Allow a user to call into the file system and ask to destroy FS
> credentials. For instance, when the user logs out after using
> a kerberized NFS share, he destroys Kerberos credentials but NFS
> credentials remain valid until the gss context expires. Allow
> the user (or things like pam) to trigger destruction of such
> credentials.
>
> A userland application would do:
>
> fd = open("/mnt", O_DIRECTORY|O_RDONLY);
> syscall(_NR_destroy_creds, fd);
>
> v2: fixing a hasty IS_DIR check, definition of __NR_destroy_creds
> and order of the patches
>
> Olga Kornievskaia (3):
> VFS adding destroy_creds call
> SUNRPC mark user credentials destroyed
> NFS define vfs destroy_creds functions
>
> arch/x86/entry/syscalls/syscall_32.tbl | 1 +
> arch/x86/entry/syscalls/syscall_64.tbl | 1 +
> fs/nfs/dir.c | 8 ++++++++
> fs/read_write.c | 22 ++++++++++++++++++++++
> include/linux/fs.h | 2 ++
> include/linux/sunrpc/auth.h | 5 +++++
> include/linux/syscalls.h | 2 +-
> include/uapi/asm-generic/unistd.h | 4 +++-
> kernel/sys_ni.c | 1 +
> net/sunrpc/auth.c | 9 +++++++++
> net/sunrpc/auth_generic.c | 15 +++++++++++++++
> net/sunrpc/auth_gss/auth_gss.c | 3 +++
> 12 files changed, 71 insertions(+), 2 deletions(-)
>

I think I'd like to see a proposed manpage for this syscall.

How do you expect this syscall to be used by userland? What will call it
and under what circumstances?

Also, this looks at first glance like a single-purpose, single-
filesystem call. Would this have any purpose at all outside of NFS?
Would this be usable with CIFS or Ceph in some fashion?

--
Jeff Layton <[email protected]>

2017-08-07 15:35:30

by Olga Kornievskaia

[permalink] [raw]
Subject: Re: [RFC v2 0/3] VFS/NFS support to destroy FS credentials

On Mon, Aug 7, 2017 at 6:27 AM, Jeff Layton <[email protected]> wrote:
> On Fri, 2017-08-04 at 10:49 -0400, Olga Kornievskaia wrote:
>> Allow a user to call into the file system and ask to destroy FS
>> credentials. For instance, when the user logs out after using
>> a kerberized NFS share, he destroys Kerberos credentials but NFS
>> credentials remain valid until the gss context expires. Allow
>> the user (or things like pam) to trigger destruction of such
>> credentials.
>>
>> A userland application would do:
>>
>> fd =3D open("/mnt", O_DIRECTORY|O_RDONLY);
>> syscall(_NR_destroy_creds, fd);
>>
>> v2: fixing a hasty IS_DIR check, definition of __NR_destroy_creds
>> and order of the patches
>>
>> Olga Kornievskaia (3):
>> VFS adding destroy_creds call
>> SUNRPC mark user credentials destroyed
>> NFS define vfs destroy_creds functions
>>
>> arch/x86/entry/syscalls/syscall_32.tbl | 1 +
>> arch/x86/entry/syscalls/syscall_64.tbl | 1 +
>> fs/nfs/dir.c | 8 ++++++++
>> fs/read_write.c | 22 ++++++++++++++++++++++
>> include/linux/fs.h | 2 ++
>> include/linux/sunrpc/auth.h | 5 +++++
>> include/linux/syscalls.h | 2 +-
>> include/uapi/asm-generic/unistd.h | 4 +++-
>> kernel/sys_ni.c | 1 +
>> net/sunrpc/auth.c | 9 +++++++++
>> net/sunrpc/auth_generic.c | 15 +++++++++++++++
>> net/sunrpc/auth_gss/auth_gss.c | 3 +++
>> 12 files changed, 71 insertions(+), 2 deletions(-)
>>
>
> I think I'd like to see a proposed manpage for this syscall.

Ok.

> How do you expect this syscall to be used by userland? What will call it
> and under what circumstances?

I think we need to provide flexibility to the userland on how it would
be triggered. It could be that the user runs an application (fslogout
/mnt). AFS has =E2=80=9Cunlog=E2=80=9D for logout I think. But such an appl=
ication
could also be integrated by an administrated into the logout script
from the shell or it could be integrated into something like pam.

> Also, this looks at first glance like a single-purpose, single-
> filesystem call. Would this have any purpose at all outside of NFS?
> Would this be usable with CIFS or Ceph in some fashion?

NFS has proposed NFS-specific logout mechanism a while back
http://marc.info/?t=3D138245185000016&r=3D1&w=3D2 and at the time it was
suggested that instead of doing a specific mechanism that only NFS
would use why not do a syscall so that other filesystems would use it.
So=E2=80=A6.

That=E2=80=99s the idea that other filesystem could make use of this
functionality to get rid of their security contexts upon user logout.
In the linux kernel, I don=E2=80=99t see security implementation by CIFS so=
if
it were to be implemented, I would imagine it would be useful. It=E2=80=99s
rather late for AFS now as it already has its own well established
mechanism.

What I=E2=80=99m not clear on is whether or not a mount point is enough to
specify what creds to get rid off for a generic file system,. CIFS is
Kerberos based so very similar to NFS. I think specifying a share
determines which creds need to go. While not proposing to convert it,
but for something like AFS, unlog takes a cell name so then fslog
could take /afs/cell.name to be specific.

I=E2=80=99m not familiar with Ceph security. According to
http://docs.ceph.com/docs/firefly/rados/operations/auth-intro/, under
the =E2=80=9Cceph limitations=E2=80=9D it says =E2=80=9CThe cephx protocol =
authenticates Ceph
clients and servers to each other. It is not intended to handle
authentication of human users or application programs run on their
behalf.=E2=80=9D If that is the case then there is no such thing as a user
logout and thus no need to destroy credentials. If there is
authentication of users where the user proves via some means his
identity via some login application. Then I imagine then there would
be a corresponding logout that the Ceph file system in the kernel
doesn=E2=80=99t know that the user have logged out and it would require use=
r
land driven trigger to get rid of such context. I have also read that
Ceph uses a keyring to store the secret key it is uses for securing
communication with the servers. Then if everything is integrated into
the keyring then again no need for a logout method.

I think this feature is useful for where the filesystem manages its
own security contexts that were bootstrapped via some user land
credentials (such Kerberos).
>
> --
> Jeff Layton <[email protected]>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
> the body of a message to [email protected]
> More majordomo info at http://vger.kernel.org/majordomo-info.html

2017-08-07 15:53:12

by Amir Goldstein

[permalink] [raw]
Subject: Re: [RFC v2 0/3] VFS/NFS support to destroy FS credentials

On Mon, Aug 7, 2017 at 12:27 PM, Jeff Layton <[email protected]> wrote:
> On Fri, 2017-08-04 at 10:49 -0400, Olga Kornievskaia wrote:
>> Allow a user to call into the file system and ask to destroy FS
>> credentials. For instance, when the user logs out after using
>> a kerberized NFS share, he destroys Kerberos credentials but NFS
>> credentials remain valid until the gss context expires. Allow
>> the user (or things like pam) to trigger destruction of such
>> credentials.
>>
>> A userland application would do:
>>
>> fd = open("/mnt", O_DIRECTORY|O_RDONLY);
>> syscall(_NR_destroy_creds, fd);
>>
>> v2: fixing a hasty IS_DIR check, definition of __NR_destroy_creds
>> and order of the patches
>>
>> Olga Kornievskaia (3):
>> VFS adding destroy_creds call
>> SUNRPC mark user credentials destroyed
>> NFS define vfs destroy_creds functions
>>
>> arch/x86/entry/syscalls/syscall_32.tbl | 1 +
>> arch/x86/entry/syscalls/syscall_64.tbl | 1 +
>> fs/nfs/dir.c | 8 ++++++++
>> fs/read_write.c | 22 ++++++++++++++++++++++
>> include/linux/fs.h | 2 ++
>> include/linux/sunrpc/auth.h | 5 +++++
>> include/linux/syscalls.h | 2 +-
>> include/uapi/asm-generic/unistd.h | 4 +++-
>> kernel/sys_ni.c | 1 +
>> net/sunrpc/auth.c | 9 +++++++++
>> net/sunrpc/auth_generic.c | 15 +++++++++++++++
>> net/sunrpc/auth_gss/auth_gss.c | 3 +++
>> 12 files changed, 71 insertions(+), 2 deletions(-)
>>
>
> I think I'd like to see a proposed manpage for this syscall.
>

And better CC linux-api...

> How do you expect this syscall to be used by userland? What will call it
> and under what circumstances?
>
> Also, this looks at first glance like a single-purpose, single-
> filesystem call. Would this have any purpose at all outside of NFS?
> Would this be usable with CIFS or Ceph in some fashion?
>
> --
> Jeff Layton <[email protected]>