clamdscan: perform real-path checks in clamd

This patch relocates the real-path check from clamdscan and clamonacc
to clamd. While clamonacc is unlikely to send directories or symlinks
to be scanned, clamdscan may send directories. Real-path checks have
to be performed on the files, not the directories -- both because the
directories may contain symlinks and because the cli_realpath()
function wasn't written to support directories on Windows.
pull/133/head
Micah Snyder (micasnyd) 5 years ago
parent c637de532b
commit 4f21133667
  1. 16
      clamd/scanner.c
  2. 2
      clamd/scanner.h
  3. 13
      clamdscan/proto.c
  4. 23
      clamonacc/client/protocol.c
  5. 12
      libclamav/others_common.c

@ -133,13 +133,25 @@ void clamd_virus_found_cb(int fd, const char *virname, void *ctx)
}
#define BUFFSIZE 1024
int scan_callback(STATBUF *sb, char *filename, const char *msg, enum cli_ftw_reason reason, struct cli_ftw_cbdata *data)
cl_error_t scan_callback(STATBUF *sb, char *filename, const char *msg, enum cli_ftw_reason reason, struct cli_ftw_cbdata *data)
{
struct scan_cb_data *scandata = data->data;
const char *virname = NULL;
int ret;
int type = scandata->type;
struct cb_context context;
char *real_filename = NULL;
if (NULL != filename) {
if (CL_SUCCESS != cli_realpath((const char *)filename, &real_filename)) {
conn_reply_errno(scandata->conn, msg, "real-path check failed:");
logg("^Failed to determine real path for: %s\n", filename);
scandata->errors++;
return CL_SUCCESS;
}
free(filename);
filename = real_filename;
}
/* detect disconnected socket,
* this should NOT detect half-shutdown sockets (SHUT_WR) */
@ -190,8 +202,8 @@ int scan_callback(STATBUF *sb, char *filename, const char *msg, enum cli_ftw_rea
break;
}
/* check whether the file is excluded */
#ifdef C_LINUX
/* check whether the file is excluded */
if (procdev && sb && (sb->st_dev == procdev)) {
free(filename);
return CL_SUCCESS;

@ -63,7 +63,7 @@ struct cb_context {
int scanfd(const client_conn_t *conn, unsigned long int *scanned, const struct cl_engine *engine, struct cl_scan_options *options, const struct optstruct *opts, int odesc, int stream);
int scanstream(int odesc, unsigned long int *scanned, const struct cl_engine *engine, struct cl_scan_options *options, const struct optstruct *opts, char term);
int scan_callback(STATBUF *sb, char *filename, const char *msg, enum cli_ftw_reason reason, struct cli_ftw_cbdata *data);
cl_error_t scan_callback(STATBUF *sb, char *filename, const char *msg, enum cli_ftw_reason reason, struct cli_ftw_cbdata *data);
int scan_pathchk(const char *path, struct cli_ftw_cbdata *data);
void hash_callback(int fd, unsigned long long size, const unsigned char *md5, const char *virname, void *ctx);
void msg_callback(enum cl_msg severity, const char *fullmsg, const char *msg, void *ctx);

@ -262,18 +262,8 @@ int dsresult(int sockd, int scantype, const char *filename, int *printok, int *e
char *bol, *eol;
struct RCVLN rcv;
STATBUF sb;
cl_error_t ret;
char *real_filename = NULL;
if (filename) {
ret = cli_realpath((const char *)filename, &real_filename);
if (CL_SUCCESS != ret) {
logg("Failed to determine real filename of %s.\n", filename);
infected = -1;
goto done;
}
filename = real_filename;
if (1 == chkpath(filename)) {
goto done;
}
@ -408,9 +398,6 @@ int dsresult(int sockd, int scantype, const char *filename, int *printok, int *e
}
done:
if (NULL != real_filename) {
free(real_filename);
}
return infected;
}

@ -195,26 +195,6 @@ int onas_dsresult(CURL *curl, int scantype, uint64_t maxstream, const char *file
onas_recvlninit(&rcv, curl);
cl_error_t ret;
char *real_filename = NULL;
if (filename) {
ret = cli_realpath((const char *)filename, &real_filename);
if (CL_SUCCESS != ret) {
logg("Failed to determine real filename of %s.\n", filename);
if (ret_code) {
*ret_code = CL_EACCES;
}
infected = -1;
goto done;
}
filename = real_filename;
}
if (ret_code) {
*ret_code = CL_SUCCESS;
}
switch (scantype) {
case MULTI:
case CONT:
@ -427,8 +407,5 @@ int onas_dsresult(CURL *curl, int scantype, uint64_t maxstream, const char *file
}
done:
if (NULL != real_filename) {
free(real_filename);
}
return infected;
}

@ -530,9 +530,9 @@ static int get_filetype(const char *fname, int flags, int need_stat,
if ((flags & FOLLOW_SYMLINK_MASK) != FOLLOW_SYMLINK_MASK) {
/* Following only one of directory/file symlinks, or none, may
* need to lstat.
* If we're following both file and directory symlinks, we don't need
* to lstat(), we can just stat() directly.*/
* need to lstat.
* If we're following both file and directory symlinks, we don't need
* to lstat(), we can just stat() directly.*/
if (*ft != ft_link) {
/* need to lstat to determine if it is a symlink */
if (LSTAT(fname, statbuf) == -1)
@ -563,7 +563,7 @@ static int get_filetype(const char *fname, int flags, int need_stat,
if (S_ISDIR(statbuf->st_mode) &&
(*ft != ft_link || (flags & CLI_FTW_FOLLOW_DIR_SYMLINK))) {
/* A directory, or (a symlink to a directory and we're following dir
* symlinks) */
* symlinks) */
*ft = ft_directory;
} else if (S_ISREG(statbuf->st_mode) &&
(*ft != ft_link || (flags & CLI_FTW_FOLLOW_FILE_SYMLINK))) {
@ -622,7 +622,7 @@ int cli_ftw(char *path, int flags, int maxdepth, cli_ftw_cb callback, struct cli
if (((flags & CLI_FTW_TRIM_SLASHES) || pathchk) && path[0] && path[1]) {
char *pathend;
/* trim slashes so that dir and dir/ behave the same when
* they are symlinks, and we are not following symlinks */
* they are symlinks, and we are not following symlinks */
#ifndef _WIN32
while (path[0] == *PATHSEP && path[1] == *PATHSEP) path++;
#endif
@ -683,7 +683,7 @@ static int cli_ftw_dir(const char *dirname, int flags, int maxdepth, cli_ftw_cb
case DT_LNK:
if (!(flags & FOLLOW_SYMLINK_MASK)) {
/* we don't follow symlinks, don't bother
* stating it */
* stating it */
errno = 0;
continue;
}

Loading…
Cancel
Save