2 điểm bởi GN⁺ 9 ngày trước | 1 bình luận | Chia sẻ qua WhatsApp
  • macOS trên nền tảng Apple Silicon giới hạn tối đa 2 máy ảo macOS có thể chạy bằng Virtualization.framework, dựa trên điều khoản trong thỏa thuận cấp phép sử dụng macOS
  • Kết quả phân tích cho thấy giới hạn này được quản lý bởi biến không công khai hv_apple_isa_vm_quota bên trong nhân XNU, và có thể ghi đè bằng tham số khởi động
  • Để vượt qua kiểm tra AppleInternal của System Integrity Protection, quy trình build và khởi động nhân phát triển (Development Kernel) được sử dụng
  • Sau khi cấu hình, đã chạy thành công tối đa 9 máy ảo macOS đồng thời trên UTM, Viable, Parallels
  • Điều đáng chú ý là Apple đã để lại khả năng ghi đè giới hạn VM bên trong nhân, mở ra khả năng cải tiến sau này thông qua công cụ tự động hóa hoặc kernel extension

Quá trình gỡ bỏ giới hạn 2 máy ảo macOS trên Apple Silicon

  • Khi chạy máy ảo macOS bằng Virtualization.framework trên máy Mac dùng Apple Silicon, có giới hạn chỉ tối đa 2 máy ảo có thể hoạt động cùng lúc
    • Giới hạn này được đặt theo điều khoản 2.B.iii trong thỏa thuận cấp phép phần mềm macOS (SLA)
    • Điều khoản này cho phép chạy tối đa 2 phiên bản macOS chỉ cho mục đích phát triển, kiểm thử, dùng macOS Server hoặc sử dụng cá nhân phi thương mại
  • Kết quả phân tích cho thấy giới hạn này được triển khai không phải ở user space mà trong vùng không công khai của nhân (XNU)
    • Nhân Intel không có cùng đoạn mã này, còn nhóm hàm hv_vm_* trong nhân Apple Silicon phụ trách ngăn xếp ảo hóa
    • Biến hv_apple_isa_vm_quota trong mã khởi tạo hv_init() quản lý số lượng VM và được tăng/giảm khi tạo hoặc xóa VM
    • Trong nhân có các tham số khởi động hypervisor=hv_apple_isa_vm_quota=, trong đó tham số sau có thể ghi đè giới hạn VM
  • Trên nhân phát hành, thay vì chỉ dùng tham số hypervisor, việc này còn bị giới hạn bởi kiểm tra AppleInternal của System Integrity Protection (SIP)
    • Tham số hv_apple_isa_vm_quota chỉ được áp dụng khi cờ CSR_ALLOW_APPLE_INTERNAL được bật
    • Để vượt qua điều này, phương pháp được dùng là khởi động nhân phát triển (Development Kernel) của Apple

Build kernel collection phát triển

  • Cần tải và cài đặt Kernel Debug Kit (KDK) từ trang Apple Developer
    • KDK phải khớp chính xác với bản build macOS của máy chủ, nếu không có thể xảy ra lỗi liên kết kernel/kext và lỗi khởi động
  • Sau khi kiểm tra kiến trúc nhân bằng lệnh uname, dùng lệnh kmutil create để tạo kernel collection phát triển (VirtualMachine.kc)
    • Ví dụ sử dụng macOS 14.0 (build 23A5301h) và nhân T6020
    • Tùy chọn --variant-suffix development chỉ định nhân phát triển và bao gồm nhiều kho lưu trữ system extension

Cấu hình khởi động nhân phát triển

  • Tắt máy Mac rồi khởi động vào recoveryOS, sau đó thực hiện các thiết lập sau trong Terminal
    1. Vô hiệu hóa System Integrity Protection (csrutil disable)
    2. Gỡ giới hạn tham số khởi động (bputil --disable-boot-args-restriction)
    3. Chỉ định kernel collection tùy chỉnh (kmutil configure-boot)
    4. Thiết lập tham số khởi động (truyền bằng lệnh nvram)
      • kcsuffix=development : khởi động nhân phát triển
      • hypervisor=0x1 : bật các tính năng đặc biệt của ngăn xếp ảo hóa
      • hv_apple_isa_vm_quota=0xFF : đặt số VM tối đa là 255
  • Sau khi khởi động lại, có thể kiểm tra việc áp dụng bằng sysctl kern.osbuildconfignvram boot-args

Kết quả chạy nhiều VM

  • Sau khi hoàn tất cấu hình, đã thử nghiệm với các giải pháp dựa trên Virtualization.framework như UTM, Viable, Parallels
    • Trên MacBook Pro M2 Pro, đã chạy thành công 9 máy ảo macOS đồng thời
    • Hệ thống vẫn hoạt động ở mức có thể kiểm thử được

Thời điểm tính năng được thêm vào và cấu trúc bên trong

  • Tham số khởi động hv_apple_isa_vm_quota được thêm từ macOS 12 Monterey cùng với ngăn xếp Virtualization
    • Ở các phiên bản sau đó (bao gồm macOS Sonoma), kiểm tra AppleInternal vẫn còn tồn tại
    • Điều này cho thấy Apple vẫn duy trì nhiều tính năng không công khai bên trong XNU

Lưu ý khi cập nhật OS

  • Khi dùng kernel collection tùy chỉnh, tính năng tự động cập nhật OS sẽ bị vô hiệu hóa
    • Do có thể phát sinh lỗi sau khi cập nhật, cần khôi phục về kernel collection mặc định
    • Trong chế độ khôi phục, có thể dùng bputil để tạo chính sách khởi động mới nhằm quay lại nhân mặc định
    • Ví dụ: dùng các tùy chọn bputil --full-security hoặc --disable-boot-args-restriction

