Skip to content

Commit 0e81cfd

Browse files
q2vendavem330
authored andcommitted
af_unix: Move SOCK_PASS{CRED,PIDFD,SEC} to struct sock.
As explained in the next patch, SO_PASSRIGHTS would have a problem if we assigned a corresponding bit to socket->flags, so it must be managed in struct sock. Mixing socket->flags and sk->sk_flags for similar options will look confusing, and sk->sk_flags does not have enough space on 32bit system. Also, as mentioned in commit 16e5726 ("af_unix: dont send SCM_CREDENTIALS by default"), SOCK_PASSCRED and SOCK_PASSPID handling is known to be slow, and managing the flags in struct socket cannot avoid that for embryo sockets. Let's move SOCK_PASS{CRED,PIDFD,SEC} to struct sock. While at it, other SOCK_XXX flags in net.h are grouped as enum. Note that assign_bit() was atomic, so the writer side is moved down after lock_sock() in setsockopt(), but the bit is only read once in sendmsg() and recvmsg(), so lock_sock() is not needed there. Signed-off-by: Kuniyuki Iwashima <[email protected]> Reviewed-by: Willem de Bruijn <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 7d8d93f commit 0e81cfd

File tree

5 files changed

+61
-61
lines changed

5 files changed

+61
-61
lines changed

include/linux/net.h

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,13 @@ struct net;
3636
* in sock->flags, but moved into sk->sk_wq->flags to be RCU protected.
3737
* Eventually all flags will be in sk->sk_wq->flags.
3838
*/
39-
#define SOCKWQ_ASYNC_NOSPACE 0
40-
#define SOCKWQ_ASYNC_WAITDATA 1
41-
#define SOCK_NOSPACE 2
42-
#define SOCK_PASSCRED 3
43-
#define SOCK_PASSSEC 4
44-
#define SOCK_SUPPORT_ZC 5
45-
#define SOCK_CUSTOM_SOCKOPT 6
46-
#define SOCK_PASSPIDFD 7
39+
enum socket_flags {
40+
SOCKWQ_ASYNC_NOSPACE,
41+
SOCKWQ_ASYNC_WAITDATA,
42+
SOCK_NOSPACE,
43+
SOCK_SUPPORT_ZC,
44+
SOCK_CUSTOM_SOCKOPT,
45+
};
4746

