Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

bpftool: Fix UAF in get_delegate_value

The return value ret pointer is pointing opts_copy, but opts_copy
gets freed in get_delegate_value before return, fix this by free
the mntent->mnt_opts strdup memory after show delegate value.

Fixes: 2d812311c2b2 ("bpftool: Add bpf_token show")
Signed-off-by: Tao Chen <chen.dylane@linux.dev>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Reviewed-by: Quentin Monnet <qmo@kernel.org>
Link: https://lore.kernel.org/bpf/20250919034816.1287280-2-chen.dylane@linux.dev

authored by

Tao Chen and committed by
Andrii Nakryiko
57cb2695 bce5749b

+37 -53
+37 -53
tools/bpf/bpftool/token.c
··· 20 20 21 21 #define MOUNTS_FILE "/proc/mounts" 22 22 23 + static struct { 24 + const char *header; 25 + const char *key; 26 + } sets[] = { 27 + {"allowed_cmds", "delegate_cmds"}, 28 + {"allowed_maps", "delegate_maps"}, 29 + {"allowed_progs", "delegate_progs"}, 30 + {"allowed_attachs", "delegate_attachs"}, 31 + }; 32 + 23 33 static bool has_delegate_options(const char *mnt_ops) 24 34 { 25 35 return strstr(mnt_ops, "delegate_cmds") || ··· 38 28 strstr(mnt_ops, "delegate_attachs"); 39 29 } 40 30 41 - static char *get_delegate_value(const char *opts, const char *key) 31 + static char *get_delegate_value(char *opts, const char *key) 42 32 { 43 33 char *token, *rest, *ret = NULL; 44 - char *opts_copy = strdup(opts); 45 34 46 - if (!opts_copy) 35 + if (!opts) 47 36 return NULL; 48 37 49 - for (token = strtok_r(opts_copy, ",", &rest); token; 38 + for (token = strtok_r(opts, ",", &rest); token; 50 39 token = strtok_r(NULL, ",", &rest)) { 51 40 if (strncmp(token, key, strlen(key)) == 0 && 52 41 token[strlen(key)] == '=') { ··· 53 44 break; 54 45 } 55 46 } 56 - free(opts_copy); 57 47 58 48 return ret; 59 49 } 60 50 61 - static void print_items_per_line(const char *input, int items_per_line) 51 + static void print_items_per_line(char *input, int items_per_line) 62 52 { 63 - char *str, *rest, *strs; 53 + char *str, *rest; 64 54 int cnt = 0; 65 55 66 56 if (!input) 67 57 return; 68 58 69 - strs = strdup(input); 70 - if (!strs) 71 - return; 72 - 73 - for (str = strtok_r(strs, ":", &rest); str; 59 + for (str = strtok_r(input, ":", &rest); str; 74 60 str = strtok_r(NULL, ":", &rest)) { 75 61 if (cnt % items_per_line == 0) 76 62 printf("\n\t "); ··· 73 69 printf("%-20s", str); 74 70 cnt++; 75 71 } 76 - 77 - free(strs); 78 72 } 79 73 80 74 #define ITEMS_PER_LINE 4 81 75 static void show_token_info_plain(struct mntent *mntent) 82 76 { 83 - char *value; 77 + size_t i; 84 78 85 79 printf("token_info %s", mntent->mnt_dir); 86 80 87 - printf("\n\tallowed_cmds:"); 88 - value = get_delegate_value(mntent->mnt_opts, "delegate_cmds"); 89 - print_items_per_line(value, ITEMS_PER_LINE); 81 + for (i = 0; i < ARRAY_SIZE(sets); i++) { 82 + char *opts, *value; 90 83 91 - printf("\n\tallowed_maps:"); 92 - value = get_delegate_value(mntent->mnt_opts, "delegate_maps"); 93 - print_items_per_line(value, ITEMS_PER_LINE); 84 + printf("\n\t%s:", sets[i].header); 85 + opts = strdup(mntent->mnt_opts); 86 + value = get_delegate_value(opts, sets[i].key); 87 + print_items_per_line(value, ITEMS_PER_LINE); 88 + free(opts); 89 + } 94 90 95 - printf("\n\tallowed_progs:"); 96 - value = get_delegate_value(mntent->mnt_opts, "delegate_progs"); 97 - print_items_per_line(value, ITEMS_PER_LINE); 98 - 99 - printf("\n\tallowed_attachs:"); 100 - value = get_delegate_value(mntent->mnt_opts, "delegate_attachs"); 101 - print_items_per_line(value, ITEMS_PER_LINE); 102 91 printf("\n"); 103 92 } 104 93 105 - static void split_json_array_str(const char *input) 94 + static void split_json_array_str(char *input) 106 95 { 107 - char *str, *rest, *strs; 96 + char *str, *rest; 108 97 109 98 if (!input) { 110 99 jsonw_start_array(json_wtr); ··· 105 108 return; 106 109 } 107 110 108 - strs = strdup(input); 109 - if (!strs) 110 - return; 111 - 112 111 jsonw_start_array(json_wtr); 113 - for (str = strtok_r(strs, ":", &rest); str; 112 + for (str = strtok_r(input, ":", &rest); str; 114 113 str = strtok_r(NULL, ":", &rest)) { 115 114 jsonw_string(json_wtr, str); 116 115 } 117 116 jsonw_end_array(json_wtr); 118 - 119 - free(strs); 120 117 } 121 118 122 119 static void show_token_info_json(struct mntent *mntent) 123 120 { 124 - char *value; 121 + size_t i; 125 122 126 123 jsonw_start_object(json_wtr); 127 - 128 124 jsonw_string_field(json_wtr, "token_info", mntent->mnt_dir); 129 125 130 - jsonw_name(json_wtr, "allowed_cmds"); 131 - value = get_delegate_value(mntent->mnt_opts, "delegate_cmds"); 132 - split_json_array_str(value); 126 + for (i = 0; i < ARRAY_SIZE(sets); i++) { 127 + char *opts, *value; 133 128 134 - jsonw_name(json_wtr, "allowed_maps"); 135 - value = get_delegate_value(mntent->mnt_opts, "delegate_maps"); 136 - split_json_array_str(value); 137 - 138 - jsonw_name(json_wtr, "allowed_progs"); 139 - value = get_delegate_value(mntent->mnt_opts, "delegate_progs"); 140 - split_json_array_str(value); 141 - 142 - jsonw_name(json_wtr, "allowed_attachs"); 143 - value = get_delegate_value(mntent->mnt_opts, "delegate_attachs"); 144 - split_json_array_str(value); 129 + jsonw_name(json_wtr, sets[i].header); 130 + opts = strdup(mntent->mnt_opts); 131 + value = get_delegate_value(opts, sets[i].key); 132 + split_json_array_str(value); 133 + free(opts); 134 + } 145 135 146 136 jsonw_end_object(json_wtr); 147 137 }