Làm thế nào tôi có thể lừa một quá trình nghĩ rằng một tập tin không tồn tại?


31

Tôi có một chương trình lưu trữ các thiết lập của nó trong ~/.config/myprogramrằng tôi sử dụng cả tương tác và với một hệ thống xếp hàng loạt. Khi chạy tương tác, tôi muốn chương trình này sử dụng các tệp cấu hình của mình (và nó cũng vậy). Nhưng khi chạy ở chế độ hàng loạt, các tệp cấu hình không cần thiết vì tôi chỉ định các tùy chọn dòng lệnh ghi đè lên tất cả các cài đặt có liên quan. Hơn nữa, truy cập các tệp cấu hình qua mạng làm tăng thời gian khởi động của chương trình thêm vài giây; nếu các tệp không tồn tại, chương trình sẽ khởi chạy nhanh hơn nhiều (vì mỗi công việc chỉ mất khoảng một phút, điều này có tác động đáng kể đến thông lượng công việc hàng loạt). Nhưng vì tôi cũng sử dụng chương trình một cách tương tác, tôi không muốn di chuyển / xóa các tệp cấu hình của mình mọi lúc. Tùy thuộc vào thời điểm các công việc hàng loạt của tôi được lên lịch trên cụm (dựa trên việc sử dụng của người dùng khác),

(Ngoài ra: hiệu suất tệp mạng quá chậm có lẽ là một lỗi, nhưng tôi chỉ là người dùng của cụm, vì vậy tôi chỉ có thể làm việc xung quanh nó chứ không thể khắc phục nó.)

Tôi có thể xây dựng một phiên bản chương trình không đọc các tệp cấu hình (hoặc không có tùy chọn dòng lệnh) để sử dụng hàng loạt, nhưng môi trường xây dựng của chương trình này được thiết kế kém và khó thiết lập. Tôi rất thích sử dụng các nhị phân được cài đặt thông qua trình quản lý gói của hệ thống.

Làm cách nào tôi có thể lừa các trường hợp cụ thể của chương trình này để giả vờ các tệp cấu hình của tôi không tồn tại (mà không sửa đổi chương trình)? Tôi hy vọng cho một gói của mẫu pretendfiledoesntexist ~/.config/myprogram -- myprogram --various-options..., nhưng tôi mở cho các giải pháp khác.


2
Bạn có thể chạy nó với tư cách là người dùng không có quyền đọc tệp.
psimon

1
@psimon Là "chỉ là người dùng" của cụm, tôi không thể tạo người dùng mới để chạy công việc hàng loạt của mình như. Tuy nhiên, đó là một ý tưởng thông minh và nếu không có đề xuất nào tốt hơn, tôi sẽ yêu cầu quản trị viên cụm làm điều đó cho tôi.
Jeffrey Bosboom

Hoặc thiết lập tập lệnh trước tiên đổi tên tệp cấu hình, chạy chương trình và sau đó đổi tên tệp cấu hình lại.
psimon

@psimon Tôi đoán rằng tôi có thể đã rõ ràng hơn: Tôi có thể đang sử dụng chương trình một cách tương tác và trong chế độ hàng loạt cùng một lúc, tùy thuộc vào thời điểm các công việc hàng loạt của tôi được lên lịch trên cụm.
Jeffrey Bosboom

1
Có, nếu nó được liên kết động, bạn có thể sử dụng một LD_PRELOADcái móc. Điều đó dễ dàng hơn (bạn có thể thực hiện điều đó trong một hoặc hai giờ, nếu bạn biết C) so với phương án thay thế ptrace. Bạn cũng có thể sử dụng fakechroot để làm điều này (đó là LD_PRELOAD, tôi tin vậy).
derobert

Câu trả lời:


33

Chương trình đó có thể giải quyết đường dẫn đến tập tin đó từ $HOME/.config/myprogram. Vì vậy, bạn có thể nói với nó thư mục nhà của bạn là ở nơi khác, như:

HOME=/nowhere your-program

Bây giờ, có thể chương trình của bạn cần một số tài nguyên khác trong thư mục nhà của bạn. Nếu bạn biết chúng là gì, bạn có thể chuẩn bị một ngôi nhà giả cho chương trình của mình với các liên kết đến tài nguyên mà nó cần trong đó.

mkdir -p ~/myprogram-home/.config
ln -s ~/.Xauthority ~/myprogram-home/
...
HOME=~/myprogram-home myprogram