4847
#ifndef ARCH_HAS_SOCKET_TYPES
4948
/**

include/net/sock.h

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,11 @@ struct sk_filter;
337337
* @sk_txtime_deadline_mode: set deadline mode for SO_TXTIME
338338
* @sk_txtime_report_errors: set report errors mode for SO_TXTIME
339339
* @sk_txtime_unused: unused txtime flags
340+
* @sk_scm_recv_flags: all flags used by scm_recv()
341+
* @sk_scm_credentials: flagged by SO_PASSCRED to recv SCM_CREDENTIALS
342+
* @sk_scm_security: flagged by SO_PASSSEC to recv SCM_SECURITY
343+
* @sk_scm_pidfd: flagged by SO_PASSPIDFD to recv SCM_PIDFD
344+
* @sk_scm_unused: unused flags for scm_recv()
340345
* @ns_tracker: tracker for netns reference
341346
* @sk_user_frags: xarray of pages the user is holding a reference on.
342347
* @sk_owner: reference to the real owner of the socket that calls
@@ -523,7 +528,16 @@ struct sock {
523528
#endif
524529
int sk_disconnects;
525530

526-
u8 sk_txrehash;
531+
union {
532+
u8 sk_txrehash;
533+
u8 sk_scm_recv_flags;
534+
struct {
535+
u8 sk_scm_credentials : 1,
536+
sk_scm_security : 1,
537+
sk_scm_pidfd : 1,
538+
sk_scm_unused : 5;
539+
};
540+
};
527541
u8 sk_clockid;
528542
u8 sk_txtime_deadline_mode : 1,
529543
sk_txtime_report_errors : 1,

net/core/scm.c

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -406,12 +406,12 @@ struct scm_fp_list *scm_fp_dup(struct scm_fp_list *fpl)
406406
EXPORT_SYMBOL(scm_fp_dup);
407407

408408
#ifdef CONFIG_SECURITY_NETWORK
409-
static void scm_passec(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm)
409+
static void scm_passec(struct sock *sk, struct msghdr *msg, struct scm_cookie *scm)
410410
{
411411
struct lsm_context ctx;
412412
int err;
413413

414-
if (test_bit(SOCK_PASSSEC, &sock->flags)) {
414+
if (sk->sk_scm_security) {
415415
err = security_secid_to_secctx(scm->secid, &ctx);
416416

417417
if (err >= 0) {
@@ -423,16 +423,16 @@ static void scm_passec(struct socket *sock, struct msghdr *msg, struct scm_cooki
423423
}
424424
}
425425

426-
static bool scm_has_secdata(struct socket *sock)
426+
static bool scm_has_secdata(struct sock *sk)
427427
{
428-
return test_bit(SOCK_PASSSEC, &sock->flags);
428+
return sk->sk_scm_security;
429429
}
430430
#else
431-
static void scm_passec(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm)
431+
static void scm_passec(struct sock *sk, struct msghdr *msg, struct scm_cookie *scm)
432432
{
433433
}
434434

435-
static bool scm_has_secdata(struct socket *sock)
435+
static bool scm_has_secdata(struct sock *sk)
436436
{
437437
return false;
438438
}
@@ -474,20 +474,19 @@ static void scm_pidfd_recv(struct msghdr *msg, struct scm_cookie *scm)
474474
fd_install(pidfd, pidfd_file);
475475
}
476476

477-
static bool __scm_recv_common(struct socket *sock, struct msghdr *msg,
477+
static bool __scm_recv_common(struct sock *sk, struct msghdr *msg,
478478
struct scm_cookie *scm, int flags)
479479
{
480480
if (!msg->msg_control) {
481-
if (test_bit(SOCK_PASSCRED, &sock->flags) ||
482-
test_bit(SOCK_PASSPIDFD, &sock->flags) ||
483-
scm->fp || scm_has_secdata(sock))
481+
if (sk->sk_scm_credentials || sk->sk_scm_pidfd ||
482+
scm->fp || scm_has_secdata(sk))
484483
msg->msg_flags |= MSG_CTRUNC;
485484

486485
scm_destroy(scm);
487486
return false;
488487
}
489488

490-
if (test_bit(SOCK_PASSCRED, &sock->flags)) {
489+
if (sk->sk_scm_credentials) {
491490
struct user_namespace *current_ns = current_user_ns();
492491
struct ucred ucreds = {
493492
.pid = scm->creds.pid,
@@ -498,7 +497,7 @@ static bool __scm_recv_common(struct socket *sock, struct msghdr *msg,
498497
put_cmsg(msg, SOL_SOCKET, SCM_CREDENTIALS, sizeof(ucreds), &ucreds);
499498
}
500499

501-
scm_passec(sock, msg, scm);
500+
scm_passec(sk, msg, scm);
502501

503502
if (scm->fp)
504503
scm_detach_fds(msg, scm);
@@ -509,7 +508,7 @@ static bool __scm_recv_common(struct socket *sock, struct msghdr *msg,
509508
void scm_recv(struct socket *sock, struct msghdr *msg,
510509
struct scm_cookie *scm, int flags)
511510
{
512-
if (!__scm_recv_common(sock, msg, scm, flags))
511+
if (!__scm_recv_common(sock->sk, msg, scm, flags))
513512
return;
514513

515514
scm_destroy_cred(scm);
@@ -519,10 +518,10 @@ EXPORT_SYMBOL(scm_recv);
519518
void scm_recv_unix(struct socket *sock, struct msghdr *msg,
520519
struct scm_cookie *scm, int flags)
521520
{
522-
if (!__scm_recv_common(sock, msg, scm, flags))
521+
if (!__scm_recv_common(sock->sk, msg, scm, flags))
523522
return;
524523

525-
if (test_bit(SOCK_PASSPIDFD, &sock->flags))
524+
if (sock->sk->sk_scm_pidfd)
526525
scm_pidfd_recv(msg, scm);
527526

528527
scm_destroy_cred(scm);

net/core/sock.c

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1220,24 +1220,6 @@ int sk_setsockopt(struct sock *sk, int level, int optname,
12201220
return 0;
12211221
}
12221222
return -EPERM;
1223-
case SO_PASSSEC:
1224-
if (!IS_ENABLED(CONFIG_SECURITY_NETWORK) || sk_may_scm_recv(sk))
1225-
return -EOPNOTSUPP;
1226-
1227-
assign_bit(SOCK_PASSSEC, &sock->flags, valbool);
1228-
return 0;
1229-
case SO_PASSCRED:
1230-
if (!sk_may_scm_recv(sk))
1231-
return -EOPNOTSUPP;
1232-
1233-
assign_bit(SOCK_PASSCRED, &sock->flags, valbool);
1234-
return 0;
1235-
case SO_PASSPIDFD:
1236-
if (!sk_is_unix(sk))
1237-
return -EOPNOTSUPP;
1238-
1239-
assign_bit(SOCK_PASSPIDFD, &sock->flags, valbool);
1240-
return 0;
12411223
case SO_TYPE:
12421224
case SO_PROTOCOL:
12431225
case SO_DOMAIN:
@@ -1568,6 +1550,26 @@ int sk_setsockopt(struct sock *sk, int level, int optname,
15681550
sock_valbool_flag(sk, SOCK_SELECT_ERR_QUEUE, valbool);
15691551
break;
15701552

1553+
case SO_PASSCRED:
1554+
if (sk_may_scm_recv(sk))
1555+
sk->sk_scm_credentials = valbool;
1556+
else
1557+
ret = -EOPNOTSUPP;
1558+
break;
1559+
1560+
case SO_PASSSEC:
1561+
if (IS_ENABLED(CONFIG_SECURITY_NETWORK) && sk_may_scm_recv(sk))
1562+
sk->sk_scm_security = valbool;
1563+
else
1564+
ret = -EOPNOTSUPP;
1565+
break;
1566+
1567+
case SO_PASSPIDFD:
1568+
if (sk_is_unix(sk))
1569+
sk->sk_scm_pidfd = valbool;
1570+
else
1571+
ret = -EOPNOTSUPP;
1572+
break;
15711573

15721574
case SO_INCOMING_CPU:
15731575
reuseport_update_incoming_cpu(sk, val);
@@ -1867,14 +1869,14 @@ int sk_getsockopt(struct sock *sk, int level, int optname,
18671869
if (!sk_may_scm_recv(sk))
18681870
return -EOPNOTSUPP;
18691871

1870-
v.val = !!test_bit(SOCK_PASSCRED, &sock->flags);
1872+
v.val = sk->sk_scm_credentials;
18711873
break;
18721874

18731875
case SO_PASSPIDFD:
18741876
if (!sk_is_unix(sk))
18751877
return -EOPNOTSUPP;
18761878

1877-
v.val = !!test_bit(SOCK_PASSPIDFD, &sock->flags);
1879+
v.val = sk->sk_scm_pidfd;
18781880
break;
18791881

18801882
case SO_PEERCRED:
@@ -1974,7 +1976,7 @@ int sk_getsockopt(struct sock *sk, int level, int optname,
19741976
if (!IS_ENABLED(CONFIG_SECURITY_NETWORK) || !sk_may_scm_recv(sk))
19751977
return -EOPNOTSUPP;
19761978

1977-
v.val = !!test_bit(SOCK_PASSSEC, &sock->flags);
1979+
v.val = sk->sk_scm_security;
19781980
break;
19791981

19801982
case SO_PEERSEC:

net/unix/af_unix.c

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -767,10 +767,7 @@ static void copy_peercred(struct sock *sk, struct sock *peersk)
767767

768768
static bool unix_may_passcred(const struct sock *sk)
769769
{
770-
struct socket *sock = sk->sk_socket;
771-
772-
return test_bit(SOCK_PASSCRED, &sock->flags) ||
773-
test_bit(SOCK_PASSPIDFD, &sock->flags);
770+
return sk->sk_scm_credentials || sk->sk_scm_pidfd;
774771
}
775772

776773
static int unix_listen(struct socket *sock, int backlog)
@@ -1713,17 +1710,6 @@ static int unix_socketpair(struct socket *socka, struct socket *sockb)
17131710
return 0;
17141711
}
17151712

1716-
static void unix_sock_inherit_flags(const struct socket *old,
1717-
struct socket *new)
1718-
{
1719-
if (test_bit(SOCK_PASSCRED, &old->flags))
1720-
set_bit(SOCK_PASSCRED, &new->flags);
1721-
if (test_bit(SOCK_PASSPIDFD, &old->flags))
1722-
set_bit(SOCK_PASSPIDFD, &new->flags);
1723-
if (test_bit(SOCK_PASSSEC, &old->flags))
1724-
set_bit(SOCK_PASSSEC, &new->flags);
1725-
}
1726-
17271713
static int unix_accept(struct socket *sock, struct socket *newsock,
17281714
struct proto_accept_arg *arg)
17291715
{
@@ -1760,7 +1746,7 @@ static int unix_accept(struct socket *sock, struct socket *newsock,
17601746
unix_state_lock(tsk);
17611747
unix_update_edges(unix_sk(tsk));
17621748
newsock->state = SS_CONNECTED;
1763-
unix_sock_inherit_flags(sock, newsock);
1749+
tsk->sk_scm_recv_flags = READ_ONCE(sk->sk_scm_recv_flags);
17641750
sock_graft(tsk, newsock);
17651751
unix_state_unlock(tsk);
17661752
return 0;

0 commit comments

Comments
 (0)