Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 113 additions & 36 deletions baseband_guard.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,18 @@ extern char *saved_command_line;
static const char *slot_suffix_from_cmdline(void)
{
const char *p = saved_command_line;
if (!p) return NULL;

if (!p)
return NULL;

p = strstr(p, "androidboot.slot_suffix=");
if (!p) return NULL;
if (!p)
return NULL;

p += strlen("androidboot.slot_suffix=");
if (p[0] == '_' && (p[1] == 'a' || p[1] == 'b')) return (p[1] == 'a') ? "_a" : "_b";
if (p[0] == '_' && (p[1] == 'a' || p[1] == 'b'))
return (p[1] == 'a') ? "_a" : "_b";

return NULL;
}

Expand All @@ -88,38 +95,55 @@ static bool inline resolve_byname_dev(const char *name, dev_t *out)
dev_t dev;
int ret;

if (!name || !out) return false;
if (!name || !out)
return false;

path = kasprintf(GFP_KERNEL, "%s/%s", BB_BYNAME_DIR, name);
if (!path) return false;
if (!path)
return false;

ret = lookup_bdev_compat(path, &dev);
kfree(path);
if (ret) return false;
if (ret)
return false;

*out = dev;

return true;
}

struct allow_node { dev_t dev; struct hlist_node h; };
struct allow_node {
dev_t dev;
struct hlist_node h;
};
DEFINE_HASHTABLE(allowed_devs, 7);

static bool allow_has(dev_t dev)
{
struct allow_node *p;
hash_for_each_possible(allowed_devs, p, h, (u64)dev)
if (p->dev == dev) return true;

hash_for_each_possible(allowed_devs, p, h, (u64)dev) {
if (p->dev == dev)
return true;
}

return false;
}

static void allow_add(dev_t dev)
{
struct allow_node *n;
if (!dev || allow_has(dev)) return;

if (!dev || allow_has(dev))
return;

n = kmalloc(sizeof(*n), GFP_ATOMIC);
if (!n) return;
if (!n)
return;

n->dev = dev;
hash_add(allowed_devs, &n->h, (u64)dev);

#if BB_DEBUG
bb_pr("allow-cache dev %u:%u\n", MAJOR(dev), MINOR(dev));
#endif
Expand All @@ -135,31 +159,42 @@ static inline bool is_allowed_partition_dev_resolve(dev_t cur)
const char *n = allowlist_names[i];
bool ok = false;

if (resolve_byname_dev(n, &dev) && dev == cur) return true;
if (resolve_byname_dev(n, &dev) && dev == cur)
return true;

if (!ok && suf) {
char *nm = kasprintf(GFP_ATOMIC, "%s%s", n, suf);
if (nm) {
ok = resolve_byname_dev(nm, &dev);
kfree(nm);
if (ok && dev == cur) return true;
if (ok && dev == cur)
return true;
}
}

if (!ok) {
char *na = kasprintf(GFP_ATOMIC, "%s_a", n);
char *nb = kasprintf(GFP_ATOMIC, "%s_b", n);

if (na) {
ok = resolve_byname_dev(na, &dev);
kfree(na);
if (ok && dev == cur) { if (nb) kfree(nb); return true; }
if (ok && dev == cur) {
if (nb)
kfree(nb);
return true;
}
}

if (nb) {
ok = resolve_byname_dev(nb, &dev);
kfree(nb);
if (ok && dev == cur) return true;
if (ok && dev == cur)
return true;
}
}
}

return false;
}

Expand All @@ -183,20 +218,25 @@ static bool is_zram_device(dev_t dev)
}

blkdev_put_compat(bdev, FMODE_READ, THIS_MODULE);

return is_zram;
}

static bool reverse_allow_match_and_cache(dev_t cur)
{
if (!cur) return false;
if (!cur)
return false;

if (is_zram_device(cur)) {
allow_add(cur);
return true;
}

if (is_allowed_partition_dev_resolve(cur)) {
allow_add(cur);
return true;
}

return false;
}

Expand All @@ -214,21 +254,31 @@ static bool current_domain_allowed(void)
size_t i;

#if BB_ANTI_SPOOF_NO_TRUST_PERMISSIVE_ONCE
if (unlikely(bbg_recently_permissive)) return false;
if (unlikely(bbg_recently_permissive))
return false;
#endif

security_cred_getsecid_compat(current_cred(), &sid);

