drm/amd/display: Implement bounds check for stream encoder creation in DCN301
[platform/kernel/linux-rpi.git] / kernel / audit.c
index 16205dd..9c8e5f7 100644 (file)
@@ -487,15 +487,19 @@ static void auditd_conn_free(struct rcu_head *rcu)
  * @pid: auditd PID
  * @portid: auditd netlink portid
  * @net: auditd network namespace pointer
+ * @skb: the netlink command from the audit daemon
+ * @ack: netlink ack flag, cleared if ack'd here
  *
  * Description:
  * This function will obtain and drop network namespace references as
  * necessary.  Returns zero on success, negative values on failure.
  */
-static int auditd_set(struct pid *pid, u32 portid, struct net *net)
+static int auditd_set(struct pid *pid, u32 portid, struct net *net,
+                     struct sk_buff *skb, bool *ack)
 {
        unsigned long flags;
        struct auditd_connection *ac_old, *ac_new;
+       struct nlmsghdr *nlh;
 
        if (!pid || !net)
                return -EINVAL;
@@ -507,6 +511,13 @@ static int auditd_set(struct pid *pid, u32 portid, struct net *net)
        ac_new->portid = portid;
        ac_new->net = get_net(net);
 
+       /* send the ack now to avoid a race with the queue backlog */
+       if (*ack) {
+               nlh = nlmsg_hdr(skb);
+               netlink_ack(skb, nlh, 0, NULL);
+               *ack = false;
+       }
+
        spin_lock_irqsave(&auditd_conn_lock, flags);
        ac_old = rcu_dereference_protected(auditd_conn,
                                           lockdep_is_held(&auditd_conn_lock));
@@ -1200,7 +1211,8 @@ static int audit_replace(struct pid *pid)
        return auditd_send_unicast_skb(skb);
 }
 
-static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
+static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh,
+                            bool *ack)
 {
        u32                     seq;
        void                    *data;
@@ -1293,7 +1305,8 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
                                /* register a new auditd connection */
                                err = auditd_set(req_pid,
                                                 NETLINK_CB(skb).portid,
-                                                sock_net(NETLINK_CB(skb).sk));
+                                                sock_net(NETLINK_CB(skb).sk),
+                                                skb, ack);
                                if (audit_enabled != AUDIT_OFF)
                                        audit_log_config_change("audit_pid",
                                                                new_pid,
@@ -1538,9 +1551,10 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
  * Parse the provided skb and deal with any messages that may be present,
  * malformed skbs are discarded.
  */
-static void audit_receive(struct sk_buff  *skb)
+static void audit_receive(struct sk_buff *skb)
 {
        struct nlmsghdr *nlh;
+       bool ack;
        /*
         * len MUST be signed for nlmsg_next to be able to dec it below 0
         * if the nlmsg_len was not aligned
@@ -1553,9 +1567,12 @@ static void audit_receive(struct sk_buff  *skb)
 
        audit_ctl_lock();
        while (nlmsg_ok(nlh, len)) {
-               err = audit_receive_msg(skb, nlh);
-               /* if err or if this message says it wants a response */
-               if (err || (nlh->nlmsg_flags & NLM_F_ACK))
+               ack = nlh->nlmsg_flags & NLM_F_ACK;
+               err = audit_receive_msg(skb, nlh, &ack);
+
+               /* send an ack if the user asked for one and audit_receive_msg
+                * didn't already do it, or if there was an error. */
+               if (ack || err)
                        netlink_ack(skb, nlh, err, NULL);
 
                nlh = nlmsg_next(nlh, &len);