Impove struct cmsghdr decoding

Print all cmsghdr structures in msg_control array,
not just the first one.
Change output format to be consistent with other parts of strace
where structures and arrays are printed.
Implement decoder for SCM_SECURITY message type.

* net.c (print_scm_rights, print_scm_creds, print_scm_security):
New functions.
(printcmsghdr): Use them.  Iterate over all members of the array.
* xlat/scmvals.in: Add SCM_SECURITY.
* tests/scm_rights.c (main): Pass one more descriptor to the receiver.
Set SO_PASSCRED on the receiver part.  Reserve enough space to receive
SCM_CREDENTIALS and SCM_RIGHTS.
* tests/scm_rights-fd.test: Update.
This commit is contained in:
Дмитрий Левин 2015-01-24 15:20:31 +00:00
parent 778dfb270f
commit b85a7f3b95
4 changed files with 160 additions and 77 deletions

176
net.c
View File

@ -339,7 +339,10 @@ printsock(struct tcb *tcp, long addr, int addrlen)
}
#if HAVE_SENDMSG
#include "xlat/scmvals.h"
# ifndef SCM_SECURITY
# define SCM_SECURITY 0x03
# endif
# include "xlat/scmvals.h"
#if SUPPORTED_PERSONALITIES > 1 && SIZEOF_LONG > 4
struct cmsghdr32 {
@ -350,91 +353,152 @@ struct cmsghdr32 {
#endif
typedef union {
char *buf;
char *ptr;
struct cmsghdr *cmsg;
#if SUPPORTED_PERSONALITIES > 1 && SIZEOF_LONG > 4
struct cmsghdr32 *cmsg32;
#endif
} union_cmsghdr;
static void
printcmsghdr(struct tcb *tcp, unsigned long addr, unsigned long len)
static bool
print_scm_rights(struct tcb *tcp, size_t cmsg_size, char *ptr, size_t cmsg_len)
{
union_cmsghdr u;
size_t cmsg_size;
unsigned long cmsg_len;
int cmsg_level;
int cmsg_type;
if (cmsg_size + sizeof(int) > cmsg_len)
return false;
cmsg_size =
int *fds = (int *) (ptr + cmsg_size);
bool seen = false;
tprints(", [");
while ((char *) fds < (ptr + cmsg_len)) {
if (seen)
tprints(", ");
else
seen = true;
printfd(tcp, *fds++);
}
tprints("]}");
return true;
}
static bool
print_scm_creds(struct tcb *tcp, size_t cmsg_size, char *ptr, size_t cmsg_len)
{
if (cmsg_size + sizeof(struct ucred) > cmsg_len)
return false;
const struct ucred *uc = (void *) (ptr + cmsg_size);
tprintf(", {pid=%u, uid=%u, gid=%u}}",
(unsigned) uc->pid, (unsigned) uc->uid, (unsigned) uc->gid);
return true;
}
static bool
print_scm_security(struct tcb *tcp, size_t cmsg_size, char *ptr, size_t cmsg_len)
{
if (cmsg_size + sizeof(char) > cmsg_len)
return false;
const char *label = (const char *) (ptr + cmsg_size);
const size_t label_len = cmsg_len - cmsg_size;
char *outstr;
const size_t alloc_len = 4 * label_len + 3;
if (label_len != alloc_len / 4 ||
!(outstr = malloc(alloc_len)))
return false;
string_quote(label, outstr, 0, label_len);
tprintf(", %s}", outstr);
free(outstr);
return true;
}
static void
printcmsghdr(struct tcb *tcp, unsigned long addr, size_t len)
{
const size_t cmsg_size =
#if SUPPORTED_PERSONALITIES > 1 && SIZEOF_LONG > 4
(current_wordsize < sizeof(long)) ? sizeof(struct cmsghdr32) :
#endif
sizeof(struct cmsghdr);
u.buf = len < cmsg_size ? NULL : malloc(len);
if (!u.buf || umoven(tcp, addr, len, u.buf) < 0) {
char *buf = len < cmsg_size ? NULL : malloc(len);
if (!buf || umoven(tcp, addr, len, buf) < 0) {
tprintf(", msg_control=%#lx", addr);
free(u.buf);
free(buf);
return;
}
cmsg_len =
union_cmsghdr u = { .ptr = buf };
tprints(", [");
while (len >= cmsg_size) {
size_t cmsg_len =
#if SUPPORTED_PERSONALITIES > 1 && SIZEOF_LONG > 4
(current_wordsize < sizeof(long)) ? u.cmsg32->cmsg_len :
(current_wordsize < sizeof(long)) ? u.cmsg32->cmsg_len :
#endif
u.cmsg->cmsg_len;
cmsg_level =
u.cmsg->cmsg_len;
int cmsg_level =
#if SUPPORTED_PERSONALITIES > 1 && SIZEOF_LONG > 4
(current_wordsize < sizeof(long)) ? u.cmsg32->cmsg_level :
(current_wordsize < sizeof(long)) ? u.cmsg32->cmsg_level :
#endif
u.cmsg->cmsg_level;
cmsg_type =
u.cmsg->cmsg_level;
int cmsg_type =
#if SUPPORTED_PERSONALITIES > 1 && SIZEOF_LONG > 4
(current_wordsize < sizeof(long)) ? u.cmsg32->cmsg_type :
(current_wordsize < sizeof(long)) ? u.cmsg32->cmsg_type :
#endif
u.cmsg->cmsg_type;
u.cmsg->cmsg_type;
tprintf(", {cmsg_len=%lu, cmsg_level=", cmsg_len);
printxval(socketlayers, cmsg_level, "SOL_???");
tprints(", cmsg_type=");
if (u.ptr != buf)
tprints(", ");
tprintf("{cmsg_len=%lu, cmsg_level=", (unsigned long) cmsg_len);
printxval(socketlayers, cmsg_level, "SOL_???");
tprints(", cmsg_type=");
if (cmsg_len > len)
cmsg_len = len;
if (cmsg_len > len)
cmsg_len = len;
if (cmsg_level == SOL_SOCKET) {
printxval(scmvals, cmsg_type, "SCM_???");
if (cmsg_type == SCM_RIGHTS
&& cmsg_size + sizeof(int) <= cmsg_len) {
int *fds = (int *) (u.buf + cmsg_size);
int first = 1;
tprints(", {");
while ((char *) fds < (u.buf + cmsg_len)) {
if (!first)
tprints(", ");
printfd(tcp, *fds++);
first = 0;
if (cmsg_level == SOL_SOCKET) {
printxval(scmvals, cmsg_type, "SCM_???");
switch (cmsg_type) {
case SCM_RIGHTS:
if (print_scm_rights(tcp, cmsg_size, u.ptr, cmsg_len))
goto next_cmsg;
break;
case SCM_CREDENTIALS:
if (print_scm_creds(tcp, cmsg_size, u.ptr, cmsg_len))
goto next_cmsg;
break;
case SCM_SECURITY:
if (print_scm_security(tcp, cmsg_size, u.ptr, cmsg_len))
goto next_cmsg;
break;
}
tprints("}}");
free(u.buf);
return;
} else {
tprintf("%u", cmsg_type);
}
if (cmsg_type == SCM_CREDENTIALS
&& cmsg_size + sizeof(struct ucred) <= cmsg_len) {
struct ucred *uc = (void *) (u.buf + cmsg_size);
tprintf("{pid=%ld, uid=%ld, gid=%ld}}",
(long)uc->pid, (long)uc->uid, (long)uc->gid);
free(u.buf);
return;
tprints(", ...}");
next_cmsg:
if (cmsg_len < cmsg_size) {
len -= cmsg_size;
break;
}
} else {
tprintf("%u", cmsg_type);
cmsg_len = (cmsg_len + current_wordsize - 1) &
(size_t) ~(current_wordsize - 1);
if (cmsg_len >= len) {
len = 0;
break;
}
u.ptr += cmsg_len;
len -= cmsg_len;
}
free(u.buf);
tprints(", ...}");
if (len)
tprints(", ...");
tprints("]");
free(buf);
}
static void

View File

@ -36,7 +36,11 @@ grep_log()
}
}
grep_log sendmsg '\(1<socket:\[[0-9]+\]>, \{msg_name\(0\)=NULL, msg_iov\(1\)=\[\{"\\x00\\x00\\x00\\x00[^"]*", [1-9][0-9]*\}\], msg_controllen=[1-9][0-9]*, \{cmsg_len=[1-9][0-9]*, cmsg_level=SOL_SOCKET, cmsg_type=SCM_RIGHTS, \{3</dev/null>\}\}, msg_flags=0\}, 0\) += [1-9][0-9]*'
grep_log recvmsg '\(0<socket:\[[0-9]+\]>, \{msg_name\(0\)=NULL, msg_iov\(1\)=\[\{"\\x00\\x00\\x00\\x00[^"]*", [1-9][0-9]*\}\], msg_controllen=[1-9][0-9]*, \{cmsg_len=[1-9][0-9]*, cmsg_level=SOL_SOCKET, cmsg_type=SCM_RIGHTS, \{3</dev/null>\}\}, msg_flags=0\}, 0\) += [1-9][0-9]*'
n='[1-9][0-9]*'
msg='\{msg_name\(0\)=NULL, msg_iov\(1\)=\[\{"\\x00\\x00\\x00\\x00[^"]*", '"$n"'\}\], msg_controllen='"$n"
rights='\{cmsg_len='"$n"', cmsg_level=SOL_SOCKET, cmsg_type=SCM_RIGHTS, \[3</dev/null>, 4</dev/zero>\]\}'
creds='\{cmsg_len='"$n"', cmsg_level=SOL_SOCKET, cmsg_type=SCM_CREDENTIALS, \{pid='"$n"', uid=[0-9]+, gid=[0-9]+\}\}'
grep_log sendmsg '\(1<socket:\[[0-9]+\]>, '"$msg"', \['"$rights"'\], msg_flags=0\}, 0\) += '"$n"
grep_log recvmsg '\(0<socket:\[[0-9]+\]>, '"$msg"', \['"$creds"', '"$rights"'\], msg_flags=0\}, 0\) += '"$n"
exit 0

View File

@ -9,11 +9,6 @@
int main(void)
{
union {
struct cmsghdr cmsghdr;
char buf[CMSG_SPACE(sizeof(int))];
} control = {};
int fd;
int data = 0;
struct iovec iov = {
@ -21,19 +16,14 @@ int main(void)
.iov_len = sizeof(iov)
};
struct msghdr mh = {
.msg_iov = &iov,
.msg_iovlen = 1,
.msg_control = &control,
.msg_controllen = sizeof(control)
};
while ((fd = open("/dev/null", O_RDWR)) < 3)
assert(fd >= 0);
(void) close(3);
int sv[2];
assert(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == 0);
int one = 1;
assert(setsockopt(sv[0], SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) == 0);
pid_t pid = fork();
assert(pid >= 0);
@ -43,14 +33,29 @@ int main(void)
assert(dup2(sv[1], 1) == 1);
assert(close(sv[1]) == 0);
assert((fd = open("/dev/null", O_RDWR)) == 3);
int fds[2];
assert((fds[0] = open("/dev/null", O_RDWR)) == 3);
assert((fds[1] = open("/dev/zero", O_RDONLY)) == 4);
struct cmsghdr *cmsg = CMSG_FIRSTHDR(&mh);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(sizeof fd);
memcpy(CMSG_DATA(cmsg), &fd, sizeof fd);
mh.msg_controllen = cmsg->cmsg_len;
union {
struct cmsghdr cmsg;
char buf[CMSG_LEN(sizeof(fds))];
} control = {
.cmsg = {
.cmsg_level = SOL_SOCKET,
.cmsg_type = SCM_RIGHTS,
.cmsg_len = CMSG_LEN(sizeof(fds))
}
};
memcpy(CMSG_DATA(&control.cmsg), fds, sizeof(fds));
struct msghdr mh = {
.msg_iov = &iov,
.msg_iovlen = 1,
.msg_control = &control,
.msg_controllen = sizeof(control)
};
assert(sendmsg(1, &mh, 0) == sizeof(iov));
assert(close(1) == 0);
@ -63,6 +68,15 @@ int main(void)
assert(dup2(sv[0], 0) == 0);
assert(close(sv[0]) == 0);
struct cmsghdr control[4];
struct msghdr mh = {
.msg_iov = &iov,
.msg_iovlen = 1,
.msg_control = control,
.msg_controllen = sizeof(control)
};
assert(recvmsg(0, &mh, 0) == sizeof(iov));
assert(close(0) == 0);
}

View File

@ -1,2 +1,3 @@
SCM_RIGHTS
SCM_CREDENTIALS
SCM_SECURITY