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

selftests/namespaces: fourteenth active reference count tests

Test that user namespace as a child also propagates correctly.
Create user_A -> user_B, verify when user_B is active that user_A
is also active. This is different from non-user namespace children.

Link: https://patch.msgid.link/20251029-work-namespace-nstree-listns-v4-36-2e6f823ebdc0@kernel.org
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Christian Brauner <brauner@kernel.org>

+132
+132
tools/testing/selftests/namespaces/ns_active_ref_test.c
··· 1817 1817 ASSERT_LT(p_fd, 0); 1818 1818 } 1819 1819 1820 + /* 1821 + * Test that user namespace as a child also propagates correctly. 1822 + * Create user_A -> user_B, verify when user_B is active that user_A 1823 + * is also active. This is different from non-user namespace children. 1824 + */ 1825 + TEST(ns_userns_child_propagation) 1826 + { 1827 + struct file_handle *ua_handle, *ub_handle; 1828 + int ret, pipefd[2]; 1829 + pid_t pid; 1830 + int status; 1831 + __u64 ua_id, ub_id; 1832 + char ua_buf[sizeof(*ua_handle) + MAX_HANDLE_SZ]; 1833 + char ub_buf[sizeof(*ub_handle) + MAX_HANDLE_SZ]; 1834 + 1835 + ASSERT_EQ(pipe(pipefd), 0); 1836 + pid = fork(); 1837 + ASSERT_GE(pid, 0); 1838 + 1839 + if (pid == 0) { 1840 + close(pipefd[0]); 1841 + 1842 + /* Create user_A */ 1843 + if (setup_userns() < 0) { 1844 + close(pipefd[1]); 1845 + exit(1); 1846 + } 1847 + 1848 + int ua_fd = open("/proc/self/ns/user", O_RDONLY); 1849 + if (ua_fd < 0) { 1850 + close(pipefd[1]); 1851 + exit(1); 1852 + } 1853 + if (ioctl(ua_fd, NS_GET_ID, &ua_id) < 0) { 1854 + close(ua_fd); 1855 + close(pipefd[1]); 1856 + exit(1); 1857 + } 1858 + close(ua_fd); 1859 + 1860 + /* Create user_B (child of user_A) */ 1861 + if (setup_userns() < 0) { 1862 + close(pipefd[1]); 1863 + exit(1); 1864 + } 1865 + 1866 + int ub_fd = open("/proc/self/ns/user", O_RDONLY); 1867 + if (ub_fd < 0) { 1868 + close(pipefd[1]); 1869 + exit(1); 1870 + } 1871 + if (ioctl(ub_fd, NS_GET_ID, &ub_id) < 0) { 1872 + close(ub_fd); 1873 + close(pipefd[1]); 1874 + exit(1); 1875 + } 1876 + close(ub_fd); 1877 + 1878 + /* Send both namespace IDs */ 1879 + write(pipefd[1], &ua_id, sizeof(ua_id)); 1880 + write(pipefd[1], &ub_id, sizeof(ub_id)); 1881 + close(pipefd[1]); 1882 + exit(0); 1883 + } 1884 + 1885 + close(pipefd[1]); 1886 + 1887 + /* Read both namespace IDs - fixed size, no parsing needed */ 1888 + ret = read(pipefd[0], &ua_id, sizeof(ua_id)); 1889 + if (ret != sizeof(ua_id)) { 1890 + close(pipefd[0]); 1891 + waitpid(pid, NULL, 0); 1892 + SKIP(return, "Failed to read user_A namespace ID"); 1893 + } 1894 + 1895 + ret = read(pipefd[0], &ub_id, sizeof(ub_id)); 1896 + close(pipefd[0]); 1897 + if (ret != sizeof(ub_id)) { 1898 + waitpid(pid, NULL, 0); 1899 + SKIP(return, "Failed to read user_B namespace ID"); 1900 + } 1901 + 1902 + /* Construct file handles from namespace IDs */ 1903 + ua_handle = (struct file_handle *)ua_buf; 1904 + ua_handle->handle_bytes = sizeof(struct nsfs_file_handle); 1905 + ua_handle->handle_type = FILEID_NSFS; 1906 + struct nsfs_file_handle *ua_fh = (struct nsfs_file_handle *)ua_handle->f_handle; 1907 + ua_fh->ns_id = ua_id; 1908 + ua_fh->ns_type = 0; 1909 + ua_fh->ns_inum = 0; 1910 + 1911 + ub_handle = (struct file_handle *)ub_buf; 1912 + ub_handle->handle_bytes = sizeof(struct nsfs_file_handle); 1913 + ub_handle->handle_type = FILEID_NSFS; 1914 + struct nsfs_file_handle *ub_fh = (struct nsfs_file_handle *)ub_handle->f_handle; 1915 + ub_fh->ns_id = ub_id; 1916 + ub_fh->ns_type = 0; 1917 + ub_fh->ns_inum = 0; 1918 + 1919 + /* Open user_B before child exits */ 1920 + int ub_fd = open_by_handle_at(FD_NSFS_ROOT, ub_handle, O_RDONLY); 1921 + if (ub_fd < 0) { 1922 + waitpid(pid, NULL, 0); 1923 + SKIP(return, "Failed to open user_B"); 1924 + } 1925 + 1926 + waitpid(pid, &status, 0); 1927 + ASSERT_TRUE(WIFEXITED(status)); 1928 + ASSERT_EQ(WEXITSTATUS(status), 0); 1929 + 1930 + /* With user_B active, user_A should also be active */ 1931 + TH_LOG("Testing user_A active when child user_B is active"); 1932 + int ua_fd = open_by_handle_at(FD_NSFS_ROOT, ua_handle, O_RDONLY); 1933 + ASSERT_GE(ua_fd, 0); 1934 + 1935 + /* Close user_B */ 1936 + TH_LOG("Closing user_B"); 1937 + close(ub_fd); 1938 + 1939 + /* user_A should remain active (we hold direct ref) */ 1940 + int ua_fd2 = open_by_handle_at(FD_NSFS_ROOT, ua_handle, O_RDONLY); 1941 + ASSERT_GE(ua_fd2, 0); 1942 + close(ua_fd2); 1943 + 1944 + /* Close user_A - should become inactive */ 1945 + TH_LOG("Closing user_A - should become inactive"); 1946 + close(ua_fd); 1947 + 1948 + ua_fd = open_by_handle_at(FD_NSFS_ROOT, ua_handle, O_RDONLY); 1949 + ASSERT_LT(ua_fd, 0); 1950 + } 1951 + 1820 1952 TEST_HARNESS_MAIN