net: inet: diag: expose the socket mark to privileged processes.
[deliverable/linux.git] / net / sctp / sctp_diag.c
index f69edcf219e514d864c4af2d57eb0429e8f4938a..807158e32f5fe5e2028d578ce078bb2d00345b73 100644 (file)
@@ -13,6 +13,7 @@ static void inet_diag_msg_sctpasoc_fill(struct inet_diag_msg *r,
 {
        union sctp_addr laddr, paddr;
        struct dst_entry *dst;
+       struct timer_list *t3_rtx = &asoc->peer.primary_path->T3_rtx_timer;
 
        laddr = list_entry(asoc->base.bind_addr.address_list.next,
                           struct sctp_sockaddr_entry, list)->a;
@@ -40,10 +41,15 @@ static void inet_diag_msg_sctpasoc_fill(struct inet_diag_msg *r,
        }
 
        r->idiag_state = asoc->state;
-       r->idiag_timer = SCTP_EVENT_TIMEOUT_T3_RTX;
-       r->idiag_retrans = asoc->rtx_data_chunks;
-       r->idiag_expires = jiffies_to_msecs(
-               asoc->timeouts[SCTP_EVENT_TIMEOUT_T3_RTX] - jiffies);
+       if (timer_pending(t3_rtx)) {
+               r->idiag_timer = SCTP_EVENT_TIMEOUT_T3_RTX;
+               r->idiag_retrans = asoc->rtx_data_chunks;
+               r->idiag_expires = jiffies_to_msecs(t3_rtx->expires - jiffies);
+       } else {
+               r->idiag_timer = 0;
+               r->idiag_retrans = 0;
+               r->idiag_expires = 0;
+       }
 }
 
 static int inet_diag_msg_sctpladdrs_fill(struct sk_buff *skb,
@@ -100,7 +106,8 @@ static int inet_sctp_diag_fill(struct sock *sk, struct sctp_association *asoc,
                               const struct inet_diag_req_v2 *req,
                               struct user_namespace *user_ns,
                               int portid, u32 seq, u16 nlmsg_flags,
-                              const struct nlmsghdr *unlh)
+                              const struct nlmsghdr *unlh,
+                              bool net_admin)
 {
        struct sctp_endpoint *ep = sctp_sk(sk)->ep;
        struct list_head *addr_list;
@@ -127,7 +134,7 @@ static int inet_sctp_diag_fill(struct sock *sk, struct sctp_association *asoc,
                r->idiag_retrans = 0;
        }
 
-       if (inet_diag_msg_attrs_fill(sk, skb, r, ext, user_ns))
+       if (inet_diag_msg_attrs_fill(sk, skb, r, ext, user_ns, net_admin))
                goto errout;
 
        if (ext & (1 << (INET_DIAG_SKMEMINFO - 1))) {
@@ -197,6 +204,7 @@ struct sctp_comm_param {
        struct netlink_callback *cb;
        const struct inet_diag_req_v2 *r;
        const struct nlmsghdr *nlh;
+       bool net_admin;
 };
 
 static size_t inet_assoc_attr_size(struct sctp_association *asoc)
@@ -213,6 +221,7 @@ static size_t inet_assoc_attr_size(struct sctp_association *asoc)
                + nla_total_size(1) /* INET_DIAG_SHUTDOWN */
                + nla_total_size(1) /* INET_DIAG_TOS */
                + nla_total_size(1) /* INET_DIAG_TCLASS */
+               + nla_total_size(4) /* INET_DIAG_MARK */
                + nla_total_size(addrlen * asoc->peer.transport_count)
                + nla_total_size(addrlen * addrcnt)
                + nla_total_size(sizeof(struct inet_diag_meminfo))
@@ -250,7 +259,8 @@ static int sctp_tsp_dump_one(struct sctp_transport *tsp, void *p)
        err = inet_sctp_diag_fill(sk, assoc, rep, req,
                                  sk_user_ns(NETLINK_CB(in_skb).sk),
                                  NETLINK_CB(in_skb).portid,
-                                 nlh->nlmsg_seq, 0, nlh);
+                                 nlh->nlmsg_seq, 0, nlh,
+                                 commp->net_admin);
        release_sock(sk);
        if (err < 0) {
                WARN_ON(err == -EMSGSIZE);
@@ -304,7 +314,8 @@ static int sctp_tsp_dump(struct sctp_transport *tsp, void *p)
                                        sk_user_ns(NETLINK_CB(cb->skb).sk),
                                        NETLINK_CB(cb->skb).portid,
                                        cb->nlh->nlmsg_seq,
-                                       NLM_F_MULTI, cb->nlh) < 0) {
+                                       NLM_F_MULTI, cb->nlh,
+                                       commp->net_admin) < 0) {
                        cb->args[3] = 1;
                        err = 2;
                        goto release;
@@ -314,7 +325,8 @@ static int sctp_tsp_dump(struct sctp_transport *tsp, void *p)
                if (inet_sctp_diag_fill(sk, assoc, skb, r,
                                        sk_user_ns(NETLINK_CB(cb->skb).sk),
                                        NETLINK_CB(cb->skb).portid,
-                                       cb->nlh->nlmsg_seq, 0, cb->nlh) < 0) {
+                                       cb->nlh->nlmsg_seq, 0, cb->nlh,
+                                       commp->net_admin) < 0) {
                        err = 2;
                        goto release;
                }
