@@ -978,49 +978,68 @@ long prctl_set_seccomp(unsigned long seccomp_mode, char __user *filter)
978
978
}
979
979
980
980
#if defined(CONFIG_SECCOMP_FILTER ) && defined(CONFIG_CHECKPOINT_RESTORE )
981
- long seccomp_get_filter (struct task_struct * task , unsigned long filter_off ,
982
- void __user * data )
981
+ static struct seccomp_filter * get_nth_filter (struct task_struct * task ,
982
+ unsigned long filter_off )
983
983
{
984
- struct seccomp_filter * filter ;
985
- struct sock_fprog_kern * fprog ;
986
- long ret ;
987
- unsigned long count = 0 ;
988
-
989
- if (!capable (CAP_SYS_ADMIN ) ||
990
- current -> seccomp .mode != SECCOMP_MODE_DISABLED ) {
991
- return - EACCES ;
992
- }
984
+ struct seccomp_filter * orig , * filter ;
985
+ unsigned long count ;
993
986
987
+ /*
988
+ * Note: this is only correct because the caller should be the (ptrace)
989
+ * tracer of the task, otherwise lock_task_sighand is needed.
990
+ */
994
991
spin_lock_irq (& task -> sighand -> siglock );
992
+
995
993
if (task -> seccomp .mode != SECCOMP_MODE_FILTER ) {
996
- ret = - EINVAL ;
997
- goto out ;
994
+ spin_unlock_irq ( & task -> sighand -> siglock ) ;
995
+ return ERR_PTR ( - EINVAL ) ;
998
996
}
999
997
1000
- filter = task -> seccomp .filter ;
1001
- while (filter ) {
1002
- filter = filter -> prev ;
998
+ orig = task -> seccomp .filter ;
999
+ __get_seccomp_filter (orig );
1000
+ spin_unlock_irq (& task -> sighand -> siglock );
1001
+
1002
+ count = 0 ;
1003
+ for (filter = orig ; filter ; filter = filter -> prev )
1003
1004
count ++ ;
1004
- }
1005
1005
1006
1006
if (filter_off >= count ) {
1007
- ret = - ENOENT ;
1007
+ filter = ERR_PTR ( - ENOENT ) ;
1008
1008
goto out ;
1009
1009
}
1010
- count -= filter_off ;
1011
1010
1012
- filter = task -> seccomp .filter ;
1013
- while (filter && count > 1 ) {
1014
- filter = filter -> prev ;
1011
+ count -= filter_off ;
1012
+ for (filter = orig ; filter && count > 1 ; filter = filter -> prev )
1015
1013
count -- ;
1016
- }
1017
1014
1018
1015
if (WARN_ON (count != 1 || !filter )) {
1019
- /* The filter tree shouldn't shrink while we're using it. */
1020
- ret = - ENOENT ;
1016
+ filter = ERR_PTR (- ENOENT );
1021
1017
goto out ;
1022
1018
}
1023
1019
1020
+ __get_seccomp_filter (filter );
1021
+
1022
+ out :
1023
+ __put_seccomp_filter (orig );
1024
+ return filter ;
1025
+ }
1026
+
1027
+ long seccomp_get_filter (struct task_struct * task , unsigned long filter_off ,
1028
+ void __user * data )
1029
+ {
1030
+ struct seccomp_filter * filter ;
1031
+ struct sock_fprog_kern * fprog ;
1032
+ long ret ;
1033
+
1034
+ if (!capable (CAP_SYS_ADMIN ) ||
1035
+ current -> seccomp .mode != SECCOMP_MODE_DISABLED ) {
1036
+ return - EACCES ;
1037
+ }
1038
+
1039
+ filter = get_nth_filter (task , filter_off );
1040
+ if (IS_ERR (filter ))
1041
+ return PTR_ERR (filter );
1042
+
1024
1043
fprog = filter -> prog -> orig_prog ;
1025
1044
if (!fprog ) {
1026
1045
/* This must be a new non-cBPF filter, since we save
@@ -1035,17 +1054,11 @@ long seccomp_get_filter(struct task_struct *task, unsigned long filter_off,
1035
1054
if (!data )
1036
1055
goto out ;
1037
1056
1038
- __get_seccomp_filter (filter );
1039
- spin_unlock_irq (& task -> sighand -> siglock );
1040
-
1041
1057
if (copy_to_user (data , fprog -> filter , bpf_classic_proglen (fprog )))
1042
1058
ret = - EFAULT ;
1043
1059
1044
- __put_seccomp_filter (filter );
1045
- return ret ;
1046
-
1047
1060
out :
1048
- spin_unlock_irq ( & task -> sighand -> siglock );
1061
+ __put_seccomp_filter ( filter );
1049
1062
return ret ;
1050
1063
}
1051
1064
#endif
0 commit comments