Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
L
lxc
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Chen Yisong
lxc
Commits
780215cf
Unverified
Commit
780215cf
authored
Feb 25, 2021
by
Christian Brauner
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
af_unix: allow caller and callee to negotiate expectations and reality
Signed-off-by:
Christian Brauner
<
christian.brauner@ubuntu.com
>
parent
265dc73a
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
128 additions
and
8 deletions
+128
-8
af_unix.c
src/lxc/af_unix.c
+52
-5
af_unix.h
src/lxc/af_unix.h
+76
-3
No files found.
src/lxc/af_unix.c
View file @
780215cf
...
@@ -113,7 +113,7 @@ int lxc_abstract_unix_connect(const char *path)
...
@@ -113,7 +113,7 @@ int lxc_abstract_unix_connect(const char *path)
}
}
int
lxc_abstract_unix_send_fds_iov
(
int
fd
,
const
int
*
sendfds
,
int
num_sendfds
,
int
lxc_abstract_unix_send_fds_iov
(
int
fd
,
const
int
*
sendfds
,
int
num_sendfds
,
struct
iovec
*
iov
,
size_t
iovlen
)
struct
iovec
*
const
iov
,
size_t
iovlen
)
{
{
__do_free
char
*
cmsgbuf
=
NULL
;
__do_free
char
*
cmsgbuf
=
NULL
;
int
ret
;
int
ret
;
...
@@ -176,6 +176,12 @@ static ssize_t lxc_abstract_unix_recv_fds_iov(int fd,
...
@@ -176,6 +176,12 @@ static ssize_t lxc_abstract_unix_recv_fds_iov(int fd,
size_t
cmsgbufsize
=
CMSG_SPACE
(
sizeof
(
struct
ucred
))
+
size_t
cmsgbufsize
=
CMSG_SPACE
(
sizeof
(
struct
ucred
))
+
CMSG_SPACE
(
ret_fds
->
fd_count_max
*
sizeof
(
int
));
CMSG_SPACE
(
ret_fds
->
fd_count_max
*
sizeof
(
int
));
if
(
ret_fds
->
flags
&
~
UNIX_FDS_ACCEPT_MASK
)
return
ret_errno
(
EINVAL
);
if
(
hweight32
((
ret_fds
->
flags
&
~
UNIX_FDS_ACCEPT_NONE
))
>
1
)
return
ret_errno
(
EINVAL
);
cmsgbuf
=
zalloc
(
cmsgbufsize
);
cmsgbuf
=
zalloc
(
cmsgbufsize
);
if
(
!
cmsgbuf
)
if
(
!
cmsgbuf
)
return
ret_errno
(
ENOMEM
);
return
ret_errno
(
ENOMEM
);
...
@@ -202,7 +208,7 @@ again:
...
@@ -202,7 +208,7 @@ again:
if
(
cmsg
->
cmsg_level
==
SOL_SOCKET
&&
cmsg
->
cmsg_type
==
SCM_RIGHTS
)
{
if
(
cmsg
->
cmsg_level
==
SOL_SOCKET
&&
cmsg
->
cmsg_type
==
SCM_RIGHTS
)
{
__u32
idx
;
__u32
idx
;
/*
/*
* This causes some compilers to complain
g
about
* This causes some compilers to complain about
* increased alignment requirements but I haven't found
* increased alignment requirements but I haven't found
* a better way to deal with this yet. Suggestions
* a better way to deal with this yet. Suggestions
* welcome!
* welcome!
...
@@ -225,7 +231,22 @@ again:
...
@@ -225,7 +231,22 @@ again:
return
syserrno_set
(
-
EFBIG
,
"Received excessive number of file descriptors"
);
return
syserrno_set
(
-
EFBIG
,
"Received excessive number of file descriptors"
);
}
}
if
(
msg
.
msg_flags
&
MSG_CTRUNC
)
{
for
(
idx
=
0
;
idx
<
num_raw
;
idx
++
)
close
(
fds_raw
[
idx
]);
return
syserrno_set
(
-
EFBIG
,
"Control message was truncated; closing all fds and rejecting incomplete message"
);
}
if
(
ret_fds
->
fd_count_max
>
num_raw
)
{
if
(
ret_fds
->
fd_count_max
>
num_raw
)
{
if
(
!
(
ret_fds
->
flags
&
UNIX_FDS_ACCEPT_LESS
))
{
for
(
idx
=
0
;
idx
<
num_raw
;
idx
++
)
close
(
fds_raw
[
idx
]);
return
syserrno_set
(
-
EINVAL
,
"Received fewer file descriptors than we expected %u != %u"
,
ret_fds
->
fd_count_max
,
num_raw
);
}
/*
/*
* Make sure any excess entries in the fd array
* Make sure any excess entries in the fd array
* are set to -EBADF so our cleanup functions
* are set to -EBADF so our cleanup functions
...
@@ -234,16 +255,33 @@ again:
...
@@ -234,16 +255,33 @@ again:
for
(
idx
=
num_raw
;
idx
<
ret_fds
->
fd_count_max
;
idx
++
)
for
(
idx
=
num_raw
;
idx
<
ret_fds
->
fd_count_max
;
idx
++
)
ret_fds
->
fd
[
idx
]
=
-
EBADF
;
ret_fds
->
fd
[
idx
]
=
-
EBADF
;
WARN
(
"Received fewer file descriptors than we expected %u != %u"
,
ret_fds
->
fd_count_max
,
num_raw
)
;
ret_fds
->
flags
|=
UNIX_FDS_RECEIVED_LESS
;
}
else
if
(
ret_fds
->
fd_count_max
<
num_raw
)
{
}
else
if
(
ret_fds
->
fd_count_max
<
num_raw
)
{
if
(
!
(
ret_fds
->
flags
&
UNIX_FDS_ACCEPT_MORE
))
{
for
(
idx
=
0
;
idx
<
num_raw
;
idx
++
)
close
(
fds_raw
[
idx
]);
return
syserrno_set
(
-
EINVAL
,
"Received more file descriptors than we expected %u != %u"
,
ret_fds
->
fd_count_max
,
num_raw
);
}
/* Make sure we close any excess fds we received. */
/* Make sure we close any excess fds we received. */
for
(
idx
=
ret_fds
->
fd_count_max
;
idx
<
num_raw
;
idx
++
)
for
(
idx
=
ret_fds
->
fd_count_max
;
idx
<
num_raw
;
idx
++
)
close
(
fds_raw
[
idx
]);
close
(
fds_raw
[
idx
]);
WARN
(
"Received more file descriptors than we expected %u != %u"
,
ret_fds
->
fd_count_max
,
num_raw
);
/* Cap the number of received file descriptors. */
/* Cap the number of received file descriptors. */
num_raw
=
ret_fds
->
fd_count_max
;
num_raw
=
ret_fds
->
fd_count_max
;
ret_fds
->
flags
|=
UNIX_FDS_RECEIVED_MORE
;
}
else
{
ret_fds
->
flags
|=
UNIX_FDS_RECEIVED_EXACT
;
}
if
(
hweight32
((
ret_fds
->
flags
&
~
UNIX_FDS_ACCEPT_MASK
))
>
1
)
{
for
(
idx
=
0
;
idx
<
num_raw
;
idx
++
)
close
(
fds_raw
[
idx
]);
return
syserrno_set
(
-
EINVAL
,
"Invalid flag combination; closing to not risk leaking fds %u != %u"
,
ret_fds
->
fd_count_max
,
num_raw
);
}
}
memcpy
(
ret_fds
->
fd
,
CMSG_DATA
(
cmsg
),
num_raw
*
sizeof
(
int
));
memcpy
(
ret_fds
->
fd
,
CMSG_DATA
(
cmsg
),
num_raw
*
sizeof
(
int
));
...
@@ -252,6 +290,15 @@ again:
...
@@ -252,6 +290,15 @@ again:
}
}
}
}
if
(
ret_fds
->
fd_count_ret
==
0
)
{
ret_fds
->
flags
|=
UNIX_FDS_RECEIVED_NONE
;
/* We expected to receive file descriptors. */
if
((
ret_fds
->
flags
&
UNIX_FDS_ACCEPT_MASK
)
&&
!
(
ret_fds
->
flags
&
UNIX_FDS_ACCEPT_NONE
))
return
syserrno_set
(
-
EINVAL
,
"Received no file descriptors"
);
}
return
ret
;
return
ret
;
}
}
...
...
src/lxc/af_unix.h
View file @
780215cf
...
@@ -12,15 +12,88 @@
...
@@ -12,15 +12,88 @@
#include "macro.h"
#include "macro.h"
#include "memory_utils.h"
#include "memory_utils.h"
#define KERNEL_SCM_MAX_FD 253
/* Allow the caller to set expectations. */
/*
* UNIX_FDS_ACCEPT_EXACT will only succeed if the exact amount of fds has been
* received (unless combined with UNIX_FDS_ACCEPT_NONE).
*/
#define UNIX_FDS_ACCEPT_EXACT ((__u32)(1 << 0))
/* default */
/*
* UNIX_FDS_ACCEPT_LESS will also succeed if less than the requested number of
* fd has been received. If the UNIX_FDS_ACCEPT_NONE flag is not raised than at
* least one fd must be received.
* */
#define UNIX_FDS_ACCEPT_LESS ((__u32)(1 << 1))
/*
* UNIX_FDS_ACCEPT_MORE will also succeed if more than the requested number of
* fds have been received. Any additional fds will be silently closed. If the
* UNIX_FDS_ACCEPT_NONE flag is not raised than at least one fd must be
* received.
*/
#define UNIX_FDS_ACCEPT_MORE ((__u32)(1 << 2))
/* wipe any extra fds */
/*
/*
*
Technically 253 is the kernel limit but we want to the struct to be a
*
UNIX_FDS_ACCEPT_NONE can be specified with any of the above flags and
*
multiple of 8
.
*
indicates that the caller will accept no file descriptors to be received
.
*/
*/
#define
KERNEL_SCM_MAX_FD 252
#define
UNIX_FDS_ACCEPT_NONE ((__u32)(1 << 3))
/* UNIX_FDS_ACCEPT_MASK is the value of all the above flags or-ed together. */
#define UNIX_FDS_ACCEPT_MASK (UNIX_FDS_ACCEPT_EXACT | UNIX_FDS_ACCEPT_LESS | UNIX_FDS_ACCEPT_MORE | UNIX_FDS_ACCEPT_NONE)
/* Allow the callee to communicate reality. */
/* UNIX_FDS_RECEIVED_EXACT indicates that the exact number of fds was received. */
#define UNIX_FDS_RECEIVED_EXACT ((__u32)(1 << 16))
/*
* UNIX_FDS_RECEIVED_LESS indicates that less than the requested number of fd
* has been received.
*/
#define UNIX_FDS_RECEIVED_LESS ((__u32)(1 << 17))
/*
* UNIX_FDS_RECEIVED_MORE indicates that more than the requested number of fd
* has been received.
*/
#define UNIX_FDS_RECEIVED_MORE ((__u32)(1 << 18))
/* UNIX_FDS_RECEIVED_NONE indicates that no fds have been received. */
#define UNIX_FDS_RECEIVED_NONE ((__u32)(1 << 19))
/**
* Defines a generic struct to receive file descriptors from unix sockets.
* @fd_count_max : Either the exact or maximum number of file descriptors the
* caller is willing to accept. Must be smaller than
* KERNEL_SCM_MAX_FDs; larger values will be rejected.
* Filled in by the caller.
* @fd_count_ret : The actually received number of file descriptors.
* Filled in by the callee.
* @flags : Flags to negotiate expectations about the number of file
* descriptors to receive.
* Filled in by the caller and callee. The caller's flag space
* is UNIX_FDS_ACCEPT_* other values will be rejected. The
* caller may only set one of {EXACT, LESS, MORE}. In addition
* they can raise the NONE flag. Any combination of {EXACT,
* LESS, MORE} will be rejected.
* The callee's flag space is UNIX_FDS_RECEIVED_*. Only ever
* one of those values will be set.
* @fd : Array to store received file descriptors into. Filled by the
* callee on success. If less file descriptors are received
* than requested in @fd_count_max the callee will ensure that
* all additional slots will be set to -EBADF. Nonetheless, the
* caller should only ever use @fd_count_ret to iterate through
* @fd after a successful receive.
*/
struct
unix_fds
{
struct
unix_fds
{
__u32
fd_count_max
;
__u32
fd_count_max
;
__u32
fd_count_ret
;
__u32
fd_count_ret
;
__u32
flags
;
__s32
fd
[
KERNEL_SCM_MAX_FD
];
__s32
fd
[
KERNEL_SCM_MAX_FD
];
}
__attribute__
((
aligned
(
8
)));
}
__attribute__
((
aligned
(
8
)));
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment