Skip to content

ParseArgs unnecessary casting leads to wrong values #4504

Open
@rscampos

Description

@rscampos

Description

I'll open an issue since I don't if the current approach is correct or not. Once we discuss it, I can submit a PR.

I was reviewing #4442 when I realized that some casting might lead to incorrect values.

The syscall execveat has the field flags as type int in the definition:

{Type: "int", Name: "flags"},

But here happens a cast to uint64 before passing parseExecFlag:

case Execveat:
if flagsArg := GetArg(event, "flags"); flagsArg != nil {
if flags, isInt32 := flagsArg.Value.(int32); isInt32 {
parseExecFlag(flagsArg, uint64(flags))
}
}

The issue happens when we call execveat using flag=-1. The value will be converted to 0xFFFFFFFFFFFFFFFF, setting all flags:

sudo ./dist/tracee -e execveat -s comm=python3.10
TIME             UID    COMM             PID     TID     RET              EVENT                     ARGS
11:29:25:554926  1000   python3.10       638196  638196  0                execveat                  dirfd: -100, pathname: /bin/ls, argv: [/bin/ls], envp: 0x0, flags: AT_EMPTY_PATH|AT_SYMLINK_NOFOLLOW|AT_EACCESS|AT_REMOVEDIR|AT_NO_AUTOMOUNT|AT_STATX_SYNC_TYPE|AT_STATX_FORCE_SYNC|AT_STATX_DONT_SYNC|AT_RECURSIVE
11:29:25:554926  1000   python3.10       638196  638196  -22              execveat                  dirfd: -100, pathname: /bin/ls, argv: [/bin/ls], envp: 0x0, flags: AT_EMPTY_PATH|AT_SYMLINK_NOFOLLOW|AT_EACCESS|AT_REMOVEDIR|AT_NO_AUTOMOUNT|AT_STATX_SYNC_TYPE|AT_STATX_FORCE_SYNC|AT_STATX_DONT_SYNC|AT_RECURSIVE

Usually, this behavior occurs when the type of the event in the definition is signed and we cast the negative value to unsigned. I think each function should have the signature aligned with the type of the field from the event defined in the definition.

Output of tracee version:

(paste your output here)

Output of uname -a:

(paste your output here)

Additional details

Python code to call execveat with flag=-1.

import ctypes
import errno
import os

SYS_EXECVEAT = 281  # ARM

AT_FDCWD = -100
exec_path = b"/bin/ls"
argv = (ctypes.c_char_p * 2)()
argv[0] = exec_path
argv[1] = None  # Null-terminated argument list

# Environment variables (null-terminated array)
envp = (ctypes.c_char_p * 1)()
envp[0] = None

# trigger
flags = -1

libc = ctypes.CDLL("libc.so.6", use_errno=True)

ret = libc.syscall(SYS_EXECVEAT, AT_FDCWD, exec_path, ctypes.byref(argv), ctypes.byref(envp), flags)

if ret == -1:
    err = ctypes.get_errno()
    print(f"Error: {os.strerror(err)} (errno={err})")
    if err == errno.ENOENT:
        print("File not found.")
    elif err == errno.EACCES:
        print("Permission denied.")
    else:
        print("Unexpected error occurred.")
else:
    print("Execveat syscall succeeded.")

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions