Files
acrn-hypervisor/tools/acrn-crashlog/usercrash/protocol.c
xiaojin2 cb39badf82 tools: acrn-crashlog: fix potential issues under common and usercrash
This patch is to fix buffer overflow, return value not unified and
variable type not matched issues. And add some judge logic to improve
code quality.

Changes:
1. Handle the fd properly in the failing case.
2. Fix buffer overflow issues and null pointer access issues.
3. Fix the format issue in log_sys.c.
4. Remove the useless branch and adjust the function logic.
5. Add some checks for the string length before using strcpy/strcat/memcpy.
6. Fix strncpy null-terminated issues.
7. Change the return value to unify the return type.

Signed-off-by: CHEN Gang <gang.c.chen@intel.com>
Signed-off-by: xiaojin2 <xiaojing.liu@intel.com>
Reviewed-by: Zhi Jin <zhi.jin@intel.com>
Reviewed-by: Liu Xinwu <xinwu.liu@intel.com>
Acked-by: Zhang Di <di.zhang@intel.com>
2018-06-21 11:29:20 +08:00

232 lines
4.7 KiB
C

/*
* Copyright (C) <2018> Intel Corporation
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* Copyright (C) 2018 Intel Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stddef.h>
#include <errno.h>
#include <stdbool.h>
#include <string.h>
#include "protocol.h"
#include "log_sys.h"
#define SUN_PATH_MAX \
(sizeof(struct sockaddr_un) - offsetof(struct sockaddr_un, sun_path))
/* Documented in header file. */
static int socket_make_sockaddr_un(const char *name,
struct sockaddr_un *p_addr, socklen_t *alen)
{
size_t name_len;
size_t socket_len;
socket_len = strlen(RESERVED_SOCKET_PREFIX);
if (socket_len >= SUN_PATH_MAX)
return -1;
strcpy(p_addr->sun_path, RESERVED_SOCKET_PREFIX);
name_len = strlen(name);
if (name_len >= (SUN_PATH_MAX - socket_len))
return -1;
strcat(p_addr->sun_path, name);
p_addr->sun_family = AF_LOCAL;
*alen = name_len + socket_len +
offsetof(struct sockaddr_un, sun_path) + 1;
return 0;
}
/**
* connect to peer named "name" on fd
* returns same fd or -1 on error.
* fd is not closed on error. that's your job.
*
*/
static int socket_local_client_connect(int fd, const char *name)
{
struct sockaddr_un addr;
socklen_t alen;
int err;
err = socket_make_sockaddr_un(name, &addr, &alen);
if (err < 0)
goto error;
if (connect(fd, (struct sockaddr *) &addr, alen) < 0) {
LOGE("connect to usercrashd failed ,error (%s)\n",
strerror(errno));
goto error;
}
return fd;
error:
return -1;
}
/**
* connect to peer named "name"
* returns fd or -1 on error
*/
int socket_local_client(const char *name, int type)
{
int s;
s = socket(AF_LOCAL, type, 0);
if (s < 0)
return -1;
if (socket_local_client_connect(s, name) < 0) {
close(s);
return -1;
}
return s;
}
static int socket_bind(int fd, const char *name)
{
struct sockaddr_un addr;
socklen_t alen;
size_t name_len;
addr.sun_family = AF_UNIX;
name_len = strlen(name);
if (name_len >= SUN_PATH_MAX)
return -1;
strcpy(addr.sun_path, name);
unlink(addr.sun_path);
alen = strlen(addr.sun_path) + sizeof(addr.sun_family);
if (bind(fd, (struct sockaddr *)&addr, alen) == -1)
return -1;
return fd;
}
static int create_socket_server(const char *name, int type)
{
int err;
int fd;
fd = socket(AF_UNIX, type, 0);
if (fd < 0)
return -1;
err = socket_bind(fd, name);
if (err < 0) {
close(fd);
return -1;
}
return fd;
}
int linux_get_control_socket(const char *name)
{
char socketName[64];
snprintf(socketName, sizeof(socketName), RESERVED_SOCKET_PREFIX "%s",
name);
return create_socket_server(socketName, SOCK_SEQPACKET);
}
ssize_t send_fd(int sockfd, const void *data, size_t len, int fd)
{
char cmsg_buf[CMSG_SPACE(sizeof(int))];
struct msghdr msg;
struct iovec iov;
struct cmsghdr *cmsg;
memset(&iov, 0, sizeof(iov));
iov.iov_base = (void *)data;
iov.iov_len = len;
memset(&msg, 0, sizeof(msg));
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = cmsg_buf;
msg.msg_controllen = sizeof(cmsg_buf);
cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
*(int *)(CMSG_DATA(cmsg)) = fd;
return sendmsg(sockfd, &msg, 0);
}
ssize_t recv_fd(int sockfd, void *data, size_t len, int *out_fd)
{
char cmsg_buf[CMSG_SPACE(sizeof(int))];
struct msghdr msg;
struct iovec iov;
struct cmsghdr *cmsg;
ssize_t result;
bool received_fd;
int fd;
memset(&iov, 0, sizeof(iov));
iov.iov_base = (void *)data;
iov.iov_len = len;
memset(&msg, 0, sizeof(msg));
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = cmsg_buf;
msg.msg_controllen = sizeof(cmsg_buf);
msg.msg_flags = 0;
cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
result = recvmsg(sockfd, &msg, 0);
if (result == -1)
return -1;
received_fd = msg.msg_controllen == sizeof(cmsg_buf);
if (received_fd)
fd = *(int *)(CMSG_DATA(cmsg));
else
return -1;
if ((msg.msg_flags & MSG_TRUNC) != 0) {
errno = EFBIG;
goto fail;
} else if ((msg.msg_flags & MSG_CTRUNC) != 0) {
errno = ERANGE;
goto fail;
}
if (out_fd) {
*out_fd = fd;
} else if (received_fd) {
errno = ERANGE;
goto fail;
}
return result;
fail:
close(fd);
return -1;
}