Skip to content
This repository was archived by the owner on May 27, 2026. It is now read-only.

Commit 1a600be

Browse files
authored
Merge pull request #50 from dmbaturin/T8306-vyos-op-run-debug-logging
vyos-op-run: T8306: improve debug logging and error reporting
2 parents cced1dd + efe8240 commit 1a600be

2 files changed

Lines changed: 38 additions & 10 deletions

File tree

debian/changelog

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
vyos-utils (0.0.6) unstable; urgency=medium
2+
3+
* Fix a permission check bypass.
4+
* Improve debug logging and error messages.
5+
6+
-- Daniil Baturin <daniil@vyos.io> Tue, 24 Feb 2026 14:38:55 +0000
7+
18
vyos-utils (0.0.5) unstable; urgency=medium
29

310
* Sanitize the environment in vyos-op-run to prevent malicious variable injection

src/vyos_op_run.ml

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -100,12 +100,14 @@ let get_string_field name obj =
100100
member name obj |> to_string
101101

102102
let read_command_definitions () =
103+
let () = Logs.debug @@ fun m -> m "Reading command definitions from %s" op_def_file in
103104
let ic = open_in op_def_file in
104105
let data = Yojson.Safe.from_channel ic in
105106
let () = close_in ic in
106107
data
107108

108109
let read_permissions () =
110+
let () = Logs.debug @@ fun m -> m "Reading user permissions from %s" permissions_file in
109111
let ic = open_in permissions_file in
110112
let data = Yojson.Safe.from_channel ic in
111113
let () = close_in ic in
@@ -218,13 +220,21 @@ let group_perms_match perms group cmd =
218220

219221
let is_admin () =
220222
(* If executed by root, skip all permission checks *)
221-
if Unix.getuid () = 0 then true else
222-
(* Otherwise, check if the user is a VyOS admin *)
223-
let admin_group = Unix.getgrnam vyos_admin_group_name in
224-
let user_groups = Unix.getgroups () in
225-
match (Array.find_opt ((=) admin_group.gr_gid) user_groups) with
226-
| Some _ -> true
227-
| None -> false
223+
if Unix.getuid () = 0 then
224+
let () = Logs.debug @@ fun m -> m "The user is root, permission checks will be skipped" in
225+
true
226+
else begin
227+
(* Otherwise, check if the user is a VyOS admin *)
228+
let admin_group = Unix.getgrnam vyos_admin_group_name in
229+
let user_groups = Unix.getgroups () in
230+
match (Array.find_opt ((=) admin_group.gr_gid) user_groups) with
231+
| Some _ ->
232+
let () = Logs.debug @@ fun m -> m "The user is a VyOS admin, permission checks will be skipped" in
233+
true
234+
| None ->
235+
let () = Logs.debug @@ fun m -> m "The user does not have VyOS admin permissions" in
236+
false
237+
end
228238

229239
let has_unsafe_characters cmd =
230240
(* XXX: this function is highly restrictive now,
@@ -244,6 +254,7 @@ let has_unsafe_characters cmd =
244254
- 'add system image': requires non-alphanumeric characters
245255
for URLs.
246256
*)
257+
let () = Logs.debug @@ fun m -> m "Checking the command for unsafe characters" in
247258
try
248259
let _ = Pcre2.exec ~pat:{|[^a-zA-Z0-9_\-\.\s]|} cmd in
249260
let () =
@@ -270,10 +281,13 @@ let is_admin_only_command cmd =
270281
if p = t then prefix_matches ps ts
271282
else false
272283
in
284+
let () = Logs.debug @@ fun m -> m "Checking if the command is admin-only" in
273285
let res = List.find_opt (fun p -> prefix_matches p cmd) admin_only_commands in
274286
match res with
275287
| None -> false
276-
| Some _ -> true
288+
| Some _ ->
289+
let () = Logs.debug @@ fun m -> m "Commandis reserved for admins" in
290+
true
277291

278292
let check_command_permissions perms cmd =
279293
let rec aux perms groups cmd =
@@ -283,6 +297,7 @@ let check_command_permissions perms cmd =
283297
if group_perms_match perms g cmd then ()
284298
else aux perms gs cmd
285299
in
300+
let () = Logs.debug @@ fun m -> m "Checking if the user is allowed to execute the command" in
286301
(* VyOS admins can execute any commands without restrictions *)
287302
if is_admin () then () else
288303
(* Operators are not allowed to execute commands
@@ -321,7 +336,6 @@ let render_command opts env command_tmpl =
321336
let run_external_command opts env command_tmpl =
322337
let cmd = render_command opts env command_tmpl in
323338
if opts.dry_run then Printf.printf "%s\n%!" cmd else
324-
let () = Logs.debug @@ fun m -> m "Command to be executed %s" cmd in
325339
(* Get the user database entry to populate the basic environment from:
326340
we cannot trust an unprivileged user to supply $SHELL
327341
or allow them to impersonate someone else by setting custom $LOGNAME, etc.
@@ -354,6 +368,7 @@ let run_external_command opts env command_tmpl =
354368
so that a user trying to do PATH=/bad/place vyos-op-run
355369
cannot achieve anything with that trick.
356370
*)
371+
let () = Logs.debug @@ fun m -> m "Executing Unix command: %s" cmd in
357372
let res = Unix.execve shell [|shell; "-c"; cmd|] env in
358373
match res with
359374
| Unix.WEXITED 0 -> ()
@@ -487,7 +502,7 @@ let () =
487502
let () = setup_logging debug in
488503
let op_defs = read_command_definitions () in
489504
let permissions = read_permissions () in
490-
let () = Logs.debug @@ fun m -> m "Executing VyOS command [%s]" (String.concat " " args) in
505+
let () = Logs.debug @@ fun m -> m "Executing VyOS command [%s]" options.vyos_command in
491506
try
492507
check_command_permissions permissions args;
493508
Unix.setuid 0;
@@ -505,6 +520,12 @@ let () =
505520
| Incomplete_command ->
506521
Printf.fprintf stderr "Incomplete command: %s\n" options.vyos_command;
507522
exit 2
523+
| Sys_error msg ->
524+
Printf.fprintf stderr "System error: %s" msg;
525+
exit 255
526+
| Unix.Unix_error (err, func, _) ->
527+
Printf.fprintf stderr "Failed to execute Unix call %s: %s" func (Unix.error_message err);
528+
exit 255
508529
| Internal_error msg ->
509530
Printf.fprintf stderr "Internal error: %s\n" msg;
510531
exit 255

0 commit comments

Comments
 (0)