#ifdef SENDER int main() { int sock, file_fd; struct sockaddr_un addr; struct msghdr msg; struct cmsghdr *cmsg; struct iovec iov[1]; char ctrl_buf[CMSG_SPACE(sizeof(int))]; // 为一个 int (fd) 分配控制消息空间 char data[] = "FD"; int data_len = strlen(data);
// 1. 创建要传递的文件 file_fd = open("testfile.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644); if (file_fd == -1) { perror("open testfile.txt"); exit(EXIT_FAILURE); } write(file_fd, "This is data in the passed file.\n", 33); printf("Created and wrote to 'testfile.txt' (fd: %d)\n", file_fd);
/** * 健壮性测试配置 */ typedef struct { int num_threads; int test_duration; int crash_probability; // 0-100,表示异常终止概率 int use_robust_mutex; } robustness_test_config_t;
在 Linux 系统中,进程和线程是程序执行的基本单位。每个线程都有一个唯一的标识符,叫做 Thread ID (TID)。对于主线程(也就是进程本身),它的 TID 通常和 Process ID (PID) 是相同的。但对于通过 clone() 或 pthread_create() 创建的子线程,它们会有自己独立的 TID。
int main() { struct user_desc u_info; long result; void *tls_mem; int my_tls_var_offset = 0; // 假设我们的 TLS 变量在 TLS 块的偏移 0 处
printf("--- Demonstrating set_thread_area (i386 specific) ---\n"); printf("This is a low-level example and may not work on all systems.\n"); printf("Architecture: %s\n", __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ ? "Little Endian" : "Big Endian"); printf("Pointer size: %zu bytes\n", sizeof(void*));
printf("Setting up TLS descriptor...\n"); printf(" Base Address: 0x%lx\n", u_info.base_addr); printf(" Entry Number requested: %u\n", u_info.entry_number);
// 4. 调用 set_thread_area 系统调用 result = syscall(SYS_set_thread_area, &u_info);
if (result == -1) { perror("set_thread_area"); munmap(tls_mem, 4096); exit(EXIT_FAILURE); }
printf("\n--- Important Notes ---\n"); printf("1. Direct use of GS register via inline assembly is complex and not portable.\n"); printf("2. Modern code should use '__thread' keyword or pthread_getspecific/setspecific.\n"); printf("3. This example is for educational purposes on i386 architecture.\n");
// 6. 清理资源 munmap(tls_mem, 4096); printf("Cleaned up TLS memory.\n");
// 2. 检查是否以 root 权限运行 if (geteuid() == 0) { printf("\nRunning as ROOT (Privileged User)\n"); // 作为 root,可以设置为任意有效的 GID // 这里我们尝试设置为 'daemon' 组 (通常 GID 1, 但请检查你的系统) target_gid = 1; printf("Attempting to set GID to %d (usually 'daemon' group)...\n", target_gid);
print_current_gids("Before setgid"); result = setgid(target_gid); if (result == 0) { printf("setgid(%d) succeeded.\n", target_gid); print_current_gids("After setgid"); printf("Note: All GIDs (Real, Effective, Saved) are now %d.\n", target_gid); } else { perror("setgid"); printf("Failed to set GID to %d.\n", target_gid); }
} else { printf("\nRunning as a REGULAR USER (UID: %d)\n", getuid());
// 作为普通用户,只能设置为自己的 rgid 或 sgid target_gid = original_rgid; // 选择设置为自己的真实 GID (这不会改变任何东西) printf("Attempting to set GID to my Real GID (%d)...\n", target_gid); print_current_gids("Before setgid"); result = setgid(target_gid); if (result == 0) { printf("setgid(%d) succeeded (as expected).\n", target_gid); print_current_gids("After setgid"); } else { perror("setgid"); }
// 尝试设置为一个无效的 GID (比如一个不存在的或不属于我的 GID) // 这通常会失败 target_gid = 9999; // 假设这是一个无效的或不属于当前用户的 GID printf("\nAttempting to set GID to an invalid/different GID (%d)...\n", target_gid); result = setgid(target_gid); if (result == -1) { if (errno == EPERM) { printf("setgid(%d) failed with EPERM (Operation not permitted) - as expected for a regular user.\n", target_gid); printf("This is because %d is not my Real GID (%d) or Saved Set-GID (%d).\n", target_gid, original_rgid, original_sgid); } else { perror("setgid"); } print_current_gids("After failed setgid"); } else { printf("setgid(%d) unexpectedly succeeded.\n", target_gid); print_current_gids("After unexpected setgid"); } }
printf("\n--- Summary ---\n"); printf("The setgid() function changes the Effective GID of the process.\n"); printf("For root: It can change to any GID, and also changes Real and Saved GID.\n"); printf("For regular users: It can only change Effective GID to Real or Saved GID.\n");
Running as a REGULAR USER (UID: 1000) Attempting to set GID to my Real GID (1000)... [Before setgid] Current GIDs - Real: 1000, Effective: 1000, Saved: 1000 setgid(1000) succeeded (as expected). [After setgid] Current GIDs - Real: 1000, Effective: 1000, Saved: 1000
Attempting to set GID to an invalid/different GID (9999)... setgid(9999) failed with EPERM (Operation not permitted) - as expected for a regular user. This is because 9999 is not my Real GID (1000) or Saved Set-GID (1000). [After failed setgid] Current GIDs - Real: 1000, Effective: 1000, Saved: 1000
--- Summary --- The setgid() function changes the Effective GID of the process. For root: It can change to any GID, and also changes Real and Saved GID. For regular users: It can only change Effective GID to Real or Saved GID.
// 3. 检查命令行参数 if (argc != 2) { printf("Usage: %s <new_hostname>\n", argv[0]); printf("Note: You need to run this program as root to change the hostname.\n"); exit(EXIT_FAILURE); }
printf("\nAttempting to change hostname to: '%s'\n", new_hostname);
// 4. 调用 sethostname // 注意:这需要 root 权限 if (sethostname(new_hostname, strlen(new_hostname)) == -1) { perror("sethostname"); if (errno == EPERM) { printf("Error: Permission denied. You must run this program as root (e.g., using sudo).\n"); } exit(EXIT_FAILURE); }
// 6. 再次使用 uname 验证 if (uname(&uname_info) == 0) { printf("[uname after change] Node name (hostname): %s\n", uname_info.nodename); }
printf("\n--- Important Notes ---\n"); printf("1. The hostname change is TEMPORARY and only lasts until the system is rebooted.\n"); printf("2. To make the change persistent, you need to update configuration files like /etc/hostname.\n"); printf("3. You need ROOT privileges to call sethostname.\n");
# 假设原始主机名是 'old-hostname' $ sudo ./sethostname_example NewTempName --- Demonstrating sethostname --- [Initial] Current hostname is: 'old-hostname' [uname] System name: Linux [uname] Node name (hostname): old-hostname [uname] Release: 5.4.0-XX-generic [uname] Version: #XX-Ubuntu SMP ... [uname] Machine: x86_64
Attempting to change hostname to: 'NewTempName' sethostname('NewTempName') succeeded. [After sethostname] Current hostname is: 'NewTempName' [uname after change] Node name (hostname): NewTempName
--- Important Notes --- 1. The hostname change is TEMPORARY and only lasts until the system is rebooted. 2. To make the change persistent, you need to update configuration files like /etc/hostname. 3. You need ROOT privileges to call sethostname.
Linux 命名空间 (Namespaces) 是 Linux 内核的一个强大特性,它提供了隔离机制。通过命名空间,可以将一组进程及其资源(如网络接口、挂载点、进程 ID 等)与系统上的其他进程隔离开来,仿佛它们运行在独立的系统中一样。这是实现 容器 (Containers) 技术(如 Docker, LXC)的核心基础之一。
Linux 支持多种类型的命名空间,每种隔离不同类型的系统资源:
Mount (mnt): 隔离文件系统挂载点。
PID (pid): 隔离进程 ID 空间。
Network (net): 隔离网络设备、IP 地址、端口等。
Interprocess Communication (ipc): 隔离 System V IPC 和 POSIX 消息队列。
printf("Child process: Mounted tmpfs on %s\n", mount_point);
// 在挂载点创建一个文件 char file_path[256]; snprintf(file_path, sizeof(file_path), "%s/test_file.txt", mount_point); FILE *f = fopen(file_path, "w"); if (f) { fprintf(f, "Hello from child process in its own mount namespace!\n"); fclose(f); printf("Child process: Created file %s\n", file_path); } else { perror("fopen (child)"); }
printf("Child process: Sleeping for 30 seconds. Check /tmp/my_test_mount from parent and child.\n"); printf("Child process: You can run 'ls /tmp/my_test_mount' in another terminal as root.\n"); sleep(30); // 睡眠,让我们有时间从外部观察
// 4. 在父进程中,检查 /tmp/my_test_mount 是否存在 // (它应该不存在,因为父进程在不同的 Mount Namespace) if (access("/tmp/my_test_mount", F_OK) == 0) { printf("Parent process: /tmp/my_test_mount EXISTS in parent namespace (unexpected!).\n"); } else { printf("Parent process: /tmp/my_test_mount does NOT exist in parent namespace (as expected).\n"); }
// 5. 现在,使用 setns 将父进程加入到子进程的 Mount Namespace printf("\n--- Calling setns to join child's mount namespace ---\n"); if (syscall(SYS_setns, child_ns_fd, CLONE_NEWNS) == -1) { perror("setns"); printf("Failed to join child's namespace. Do you have root privileges?\n"); close(parent_ns_fd); close(child_ns_fd); kill(child_pid, SIGKILL); waitpid(child_pid, NULL, 0); free(child_stack); exit(EXIT_FAILURE); } printf("Parent process successfully joined child's mount namespace.\n");
// 6. 再次检查 /tmp/my_test_mount // (现在它应该存在了,因为父进程已经加入了子进程的命名空间) if (access("/tmp/my_test_mount", F_OK) == 0) { printf("Parent process (after setns): /tmp/my_test_mount NOW EXISTS in current namespace.\n"); printf("Parent process (after setns): You can now see the file created by the child.\n"); // 尝试读取子进程创建的文件 char file_path[256]; snprintf(file_path, sizeof(file_path), "%s/test_file.txt", "/tmp/my_test_mount"); FILE *f = fopen(file_path, "r"); if (f) { char buffer[256]; if (fgets(buffer, sizeof(buffer), f)) { printf("Parent process (after setns): Read from file: %s", buffer); } fclose(f); } else { perror("fopen (parent after setns)"); } } else { printf("Parent process (after setns): /tmp/my_test_mount STILL does not exist (unexpected!).\n"); }
// 7. 清理和等待 printf("\n--- Cleaning up ---\n"); close(parent_ns_fd); close(child_ns_fd);
// 等待子进程结束 int status; waitpid(child_pid, &status, 0); if (WIFEXITED(status)) { printf("Child process exited with status %d.\n", WEXITSTATUS(status)); } else { printf("Child process did not exit normally.\n"); }
free(child_stack); printf("Main process finished.\n");
--- Demonstrating setns with Mount Namespace --- Main process PID: 12345 Opened parent's mount namespace fd: 3 Created child process with new mount namespace. PID: 12346 Child process (PID: 12346) started. Child process: Mounted tmpfs on /tmp/my_test_mount Child process: Created file /tmp/my_test_mount/test_file.txt Child process: Sleeping for 30 seconds. Check /tmp/my_test_mount from parent and child. Opened child's mount namespace fd: 4 Parent process: /tmp/my_test_mount does NOT exist in parent namespace (as expected).
--- Calling setns to join child's mount namespace --- Parent process successfully joined child's mount namespace. Parent process (after setns): /tmp/my_test_mount NOW EXISTS in current namespace. Parent process (after setns): You can now see the file created by the child. Parent process (after setns): Read from file: Hello from child process in its own mount namespace!
--- Cleaning up --- Child process exited with status 0. Main process finished.
总结:setns 是一个强大的系统调用,是 Linux 容器技术的基石之一。它允许进程动态地加入到已存在的命名空间中,从而获得该命名空间的视图和资源访问权限。对于 Linux 编程新手来说,理解命名空间的概念是第一步,setns 则是实现命名空间操作的关键工具。直接使用它进行编程比较复杂,通常在容器运行时(如 runc)或高级系统管理脚本中会用到。日常开发中,使用 nsenter 或容器管理工具(如 docker exec)是更常见的与命名空间交互的方式。
# Using dd (macOS) sudo dd if=ubuntu-22.04.4-desktop-amd64.iso of=/dev/rdiskX bs=1m
# Using balenaEtcher CLI sudo etcher-cli ubuntu-22.04.4-desktop-amd64.iso --drive /dev/sdX
🔄 Repository Mirror Configuration
Using Chinese Mirrors for Package Updates
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
# Backup original sources list sudo cp /etc/apt/sources.list /etc/apt/sources.list.backup
# Edit sources list sudo nano /etc/apt/sources.list
# Replace with Tsinghua mirror (Ubuntu 22.04 example) deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy main restricted universe multiverse deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy main restricted universe multiverse deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-updates main restricted universe multiverse deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-updates main restricted universe multiverse deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-backports main restricted universe multiverse deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-backports main restricted universe multiverse deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-security main restricted universe multiverse deb-src https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ jammy-security main restricted universe multiverse
Quick Mirror Switch Script
1 2 3 4 5
#!/bin/bash # Switch to Tsinghua mirror sudo sed -i 's/archive.ubuntu.com/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.list sudo sed -i 's/security.ubuntu.com/mirrors.tuna.tsinghua.edu.cn/g' /etc/apt/sources.list sudo apt update
# Test download speed (small file) time wget -O /dev/null https://mirrors.tuna.tsinghua.edu.cn/ubuntu-releases/HEADER.html
# Compare multiple mirrors for mirror in "releases.ubuntu.com" "mirrors.tuna.tsinghua.edu.cn" "mirrors.aliyun.com"; do echo "Testing $mirror:" time wget -O /dev/null "https://$mirror/ubuntu-releases/HEADER.html" 2>&1 | grep real done
🆘 Troubleshooting
Common Issues
Download interrupted: Use wget -c to resume
Checksum mismatch: Re-download from different mirror
Slow download: Try different geographic mirrors
Connection timeout: Check firewall/proxy settings
Alternative Download Methods
Torrent: Official Ubuntu torrents available
BitTorrent: P2P download option
CDN: Use commercial CDN mirrors
Local cache: University/institutional mirrors
All links marked with ✅ have been verified as working. This collection provides comprehensive options for downloading Ubuntu from the fastest and most reliable sources based on your geographic location.