Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/seccomp: Allow syscall nr and ret value to be set separately

In preparation for setting syscall nr and ret values separately, refactor
the helpers to take a pointer to a value, so that a NULL can indicate
"do not change this respective value". This is done to keep the regset
read/write happening once and in one code path.

Acked-by: Christian Brauner <christian.brauner@ubuntu.com>
Link: https://lore.kernel.org/lkml/20200921075031.j4gruygeugkp2zwd@wittgenstein/
Signed-off-by: Kees Cook <keescook@chromium.org>

+47 -12
+47 -12
tools/testing/selftests/seccomp/seccomp_bpf.c
··· 1888 1888 } 1889 1889 1890 1890 /* Architecture-specific syscall changing routine. */ 1891 - void change_syscall(struct __test_metadata *_metadata, 1892 - pid_t tracee, int syscall, int result) 1891 + void __change_syscall(struct __test_metadata *_metadata, 1892 + pid_t tracee, long *syscall, long *ret) 1893 1893 { 1894 1894 ARCH_REGS orig, regs; 1895 + 1896 + /* Do not get/set registers if we have nothing to do. */ 1897 + if (!syscall && !ret) 1898 + return; 1895 1899 1896 1900 EXPECT_EQ(0, ARCH_GETREGS(regs)) { 1897 1901 return; 1898 1902 } 1899 1903 orig = regs; 1900 1904 1901 - SYSCALL_NUM_SET(regs, syscall); 1905 + if (syscall) 1906 + SYSCALL_NUM_SET(regs, *syscall); 1902 1907 1903 - /* If syscall is skipped, change return value. */ 1904 - if (syscall == -1) 1905 - SYSCALL_RET_SET(regs, result); 1908 + if (ret) 1909 + SYSCALL_RET_SET(regs, *ret); 1906 1910 1907 1911 /* Flush any register changes made. */ 1908 1912 if (memcmp(&orig, &regs, sizeof(orig)) != 0) 1909 1913 EXPECT_EQ(0, ARCH_SETREGS(regs)); 1914 + } 1915 + 1916 + /* Change only syscall number. */ 1917 + void change_syscall_nr(struct __test_metadata *_metadata, 1918 + pid_t tracee, long syscall) 1919 + { 1920 + __change_syscall(_metadata, tracee, &syscall, NULL); 1921 + } 1922 + 1923 + /* Change syscall return value (and set syscall number to -1). */ 1924 + void change_syscall_ret(struct __test_metadata *_metadata, 1925 + pid_t tracee, long ret) 1926 + { 1927 + long syscall = -1; 1928 + 1929 + __change_syscall(_metadata, tracee, &syscall, &ret); 1910 1930 } 1911 1931 1912 1932 void tracer_seccomp(struct __test_metadata *_metadata, pid_t tracee, ··· 1944 1924 case 0x1002: 1945 1925 /* change getpid to getppid. */ 1946 1926 EXPECT_EQ(__NR_getpid, get_syscall(_metadata, tracee)); 1947 - change_syscall(_metadata, tracee, __NR_getppid, 0); 1927 + change_syscall_nr(_metadata, tracee, __NR_getppid); 1948 1928 break; 1949 1929 case 0x1003: 1950 1930 /* skip gettid with valid return code. */ 1951 1931 EXPECT_EQ(__NR_gettid, get_syscall(_metadata, tracee)); 1952 - change_syscall(_metadata, tracee, -1, 45000); 1932 + change_syscall_ret(_metadata, tracee, 45000); 1953 1933 break; 1954 1934 case 0x1004: 1955 1935 /* skip openat with error. */ 1956 1936 EXPECT_EQ(__NR_openat, get_syscall(_metadata, tracee)); 1957 - change_syscall(_metadata, tracee, -1, -ESRCH); 1937 + change_syscall_ret(_metadata, tracee, -ESRCH); 1958 1938 break; 1959 1939 case 0x1005: 1960 1940 /* do nothing (allow getppid) */ ··· 1981 1961 int ret; 1982 1962 unsigned long msg; 1983 1963 static bool entry; 1964 + long syscall_nr_val, syscall_ret_val; 1965 + long *syscall_nr = NULL, *syscall_ret = NULL; 1984 1966 FIXTURE_DATA(TRACE_syscall) *self = args; 1985 1967 1986 1968 /* ··· 2009 1987 else 2010 1988 return; 2011 1989 1990 + syscall_nr = &syscall_nr_val; 1991 + syscall_ret = &syscall_ret_val; 1992 + 1993 + /* Now handle the actual rewriting cases. */ 2012 1994 switch (self->syscall_nr) { 2013 1995 case __NR_getpid: 2014 - change_syscall(_metadata, tracee, __NR_getppid, 0); 1996 + syscall_nr_val = __NR_getppid; 1997 + /* Never change syscall return for this case. */ 1998 + syscall_ret = NULL; 2015 1999 break; 2016 2000 case __NR_gettid: 2017 - change_syscall(_metadata, tracee, -1, 45000); 2001 + syscall_nr_val = -1; 2002 + syscall_ret_val = 45000; 2018 2003 break; 2019 2004 case __NR_openat: 2020 - change_syscall(_metadata, tracee, -1, -ESRCH); 2005 + syscall_nr_val = -1; 2006 + syscall_ret_val = -ESRCH; 2021 2007 break; 2008 + default: 2009 + /* Unhandled, do nothing. */ 2010 + return; 2022 2011 } 2012 + 2013 + __change_syscall(_metadata, tracee, syscall_nr, syscall_ret); 2023 2014 } 2024 2015 2025 2016 FIXTURE_VARIANT(TRACE_syscall) {