aboutsummaryrefslogtreecommitdiff
path: root/linux-user
diff options
context:
space:
mode:
authorLaurent Vivier <laurent@vivier.eu>2020-02-04 22:19:01 +0100
committerLaurent Vivier <laurent@vivier.eu>2020-02-12 18:56:45 +0100
commit6d485a55d0cd8fbb8b4337b298f79ddb0c2a5511 (patch)
treef1a9d76265211a101344ae481773c13d44d751ba /linux-user
parent6bc024e713fd35eb5fddbe16acd8dc92d27872a9 (diff)
downloadqemu-6d485a55d0cd8fbb8b4337b298f79ddb0c2a5511.zip
qemu-6d485a55d0cd8fbb8b4337b298f79ddb0c2a5511.tar.gz
qemu-6d485a55d0cd8fbb8b4337b298f79ddb0c2a5511.tar.bz2
linux-user: implement TARGET_SO_PEERSEC
"The purpose of this option is to allow an application to obtain the security credentials of a Unix stream socket peer. It is analogous to SO_PEERCRED (which provides authentication using standard Unix credentials of pid, uid and gid), and extends this concept to other security models." -- https://lwn.net/Articles/62370/ Until now it was passed to the kernel with an "int" argument and fails when it was supported by the host because the parameter is like a filename: it is always a \0-terminated string with no embedded \0 characters, but is not guaranteed to be ASCII or UTF-8. I've tested the option with the following program: /* * cc -o getpeercon getpeercon.c */ #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> int main(void) { int fd; struct sockaddr_in server, addr; int ret; socklen_t len; char buf[256]; fd = socket(PF_INET, SOCK_STREAM, 0); if (fd == -1) { perror("socket"); return 1; } server.sin_family = AF_INET; inet_aton("127.0.0.1", &server.sin_addr); server.sin_port = htons(40390); connect(fd, (struct sockaddr*)&server, sizeof(server)); len = sizeof(buf); ret = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, buf, &len); if (ret == -1) { perror("getsockopt"); return 1; } printf("%d %s\n", len, buf); return 0; } On host: $ ./getpeercon 33 system_u:object_r:unlabeled_t:s0 With qemu-aarch64/bionic without the patch: $ ./getpeercon getsockopt: Numerical result out of range With the patch: $ ./getpeercon 33 system_u:object_r:unlabeled_t:s0 Bug: https://bugs.launchpad.net/qemu/+bug/1823790 Reported-by: Matthias Lüscher <lueschem@gmail.com> Tested-by: Matthias Lüscher <lueschem@gmail.com> Signed-off-by: Laurent Vivier <laurent@vivier.eu> Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com> Message-Id: <20200204211901.1731821-1-laurent@vivier.eu>
Diffstat (limited to 'linux-user')
-rw-r--r--linux-user/syscall.c22
1 files changed, 22 insertions, 0 deletions
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index d60142f..c930577 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -2344,6 +2344,28 @@ static abi_long do_getsockopt(int sockfd, int level, int optname,
}
break;
}
+ case TARGET_SO_PEERSEC: {
+ char *name;
+
+ if (get_user_u32(len, optlen)) {
+ return -TARGET_EFAULT;
+ }
+ if (len < 0) {
+ return -TARGET_EINVAL;
+ }
+ name = lock_user(VERIFY_WRITE, optval_addr, len, 0);
+ if (!name) {
+ return -TARGET_EFAULT;
+ }
+ lv = len;
+ ret = get_errno(getsockopt(sockfd, level, SO_PEERSEC,
+ name, &lv));
+ if (put_user_u32(lv, optlen)) {
+ ret = -TARGET_EFAULT;
+ }
+ unlock_user(name, optval_addr, lv);
+ break;
+ }
case TARGET_SO_LINGER:
{
struct linger lg;