| @@ -200,6 +200,8 @@ static inline void seccomp_cache_prepare(struct seccomp_filter *sfilter) · 199 unmodified lines |
| 200 | * the filter can be freed. | 200 | * the filter can be freed. |
| 201 | * @cache: cache of arch/syscall mappings to actions | 201 | * @cache: cache of arch/syscall mappings to actions |
| 202 | * @log: true if all actions except for SECCOMP_RET_ALLOW should be logged | 202 | * @log: true if all actions except for SECCOMP_RET_ALLOW should be logged |
| | 203 | * @wait_killable_recv: Put notifying process in killable state once the |
| | 204 | * notification is received by the userspace listener. |
| 203 | * @prev: points to a previously installed, or inherited, filter | 205 | * @prev: points to a previously installed, or inherited, filter |
| 204 | * @prog: the BPF program to evaluate | 206 | * @prog: the BPF program to evaluate |
| 205 | * @notif: the struct that holds all notification related information | 207 | * @notif: the struct that holds all notification related information |
| @@ -220,6 +222,7 @@ struct seccomp_filter { · 14 unmodified lines |
| 220 | refcount_t refs; | 222 | refcount_t refs; |
| 221 | refcount_t users; | 223 | refcount_t users; |
| 222 | bool log; | 224 | bool log; |
| | 225 | bool wait_killable_recv; |
| 223 | struct action_cache cache; | 226 | struct action_cache cache; |
| 224 | struct seccomp_filter *prev; | 227 | struct seccomp_filter *prev; |
| 225 | struct bpf_prog *prog; | 228 | struct bpf_prog *prog; |
| @@ -893,6 +896,10 @@ static long seccomp_attach_filter(unsigned int flags, · 667 unmodified lines |
| 893 | if (flags & SECCOMP_FILTER_FLAG_LOG) | 896 | if (flags & SECCOMP_FILTER_FLAG_LOG) |
| 894 | filter->log = true; | 897 | filter->log = true; |
| 895 | | 898 | |
| | 899 | /* Set wait killable flag, if present. */ |
| | 900 | if (flags & SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV) |
| | 901 | filter->wait_killable_recv = true; |
| | 902 | |
| 896 | /* | 903 | /* |
| 897 | * If there is an existing filter, make it the prev and don't drop its | 904 | * If there is an existing filter, make it the prev and don't drop its |
| 898 | * task reference. | 905 | * task reference. |
| @@ -1080,6 +1087,12 @@ static void seccomp_handle_addfd(struct seccomp_kaddfd *addfd, struct seccomp_kn · 181 unmodified lines |
| 1080 | complete(&addfd->completion); | 1087 | complete(&addfd->completion); |
| 1081 | } | 1088 | } |
| 1082 | | 1089 | |
| | 1090 | static bool should_sleep_killable(struct seccomp_filter *match, |
| | 1091 | struct seccomp_knotif *n) |
| | 1092 | { |
| | 1093 | return match->wait_killable_recv && n->state == SECCOMP_NOTIFY_SENT; |
| | 1094 | } |
| | 1095 | |
| 1083 | static int seccomp_do_user_notification(int this_syscall, | 1096 | static int seccomp_do_user_notification(int this_syscall, |
| 1084 | struct seccomp_filter *match, | 1097 | struct seccomp_filter *match, |
| 1085 | const struct seccomp_data *sd) | 1098 | const struct seccomp_data *sd) |
| @@ -1110,11 +1123,25 @@ static int seccomp_do_user_notification(int this_syscall, · 24 unmodified lines |
| 1110 | * This is where we wait for a reply from userspace. | 1123 | * This is where we wait for a reply from userspace. |
| 1111 | */ | 1124 | */ |
| 1112 | do { | 1125 | do { |
| | 1126 | bool wait_killable = should_sleep_killable(match, &n); |
| | 1127 | |
| 1113 | mutex_unlock(&match->notify_lock); | 1128 | mutex_unlock(&match->notify_lock); |
| 1114 | err = wait_for_completion_interruptible(&n.ready); | 1129 | if (wait_killable) |
| | 1130 | err = wait_for_completion_killable(&n.ready); |
| | 1131 | else |
| | 1132 | err = wait_for_completion_interruptible(&n.ready); |
| 1115 | mutex_lock(&match->notify_lock); | 1133 | mutex_lock(&match->notify_lock); |
| 1116 | if (err != 0) | 1134 | |
| | 1135 | if (err != 0) { |
| | 1136 | /* |
| | 1137 | * Check to see if the notifcation got picked up and |
| | 1138 | * whether we should switch to wait killable. |
| | 1139 | */ |
| | 1140 | if (!wait_killable && should_sleep_killable(match, &n)) |
| | 1141 | continue; |
| | 1142 | |
| 1117 | goto interrupted; | 1143 | goto interrupted; |
| | 1144 | } |
| 1118 | | 1145 | |
| 1119 | addfd = list_first_entry_or_null(&n.addfd, | 1146 | addfd = list_first_entry_or_null(&n.addfd, |
| 1120 | struct seccomp_kaddfd, list); | 1147 | struct seccomp_kaddfd, list); |
| @@ -1484,6 +1511,9 @@ out: · 363 unmodified lines |
| 1484 | mutex_lock(&filter->notify_lock); | 1511 | mutex_lock(&filter->notify_lock); |
| 1485 | knotif = find_notification(filter, unotif.id); | 1512 | knotif = find_notification(filter, unotif.id); |
| 1486 | if (knotif) { | 1513 | if (knotif) { |
| | 1514 | /* Reset the process to make sure it's not stuck */ |
| | 1515 | if (should_sleep_killable(filter, knotif)) |
| | 1516 | complete(&knotif->ready); |
| 1487 | knotif->state = SECCOMP_NOTIFY_INIT; | 1517 | knotif->state = SECCOMP_NOTIFY_INIT; |
| 1488 | up(&filter->notif->request); | 1518 | up(&filter->notif->request); |
| 1489 | } | 1519 | } |
| @@ -1829,6 +1859,14 @@ static long seccomp_set_mode_filter(unsigned int flags, · 339 unmodified lines |
| 1829 | ((flags & SECCOMP_FILTER_FLAG_TSYNC_ESRCH) == 0)) | 1859 | ((flags & SECCOMP_FILTER_FLAG_TSYNC_ESRCH) == 0)) |
| 1830 | return -EINVAL; | 1860 | return -EINVAL; |
| 1831 | | 1861 | |
| | 1862 | /* |
| | 1863 | * The SECCOMP_FILTER_FLAG_WAIT_KILLABLE_SENT flag doesn't make sense |
| | 1864 | * without the SECCOMP_FILTER_FLAG_NEW_LISTENER flag. |
| | 1865 | */ |
| | 1866 | if ((flags & SECCOMP_FILTER_FLAG_WAIT_KILLABLE_RECV) && |
| | 1867 | ((flags & SECCOMP_FILTER_FLAG_NEW_LISTENER) == 0)) |
| | 1868 | return -EINVAL; |
| | 1869 | |
| 1832 | /* Prepare the new filter before holding any locks. */ | 1870 | /* Prepare the new filter before holding any locks. */ |
| 1833 | prepared = seccomp_prepare_user_filter(filter); | 1871 | prepared = seccomp_prepare_user_filter(filter); |
| 1834 | if (IS_ERR(prepared)) | 1872 | if (IS_ERR(prepared)) |