@@ -350,7 +362,7 @@ static int sctp_ep_dump(struct sctp_endpoint *ep, void *p)
        if (cb->args[4] < cb->args[1])
                goto next;
 
-       if ((r->idiag_states & ~TCPF_LISTEN) && !list_empty(&ep->asocs))
+       if (!(r->idiag_states & TCPF_LISTEN) && !list_empty(&ep->asocs))
                goto next;
 
        if (r->sdiag_family != AF_UNSPEC &&
@@ -369,7 +381,7 @@ static int sctp_ep_dump(struct sctp_endpoint *ep, void *p)
                                sk_user_ns(NETLINK_CB(cb->skb).sk),
                                NETLINK_CB(cb->skb).portid,
                                cb->nlh->nlmsg_seq, NLM_F_MULTI,
-                               cb->nlh) < 0) {
+                               cb->nlh, commp->net_admin) < 0) {
                err = 2;
                goto out;
        }
@@ -406,6 +418,7 @@ static int sctp_diag_dump_one(struct sk_buff *in_skb,
                .skb = in_skb,
                .r = req,
                .nlh = nlh,
+               .net_admin = netlink_net_capable(in_skb, CAP_NET_ADMIN),
        };
 
        if (req->sdiag_family == AF_INET) {
@@ -418,11 +431,13 @@ static int sctp_diag_dump_one(struct sk_buff *in_skb,
                paddr.v4.sin_family = AF_INET;
        } else {
                laddr.v6.sin6_port = req->id.idiag_sport;
-               memcpy(&laddr.v6.sin6_addr, req->id.idiag_src, 64);
+               memcpy(&laddr.v6.sin6_addr, req->id.idiag_src,
+                      sizeof(laddr.v6.sin6_addr));
                laddr.v6.sin6_family = AF_INET6;
 
                paddr.v6.sin6_port = req->id.idiag_dport;
-               memcpy(&paddr.v6.sin6_addr, req->id.idiag_dst, 64);
+               memcpy(&paddr.v6.sin6_addr, req->id.idiag_dst,
+                      sizeof(paddr.v6.sin6_addr));
                paddr.v6.sin6_family = AF_INET6;
        }
 
@@ -439,6 +454,7 @@ static void sctp_diag_dump(struct sk_buff *skb, struct netlink_callback *cb,
                .skb = skb,
                .cb = cb,
                .r = r,
+               .net_admin = netlink_net_capable(cb->skb, CAP_NET_ADMIN),
        };
 
        /* eps hashtable dumps
@@ -465,7 +481,7 @@ skip:
         * 3 : to mark if we have dumped the ep info of the current asoc
         * 4 : to work as a temporary variable to traversal list
         */
-       if (!(idiag_states & ~TCPF_LISTEN))
+       if (!(idiag_states & ~(TCPF_LISTEN | TCPF_CLOSE)))
                goto done;
        sctp_for_each_transport(sctp_tsp_dump, net, cb->args[2], &commp);
 done:
This page took 0.032484 seconds and 5 git commands to generate.