From patchwork Thu Apr 28 04:34:35 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shirish Pargaonkar X-Patchwork-Id: 738381 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id p3S4UaJm020688 for ; Thu, 28 Apr 2011 04:30:38 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751884Ab1D1Eaf (ORCPT ); Thu, 28 Apr 2011 00:30:35 -0400 Received: from mail-gy0-f174.google.com ([209.85.160.174]:37082 "EHLO mail-gy0-f174.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751649Ab1D1Eaf (ORCPT ); Thu, 28 Apr 2011 00:30:35 -0400 Received: by gyd10 with SMTP id 10so846007gyd.19 for ; Wed, 27 Apr 2011 21:30:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:from:to:cc:subject:date:message-id:x-mailer; bh=X/KKrMQHniiUAlQDFD3NQgY2/4KfUNjOOXJjNvEqwyM=; b=JtZB1nLeYaUjxZZ8gvBVbtz9mHq6Q076jDwz0OtfhcsF2a+XmLYFbxEqIQ8lPPeFeu 0bSFd22feV4kVM/rAukmQghbYJ0ngGPdl1fePpRSKxQdHcRz0bEvAq/XE1rb1C6+ZuNb aiyCcfzYwIFpzuBJjaHizNcPlx4w1lxAMVO1E= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=from:to:cc:subject:date:message-id:x-mailer; b=q8XJ4085s8MQIaCoAj+Nh6BfVC1mlCgqh94E9uh8WMpXRJmqxbfKr9KlkS1Fc82RSy SiCE5ob0D9HWnM8e+OCNnmPGaBCWNG1vsClJs1dq51I9OndbJNpIf2gqq0j+03cIQ4G1 5w2nxSgbExnh6AJFSsP7JIXULjWhG/7GPmBxQ= Received: by 10.151.3.3 with SMTP id f3mr2601359ybi.96.1303965034316; Wed, 27 Apr 2011 21:30:34 -0700 (PDT) Received: from localhost ([32.97.110.58]) by mx.google.com with ESMTPS id r18sm774693yba.26.2011.04.27.21.30.32 (version=TLSv1/SSLv3 cipher=OTHER); Wed, 27 Apr 2011 21:30:33 -0700 (PDT) From: shirishpargaonkar@gmail.com To: smfrench@gmail.com Cc: linux-cifs@vger.kernel.org, Shirish Pargaonkar Subject: [PATCH 1/1] cifs: Add idmap key and related data structures and functions (try #17 repost) Date: Wed, 27 Apr 2011 23:34:35 -0500 Message-Id: <1303965275-21280-1-git-send-email-shirishpargaonkar@gmail.com> X-Mailer: git-send-email 1.6.0.2 Sender: linux-cifs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-cifs@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Thu, 28 Apr 2011 04:30:38 +0000 (UTC) From: Shirish Pargaonkar Define (global) data structures to store ids, uids and gids, to which a SID maps. There are two separate trees, one for SID/uid and another one for SID/gid. A new type of key, cifs_idmap_key_type, is used. Keys are instantiated and searched using credential of the root by overriding and restoring the credentials of the caller requesting the key. Id mapping functions are invoked under config option of cifs acl. Signed-off-by: Shirish Pargaonkar --- fs/cifs/cifsacl.c | 138 +++++++++++++++++++++++++++++++++++++++++++++++++++ fs/cifs/cifsfs.c | 29 ++++++++--- fs/cifs/cifsglob.h | 5 ++ fs/cifs/cifsproto.h | 3 + 4 files changed, 167 insertions(+), 8 deletions(-) diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index a0d11ea..061fc3a 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -23,6 +23,10 @@ #include #include +#include +#include +#include +#include #include "cifspdu.h" #include "cifsglob.h" #include "cifsacl.h" @@ -50,6 +54,140 @@ static const struct cifs_sid sid_authusers = { /* group users */ static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} }; +static const struct cred *root_cred; + +/* + * Run idmap cache shrinker. + */ +static int +cifs_idmap_shrinker(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask) +{ + /* Use a pruning scheme in a subsequent patch instead */ + cifs_destroy_idmaptrees(); + return 0; +} + +static struct shrinker cifs_shrinker = { + .shrink = cifs_idmap_shrinker, + .seeks = DEFAULT_SEEKS, +}; + +static int +cifs_idmap_key_instantiate(struct key *key, const void *data, size_t datalen) +{ + char *payload; + + payload = kmalloc(datalen, GFP_KERNEL); + if (!payload) + return -ENOMEM; + + memcpy(payload, data, datalen); + key->payload.data = payload; + return 0; +} + +static inline void +cifs_idmap_key_destroy(struct key *key) +{ + kfree(key->payload.data); +} + +static +struct key_type cifs_idmap_key_type = { + .name = "cifs.cifs_idmap", + .instantiate = cifs_idmap_key_instantiate, + .destroy = cifs_idmap_key_destroy, + .describe = user_describe, + .match = user_match, +}; + +int +init_cifs_idmap(void) +{ + struct cred *cred; + struct key *keyring; + int ret; + + cFYI(1, "Registering the %s key type\n", cifs_idmap_key_type.name); + + /* create an override credential set with a special thread keyring in + * which requests are cached + * + * this is used to prevent malicious redirections from being installed + * with add_key(). + */ + cred = prepare_kernel_cred(NULL); + if (!cred) + return -ENOMEM; + + keyring = key_alloc(&key_type_keyring, ".cifs_idmap", 0, 0, cred, + (KEY_POS_ALL & ~KEY_POS_SETATTR) | + KEY_USR_VIEW | KEY_USR_READ, + KEY_ALLOC_NOT_IN_QUOTA); + if (IS_ERR(keyring)) { + ret = PTR_ERR(keyring); + goto failed_put_cred; + } + + ret = key_instantiate_and_link(keyring, NULL, 0, NULL, NULL); + if (ret < 0) + goto failed_put_key; + + ret = register_key_type(&cifs_idmap_key_type); + if (ret < 0) + goto failed_put_key; + + /* instruct request_key() to use this special keyring as a cache for + * the results it looks up */ + cred->thread_keyring = keyring; + cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING; + root_cred = cred; + + spin_lock_init(&siduidlock); + uidtree = RB_ROOT; + spin_lock_init(&sidgidlock); + gidtree = RB_ROOT; + + register_shrinker(&cifs_shrinker); + + cFYI(1, "cifs idmap keyring: %d\n", key_serial(keyring)); + return 0; + +failed_put_key: + key_put(keyring); +failed_put_cred: + put_cred(cred); + return ret; +} + +void +exit_cifs_idmap(void) +{ + key_revoke(root_cred->thread_keyring); + unregister_key_type(&cifs_idmap_key_type); + put_cred(root_cred); + unregister_shrinker(&cifs_shrinker); + cFYI(1, "Unregistered %s key type\n", cifs_idmap_key_type.name); +} + +void +cifs_destroy_idmaptrees(void) +{ + struct rb_root *root; + struct rb_node *node; + + root = &uidtree; + spin_lock(&siduidlock); + while ((node = rb_first(root))) + rb_erase(node, root); + spin_unlock(&siduidlock); + + root = &gidtree; + spin_lock(&sidgidlock); + while ((node = rb_first(root))) + rb_erase(node, root); + spin_unlock(&sidgidlock); +} int match_sid(struct cifs_sid *ctsid) { diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 30fc505..6c1d738 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -1033,22 +1033,31 @@ init_cifs(void) if (rc) goto out_destroy_mids; - rc = register_filesystem(&cifs_fs_type); - if (rc) - goto out_destroy_request_bufs; #ifdef CONFIG_CIFS_UPCALL rc = register_key_type(&cifs_spnego_key_type); if (rc) - goto out_unregister_filesystem; -#endif + goto out_destroy_request_bufs; +#endif /* CONFIG_CIFS_UPCALL */ + +#ifdef CONFIG_CIFS_ACL + rc = init_cifs_idmap(); + if (rc) + goto out_destroy_request_bufs; +#endif /* CONFIG_CIFS_ACL */ + + rc = register_filesystem(&cifs_fs_type); + if (rc) + goto out_destroy_request_bufs; return 0; +out_destroy_request_bufs: +#ifdef CONFIG_CIFS_ACL + exit_cifs_idmap(); +#endif #ifdef CONFIG_CIFS_UPCALL -out_unregister_filesystem: - unregister_filesystem(&cifs_fs_type); + unregister_key_type(&cifs_spnego_key_type); #endif -out_destroy_request_bufs: cifs_destroy_request_bufs(); out_destroy_mids: cifs_destroy_mids(); @@ -1070,6 +1079,10 @@ exit_cifs(void) #ifdef CONFIG_CIFS_DFS_UPCALL cifs_dfs_release_automount_timer(); #endif +#ifdef CONFIG_CIFS_ACL + cifs_destroy_idmaptrees(); + exit_cifs_idmap(); +#endif #ifdef CONFIG_CIFS_UPCALL unregister_key_type(&cifs_spnego_key_type); #endif diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 108a1e9..76b4517 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -833,6 +833,11 @@ GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/ /* reconnect after this many failed echo attempts */ GLOBAL_EXTERN unsigned short echo_retries; +GLOBAL_EXTERN struct rb_root uidtree; +GLOBAL_EXTERN struct rb_root gidtree; +GLOBAL_EXTERN spinlock_t siduidlock; +GLOBAL_EXTERN spinlock_t sidgidlock; + void cifs_oplock_break(struct work_struct *work); void cifs_oplock_break_get(struct cifsFileInfo *cfile); void cifs_oplock_break_put(struct cifsFileInfo *cfile); diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 0e4e057..7c1ed01 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -53,6 +53,9 @@ do { \ cFYI(1, "CIFS VFS: leaving %s (xid = %d) rc = %d", \ __func__, curr_xid, (int)rc); \ } while (0) +extern int init_cifs_idmap(void); +extern void exit_cifs_idmap(void); +extern void cifs_destroy_idmaptrees(void); extern char *build_path_from_dentry(struct dentry *); extern char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb, struct cifsTconInfo *tcon);