5
Câu trả lời này giải quyết vấn đề của tôi, vì vậy tôi đã chấp nhận nó mặc dù đó không phải là câu trả lời chung chung cho câu hỏi trong tiêu đề của câu hỏi này. Một hook tải trước, như được mô tả trong một câu trả lời khác, là một giải pháp tổng quát hơn (nhưng cũng có nỗ lực cao hơn).
Jeffrey Bosboom

28

Nếu vẫn thất bại, hãy viết thư viện trình bao bọc mà bạn sẽ sử dụng LD_PRELOADđể cuộc gọi đến open("/home/you/my-program/config.interactive")bị chặn nhưng bất kỳ cuộc gọi nào khác sẽ đi qua. Điều này hoạt động cho bất kỳ loại chương trình, ngay cả các kịch bản shell, vì nó sẽ lọc các cuộc gọi hệ thống.

extern int errno;

int open(const char *pathname, int flags)
{
  char *config_path = get_config_file_path();
  if (!strstr(pathname, config_path))
  {
    return get_real_open(pathname, flags);
  }
  else
  {
    errno = ENOENT;
    return -1;
  }
}

Lưu ý: Tôi chưa kiểm tra mã này và tôi không chắc chắn 100% rằng errnophần đó hoạt động.

Nhìn vào cách fakerootnó cho các cuộc gọi như getuid(2)stat(2).

Về cơ bản, trình liên kết sẽ liên kết ứng dụng đó với thư viện của bạn, ghi đè openbiểu tượng. Vì bạn không thể sử dụng hai hàm khác nhau có tên opentrong thư viện của riêng mình, bạn phải tách nó trong phần thứ hai (ví dụ get_real_open) sẽ lần lượt liên kết với opencuộc gọi ban đầu .

Nguyên: ./Application

Application -----> libc.so
            open()

Bị chặn: LD_PRELOAD=yourlib_wrap.so ./Application

Application -----> yourlib_wrap.so --------------> yourlib_impl.so -----> libc.so
            open()                 get_real_open()                 open()

Chỉnh sửa: Rõ ràng có một ldcờ bạn có thể bật ( --wrap <symbol>) cho phép bạn viết các hàm bao mà không cần phải dùng đến liên kết đôi:

/* yourlib.c */
#include <stdio.h>

int __real_open(const char *pathname, int flags)

int __wrap_open(const char *pathname, int flags)
{
  char *config_path = get_config_file_path();
  if (!strstr(pathname, config_path))
  {
    /* the undefined reference here will resolve to "open" at linking time */
    return __real_open(pathname, flags);
  }
  else
  {
    errno = ENOENT;
    return -1; 
  }
}

2

Di chuyển tệp cấu hình của bạn ra khỏi đường và viết trình bao bọc kịch bản lệnh shell cho trường hợp sử dụng tương tác sao chép tệp vào đích thông thường của nó, chạy chương trình và xóa tệp khi thoát.


Xem chỉnh sửa gần đây của tôi: Tôi không kiểm soát lập lịch hàng loạt, vì vậy tôi có thể sử dụng chương trình một cách tương tác và là một phần của công việc hàng loạt cùng một lúc.
Jeffrey Bosboom

1

Điều này nên có thể với unionfs / aufs. Bạn tạo một chrootmôi trường cho quá trình. Bạn sử dụng thư mục thực như là lớp chỉ đọc và đặt một cái trống lên trên nó. Sau đó, bạn gắn khối lượng unionfs vào thư mục tương ứng trong chrootmôi trường và xóa tệp ở đó. Quá trình sẽ không nhìn thấy nó nhưng tất cả những người khác làm.


0

Đổi tên tập tin cấu hình thành ví dụ config.interactive. Tạo một tập tin trống khác gọi là eg config.script.

Bây giờ, hãy tạo một liên kết mềm có tên config(hoặc bất cứ thứ gì ứng dụng mong đợi dưới dạng tệp cấu hình) cho bất kỳ cấu hình thực nào bạn cần và chạy ứng dụng của bạn.

ln -s config.interactive config

Hãy nhớ để dọn dẹp liên kết của bạn sau đó.


Xem chỉnh sửa gần đây của tôi: Tôi không kiểm soát lập lịch hàng loạt, vì vậy tôi có thể sử dụng chương trình một cách tương tác và là một phần của công việc hàng loạt cùng một lúc. Câu trả lời này về cơ bản giống như di chuyển các tệp xung quanh, bằng tay hoặc bằng một tập lệnh.
Jeffrey Bosboom

