diff options
Diffstat (limited to 'net/sunrpc')
-rw-r--r-- | net/sunrpc/auth_gss/auth_gss.c | 62 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/svcauth_gss.c | 8 | ||||
-rw-r--r-- | net/sunrpc/netns.h | 4 | ||||
-rw-r--r-- | net/sunrpc/rpc_pipe.c | 5 | ||||
-rw-r--r-- | net/sunrpc/sched.c | 8 | ||||
-rw-r--r-- | net/sunrpc/svcauth_unix.c | 12 |
6 files changed, 69 insertions, 30 deletions
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index 7da6b457f66a..fc2f78d6a9b4 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c | |||
@@ -52,6 +52,8 @@ | |||
52 | #include <linux/sunrpc/gss_api.h> | 52 | #include <linux/sunrpc/gss_api.h> |
53 | #include <asm/uaccess.h> | 53 | #include <asm/uaccess.h> |
54 | 54 | ||
55 | #include "../netns.h" | ||
56 | |||
55 | static const struct rpc_authops authgss_ops; | 57 | static const struct rpc_authops authgss_ops; |
56 | 58 | ||
57 | static const struct rpc_credops gss_credops; | 59 | static const struct rpc_credops gss_credops; |
@@ -85,8 +87,6 @@ struct gss_auth { | |||
85 | }; | 87 | }; |
86 | 88 | ||
87 | /* pipe_version >= 0 if and only if someone has a pipe open. */ | 89 | /* pipe_version >= 0 if and only if someone has a pipe open. */ |
88 | static int pipe_version = -1; | ||
89 | static atomic_t pipe_users = ATOMIC_INIT(0); | ||
90 | static DEFINE_SPINLOCK(pipe_version_lock); | 90 | static DEFINE_SPINLOCK(pipe_version_lock); |
91 | static struct rpc_wait_queue pipe_version_rpc_waitqueue; | 91 | static struct rpc_wait_queue pipe_version_rpc_waitqueue; |
92 | static DECLARE_WAIT_QUEUE_HEAD(pipe_version_waitqueue); | 92 | static DECLARE_WAIT_QUEUE_HEAD(pipe_version_waitqueue); |
@@ -266,24 +266,27 @@ struct gss_upcall_msg { | |||
266 | char databuf[UPCALL_BUF_LEN]; | 266 | char databuf[UPCALL_BUF_LEN]; |
267 | }; | 267 | }; |
268 | 268 | ||
269 | static int get_pipe_version(void) | 269 | static int get_pipe_version(struct net *net) |
270 | { | 270 | { |
271 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
271 | int ret; | 272 | int ret; |
272 | 273 | ||
273 | spin_lock(&pipe_version_lock); | 274 | spin_lock(&pipe_version_lock); |
274 | if (pipe_version >= 0) { | 275 | if (sn->pipe_version >= 0) { |
275 | atomic_inc(&pipe_users); | 276 | atomic_inc(&sn->pipe_users); |
276 | ret = pipe_version; | 277 | ret = sn->pipe_version; |
277 | } else | 278 | } else |
278 | ret = -EAGAIN; | 279 | ret = -EAGAIN; |
279 | spin_unlock(&pipe_version_lock); | 280 | spin_unlock(&pipe_version_lock); |
280 | return ret; | 281 | return ret; |
281 | } | 282 | } |
282 | 283 | ||
283 | static void put_pipe_version(void) | 284 | static void put_pipe_version(struct net *net) |
284 | { | 285 | { |
285 | if (atomic_dec_and_lock(&pipe_users, &pipe_version_lock)) { | 286 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); |
286 | pipe_version = -1; | 287 | |
288 | if (atomic_dec_and_lock(&sn->pipe_users, &pipe_version_lock)) { | ||
289 | sn->pipe_version = -1; | ||
287 | spin_unlock(&pipe_version_lock); | 290 | spin_unlock(&pipe_version_lock); |
288 | } | 291 | } |
289 | } | 292 | } |
@@ -291,9 +294,10 @@ static void put_pipe_version(void) | |||
291 | static void | 294 | static void |
292 | gss_release_msg(struct gss_upcall_msg *gss_msg) | 295 | gss_release_msg(struct gss_upcall_msg *gss_msg) |
293 | { | 296 | { |
297 | struct net *net = rpc_net_ns(gss_msg->auth->client); | ||
294 | if (!atomic_dec_and_test(&gss_msg->count)) | 298 | if (!atomic_dec_and_test(&gss_msg->count)) |
295 | return; | 299 | return; |
296 | put_pipe_version(); | 300 | put_pipe_version(net); |
297 | BUG_ON(!list_empty(&gss_msg->list)); | 301 | BUG_ON(!list_empty(&gss_msg->list)); |
298 | if (gss_msg->ctx != NULL) | 302 | if (gss_msg->ctx != NULL) |
299 | gss_put_ctx(gss_msg->ctx); | 303 | gss_put_ctx(gss_msg->ctx); |
@@ -439,7 +443,10 @@ static void gss_encode_msg(struct gss_upcall_msg *gss_msg, | |||
439 | struct rpc_clnt *clnt, | 443 | struct rpc_clnt *clnt, |
440 | const char *service_name) | 444 | const char *service_name) |
441 | { | 445 | { |
442 | if (pipe_version == 0) | 446 | struct net *net = rpc_net_ns(clnt); |
447 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
448 | |||
449 | if (sn->pipe_version == 0) | ||
443 | gss_encode_v0_msg(gss_msg); | 450 | gss_encode_v0_msg(gss_msg); |
444 | else /* pipe_version == 1 */ | 451 | else /* pipe_version == 1 */ |
445 | gss_encode_v1_msg(gss_msg, clnt, service_name); | 452 | gss_encode_v1_msg(gss_msg, clnt, service_name); |
@@ -455,7 +462,7 @@ gss_alloc_msg(struct gss_auth *gss_auth, struct rpc_clnt *clnt, | |||
455 | gss_msg = kzalloc(sizeof(*gss_msg), GFP_NOFS); | 462 | gss_msg = kzalloc(sizeof(*gss_msg), GFP_NOFS); |
456 | if (gss_msg == NULL) | 463 | if (gss_msg == NULL) |
457 | return ERR_PTR(-ENOMEM); | 464 | return ERR_PTR(-ENOMEM); |
458 | vers = get_pipe_version(); | 465 | vers = get_pipe_version(rpc_net_ns(clnt)); |
459 | if (vers < 0) { | 466 | if (vers < 0) { |
460 | kfree(gss_msg); | 467 | kfree(gss_msg); |
461 | return ERR_PTR(vers); | 468 | return ERR_PTR(vers); |
@@ -559,24 +566,34 @@ out: | |||
559 | static inline int | 566 | static inline int |
560 | gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred) | 567 | gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred) |
561 | { | 568 | { |
569 | struct net *net = rpc_net_ns(gss_auth->client); | ||
570 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
562 | struct rpc_pipe *pipe; | 571 | struct rpc_pipe *pipe; |
563 | struct rpc_cred *cred = &gss_cred->gc_base; | 572 | struct rpc_cred *cred = &gss_cred->gc_base; |
564 | struct gss_upcall_msg *gss_msg; | 573 | struct gss_upcall_msg *gss_msg; |
574 | unsigned long timeout; | ||
565 | DEFINE_WAIT(wait); | 575 | DEFINE_WAIT(wait); |
566 | int err = 0; | 576 | int err; |
567 | 577 | ||
568 | dprintk("RPC: %s for uid %u\n", | 578 | dprintk("RPC: %s for uid %u\n", |
569 | __func__, from_kuid(&init_user_ns, cred->cr_uid)); | 579 | __func__, from_kuid(&init_user_ns, cred->cr_uid)); |
570 | retry: | 580 | retry: |
581 | err = 0; | ||
582 | /* Default timeout is 15s unless we know that gssd is not running */ | ||
583 | timeout = 15 * HZ; | ||
584 | if (!sn->gssd_running) | ||
585 | timeout = HZ >> 2; | ||
571 | gss_msg = gss_setup_upcall(gss_auth->client, gss_auth, cred); | 586 | gss_msg = gss_setup_upcall(gss_auth->client, gss_auth, cred); |
572 | if (PTR_ERR(gss_msg) == -EAGAIN) { | 587 | if (PTR_ERR(gss_msg) == -EAGAIN) { |
573 | err = wait_event_interruptible_timeout(pipe_version_waitqueue, | 588 | err = wait_event_interruptible_timeout(pipe_version_waitqueue, |
574 | pipe_version >= 0, 15*HZ); | 589 | sn->pipe_version >= 0, timeout); |
575 | if (pipe_version < 0) { | 590 | if (sn->pipe_version < 0) { |
591 | if (err == 0) | ||
592 | sn->gssd_running = 0; | ||
576 | warn_gssd(); | 593 | warn_gssd(); |
577 | err = -EACCES; | 594 | err = -EACCES; |
578 | } | 595 | } |
579 | if (err) | 596 | if (err < 0) |
580 | goto out; | 597 | goto out; |
581 | goto retry; | 598 | goto retry; |
582 | } | 599 | } |
@@ -707,20 +724,22 @@ out: | |||
707 | 724 | ||
708 | static int gss_pipe_open(struct inode *inode, int new_version) | 725 | static int gss_pipe_open(struct inode *inode, int new_version) |
709 | { | 726 | { |
727 | struct net *net = inode->i_sb->s_fs_info; | ||
728 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
710 | int ret = 0; | 729 | int ret = 0; |
711 | 730 | ||
712 | spin_lock(&pipe_version_lock); | 731 | spin_lock(&pipe_version_lock); |
713 | if (pipe_version < 0) { | 732 | if (sn->pipe_version < 0) { |
714 | /* First open of any gss pipe determines the version: */ | 733 | /* First open of any gss pipe determines the version: */ |
715 | pipe_version = new_version; | 734 | sn->pipe_version = new_version; |
716 | rpc_wake_up(&pipe_version_rpc_waitqueue); | 735 | rpc_wake_up(&pipe_version_rpc_waitqueue); |
717 | wake_up(&pipe_version_waitqueue); | 736 | wake_up(&pipe_version_waitqueue); |
718 | } else if (pipe_version != new_version) { | 737 | } else if (sn->pipe_version != new_version) { |
719 | /* Trying to open a pipe of a different version */ | 738 | /* Trying to open a pipe of a different version */ |
720 | ret = -EBUSY; | 739 | ret = -EBUSY; |
721 | goto out; | 740 | goto out; |
722 | } | 741 | } |
723 | atomic_inc(&pipe_users); | 742 | atomic_inc(&sn->pipe_users); |
724 | out: | 743 | out: |
725 | spin_unlock(&pipe_version_lock); | 744 | spin_unlock(&pipe_version_lock); |
726 | return ret; | 745 | return ret; |
@@ -740,6 +759,7 @@ static int gss_pipe_open_v1(struct inode *inode) | |||
740 | static void | 759 | static void |
741 | gss_pipe_release(struct inode *inode) | 760 | gss_pipe_release(struct inode *inode) |
742 | { | 761 | { |
762 | struct net *net = inode->i_sb->s_fs_info; | ||
743 | struct rpc_pipe *pipe = RPC_I(inode)->pipe; | 763 | struct rpc_pipe *pipe = RPC_I(inode)->pipe; |
744 | struct gss_upcall_msg *gss_msg; | 764 | struct gss_upcall_msg *gss_msg; |
745 | 765 | ||
@@ -758,7 +778,7 @@ restart: | |||
758 | } | 778 | } |
759 | spin_unlock(&pipe->lock); | 779 | spin_unlock(&pipe->lock); |
760 | 780 | ||
761 | put_pipe_version(); | 781 | put_pipe_version(net); |
762 | } | 782 | } |
763 | 783 | ||
764 | static void | 784 | static void |
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c index 871c73c92165..29b4ba93ab3c 100644 --- a/net/sunrpc/auth_gss/svcauth_gss.c +++ b/net/sunrpc/auth_gss/svcauth_gss.c | |||
@@ -1287,7 +1287,7 @@ static bool use_gss_proxy(struct net *net) | |||
1287 | 1287 | ||
1288 | #ifdef CONFIG_PROC_FS | 1288 | #ifdef CONFIG_PROC_FS |
1289 | 1289 | ||
1290 | static bool set_gss_proxy(struct net *net, int type) | 1290 | static int set_gss_proxy(struct net *net, int type) |
1291 | { | 1291 | { |
1292 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | 1292 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); |
1293 | int ret = 0; | 1293 | int ret = 0; |
@@ -1317,10 +1317,12 @@ static inline bool gssp_ready(struct sunrpc_net *sn) | |||
1317 | return false; | 1317 | return false; |
1318 | } | 1318 | } |
1319 | 1319 | ||
1320 | static int wait_for_gss_proxy(struct net *net) | 1320 | static int wait_for_gss_proxy(struct net *net, struct file *file) |
1321 | { | 1321 | { |
1322 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | 1322 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); |
1323 | 1323 | ||
1324 | if (file->f_flags & O_NONBLOCK && !gssp_ready(sn)) | ||
1325 | return -EAGAIN; | ||
1324 | return wait_event_interruptible(sn->gssp_wq, gssp_ready(sn)); | 1326 | return wait_event_interruptible(sn->gssp_wq, gssp_ready(sn)); |
1325 | } | 1327 | } |
1326 | 1328 | ||
@@ -1362,7 +1364,7 @@ static ssize_t read_gssp(struct file *file, char __user *buf, | |||
1362 | size_t len; | 1364 | size_t len; |
1363 | int ret; | 1365 | int ret; |
1364 | 1366 | ||
1365 | ret = wait_for_gss_proxy(net); | 1367 | ret = wait_for_gss_proxy(net, file); |
1366 | if (ret) | 1368 | if (ret) |
1367 | return ret; | 1369 | return ret; |
1368 | 1370 | ||
diff --git a/net/sunrpc/netns.h b/net/sunrpc/netns.h index 7111a4c9113b..74d948f5d5a1 100644 --- a/net/sunrpc/netns.h +++ b/net/sunrpc/netns.h | |||
@@ -28,7 +28,11 @@ struct sunrpc_net { | |||
28 | wait_queue_head_t gssp_wq; | 28 | wait_queue_head_t gssp_wq; |
29 | struct rpc_clnt *gssp_clnt; | 29 | struct rpc_clnt *gssp_clnt; |
30 | int use_gss_proxy; | 30 | int use_gss_proxy; |
31 | int pipe_version; | ||
32 | atomic_t pipe_users; | ||
31 | struct proc_dir_entry *use_gssp_proc; | 33 | struct proc_dir_entry *use_gssp_proc; |
34 | |||
35 | unsigned int gssd_running; | ||
32 | }; | 36 | }; |
33 | 37 | ||
34 | extern int sunrpc_net_id; | 38 | extern int sunrpc_net_id; |
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index a9129f8d7070..e7ce4b3eb0bd 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c | |||
@@ -216,11 +216,14 @@ rpc_destroy_inode(struct inode *inode) | |||
216 | static int | 216 | static int |
217 | rpc_pipe_open(struct inode *inode, struct file *filp) | 217 | rpc_pipe_open(struct inode *inode, struct file *filp) |
218 | { | 218 | { |
219 | struct net *net = inode->i_sb->s_fs_info; | ||
220 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
219 | struct rpc_pipe *pipe; | 221 | struct rpc_pipe *pipe; |
220 | int first_open; | 222 | int first_open; |
221 | int res = -ENXIO; | 223 | int res = -ENXIO; |
222 | 224 | ||
223 | mutex_lock(&inode->i_mutex); | 225 | mutex_lock(&inode->i_mutex); |
226 | sn->gssd_running = 1; | ||
224 | pipe = RPC_I(inode)->pipe; | 227 | pipe = RPC_I(inode)->pipe; |
225 | if (pipe == NULL) | 228 | if (pipe == NULL) |
226 | goto out; | 229 | goto out; |
@@ -1069,6 +1072,8 @@ void rpc_pipefs_init_net(struct net *net) | |||
1069 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | 1072 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); |
1070 | 1073 | ||
1071 | mutex_init(&sn->pipefs_sb_lock); | 1074 | mutex_init(&sn->pipefs_sb_lock); |
1075 | sn->gssd_running = 1; | ||
1076 | sn->pipe_version = -1; | ||
1072 | } | 1077 | } |
1073 | 1078 | ||
1074 | /* | 1079 | /* |
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index f8529fc8e542..5356b120dbf8 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c | |||
@@ -324,11 +324,17 @@ EXPORT_SYMBOL_GPL(__rpc_wait_for_completion_task); | |||
324 | * Note: If the task is ASYNC, and is being made runnable after sitting on an | 324 | * Note: If the task is ASYNC, and is being made runnable after sitting on an |
325 | * rpc_wait_queue, this must be called with the queue spinlock held to protect | 325 | * rpc_wait_queue, this must be called with the queue spinlock held to protect |
326 | * the wait queue operation. | 326 | * the wait queue operation. |
327 | * Note the ordering of rpc_test_and_set_running() and rpc_clear_queued(), | ||
328 | * which is needed to ensure that __rpc_execute() doesn't loop (due to the | ||
329 | * lockless RPC_IS_QUEUED() test) before we've had a chance to test | ||
330 | * the RPC_TASK_RUNNING flag. | ||
327 | */ | 331 | */ |
328 | static void rpc_make_runnable(struct rpc_task *task) | 332 | static void rpc_make_runnable(struct rpc_task *task) |
329 | { | 333 | { |
334 | bool need_wakeup = !rpc_test_and_set_running(task); | ||
335 | |||
330 | rpc_clear_queued(task); | 336 | rpc_clear_queued(task); |
331 | if (rpc_test_and_set_running(task)) | 337 | if (!need_wakeup) |
332 | return; | 338 | return; |
333 | if (RPC_IS_ASYNC(task)) { | 339 | if (RPC_IS_ASYNC(task)) { |
334 | INIT_WORK(&task->u.tk_work, rpc_async_schedule); | 340 | INIT_WORK(&task->u.tk_work, rpc_async_schedule); |
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c index c3f9e1ef7f53..06bdf5a1082c 100644 --- a/net/sunrpc/svcauth_unix.c +++ b/net/sunrpc/svcauth_unix.c | |||
@@ -810,11 +810,15 @@ svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp) | |||
810 | goto badcred; | 810 | goto badcred; |
811 | argv->iov_base = (void*)((__be32*)argv->iov_base + slen); /* skip machname */ | 811 | argv->iov_base = (void*)((__be32*)argv->iov_base + slen); /* skip machname */ |
812 | argv->iov_len -= slen*4; | 812 | argv->iov_len -= slen*4; |
813 | 813 | /* | |
814 | * Note: we skip uid_valid()/gid_valid() checks here for | ||
815 | * backwards compatibility with clients that use -1 id's. | ||
816 | * Instead, -1 uid or gid is later mapped to the | ||
817 | * (export-specific) anonymous id by nfsd_setuser. | ||
818 | * Supplementary gid's will be left alone. | ||
819 | */ | ||
814 | cred->cr_uid = make_kuid(&init_user_ns, svc_getnl(argv)); /* uid */ | 820 | cred->cr_uid = make_kuid(&init_user_ns, svc_getnl(argv)); /* uid */ |
815 | cred->cr_gid = make_kgid(&init_user_ns, svc_getnl(argv)); /* gid */ | 821 | cred->cr_gid = make_kgid(&init_user_ns, svc_getnl(argv)); /* gid */ |
816 | if (!uid_valid(cred->cr_uid) || !gid_valid(cred->cr_gid)) | ||
817 | goto badcred; | ||
818 | slen = svc_getnl(argv); /* gids length */ | 822 | slen = svc_getnl(argv); /* gids length */ |
819 | if (slen > 16 || (len -= (slen + 2)*4) < 0) | 823 | if (slen > 16 || (len -= (slen + 2)*4) < 0) |
820 | goto badcred; | 824 | goto badcred; |
@@ -823,8 +827,6 @@ svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp) | |||
823 | return SVC_CLOSE; | 827 | return SVC_CLOSE; |
824 | for (i = 0; i < slen; i++) { | 828 | for (i = 0; i < slen; i++) { |
825 | kgid_t kgid = make_kgid(&init_user_ns, svc_getnl(argv)); | 829 | kgid_t kgid = make_kgid(&init_user_ns, svc_getnl(argv)); |
826 | if (!gid_valid(kgid)) | ||
827 | goto badcred; | ||
828 | GROUP_AT(cred->cr_group_info, i) = kgid; | 830 | GROUP_AT(cred->cr_group_info, i) = kgid; |
829 | } | 831 | } |
830 | if (svc_getu32(argv) != htonl(RPC_AUTH_NULL) || svc_getu32(argv) != 0) { | 832 | if (svc_getu32(argv) != htonl(RPC_AUTH_NULL) || svc_getu32(argv) != 0) { |