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) { |