if (!sid) return false;
if (security_secid_to_secctx(sid, &ctx, &len)) return false;
if (!ctx || !len) goto out;
if (!sid)
return false;

if (security_secid_to_secctx(sid, &ctx, &len))
return false;

if (!ctx || !len)
goto out;

for (i = 0; i < allowed_domain_substrings_cnt; i++) {
const char *needle = allowed_domain_substrings[i];
if (needle && *needle) {
if (strnstr(ctx, needle, len)) { ok = true; break; }
if (strnstr(ctx, needle, len)) {
ok = true;
break;
}
}
}

out:
security_release_secctx(ctx, len);
return ok;
Expand All @@ -240,32 +290,46 @@ static bool current_domain_allowed(void)
static const char *bbg_file_path(struct file *file, char *buf, int buflen)
{
char *p;
if (!file || !buf || buflen <= 0) return NULL;

if (!file || !buf || buflen <= 0)
return NULL;

buf[0] = '\0';
p = d_path(&file->f_path, buf, buflen);

return IS_ERR(p) ? NULL : p;
}

static int bbg_get_cmdline(char *buf, int buflen)
{
int n, i;
if (!buf || buflen <= 0) return 0;

if (!buf || buflen <= 0)
return 0;

n = get_cmdline(current, buf, buflen);
if (n <= 0) return 0;
for (i = 0; i < n - 1; i++) if (buf[i] == '\0') buf[i] = ' ';
if (n < buflen) buf[n] = '\0';
else buf[buflen - 1] = '\0';
if (n <= 0)
return 0;

for (i = 0; i < n - 1; i++) {
if (buf[i] == '\0')
buf[i] = ' ';
}

if (n < buflen)
buf[n] = '\0';
else
buf[buflen - 1] = '\0';

return n;
}

static void bbg_log_deny_detail(const char *why, struct file *file, unsigned int cmd_opt)
{
const int PATH_BUFLEN = 256;
const int CMD_BUFLEN = 256;

char *pathbuf = kmalloc(PATH_BUFLEN, GFP_ATOMIC);
char *cmdbuf = kmalloc(CMD_BUFLEN, GFP_ATOMIC);

const char *path = pathbuf ? bbg_file_path(file, pathbuf, PATH_BUFLEN) : NULL;
struct inode *inode = file ? file_inode(file) : NULL;
dev_t dev = inode ? inode->i_rdev : 0;
Expand Down Expand Up @@ -307,21 +371,29 @@ static void bbg_log_deny_detail(const char *why, struct file *file, unsigned int

static int deny(const char *why, struct file *file, unsigned int cmd_opt)
{
if (!BB_ENFORCING) return 0;
if (!BB_ENFORCING)
return 0;

bbg_log_deny_detail(why, file, cmd_opt);

bb_pr_rl("deny %s pid=%d comm=%s\n", why, current->pid, current->comm);

return -EPERM;
}

static int bb_file_permission(struct file *file, int mask)
{
struct inode *inode;

if (!(mask & MAY_WRITE)) return 0;
if (!file) return 0;
if (!(mask & MAY_WRITE))
return 0;

if (!file)
return 0;

inode = file_inode(file);
if (likely(!S_ISBLK(inode->i_mode))) return 0;
if (likely(!S_ISBLK(inode->i_mode)))
return 0;

if (likely(current_domain_allowed()))
return 0;
Expand Down Expand Up @@ -363,9 +435,12 @@ static int bb_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct inode *inode;

if (!file) return 0;
if (!file)
return 0;

inode = file_inode(file);
if (likely(!S_ISBLK(inode->i_mode))) return 0;
if (likely(!S_ISBLK(inode->i_mode)))
return 0;

if (!is_destructive_ioctl(cmd))
return 0;
Expand Down Expand Up @@ -414,7 +489,9 @@ DEFINE_LSM(baseband_guard) = {
#ifdef CONFIG_SECURITY_SELINUX_DEVELOP
int bbg_process_setpermissive(void) {
#if BB_ANTI_SPOOF_NO_TRUST_PERMISSIVE_ONCE
if (!bbg_recently_permissive) bbg_recently_permissive = true;
if (!bbg_recently_permissive)
bbg_recently_permissive = true;

return 0;
#elif BB_ANTI_SPOOF_DISABLE_PERMISSIVE
return 1;
Expand Down
Loading