2012-02-15 39 views
6

Tôi có một quy trình với quyền 4750. Hai người dùng tồn tại trong hệ thống Linux của tôi. Người dùng root và người dùng appz. Quá trình kế thừa quyền của người quản lý quy trình chạy dưới dạng người dùng "appz".cách chính xác để chạy các chương trình setuid trong C

Tôi có hai thói quen cơ bản:

void do_root (void) 
{ 
     int status; 
     status = seteuid (euid); 
     if (status < 0) { 
     exit (status); 
     }  
} 

/* undo root permissions */ 
void undo_root (void) 
{ 
int status; 
     status = seteuid (ruid); 
     if (status < 0) { 
       exit (status); 
     } 
     status = setuid(ruid); 
     if (status < 0) { 
       exit (status); 
     } 
} 

dòng chảy của tôi là như sau:

int main() { 
undo_root(); 
do some stuff; 
do_root(); 
bind(port 80); //needs root perm 
undo_root(); 
while(1) { 

    accept commads() 
    if (commands needs root user access) 
    { 
     do_root(); 
     execute(); 
     undo_root(); 

    } 

} 

Như bạn có thể thấy tôi muốn thực hiện một số lệnh như root. Tôi đang cố gắng để giảm quyền tạm thời và nếu các nhiệm vụ cần truy cập root tôi quấn lệnh giữa một cuộc gọi do_root và undo_root.

Tuy nhiên có vẻ như chương trình của tôi không hoạt động.

Cách kinh điển để làm điều đó là gì?

+0

Thay vì thoát khi seteuid không thành công, hãy gọi perror() và chương trình của bạn sẽ cho bạn biết tại sao nó không thành công. –

+4

Khi bạn thả quyền root, bạn không thể lấy lại chúng !! – Petesh

+0

Về mặt kỹ thuật, đó là tệp giữ chương trình có quyền 4750, không phải là quá trình. Bạn không trực tiếp nói rằng các điều khoản là 'root: group: 4750' - đó có phải là suy luận an toàn không? –

Trả lời

5

Cách trường học cũ là trong cả hai do_root và undo_root sử dụng setreuid() để trao đổi ruid và euid:

setreuid(geteuid(), getuid()); 

này là hoàn toàn chấp nhận được nếu chương trình là đủ nhỏ để làm một kiểm toán an ninh hoàn chỉnh .

Cách học mới phức tạp hơn nhiều và liên quan đến ngã ba() đưa ra một đứa trẻ chấp nhận chỉ thị cho việc cần làm là root và sau đó làm setuid (getuid()) để thả root vĩnh viễn trong parent .. trẻ có trách nhiệm xác nhận tất cả các chỉ thị mà nó nhận được. Đối với một chương trình đủ lớn, điều này sẽ giảm số lượng mã phải được kiểm tra bảo mật và cho phép người dùng quản lý quy trình có kiểm soát công việc hoặc giết nó, v.v.

+0

ý của bạn là gì? Chỉ cần sao chép và dán mã của bạn trong cả hai chức năng? – cateof

+0

Có. __________ – Joshua

2

Trang setuid người đàn ông nói như sau:

... một chương trình set-user-ID-gốc có nhu cầu tạm thời thả rễ đặc quyền, giả danh tính của một người sử dụng không phải root, và sau đó lấy lại đặc quyền gốc sau đó không thể sử dụng setuid()

Có nghĩa là bạn không thể sử dụng setuid(). Bạn phải sử dụng seteuid() và, có thể, setreuid(). Xem Setuid Program Example để biết thêm chi tiết.

+0

Chương trình của tôi dựa hoàn toàn vào trang GNU này. Thay vì do_setuid, ban đầu tôi đã làm do_root. – cateof

+0

@cateof: Tôi thấy bạn sử dụng hàm 'setuid' trong mã bạn đã đăng. Đó là vé một chiều. –

5

Có một bài báo 'Setuid Demystified' của Hao Chen, David Wagner và Drew Dean. Nó được trình bày tại USENIX 2002. Nó mô tả cách setuid() và quá trình chuyển đổi hoạt động rất chi tiết (đúng như năm 2002). Đó là giá trị đọc (nhiều lần - tôi phải là một hoặc hai năm quá hạn trên một lần đọc lại của nó).

Về cơ bản, như Petesh ghi nhận trong một chú thích, khi một quá trình với euid 0 không setuid(nuid) với nuid != 0, không có cách nào trở lại root (euid 0) đặc quyền. Và, quả thực, điều quan trọng là nó là như vậy. Nếu không, khi bạn đăng nhập, quy trình root đăng nhập bạn không thể giới hạn bạn với các đặc quyền của riêng bạn - bạn có thể quay lại root. UID đã lưu làm phức tạp mọi thứ, nhưng tôi không tin rằng nó ảnh hưởng đến bẫy một chiều của EUID 0 đang thực hiện setuid().

Các vấn đề liên quan