1
Đừng! Tôi cần suy nghĩ và gõ nhanh hơn. Nó có phải là một ứng dụng lớn? Nó có thể được chuyển đến một chroot và chạy từ đó một cách tương tác? Tất cả phụ thuộc vào những gì chương trình tương tác với, tôi cho rằng. Nó cũng có thể là một nhiệm vụ rất tẻ nhạt để có được tất cả mọi thứ nó yêu cầu vào một chroot quá. (Tôi nghĩ rằng tôi đã nói về bản thân mình từ lựa chọn đó!)
garethTheRed

0

Nếu bạn đã mô tả chính xác cách chương trình của bạn sử dụng tệp cấu hình, tôi đã bỏ qua nó. Nhiều chương trình (như bashvi) sẽ kiểm tra tệp cấu hình ngay khi bắt đầu; Nếu tập tin tồn tại, đọc nó và đóng nó. Các chương trình này không bao giờ truy cập các tệp khởi tạo này một lần nữa. Nếu chương trình của bạn là như thế, hãy đọc tiếp.

Tôi biết bạn đã từ chối câu trả lời làm cho tệp cấu hình thực sự không tồn tại (bằng cách đổi tên nó), nhưng tôi có một nếp nhăn mà tôi chưa thấy ai đề xuất. Làm điều này khi bạn gọi chương trình trong chế độ hàng loạt:

DELAY_TIME=1
REALPATH="~/.config/myprogram"
HOLDPATH="${REALPATH}.hold"

mv "$REALPATH" "$HOLDPATH"
(sleep "$DELAY_TIME"; mv "$HOLDPATH" "$REALPATH")&
myprogram

Thao tác này sẽ di chuyển tệp cấu hình ra khỏi đường đi, nhưng sau đó di chuyển nó trở lại sau một giây, ngay cả khi myprogramvẫn đang chạy. Điều này tạo ra một cửa sổ thời gian rất ngắn trong đó tệp không có sẵn - xác suất bạn sẽ chạy chương trình tương tác trong cửa sổ này là bao nhiêu? (Ngay cả khi bạn làm như vậy, bạn chỉ có thể thoát và khởi động lại, và tệp cấu hình có thể sẽ trở lại đúng vị trí.)

Điều này không tạo ra một điều kiện chủng tộc; nếu chương trình mất quá nhiều thời gian để mở tệp, nó có thể nhận được tệp thực. Nếu điều này xảy ra thường xuyên đến mức đó là một vấn đề, chỉ cần tăng giá trị của DELAY_TIME.


1
Điều tồi tệ nhất có thể đi sai là gì? Tôi thực sự đã thấy điều đó xảy ra. Trong sản xuất.
Henk Langeveld

-1

Tôi thích câu trả lời của Stephane, nhưng điều này sẽ lừa bất kỳ chương trình nào tin rằng bất kỳ tệp nào đều trống - (vì nha của nó tạm thời trỏ đến một tệp thực sự trống) :

cat <./test.txt
###OUTPUT###
notempty

mount --bind /dev/null ./test.txt
cat <./test.txt
###NO OUTPUT###

umount ./test.txt
cat <./test.txt
###OUTPUT###
notempty

Bạn cũng có thể:

mount --bind ./someotherconfig.conf ./unwanted.conf

Nếu bạn muốn.


Điều này về cơ bản tương đương với một vài câu trả lời trước đó (ngoại trừ, tôi tin rằng, câu hỏi này đòi hỏi người dùng phải được đặc quyền). OP đã từ chối những câu trả lời khác vì anh ta không muốn lừa bất kỳ quy trình nào - anh ta muốn lừa cuộc gọi hàng loạt của chương trình, trong khi để lời gọi tương tác nhìn thấy tệp cấu hình bình thường.
Scott

@Scott - tôi không đồng ý - mọi câu trả lời khác trước câu hỏi này đều đề xuất một số biến thể mvkhi nhập tệp - điều này có thể có hậu quả khác ngoài việc ảnh hưởng đến răng của nó như thực sự cắt bớt tệp hoặc những thứ khác, v.v. - trong khi điều này không hoạt động gì ngoài. Tuy nhiên, tôi nên unsharemounttôi đoán ...
mikeserv
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.