Kết luận và ý tưởng cải tiến trong tương lai

  • Bài viết xác nhận cách Apple triển khai giới hạn VM và kiểm chứng bằng thực nghiệm một phương pháp gỡ giới hạn không chính thức
    • Dù nhóm Virtualization chưa tài liệu hóa chính thức, việc Apple để lại chức năng ghi đè giới hạn VM trong nhân là điểm đáng chú ý
  • Các hướng cải tiến trong tương lai
    • Phát triển công cụ tự động hóa build KC và cấu hình khởi động
      • Tự động tạo kernel collection phát triển theo từng máy chủ và hỗ trợ thiết lập trong chế độ khôi phục
    • Triển khai chức năng ghi đè biến hv_apple_isa_vm_quota thông qua kernel extension (kext)
      • Khảo sát khả năng gỡ giới hạn mà không cần khởi động nhân phát triển
  • Chủ đề nghiên cứu tiếp theo là khả năng đăng ký DEP và ghi đè số serial của VM trên Apple Silicon

1 bình luận

 
Ý kiến trên Hacker News
  • Một giới hạn như thế này áp dụng giống nhau cho mọi máy Mac là quá vô lý
    Nếu đã mua Mac mạnh hơn thì phải có thể ảo hóa được nhiều phiên bản macOS hơn
    Ví dụ giới hạn kiểu M5 là 2, M5 Pro là 4, M5 Max là 8 có vẻ sẽ hợp lý hơn

    • Thậm chí tôi còn không hiểu vì sao lại phải đặt giới hạn ngay từ đầu
      Hiệu năng phần cứng mới là giới hạn tự nhiên, người dùng tự khắc sẽ dừng lại
    • Cái này có vẻ là quyết định kinh doanh hơn là vấn đề tài nguyên
      Khả năng cao là để chặn các dịch vụ Mac VPS giá rẻ
    • Đây không phải giới hạn phần cứng mà là đang đấu với nỗi lo doanh số của Tim Cook
    • Mua giấy phép Windows 11 Pro với giá 100 USD thì giới hạn VM là 1024
      Hyper‑V có thể chạy đồng thời tối đa 1024 VM nếu phần cứng chịu nổi
      Ngay cả chiếc laptop Windows ARM nhỏ của tôi cũng chạy 4 cái không vấn đề gì
    • Thật sự quá vô lý
      Tôi chạy VM để thử openclaw, nhưng rồi ngỡ ngàng khi thấy bị hạn chế truy cập iCloud và App Store
  • Khá thú vị khi 2 năm sau khi viết bài blog này, Mykola Grymalyuk lại vào làm ở Apple
    Tự nhiên nhớ đến meme “chết như một anh hùng hoặc...”

  • Từ M3 trở lên có thể chạy nested VM bằng Hypervisor.framework / Virtualization.framework
    Nếu cách này vượt được giới hạn thì khá thú vị đấy

    • Nếu tôi nhớ không nhầm thì chỉ Linux guest mới nested được
      macOS chỉ đi được một tầng, nên không thể chạy thêm một macOS guest khác bên trong macOS guest
    • Nếu mỗi VM lại có thể chạy 2 VM nữa thì có thể tạo ra chuỗi VM vô hạn
      Tôi lười quá nhưng mong ai đó thử hộ
  • Tôi thật sự tò mò vì sao Apple lại đặt giới hạn kiểu này

    • Mô hình kinh doanh của Apple là bán phần cứng kèm phần mềm
      Doanh số phần cứng tài trợ cho việc phát triển phần mềm, nên họ không muốn người không mua phần cứng vẫn dùng macOS
    • macOS có rất nhiều kiểu ràng buộc người dùng như thế này
      Việc Apple giữ quyền kiểm soát luôn được ưu tiên hơn tự do của người dùng
    • Có lẽ đây cũng là biện pháp để ngăn việc dùng một máy Mac duy nhất để vận hành trang trại tài khoản trực tuyến (identity farm)
  • Việc có thể biên dịch kernel tùy chỉnh, khởi động nó và thậm chí lên được GUI thật đáng ngạc nhiên

  • Bản thân bài viết rất thú vị, nhưng dùng một nền tảng có những giới hạn tùy tiện như vậy cho mục đích phát triển thì thật kỳ lạ

    • Tôi nghi ngờ không biết 20 năm qua Apple có từng là một nền tảng phát triển nghiêm túc hay không
      Nhiều lập trình viên dùng vì phần cứng cao cấp, nhưng macOS lúc nào cũng là “gần giống Linux nhưng là một OS do công ty lấy iTunes làm trung tâm kiểm soát”
  • Trên Apple Silicon, dùng custom kernel collection sẽ khiến không thể cập nhật OS tự động
    Nhưng biết đâu đây lại là một phúc lành trá hình

  • Không rõ cái này có hoạt động với lume không
    Hiện tại nó cũng có giới hạn tương tự

    • Có vẻ là được
      Theo tôi biết thì lume là wrapper mỏng quanh Virtualization.framework của Apple
  • Tôi nghe nói chỉ cần tắt SIP và đặt boot arg là làm được, không cần custom kernel

    • Nếu đúng vậy thì đây là một mẹo bị đánh giá thấp
  • Apple giới hạn VM ở 2 cái à?

    • Đúng vậy, theo giấy phép thì macOS VM chỉ được tối đa 2 cái
      Còn guest dùng OS khác thì có thể chạy không giới hạn