@@ -155,7 +155,7 @@ int aa_audit_file(struct aa_profile *profile, struct file_perms *perms,
*
* Returns: new permission mapping
*/
-static u32 map_old_perms(u32 old)
+u32 map_old_perms(u32 old)
{
u32 new = old & 0xf;
if (old & MAY_READ)
@@ -186,6 +186,8 @@ static inline void aa_free_file_rules(struct aa_file_rules *rules)
aa_free_domain_entries(&rules->trans);
}
+u32 map_old_perms(u32 old);
+
#define ACC_FMODE(x) (("\000\004\002\006"[(x)&O_ACCMODE]) | (((x) << 1) & 0x40))
/* from namei.c */
@@ -21,5 +21,6 @@
int aa_getprocattr(struct aa_profile *profile, char **string);
int aa_setprocattr_changehat(char *args, size_t size, int test);
int aa_setprocattr_changeprofile(char *fqname, bool onexec, int test);
+int aa_setprocattr_perm(char *fqname, size_t size);
#endif /* __AA_PROCATTR_H */
@@ -559,10 +559,6 @@ static int apparmor_setprocattr(struct task_struct *task, char *name,
args[size] = '\0';
}
- /* task can only write its own attributes */
- if (current != task)
- return -EACCES;
-
args = value;
args = strim(args);
command = strsep(&args, " ");
@@ -575,17 +571,25 @@ static int apparmor_setprocattr(struct task_struct *task, char *name,
arg_size = size - (args - (char *) value);
if (strcmp(name, "current") == 0) {
if (strcmp(command, "changehat") == 0) {
+ /* task can only write its own attributes */
+ if (current != task)
+ return -EACCES;
error = aa_setprocattr_changehat(args, arg_size,
!AA_DO_TEST);
} else if (strcmp(command, "permhat") == 0) {
error = aa_setprocattr_changehat(args, arg_size,
AA_DO_TEST);
} else if (strcmp(command, "changeprofile") == 0) {
+ /* task can only write its own attributes */
+ if (current != task)
+ return -EACCES;
error = aa_setprocattr_changeprofile(args, !AA_ONEXEC,
!AA_DO_TEST);
} else if (strcmp(command, "permprofile") == 0) {
error = aa_setprocattr_changeprofile(args, !AA_ONEXEC,
AA_DO_TEST);
+ } else if (strcmp(command, "perm") == 0) {
+ error = aa_setprocattr_perm(args, arg_size);
} else {
struct common_audit_data sa;
COMMON_AUDIT_DATA_INIT(&sa, NONE);
@@ -162,3 +162,37 @@ int aa_setprocattr_changeprofile(char *fqname, bool onexec, int test)
name = aa_split_fqname(fqname, &ns_name);
return aa_change_profile(ns_name, name, onexec, test);
}
+
+/**
+ * aa_setprocattr_perm - generic perm test can be used to determine transition
+ * @args: args from writting to /proc/<pid>/attr/current (NOT NULL)
+ * @size: size of the args
+ */
+int aa_setprocattr_perm(char *args, size_t size)
+{
+ struct aa_profile *profile;
+ char *permstr, *val = args;
+ u32 mask, perms;
+ unsigned int state;
+
+ if (!args)
+ return -EINVAL;
+ permstr = strsep(&val, " ");
+ if (!val)
+ return -EINVAL;
+ mask = simple_strtoul(permstr, NULL, 0);
+ size -= val - args;
+
+ profile = aa_current_profile();
+ if (profile->policy) {
+ state = aa_dfa_match_len(profile->policy, profile->policy_start,
+ args, size);
+ perms = map_old_perms(dfa_user_allow(profile->policy, state));
+ } else
+ perms = 0;
+
+ if (mask & ~perms)
+ return -EACCES;
+
+ return 0;
+}
The generic perm query replaces the remove perm_ipc. Also while only the current task may set its security context, allow any task with sufficient perms to query if the security context could be set. Signed-off-by: John Johansen <john.johansen@canonical.com> --- security/apparmor/file.c | 2 +- security/apparmor/include/file.h | 2 ++ security/apparmor/include/procattr.h | 1 + security/apparmor/lsm.c | 12 ++++++++---- security/apparmor/procattr.c | 34 ++++++++++++++++++++++++++++++++++ 5 files changed, 46 insertions(+), 5 deletions(-)