summaryrefslogtreecommitdiff
path: root/net/unix/af_unix.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/unix/af_unix.c')
-rw-r--r--net/unix/af_unix.c78
1 files changed, 48 insertions, 30 deletions
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 52b155123985..a8895786e016 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -646,9 +646,6 @@ static void unix_sock_destructor(struct sock *sk)
return;
}
- if (sk->sk_peer_pid)
- pidfs_put_pid(sk->sk_peer_pid);
-
if (u->addr)
unix_release_addr(u->addr);
@@ -780,7 +777,6 @@ static void drop_peercred(struct unix_peercred *peercred)
swap(peercred->peer_pid, pid);
swap(peercred->peer_cred, cred);
- pidfs_put_pid(pid);
put_pid(pid);
put_cred(cred);
}
@@ -813,7 +809,6 @@ static void copy_peercred(struct sock *sk, struct sock *peersk)
spin_lock(&sk->sk_peer_lock);
sk->sk_peer_pid = get_pid(peersk->sk_peer_pid);
- pidfs_get_pid(sk->sk_peer_pid);
sk->sk_peer_cred = get_cred(peersk->sk_peer_cred);
spin_unlock(&sk->sk_peer_lock);
}
@@ -1945,7 +1940,7 @@ static void unix_destruct_scm(struct sk_buff *skb)
struct scm_cookie scm;
memset(&scm, 0, sizeof(scm));
- scm.pid = UNIXCB(skb).pid;
+ scm.pid = UNIXCB(skb).pid;
if (UNIXCB(skb).fp)
unix_detach_fds(&scm, skb);
@@ -1971,22 +1966,46 @@ static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool sen
return err;
}
-/*
+static void unix_skb_to_scm(struct sk_buff *skb, struct scm_cookie *scm)
+{
+ scm_set_cred(scm, UNIXCB(skb).pid, UNIXCB(skb).uid, UNIXCB(skb).gid);
+ unix_set_secdata(scm, skb);
+}
+
+/**
+ * unix_maybe_add_creds() - Adds current task uid/gid and struct pid to skb if needed.
+ * @skb: skb to attach creds to.
+ * @sk: Sender sock.
+ * @other: Receiver sock.
+ *
* Some apps rely on write() giving SCM_CREDENTIALS
* We include credentials if source or destination socket
* asserted SOCK_PASSCRED.
+ *
+ * Context: May sleep.
+ * Return: On success zero, on error a negative error code is returned.
*/
-static void unix_maybe_add_creds(struct sk_buff *skb, const struct sock *sk,
- const struct sock *other)
+static int unix_maybe_add_creds(struct sk_buff *skb, const struct sock *sk,
+ const struct sock *other)
{
if (UNIXCB(skb).pid)
- return;
+ return 0;
if (unix_may_passcred(sk) || unix_may_passcred(other) ||
!other->sk_socket) {
- UNIXCB(skb).pid = get_pid(task_tgid(current));
+ struct pid *pid;
+ int err;
+
+ pid = task_tgid(current);
+ err = pidfs_register_pid(pid);
+ if (unlikely(err))
+ return err;
+
+ UNIXCB(skb).pid = get_pid(pid);
current_uid_gid(&UNIXCB(skb).uid, &UNIXCB(skb).gid);
}
+
+ return 0;
}
static bool unix_skb_scm_eq(struct sk_buff *skb,
@@ -2121,6 +2140,10 @@ lookup:
goto out_sock_put;
}
+ err = unix_maybe_add_creds(skb, sk, other);
+ if (err)
+ goto out_sock_put;
+
restart:
sk_locked = 0;
unix_state_lock(other);
@@ -2229,7 +2252,6 @@ restart_locked:
if (sock_flag(other, SOCK_RCVTSTAMP))
__net_timestamp(skb);
- unix_maybe_add_creds(skb, sk, other);
scm_stat_add(other, skb);
skb_queue_tail(&other->sk_receive_queue, skb);
unix_state_unlock(other);
@@ -2273,6 +2295,10 @@ static int queue_oob(struct sock *sk, struct msghdr *msg, struct sock *other,
if (err < 0)
goto out;
+ err = unix_maybe_add_creds(skb, sk, other);
+ if (err)
+ goto out;
+
skb_put(skb, 1);
err = skb_copy_datagram_from_iter(skb, 0, &msg->msg_iter, 1);
@@ -2292,7 +2318,6 @@ static int queue_oob(struct sock *sk, struct msghdr *msg, struct sock *other,
goto out_unlock;
}
- unix_maybe_add_creds(skb, sk, other);
scm_stat_add(other, skb);
spin_lock(&other->sk_receive_queue.lock);
@@ -2386,6 +2411,10 @@ static int unix_stream_sendmsg(struct socket *sock, struct msghdr *msg,
fds_sent = true;
+ err = unix_maybe_add_creds(skb, sk, other);
+ if (err)
+ goto out_free;
+
if (unlikely(msg->msg_flags & MSG_SPLICE_PAGES)) {
skb->ip_summed = CHECKSUM_UNNECESSARY;
err = skb_splice_from_iter(skb, &msg->msg_iter, size,
@@ -2416,7 +2445,6 @@ static int unix_stream_sendmsg(struct socket *sock, struct msghdr *msg,
goto out_free;
}
- unix_maybe_add_creds(skb, sk, other);
scm_stat_add(other, skb);
skb_queue_tail(&other->sk_receive_queue, skb);
unix_state_unlock(other);
@@ -2564,8 +2592,7 @@ int __unix_dgram_recvmsg(struct sock *sk, struct msghdr *msg, size_t size,
memset(&scm, 0, sizeof(scm));
- scm_set_cred(&scm, UNIXCB(skb).pid, UNIXCB(skb).uid, UNIXCB(skb).gid);
- unix_set_secdata(&scm, skb);
+ unix_skb_to_scm(skb, &scm);
if (!(flags & MSG_PEEK)) {
if (UNIXCB(skb).fp)
@@ -2954,8 +2981,7 @@ unlock:
break;
} else if (unix_may_passcred(sk)) {
/* Copy credentials */
- scm_set_cred(&scm, UNIXCB(skb).pid, UNIXCB(skb).uid, UNIXCB(skb).gid);
- unix_set_secdata(&scm, skb);
+ unix_skb_to_scm(skb, &scm);
check_creds = true;
}
@@ -3191,7 +3217,6 @@ EXPORT_SYMBOL_GPL(unix_outq_len);
static int unix_open_file(struct sock *sk)
{
- struct path path;
struct file *f;
int fd;
@@ -3201,27 +3226,20 @@ static int unix_open_file(struct sock *sk)
if (!smp_load_acquire(&unix_sk(sk)->addr))
return -ENOENT;
- path = unix_sk(sk)->path;
- if (!path.dentry)
+ if (!unix_sk(sk)->path.dentry)
return -ENOENT;
- path_get(&path);
-
fd = get_unused_fd_flags(O_CLOEXEC);
if (fd < 0)
- goto out;
+ return fd;
- f = dentry_open(&path, O_PATH, current_cred());
+ f = dentry_open(&unix_sk(sk)->path, O_PATH, current_cred());
if (IS_ERR(f)) {
put_unused_fd(fd);
- fd = PTR_ERR(f);
- goto out;
+ return PTR_ERR(f);
}
fd_install(fd, f);
-out:
- path_put(&path);
-
return fd;
}