diff --git a/include/linux/netfilter/xt_qtaguid.h b/include/linux/netfilter/xt_qtaguid.h index adb2e4c393923bd8638555c282b5859e5add2ce3..ca60fbdec2f3b056bce47d1c0fe743f7d4712db9 100644 --- a/include/linux/netfilter/xt_qtaguid.h +++ b/include/linux/netfilter/xt_qtaguid.h @@ -10,5 +10,4 @@ #define XT_QTAGUID_SOCKET XT_OWNER_SOCKET #define xt_qtaguid_match_info xt_owner_match_info -int qtaguid_untag(struct socket *sock); #endif /* _XT_QTAGUID_MATCH_H */ diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index c312db43d6cf4104d01581fe56f68af61e26df4e..db333aa0abf8a440999da90aec3e88720d6c4888 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -89,7 +89,6 @@ #include <linux/netfilter_ipv4.h> #include <linux/random.h> #include <linux/slab.h> -#include <linux/netfilter/xt_qtaguid.h> #include <asm/uaccess.h> @@ -418,9 +417,6 @@ int inet_release(struct socket *sock) if (sk) { long timeout; -#ifdef CONFIG_NETFILTER_XT_MATCH_QTAGUID - qtaguid_untag(sock); -#endif sock_rps_reset_flow(sk); /* Applications forget to leave groups before exiting */ diff --git a/net/netfilter/xt_qtaguid.c b/net/netfilter/xt_qtaguid.c index c260adc0fd86311e03c68967e9681069565db64b..dee6af5d759548e0505f5635ed14166a39b60320 100644 --- a/net/netfilter/xt_qtaguid.c +++ b/net/netfilter/xt_qtaguid.c @@ -320,7 +320,7 @@ static void sock_tag_tree_erase(struct rb_root *st_to_free_tree) st_entry->tag, get_uid_from_tag(st_entry->tag)); rb_erase(&st_entry->sock_node, st_to_free_tree); - sock_put(st_entry->sk); + sockfd_put(st_entry->socket); kfree(st_entry); } } @@ -1917,12 +1917,12 @@ static int qtaguid_ctrl_proc_show(struct seq_file *m, void *v) { struct sock_tag *sock_tag_entry = v; uid_t uid; + long f_count; CT_DEBUG("qtaguid: proc ctrl pid=%u tgid=%u uid=%u\n", current->pid, current->tgid, from_kuid(&init_user_ns, current_fsuid())); if (sock_tag_entry != SEQ_START_TOKEN) { - int sk_ref_count; uid = get_uid_from_tag(sock_tag_entry->tag); CT_DEBUG("qtaguid: proc_read(): sk=%p tag=0x%llx (uid=%u) " "pid=%u\n", @@ -1931,13 +1931,13 @@ static int qtaguid_ctrl_proc_show(struct seq_file *m, void *v) uid, sock_tag_entry->pid ); - sk_ref_count = atomic_read( - &sock_tag_entry->sk->sk_refcnt); + f_count = atomic_long_read( + &sock_tag_entry->socket->file->f_count); seq_printf(m, "sock=%pK tag=0x%llx (uid=%u) pid=%u " - "f_count=%d\n", + "f_count=%lu\n", sock_tag_entry->sk, sock_tag_entry->tag, uid, - sock_tag_entry->pid, sk_ref_count); + sock_tag_entry->pid, f_count); } else { seq_printf(m, "events: sockets_tagged=%llu " "sockets_untagged=%llu " @@ -2233,8 +2233,8 @@ static int ctrl_cmd_tag(const char *input) from_kuid(&init_user_ns, current_fsuid())); goto err; } - CT_DEBUG("qtaguid: ctrl_tag(%s): socket->...->sk_refcnt=%d ->sk=%p\n", - input, atomic_read(&el_socket->sk->sk_refcnt), + CT_DEBUG("qtaguid: ctrl_tag(%s): socket->...->f_count=%ld ->sk=%p\n", + input, atomic_long_read(&el_socket->file->f_count), el_socket->sk); if (argc < 3) { acct_tag = make_atag_from_value(0); @@ -2278,9 +2278,16 @@ static int ctrl_cmd_tag(const char *input) struct tag_ref *prev_tag_ref_entry; CT_DEBUG("qtaguid: ctrl_tag(%s): retag for sk=%p " - "st@%p ...->sk_refcnt=%d\n", + "st@%p ...->f_count=%ld\n", input, el_socket->sk, sock_tag_entry, - atomic_read(&el_socket->sk->sk_refcnt)); + atomic_long_read(&el_socket->file->f_count)); + /* + * This is a re-tagging, so release the sock_fd that was + * locked at the time of the 1st tagging. + * There is still the ref from this call's sockfd_lookup() so + * it can be done within the spinlock. + */ + sockfd_put(sock_tag_entry->socket); prev_tag_ref_entry = lookup_tag_ref(sock_tag_entry->tag, &uid_tag_data_entry); BUG_ON(IS_ERR_OR_NULL(prev_tag_ref_entry)); @@ -2300,12 +2307,8 @@ static int ctrl_cmd_tag(const char *input) res = -ENOMEM; goto err_tag_unref_put; } - /* - * Hold the sk refcount here to make sure the sk pointer cannot - * be freed and reused - */ - sock_hold(el_socket->sk); sock_tag_entry->sk = el_socket->sk; + sock_tag_entry->socket = el_socket; sock_tag_entry->pid = current->tgid; sock_tag_entry->tag = combine_atag_with_uid(acct_tag, uid_int); spin_lock_bh(&uid_tag_data_tree_lock); @@ -2332,11 +2335,10 @@ static int ctrl_cmd_tag(const char *input) atomic64_inc(&qtu_events.sockets_tagged); } spin_unlock_bh(&sock_tag_list_lock); - /* We keep the ref to the sk until it is untagged */ - CT_DEBUG("qtaguid: ctrl_tag(%s): done st@%p ...->sk_refcnt=%d\n", + /* We keep the ref to the socket (file) until it is untagged */ + CT_DEBUG("qtaguid: ctrl_tag(%s): done st@%p ...->f_count=%ld\n", input, sock_tag_entry, - atomic_read(&el_socket->sk->sk_refcnt)); - sockfd_put(el_socket); + atomic_long_read(&el_socket->file->f_count)); return 0; err_tag_unref_put: @@ -2344,8 +2346,8 @@ err_tag_unref_put: tag_ref_entry->num_sock_tags--; free_tag_ref_from_utd_entry(tag_ref_entry, uid_tag_data_entry); err_put: - CT_DEBUG("qtaguid: ctrl_tag(%s): done. ...->sk_refcnt=%d\n", - input, atomic_read(&el_socket->sk->sk_refcnt) - 1); + CT_DEBUG("qtaguid: ctrl_tag(%s): done. ...->f_count=%ld\n", + input, atomic_long_read(&el_socket->file->f_count) - 1); /* Release the sock_fd that was grabbed by sockfd_lookup(). */ sockfd_put(el_socket); return res; @@ -2361,6 +2363,10 @@ static int ctrl_cmd_untag(const char *input) int sock_fd = 0; struct socket *el_socket; int res, argc; + struct sock_tag *sock_tag_entry; + struct tag_ref *tag_ref_entry; + struct uid_tag_data *utd_entry; + struct proc_qtu_data *pqd_entry; argc = sscanf(input, "%c %d", &cmd, &sock_fd); CT_DEBUG("qtaguid: ctrl_untag(%s): argc=%d cmd=%c sock_fd=%d\n", @@ -2380,26 +2386,12 @@ static int ctrl_cmd_untag(const char *input) CT_DEBUG("qtaguid: ctrl_untag(%s): socket->...->f_count=%ld ->sk=%p\n", input, atomic_long_read(&el_socket->file->f_count), el_socket->sk); - res = qtaguid_untag(el_socket); - sockfd_put(el_socket); -err: - return res; -} - -int qtaguid_untag(struct socket *el_socket) -{ - int res; - struct sock_tag *sock_tag_entry; - struct tag_ref *tag_ref_entry; - struct uid_tag_data *utd_entry; - struct proc_qtu_data *pqd_entry; - spin_lock_bh(&sock_tag_list_lock); sock_tag_entry = get_sock_stat_nl(el_socket->sk); if (!sock_tag_entry) { spin_unlock_bh(&sock_tag_list_lock); res = -EINVAL; - return res; + goto err_put; } /* * The socket already belongs to the current process @@ -2433,17 +2425,30 @@ int qtaguid_untag(struct socket *el_socket) tag_ref_entry->num_sock_tags--; spin_unlock_bh(&sock_tag_list_lock); /* - * Release the sock_fd that was grabbed at tag time. + * Release the sock_fd that was grabbed at tag time, + * and once more for the sockfd_lookup() here. */ - sock_put(sock_tag_entry->sk); - CT_DEBUG("qtaguid: done. st@%p ...->sk_refcnt=%d\n", - sock_tag_entry, - atomic_read(&el_socket->sk->sk_refcnt)); + sockfd_put(sock_tag_entry->socket); + CT_DEBUG("qtaguid: ctrl_untag(%s): done. st@%p ...->f_count=%ld\n", + input, sock_tag_entry, + atomic_long_read(&el_socket->file->f_count) - 1); + sockfd_put(el_socket); kfree(sock_tag_entry); atomic64_inc(&qtu_events.sockets_untagged); return 0; + +err_put: + CT_DEBUG("qtaguid: ctrl_untag(%s): done. socket->...->f_count=%ld\n", + input, atomic_long_read(&el_socket->file->f_count) - 1); + /* Release the sock_fd that was grabbed by sockfd_lookup(). */ + sockfd_put(el_socket); + return res; + +err: + CT_DEBUG("qtaguid: ctrl_untag(%s): done.\n", input); + return res; } static ssize_t qtaguid_ctrl_parse(const char *input, size_t count) diff --git a/net/netfilter/xt_qtaguid_internal.h b/net/netfilter/xt_qtaguid_internal.h index 8178fbdfb0366b952a36e86138cfc1fa2a4a2bbd..6dc14a9c688966addc6ef949209fa70a70d00024 100644 --- a/net/netfilter/xt_qtaguid_internal.h +++ b/net/netfilter/xt_qtaguid_internal.h @@ -256,6 +256,8 @@ struct iface_stat_work { struct sock_tag { struct rb_node sock_node; struct sock *sk; /* Only used as a number, never dereferenced */ + /* The socket is needed for sockfd_put() */ + struct socket *socket; /* Used to associate with a given pid */ struct list_head list; /* in proc_qtu_data.sock_tag_list */ pid_t pid; diff --git a/net/netfilter/xt_qtaguid_print.c b/net/netfilter/xt_qtaguid_print.c index 2a7190d285e607cd523cbca4bce417fd12933dd5..f6a00a3520ed577218a503f8b0352d2b7f8e5094 100644 --- a/net/netfilter/xt_qtaguid_print.c +++ b/net/netfilter/xt_qtaguid_print.c @@ -24,7 +24,7 @@ #include <linux/rbtree.h> #include <linux/slab.h> #include <linux/spinlock_types.h> -#include <net/sock.h> + #include "xt_qtaguid_internal.h" #include "xt_qtaguid_print.h" @@ -237,10 +237,10 @@ char *pp_sock_tag(struct sock_tag *st) tag_str = pp_tag_t(&st->tag); res = kasprintf(GFP_ATOMIC, "sock_tag@%p{" "sock_node=rb_node{...}, " - "sk=%p (f_count=%d), list=list_head{...}, " + "sk=%p socket=%p (f_count=%lu), list=list_head{...}, " "pid=%u, tag=%s}", - st, st->sk, atomic_read( - &st->sk->sk_refcnt), + st, st->sk, st->socket, atomic_long_read( + &st->socket->file->f_count), st->pid, tag_str); _bug_on_err_or_null(res); kfree(tag_str);